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/__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/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..c8930b7c 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 { @@ -157,6 +158,8 @@ declare module "react-native-appsflyer" { setCollectIMEI(isCollect: boolean, successC?: SuccessCB): void setCollectAndroidID(isCollect: boolean, successC?: SuccessCB): void setDisableNetworkData(disable: boolean): void + startSdk(): 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;