Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 61 additions & 30 deletions .af-smoke/rc-test-plan.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"_meta": {
"plan_id": "reactnative-rc-smoke",
"plugin": "reactnative",
"version": "1.0.0",
"description": "Post-publish smoke plan for the AppsFlyer React Native plugin. Exercises SMOKE-001/002/003 against example_rc_smoke/, which pins react-native-appsflyer@<X.Y.Z-rcN> from npm. This plan never depends on plugin source.",
"version": "1.1.0",
"description": "Post-publish smoke plan for the AppsFlyer React Native plugin. Exercises SMOKE-001/002/003 (E2E-001/002/003 subset) against example_rc_smoke/, which pins react-native-appsflyer@<X.Y.Z-rcN|X.Y.Z-vN> from npm. This plan never depends on plugin source.",
"platforms": ["android", "ios"],
"schema_version": "1.0.0",
"tooling_contract_ref": "SMOKE-001, SMOKE-002, SMOKE-003"
Expand All @@ -28,33 +28,35 @@
"id": "phase_1",
"name": "Cold launch smoke (RC artifact)",
"scenario_ref": "SMOKE-001",
"description": "Fresh install using the npm-pinned RC build. Validates SDK startup, install conversion data, pre/post-start API markers, and standard events.",
"description": "Fresh install using the npm-pinned RC build. Validates SDK startup, install conversion data, pre/post-start API markers, and standard events. Shorter wait than E2E-001.",
"requires_fresh_install": true,
"requires_device_identity_reset": true,
"wait_after_launch_sec": 60,
"checks": [
{
"id": "sdk_started",
"description": "start returns a result",
"description": "start was called",
"type": "log_contains",
"pattern": "[AF_QA][start] result:",
"fail_action": "abort"
},
{
"id": "conversion_data",
"description": "registerConversionListener callback fires",
"id": "is_first_launch_true",
"description": "registerConversionListener fires with is_first_launch=true",
"type": "log_contains",
"pattern": "[AF_QA][CALLBACK][registerConversionListener]",
"payload_check": {"field": "is_first_launch", "expected": "true"},
"fail_action": "fail"
},
{
"id": "pre_start_complete",
"id": "pre_start_apis_complete",
"description": "Pre-start auto APIs ran",
"type": "log_contains",
"pattern": "[AF_QA][AUTO_APIS] --- Pre-start auto APIs complete ---",
"fail_action": "fail"
},
{
"id": "post_start_complete",
"id": "post_start_apis_complete",
"description": "Post-start auto APIs ran",
"type": "log_contains",
"pattern": "[AF_QA][AUTO_APIS] --- Post-start auto APIs complete ---",
Expand All @@ -69,10 +71,10 @@
"fail_action": "fail"
},
{
"id": "no_fatal",
"description": "No fatal exceptions or process crashes",
"id": "no_fatal_errors",
"description": "No fatal exceptions or SDK errors in logs",
"type": "absent",
"patterns": ["FATAL EXCEPTION", "Process crashed"],
"patterns": ["Fatal Exception", "FATAL EXCEPTION", "[AF_QA][start] error:"],
"fail_action": "fail"
}
]
Expand All @@ -82,7 +84,7 @@
"id": "phase_2",
"name": "Background deep link (RC artifact)",
"scenario_ref": "SMOKE-002",
"description": "Backgrounds the RC build after Phase 1. Deep link returns app to foreground. onDeepLinking fires with expected deep link value.",
"description": "App backgrounded after Phase 1, then deep link triggers re-entry. Verifies URL is delivered to native layer. onDeepLinking attribution (FOUND/value) requires real OneLink and is warn-only in CI.",
"requires_fresh_install": false,
"wait_after_trigger_sec": 15,
"deep_link_url": "afqa-reactnative://deeplink?deep_link_value=qa_deeplink_bg&af_sub1=background_test&pid=testmedia&c=deeplink_test",
Expand All @@ -96,24 +98,38 @@
},
"checks": [
{
"id": "deep_link_received",
"description": "onDeepLinking callback fires",
"id": "deeplink_url_received",
"description": "Deep link URL delivered to native app layer",
"type": "log_contains",
"pattern": "[AF_QA][CALLBACK][onDeepLinking]",
"pattern": "[AF_QA][DEEPLINK_NATIVE]",
"fail_action": "fail"
},
{
"id": "deep_link_value",
"description": "Deep link value matches qa_deeplink_bg",
"id": "deeplink_callback_fired",
"description": "onDeepLinking callback fires after deep link (any status)",
"type": "log_contains",
"pattern": "qa_deeplink_bg",
"pattern": "[AF_QA][CALLBACK][onDeepLinking]",
"fail_action": "fail"
},
{
"id": "no_fatal",
"id": "deeplink_status_found",
"description": "onDeepLinking fires with Status.FOUND (requires real OneLink attribution — expected to warn in CI)",
"type": "log_contains",
"pattern": "status=FOUND",
"fail_action": "warn"
},
{
"id": "deeplink_value_bg",
"description": "deepLinkValue matches qa_deeplink_bg (requires server-side attribution — expected to warn in CI)",
"type": "log_contains",
"pattern": "deepLinkValue=qa_deeplink_bg",
"fail_action": "warn"
},
{
"id": "no_fatal_errors",
"description": "No fatal exceptions after deep link",
"type": "absent",
"patterns": ["FATAL EXCEPTION", "Process crashed"],
"patterns": ["Fatal Exception", "FATAL EXCEPTION"],
"fail_action": "fail"
}
]
Expand All @@ -123,7 +139,7 @@
"id": "phase_3",
"name": "Foreground deep link (RC artifact)",
"scenario_ref": "SMOKE-003",
"description": "Fresh install of the RC build, then deep link while app is in foreground. Verifies SDK start and deep link callback.",
"description": "Fresh install of the RC build. App in foreground after SDK start, then deep link. Attribution checks (FOUND/value) are warn-only in CI.",
"requires_fresh_install": true,
"wait_after_launch_sec": 60,
"wait_after_trigger_sec": 15,
Expand All @@ -145,31 +161,46 @@
"fail_action": "abort"
},
{
"id": "deep_link_received",
"description": "onDeepLinking callback fires after foreground deep link",
"id": "deeplink_url_received",
"description": "Deep link URL delivered to native app layer",
"type": "log_contains",
"pattern": "[AF_QA][CALLBACK][onDeepLinking]",
"pattern": "[AF_QA][DEEPLINK_NATIVE]",
"fail_action": "fail"
},
{
"id": "deep_link_value",
"description": "Deep link value matches qa_deeplink_fg",
"id": "deeplink_callback_fired",
"description": "onDeepLinking callback fires after deep link (any status)",
"type": "log_contains",
"pattern": "qa_deeplink_fg",
"pattern": "[AF_QA][CALLBACK][onDeepLinking]",
"fail_action": "fail"
},
{
"id": "no_fatal",
"id": "deeplink_status_found",
"description": "onDeepLinking fires with Status.FOUND (requires real OneLink attribution — expected to warn in CI)",
"type": "log_contains",
"pattern": "status=FOUND",
"fail_action": "warn"
},
{
"id": "deeplink_value_fg",
"description": "deepLinkValue matches qa_deeplink_fg (requires server-side attribution — expected to warn in CI)",
"type": "log_contains",
"pattern": "deepLinkValue=qa_deeplink_fg",
"fail_action": "warn"
},
{
"id": "no_fatal_errors",
"description": "No fatal exceptions",
"type": "absent",
"patterns": ["FATAL EXCEPTION", "Process crashed"],
"patterns": ["Fatal Exception", "FATAL EXCEPTION"],
"fail_action": "fail"
}
]
}
],

"report": {
"output_dir": ".af-smoke/reports"
"output_dir": ".af-smoke/reports",
"format": "json"
}
}
2 changes: 1 addition & 1 deletion .claude/rules/native-android.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Emitted via `reactApplicationContext.emitDeviceEvent("RNAppsFlyer_rpcEvent", pay

## Build setup

`android/build.gradle` pins `af-android-plugin-bridge:7.0.12` explicitly — `af-android-sdk-bom:7.0.1` doesn't carry a matching version. `namespace` is declared for AGP 8.0+. `minSdkVersion` defaults to 21 — verify `plugin_bridge`'s own `minSdkVersion` is ≤21 before release.
`android/build.gradle` pins `af-android-plugin-bridge:7.0.13` explicitly — `af-android-sdk-bom:7.0.1` doesn't carry a matching version. `namespace` is declared for AGP 8.0+. `minSdkVersion` defaults to 21 — verify `plugin_bridge`'s own `minSdkVersion` is ≤21 before release.

`AppsFlyerRpcHandler`'s constructor takes `contextProvider: () -> Context`, not `context: Context` — a named-arg call using `context =` fails to compile. `RNAppsFlyerModule.kt` passes `contextProvider = { reactApplicationContext.currentActivity ?: reactApplicationContext }`, invoked fresh on every call (not cached), so `init()` can backfill a missed `onActivityResumed` transition instead of stalling session-ready.

Expand Down
2 changes: 1 addition & 1 deletion .claude/rules/release-versioning.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ Deprecated methods must keep working at runtime. Add a backward-compat test in `

## Tag convention

All tags use the `v` prefix (`v6.18.0`, `v7.0.2`, ...). `release.yml` tags every production release (`v$VERSION`) and every RC (`v$VERSION-rcN`).
All tags use the `v` prefix (`v6.18.0`, `v7.0.2`, `v7.0.2-v2`, ...). `release.yml` accepts `X.Y.Z-rcN` on the RC path, and `X.Y.Z` or `X.Y.Z-vN` on production. GitHub tags are always `v$VERSION` (so `7.0.2-v2` becomes `v7.0.2-v2`). `-vN` is part of the version identity and is not stripped on promote.

## Native SDK dependency update

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/rc-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ on:
workflow_dispatch:
inputs:
rc_version:
description: 'RC version to smoke, e.g. 6.18.0-rc1 (must exist on npm)'
description: 'RC version to smoke, e.g. 6.18.0-rc1 or 7.0.2-v2 (must exist on npm)'
required: true
type: string
release_branch:
Expand Down Expand Up @@ -117,8 +117,8 @@ jobs:
# published. Dry runs naturally fail the visibility poll below and
# emit a skipped check-run.
VERSION=$(node -p "require('./package.json').version")
if [[ ! "$VERSION" =~ -rc[0-9]+$ ]]; then
echo "package.json version is not an RC ($VERSION); skipping."
if [[ ! "$VERSION" =~ -(rc|v)[0-9]+$ ]]; then
echo "package.json version is not an RC or -vN tag ($VERSION); skipping."
echo "should_run=false" >> "$GITHUB_OUTPUT"
echo "skip_reason=not_rc_version" >> "$GITHUB_OUTPUT"
echo "rc_version=$VERSION" >> "$GITHUB_OUTPUT"
Expand Down
13 changes: 7 additions & 6 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ on:
- rc
- production
rn_version:
description: 'Plugin version (e.g., 6.18.0-rc1 for RC, 6.18.0 for production)'
description: 'Plugin version (e.g., 6.18.0-rc1 for RC, 6.18.0 or 7.0.2-v2 for production)'
required: true
type: string
ios_sdk_version:
Expand Down Expand Up @@ -610,12 +610,12 @@ jobs:
echo "Extracted version from package.json: $VERSION"
fi

# Validate version format (X.Y.Z, no -rc suffix for production)
if [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
# Validate version format (X.Y.Z or X.Y.Z-vN; no -rc suffix for production)
if [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+(-v[0-9]+)?$ ]]; then
echo "Valid production version format: $VERSION"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
else
echo "::error::Invalid production version format: $VERSION (expected X.Y.Z)"
echo "::error::Invalid production version format: $VERSION (expected X.Y.Z or X.Y.Z-vN)"
exit 1
fi

Expand Down Expand Up @@ -728,7 +728,7 @@ jobs:
if [[ "$TAG" == "rc" ]]; then
npm publish --tag rc --provenance
else
npm publish --provenance
npm publish --tag latest --provenance
fi
echo "Published $VERSION to npm"

Expand Down Expand Up @@ -1242,7 +1242,8 @@ jobs:
CI_JIRA_DOMAIN: ${{ secrets.CI_JIRA_DOMAIN }}
run: |
set +e
JIRA_FIX_VERSION="React Native SDK v$VERSION"
BASE_VERSION="${VERSION%%-v*}"
JIRA_FIX_VERSION="React Native SDK v$BASE_VERSION"

echo "Looking for Jira tickets with fix version: $JIRA_FIX_VERSION"

Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 7.0.2-v2
Release date: *2026-09-14*

- React Native >> `@appsflyer-sdk/js-core-plugin` 7.1.0
- React Native >> Android `af-android-plugin-bridge` 7.0.13
- React Native >> Added Android ID setters `setAndroidIdData`, `setImeiData`, and `setOaidData`

## 7.0.2
Release date: *2026-08-26*

Expand Down
65 changes: 63 additions & 2 deletions Docs/RN_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ The list of available methods for this plugin is described below.
- [enableFacebookDeferredApplinks](#enablefacebookdeferredapplinks)
- [Android Only APIs](#android-only-apis)
- [setCollectAndroidID](#setcollectandroidid)
- [setAndroidIdData](#setandroididdata)
- [setImeiData](#setimeidata)
- [setOaidData](#setoaiddata)
- [setCollectIMEI — removed in 7.0.0](#setcollectimei--removed-in-700)
- [setDisableNetworkData `setDisableNetworkData(isDisable)`](#setdisablenetworkdata-setdisablenetworkdataisdisable)
- [performDeepLinking](#performdeeplinking)
Expand Down Expand Up @@ -1199,10 +1202,68 @@ if (Platform.OS == 'android') {

---

### setAndroidIdData
`setAndroidIdData(params) : Promise<void>`

Explicitly send the Android ID to AppsFlyer. Call before `start()`.

| parameter | type | description |
| --------- | ------ | ------------------ |
| androidId | string | Android ID to send |

*Example:*

```javascript
if (Platform.OS == 'android') {
AppsFlyer.setAndroidIdData({ androidId: 'android-id-value' });
}
```

---

### setImeiData
`setImeiData(params) : Promise<void>`

Explicitly send the device IMEI to AppsFlyer. Call before `start()`.
This is the manual-IMEI setter; `setCollectIMEI` was removed in 7.0.0.

| parameter | type | description |
| --------- | ------ | ------------ |
| imei | string | IMEI to send |

*Example:*

```javascript
if (Platform.OS == 'android') {
AppsFlyer.setImeiData({ imei: 'imei-value' });
}
```

---

### setOaidData
`setOaidData(params) : Promise<void>`

Explicitly send the device OAID to AppsFlyer. Call before `start()`.

| parameter | type | description |
| --------- | ------ | ------------ |
| oaid | string | OAID to send |

*Example:*

```javascript
if (Platform.OS == 'android') {
AppsFlyer.setOaidData({ oaid: 'oaid-value' });
}
```

---

### setCollectIMEI — removed in 7.0.0

Android IMEI-collection opt-out has no RPC equivalent and is **removed** with no adapter
(IMEI collection has also been phased out at the OS level on modern Android versions). See
Android IMEI-collection opt-out has no RPC equivalent and is **removed**.
To pass IMEI yourself, use [setImeiData](#setimeidata). See
[MIGRATION.md](../MIGRATION.md#full-api-change-reference).

### setDisableNetworkData
Expand Down
Loading
Loading