diff --git a/.github/workflows/scripts/releaseNotesGenerator.sh b/.github/workflows/scripts/releaseNotesGenerator.sh
index 51419370..2c0f5897 100755
--- a/.github/workflows/scripts/releaseNotesGenerator.sh
+++ b/.github/workflows/scripts/releaseNotesGenerator.sh
@@ -2,7 +2,7 @@ JIRA_TOKEN=$1
JIRA_FIXED_VERSION=$2
fixed_version_found=false
-curl -X GET -H "Authorization: Basic $JIRA_TOKEN=" https://appsflyer.atlassian.net/rest/api/3/project/11400/versions | jq -r '.[] | .name+""+.id' | while read version ; do
+curl -X GET -H "Authorization: Basic $JIRA_TOKEN=" https://appsflyer.atlassian.net/rest/api/3/project/11723/versions | jq -r '.[] | .name+""+.id' | while read version ; do
if [[ "$version" == *"$JIRA_FIXED_VERSION"* ]] ;then
echo "$JIRA_FIXED_VERSION Found!"
fixed_version_found=true
diff --git a/.gitignore b/.gitignore
index 53d78edd..8cfdc82a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,6 +36,7 @@ local.properties
android/gradlew.bat
.vscode
android/gradle
+android/gradlew
android/.project
# node.js
@@ -50,7 +51,7 @@ buck-out/
android/app/libs
android/keystores/debug.keystore
-
+.watchmanconfig
coverage/
package-lock.json
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c751e6fd..c4625529 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,9 @@
+## 6.9.1
+ Release date: *2022-09-22*
+
+- React Native >> Support Deep Linking without calling startSDK()
+- React Native >> Separate between initSDK and startSDK
+
## 6.8.2
Release date: *2022-08-30*
diff --git a/Docs/API.md b/Docs/API.md
index 6c9ce367..64724432 100644
--- a/Docs/API.md
+++ b/Docs/API.md
@@ -4,6 +4,7 @@
The list of available methods for this plugin is described below.
- [Android & iOS APIs](#allAPI)
- [initSDK](#initSDK)
+ - [startSdk](#startSdk)
- [logEvent](#logEvent)
- [setCustomerUserId](#setCustomerUserId)
- [stop](#stop)
@@ -30,6 +31,7 @@ The list of available methods for this plugin is described below.
- [setCollectAndroidID](#setCollectAndroidID)
- [setCollectIMEI](#setCollectIMEI)
- [setDisableNetworkData](#setDisableNetworkData)
+ - [performOnDeepLinking](#performOnDeepLinking)
- [iOS Only APIs](#iOSOnly)
- [disableCollectASA](#disableCollectASA)
- [setUseReceiptValidationSandbox](#setUseReceiptValidationSandbox)
@@ -64,6 +66,7 @@ The dev key is required for all apps and the appID is required only for iOS.
{
console.log(res);
@@ -88,6 +92,44 @@ appsFlyer.initSdk(
}
);
```
+
+---
+
+##### **`startSdk()`**
+
+In version 6.9.1 of the react-native-appslfyer SDK we added the option of splitting between the initialization stage and start stage. All you need to do is add the property manualStart: true to the init object, and later call appsFlyer.startSdk() whenever you decide. If this property is set to false or doesn’t exist, the sdk will start after calling `appsFlyer.initSdk(...)`.
+
+*Example:*
+```javascript
+const option = {
+ isDebug: true,
+ devKey: 'UsxXxXxed',
+ appId: '75xXxXxXxXx11',
+ onInstallConversionDataListener: true,
+ onDeepLinkListener: true,
+ timeToWaitForATTUserAuthorization: 5,
+ manualStart: true, // <--- for manual start.
+};
+
+appsFlyer.initSdk(
+ option,
+ () => {
+ if (!option.manualStart) {
+ console.warn('AppsFlyer SDK started!');
+ } else {
+ console.warn('AppsFlyer SDK init, didn\'t send launch yet');
+ }
+ },
+ err => {
+ // handle error
+ },
+ );
+ //...
+ // app flow
+ //...
+
+ appsFlyer.startSdk(); // <--- Here we send launch
+```
---
##### **`logEvent(eventName, eventValues, success, error)`**
@@ -713,13 +755,57 @@ Use to opt-out of collecting the network operator name (carrier) and sim operato
*Example:*
-
```javascript
if (Platform.OS == 'android') {
appsFlyer.setDisableNetworkData(true);
}
```
+##### **`performOnDeepLinking()`**
+
+Enables manual triggering of deep link resolution. This method allows apps that are delaying the call to `appsFlyer.startSdk()` to resolve deep links before the SDK starts.
+Note:
This API will trigger the `appsFlyer.onDeepLink` callback. In the following example, we check if `res.deepLinkStatus` is equal to “FOUND” inside `appsFlyer.onDeepLink` callback to extract the deeplink parameters.
+
+*Example:*
+```javascript
+// Let's say we want the resolve a deeplink and get the deeplink params when the user clicks on it but delay the actual 'start' of the sdk (not sending launch to appsflyer).
+
+const option = {
+ isDebug: true,
+ devKey: 'UsxXxXxed',
+ appId: '75xXxXxXxXx11',
+ onInstallConversionDataListener: true,
+ onDeepLinkListener: true,
+ manualStart: true, // <--- for manual start.
+};
+
+const onDeepLink = appsFlyer.onDeepLink(res => {
+ if (res.deepLinkStatus == 'FOUND') {
+ // here we will get the deeplink params after resolving it.
+ // more flow...
+ }
+});
+
+appsFlyer.initSdk(
+ option,
+ () => {
+ if (!option.manualStart) {
+ console.warn('AppsFlyer SDK started!');
+ } else {
+ console.warn('AppsFlyer SDK init, didn\'t send launch yet');
+ }
+ },
+ () => {},
+);
+
+if (Platform.OS == 'android') {
+ appsFlyer.performOnDeepLinking();
+}
+
+// more app flow...
+
+appsFlyer.startSdk(); // <--- Here we send launch
+```
## iOS Only APIs
##### **`disableCollectASA(shouldDisable)`**
diff --git a/README.md b/README.md
index 909073ac..e2d90ed1 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@
### This plugin is built for
-- Android AppsFlyer SDK **v6.8.2**
+- Android AppsFlyer SDK **v6.9.1**
- iOS AppsFlyer SDK **v6.8.1**
## ❗❗ Breaking changes when updating to v6.x.x❗❗
diff --git a/__tests__/index.test.js b/__tests__/index.test.js
index c0f07d99..1d1553b6 100644
--- a/__tests__/index.test.js
+++ b/__tests__/index.test.js
@@ -205,6 +205,36 @@ describe("Test appsFlyer API's", () => {
appsFlyer.sendPushNotificationData({ foo: 'bar' });
expect(RNAppsFlyer.sendPushNotificationData).toHaveBeenCalledTimes(1);
});
+
+ test('it calls appsFlyer.appendParametersToDeepLinkingURL(dummy-url, foo)', () => {
+ appsFlyer.appendParametersToDeepLinkingURL('dummy-url', 'foo');
+ expect(RNAppsFlyer.appendParametersToDeepLinkingURL).toHaveBeenCalledTimes(0);
+ });
+
+ test('it calls appsFlyer.appendParametersToDeepLinkingURL(dummy-url, boolean)', () => {
+ appsFlyer.appendParametersToDeepLinkingURL('dummy-url', true);
+ expect(RNAppsFlyer.appendParametersToDeepLinkingURL).toHaveBeenCalledTimes(0);
+ });
+
+ test('it calls appsFlyer.appendParametersToDeepLinkingURL(dummy-url, {})', () => {
+ appsFlyer.appendParametersToDeepLinkingURL('dummy-url', {});
+ expect(RNAppsFlyer.appendParametersToDeepLinkingURL).toHaveBeenCalledTimes(1);
+ });
+
+ test('it calls appsFlyer.setDisableNetworkData(true)', () => {
+ appsFlyer.setDisableNetworkData(true);
+ expect(RNAppsFlyer.setDisableNetworkData).toHaveBeenCalledTimes(1);
+ });
+
+ test('it calls appsFlyer.startSdk()', () => {
+ appsFlyer.startSdk();
+ expect(RNAppsFlyer.startSdk).toHaveBeenCalledTimes(1);
+ });
+
+ test('it calls appsFlyer.performOnDeepLinking()', () => {
+ appsFlyer.performOnDeepLinking();
+ expect(RNAppsFlyer.performOnDeepLinking).toHaveBeenCalledTimes(1);
+ });
});
describe('Test native event emitter', () => {
diff --git a/__tests__/setup.js b/__tests__/setup.js
index e6bca2ed..2f18beb7 100644
--- a/__tests__/setup.js
+++ b/__tests__/setup.js
@@ -18,6 +18,10 @@ jest.mock('../node_modules/react-native/Libraries/BatchedBridge/NativeModules',
setSharingFilterForPartners: jest.fn(),
setCurrentDeviceLanguage: jest.fn(),
sendPushNotificationData: jest.fn(),
+ appendParametersToDeepLinkingURL: jest.fn(),
+ setDisableNetworkData: jest.fn(),
+ performOnDeepLinking: jest.fn(),
+ startSdk: jest.fn(),
},
};
});
diff --git a/android/build.gradle b/android/build.gradle
index 519d65c1..fe4a34e7 100755
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -54,5 +54,5 @@ repositories {
dependencies {
implementation "com.facebook.react:react-native:${safeExtGet('reactNativeVersion', '+')}"
implementation "com.android.installreferrer:installreferrer:${safeExtGet('installReferrerVersion', '2.1')}"
- implementation "com.appsflyer:af-android-sdk:${safeExtGet('appsflyerVersion', '6.8.2')}"
+ implementation "com.appsflyer:af-android-sdk:${safeExtGet('appsflyerVersion', '6.9.1')}"
}
diff --git a/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerModule.java b/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerModule.java
index b670d380..82264b99 100755
--- a/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerModule.java
+++ b/android/src/main/java/com/appsflyer/reactnative/RNAppsFlyerModule.java
@@ -50,11 +50,13 @@ public class RNAppsFlyerModule extends ReactContextBaseJavaModule {
private ReactApplicationContext reactContext;
private Application application;
+ private String personalDevKey;
public RNAppsFlyerModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
this.application = (Application) reactContext.getApplicationContext();
+ this.personalDevKey = "";
}
@Override
@@ -128,6 +130,7 @@ private String callSdkInternal(ReadableMap _options) {
boolean isDebug;
boolean isConversionData;
boolean isDeepLinking;
+ boolean isManualStartMode;
AppsFlyerLib instance = AppsFlyerLib.getInstance();
JSONObject options = RNUtil.readableMapToJson(_options);
@@ -135,6 +138,8 @@ private String callSdkInternal(ReadableMap _options) {
if (devKey.trim().equals("")) {
return NO_DEVKEY_FOUND;
}
+ this.personalDevKey = devKey;
+
isDebug = options.optBoolean(afIsDebug, false);
instance.setDebugLog(isDebug);
@@ -143,22 +148,15 @@ private String callSdkInternal(ReadableMap _options) {
Log.d("AppsFlyer", "Starting SDK");
}
isDeepLinking = options.optBoolean(afDeepLink, false);
+ isManualStartMode = options.optBoolean("manualStart", false);
instance.init(devKey, (isConversionData == true) ? registerConversionListener() : null, application.getApplicationContext());
if (isDeepLinking) {
instance.subscribeForDeepLink(registerDeepLinkListener());
}
- Intent intent = null;
- Activity currentActivity = getCurrentActivity();
- if (currentActivity != null) {
- // register for lifecycle with Activity (automatically fetching deeplink from Activity if present)
- instance.start(currentActivity, devKey);
- } else {
- // register for lifecycle with Application (cannot fetch deeplink without access to the Activity,
- // also sending first session manually)
- instance.logEvent(application, null, null);
- instance.start(application, devKey);
+ if (!isManualStartMode) {
+ startSdk();
}
return null;
}
@@ -262,6 +260,20 @@ private void sendEvent(ReactContext reactContext,
.emit(eventName, params);
}
+ @ReactMethod
+ public void startSdk() {
+ Activity currentActivity = getCurrentActivity();
+ if (currentActivity != null) {
+ // register for lifecycle with Activity (automatically fetching deeplink from Activity if present)
+ AppsFlyerLib.getInstance().start(currentActivity, this.personalDevKey);
+ } else {
+ // register for lifecycle with Application (cannot fetch deeplink without access to the Activity,
+ // also sending first session manually)
+ AppsFlyerLib.getInstance().logEvent(this.application, null, null);
+ AppsFlyerLib.getInstance().start(this.application, this.personalDevKey);
+ }
+ }
+
@ReactMethod
public void logEvent(
final String eventName, ReadableMap eventData,
@@ -766,6 +778,21 @@ public void appendParametersToDeepLinkingURL(String contains, ReadableMap parame
public void setDisableNetworkData(Boolean disabled) {
AppsFlyerLib.getInstance().setDisableNetworkData(disabled);
}
+
+ @ReactMethod
+ public void performOnDeepLinking() {
+ Activity activity = getCurrentActivity();
+ if (activity != null) {
+ Intent intent = activity.getIntent();
+ if (intent != null) {
+ AppsFlyerLib.getInstance().performOnDeepLinking(intent, this.application);
+ } else {
+ Log.d("AppsFlyer", "performOnDeepLinking: intent is null!");
+ }
+ } else{
+ Log.d("AppsFlyer", "performOnDeepLinking: activity is null!");
+ }
+ }
@ReactMethod
public void addListener(String eventName) {
diff --git a/index.d.ts b/index.d.ts
index ec14a6f1..3e2a03f2 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -79,6 +79,7 @@ declare module "react-native-appsflyer" {
onInstallConversionDataListener?: boolean;
onDeepLinkListener?: boolean;
timeToWaitForATTUserAuthorization?: number; // iOS only
+ manualStart?: boolean
}
export interface InAppPurchase {
@@ -142,6 +143,7 @@ declare module "react-native-appsflyer" {
setSharingFilterForPartners(partners: string[]): void
setPartnerData(partnerId: string, partnerData: object): void
appendParametersToDeepLinkingURL(contains: string, parameters: object): void
+ startSdk(): void
/**
* For iOS Only
@@ -157,6 +159,7 @@ declare module "react-native-appsflyer" {
setCollectIMEI(isCollect: boolean, successC?: SuccessCB): void
setCollectAndroidID(isCollect: boolean, successC?: SuccessCB): void
setDisableNetworkData(disable: boolean): void
+ performOnDeepLinking(): void
};
export default appsFlyer;
diff --git a/index.js b/index.js
index a8cbb8b3..f0e703f2 100755
--- a/index.js
+++ b/index.js
@@ -608,6 +608,14 @@ appsFlyer.setDisableNetworkData = (disable) => {
return RNAppsFlyer.setDisableNetworkData(disable);
};
+appsFlyer.startSdk = () => {
+ return RNAppsFlyer.startSdk();
+};
+
+appsFlyer.performOnDeepLinking = () => {
+ return RNAppsFlyer.performOnDeepLinking();
+};
+
function AFParseJSONException(_message, _data) {
this.message = _message;
this.data = _data;
diff --git a/ios/RNAppsFlyer.h b/ios/RNAppsFlyer.h
index 919a096a..143c38bd 100755
--- a/ios/RNAppsFlyer.h
+++ b/ios/RNAppsFlyer.h
@@ -18,6 +18,7 @@
@interface RNAppsFlyer: RCTEventEmitter
+@property (readwrite, nonatomic) BOOL isManualStart;
@end
diff --git a/ios/RNAppsFlyer.m b/ios/RNAppsFlyer.m
index b9c6376b..b25c3d14 100755
--- a/ios/RNAppsFlyer.m
+++ b/ios/RNAppsFlyer.m
@@ -38,6 +38,7 @@ -(NSError *) callSdkInternal:(NSDictionary*)initSdkOptions {
BOOL isDebug = NO;
BOOL isConversionData = YES;
BOOL isDeepLinking = NO;
+ BOOL isManualStart = NO;
NSNumber* interval = 0;
if (![initSdkOptions isKindOfClass:[NSNull class]]) {
@@ -48,6 +49,8 @@ -(NSError *) callSdkInternal:(NSDictionary*)initSdkOptions {
devKey = (NSString*)[initSdkOptions objectForKey: afDevKey];
appId = (NSString*)[initSdkOptions objectForKey: afAppId];
interval = (NSNumber*)[initSdkOptions objectForKey: timeToWaitForATTUserAuthorization];
+ isManualStart = [[initSdkOptions objectForKey:@"manualStart"] boolValue];
+ [self setIsManualStart:isManualStart];
isDebugValue = [initSdkOptions objectForKey: afIsDebug];
if ([isDebugValue isKindOfClass:[NSNumber class]]) {
@@ -103,11 +106,18 @@ -(NSError *) callSdkInternal:(NSDictionary*)initSdkOptions {
selector:@selector(sendLaunch:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
- [[AppsFlyerLib shared] start];
+ if (!isManualStart) {
+ [[AppsFlyerLib shared] start];
+ }
return nil;
}
}
+RCT_EXPORT_METHOD(startSdk) {
+ [self setIsManualStart:NO];
+ [[AppsFlyerLib shared] start];
+}
+
RCT_EXPORT_METHOD(logEvent: (NSString *)eventName eventValues:(NSDictionary *)eventValues
successCallback :(RCTResponseSenderBlock)successCallback
errorCallback:(RCTResponseSenderBlock)errorCallback) {
@@ -213,7 +223,9 @@ -(NSError *) callSdkInternal:(NSDictionary*)initSdkOptions {
-(void)sendLaunch:(UIApplication *)application {
[[NSNotificationCenter defaultCenter] postNotificationName:RNAFBridgeInitializedNotification object:self];
- [[AppsFlyerLib shared] start];
+ if (![self isManualStart]) {
+ [[AppsFlyerLib shared] start];
+ }
}
RCT_EXPORT_METHOD(setAdditionalData: (NSDictionary *)additionalData callback:(RCTResponseSenderBlock)callback) {
diff --git a/package.json b/package.json
index 98f23350..90355d29 100755
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-native-appsflyer",
- "version": "6.8.2",
+ "version": "6.9.1",
"description": "React Native Appsflyer plugin",
"main": "index.js",
"types": "index.d.ts",