mergn-react-native 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +44 -0
  2. package/README.md +131 -0
  3. package/android/build.gradle +66 -0
  4. package/android/src/main/java/com/mergn/reactnative/MergnModule.java +152 -0
  5. package/android/src/main/java/com/mergn/reactnative/MergnPackage.java +31 -0
  6. package/app.plugin.js +2 -0
  7. package/docs/ANDROID.md +147 -0
  8. package/docs/IOS.md +156 -0
  9. package/docs/MIGRATION.md +365 -0
  10. package/ios/MergnModule.swift +149 -0
  11. package/ios/MergnModuleBridge.m +14 -0
  12. package/ios/MergnNotificationHandler.swift +160 -0
  13. package/ios/NotificationService/Info.plist +31 -0
  14. package/ios/NotificationService/NotificationService.swift +82 -0
  15. package/mergn-react-native.podspec +32 -0
  16. package/package.json +49 -0
  17. package/plugin/index.js +219 -0
  18. package/react-native.config.js +19 -0
  19. package/scripts/release-ios.sh +79 -0
  20. package/scripts/verify-package.js +58 -0
  21. package/sdk/MergnSDK.podspec +28 -0
  22. package/sdk/mergn_ios.xcframework/Info.plist +44 -0
  23. package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/Info.plist +0 -0
  24. package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios.abi.json +2517 -0
  25. package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios.private.swiftinterface +82 -0
  26. package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  27. package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios.swiftinterface +82 -0
  28. package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/mergn_ios +0 -0
  29. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Info.plist +0 -0
  30. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios-simulator.abi.json +2517 -0
  31. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +82 -0
  32. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  33. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios-simulator.swiftinterface +82 -0
  34. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Modules/mergn_ios.swiftmodule/x86_64-apple-ios-simulator.abi.json +2517 -0
  35. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Modules/mergn_ios.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +82 -0
  36. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Modules/mergn_ios.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  37. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Modules/mergn_ios.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +82 -0
  38. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/_CodeSignature/CodeResources +101 -0
  39. package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/mergn_ios +0 -0
  40. package/src/index.d.ts +37 -0
  41. package/src/index.js +34 -0
package/LICENSE ADDED
@@ -0,0 +1,44 @@
1
+ MERGN React Native SDK — License Agreement
2
+
3
+ Copyright (c) 2026 MERGN. All rights reserved.
4
+
5
+ 1. Grant of License
6
+ MERGN grants you a non-exclusive, non-transferable, revocable license to
7
+ install and use this package (the "Software"), including the MERGN mobile
8
+ SDK binaries distributed with or referenced by it, solely to integrate
9
+ MERGN services into your own applications.
10
+
11
+ 2. Restrictions
12
+ You may not:
13
+ (a) reverse engineer, decompile, or disassemble the SDK binaries, except to
14
+ the extent such restriction is prohibited by applicable law;
15
+ (b) redistribute, sublicense, sell, or rent the Software as a standalone
16
+ product, or as part of any product that competes with MERGN;
17
+ (c) remove or alter any copyright, trademark, or proprietary notice.
18
+
19
+ Redistributing the Software as an embedded component of your own
20
+ application is permitted and expected.
21
+
22
+ 3. Ownership
23
+ MERGN retains all right, title, and interest in the Software. This license
24
+ conveys no ownership.
25
+
26
+ 4. Third-Party Components
27
+ The Software depends on third-party open-source components, each governed
28
+ by its own license. Those licenses are unaffected by this agreement.
29
+
30
+ 5. No Warranty
31
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
34
+
35
+ 6. Limitation of Liability
36
+ IN NO EVENT SHALL MERGN BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER
37
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING
38
+ FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE OR ITS USE.
39
+
40
+ 7. Termination
41
+ This license terminates automatically if you breach any term. On
42
+ termination you must cease use and remove the Software from your products.
43
+
44
+ For commercial terms, support, or questions: https://mergn.com
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # mergn-react-native
2
+
3
+ MERGN SDK for React Native. One JS API, native SDKs on both platforms.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm install mergn-react-native
9
+ ```
10
+
11
+ Add the plugin to `app.json`:
12
+
13
+ ```json
14
+ {
15
+ "expo": {
16
+ "plugins": ["mergn-react-native"]
17
+ }
18
+ }
19
+ ```
20
+
21
+ Then rebuild the native projects:
22
+
23
+ ```sh
24
+ npx expo prebuild
25
+ npx expo run:android
26
+ npx expo run:ios # macOS only
27
+ ```
28
+
29
+ That's it. The Android `.aar` and the iOS `.xcframework` ship inside this
30
+ package, and autolinking registers the native module — you do not edit
31
+ `MainApplication`, `settings.gradle`, or the `Podfile`.
32
+
33
+ > **Expo Go will not work.** This package contains native code, so it needs a
34
+ > development build (`expo run:*`) or an EAS build.
35
+
36
+ ## Usage
37
+
38
+ ```js
39
+ import Mergn from "mergn-react-native";
40
+
41
+ // Once, as early as possible — pending events are dropped until this resolves.
42
+ await Mergn.registerApi("YOUR_MERGN_API_KEY");
43
+
44
+ await Mergn.performEvent("Collection Viewed", { title: "Beauty" });
45
+ await Mergn.setAttribute("Email", "user@example.com");
46
+ await Mergn.login("user@example.com");
47
+ await Mergn.setFirebaseToken(fcmToken);
48
+ ```
49
+
50
+ Every method returns a Promise resolving to a status string from the native SDK.
51
+ Identical method names, arguments and results on Android and iOS.
52
+
53
+ | Method | Purpose |
54
+ | --- | --- |
55
+ | `registerApi(apiKey)` | Register your API key. Call first. |
56
+ | `performEvent(name, props?)` | Record an event. |
57
+ | `setAttribute(name, value)` | Set a user attribute. |
58
+ | `login(id)` | Identify the user. |
59
+ | `setFirebaseToken(token)` | Give MERGN the push token. |
60
+ | `setAppContext(token)` | Currently the same path as `setFirebaseToken`. |
61
+
62
+ ### `setAttribute` de-duplicates
63
+
64
+ Sending the same value twice for one attribute is a deliberate no-op in the SDK
65
+ ("value is same as previous"). Use a changed value when testing.
66
+
67
+ ## Push notifications
68
+
69
+ You need Firebase configured in your own app — this package does not bundle it.
70
+
71
+ ```sh
72
+ npx expo install @react-native-firebase/app @react-native-firebase/messaging
73
+ ```
74
+
75
+ - **Android:** put `google-services.json` in your project and configure the
76
+ Firebase plugin. This package's config plugin already declares MERGN's
77
+ messaging service and the notification permissions.
78
+ - **iOS:** add `GoogleService-Info.plist`, upload an APNs key to Firebase, and
79
+ add the push capability. Register the app's bundle ID in Firebase.
80
+
81
+ Pass the token you get from `messaging().getToken()` to
82
+ `Mergn.setFirebaseToken(token)`.
83
+
84
+ ### Rich push images on iOS (optional)
85
+
86
+ iOS only renders a notification image if the app contains a **Notification
87
+ Service Extension** — a separate binary that must be a target of your app, so
88
+ no library can provide it. Without one, a push carrying `mutable-content: 1`
89
+ and an `image` URL still arrives, just as text.
90
+
91
+ To add it: **Xcode → File → New → Target → Notification Service Extension**,
92
+ then copy the implementation from
93
+ `node_modules/mergn-react-native/ios/NotificationService/NotificationService.swift`.
94
+ Set the extension's deployment target to match your app (it must not be higher).
95
+
96
+ Android needs nothing here — MERGN's SDK handles images itself.
97
+
98
+ ## Platform guides
99
+
100
+ | | |
101
+ | --- | --- |
102
+ | [docs/ANDROID.md](docs/ANDROID.md) | Android setup, push, popups, troubleshooting |
103
+ | [docs/IOS.md](docs/IOS.md) | iOS setup, push, rich images, troubleshooting |
104
+ | [docs/MIGRATION.md](docs/MIGRATION.md) | **Upgrading from a manual integration — read this first if you copied MergnModule.java into your app** |
105
+
106
+ ## Requirements
107
+
108
+ | | |
109
+ | --- | --- |
110
+ | iOS | 14.0+ |
111
+ | Android | minSdk 24+ |
112
+ | React Native | 0.72+ |
113
+ | Expo | SDK 50+ |
114
+
115
+ ## Troubleshooting
116
+
117
+ **`MergnModule.<method> is unavailable`** — the native module did not load.
118
+ Rebuild (`npx expo prebuild && npx expo run:ios`). Expo Go cannot load it.
119
+
120
+ **`pod install` fails with "Unable to find compatibility version string for
121
+ object version 70"** — newer Xcode writes a project format older CocoaPods
122
+ cannot read. This package's config plugin pins it; make sure the plugin is in
123
+ your `app.json` and re-run `npx expo prebuild`. Or update CocoaPods.
124
+
125
+ **iOS build fails with "Cycle inside <YourApp>"** — caused by
126
+ `@react-native-firebase`'s script phase once an app extension is embedded. The
127
+ config plugin fixes this too; ensure it is listed in `app.json`.
128
+
129
+ **Events reach the SDK but nothing appears in the dashboard** — check
130
+ `registerApi` resolved before you sent them, and confirm your API key and
131
+ bundle ID / package name are provisioned in your MERGN account.
@@ -0,0 +1,66 @@
1
+ // Android library module for mergn-react-native.
2
+ // React Native autolinking discovers this via react-native.config.js, so the
3
+ // client never edits settings.gradle or app/build.gradle.
4
+ buildscript {
5
+ repositories { google(); mavenCentral() }
6
+ dependencies { classpath 'com.android.tools.build:gradle:8.1.1' }
7
+ }
8
+
9
+ apply plugin: 'com.android.library'
10
+
11
+ def safeExtGet(prop, fallback) {
12
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
13
+ }
14
+
15
+ android {
16
+ namespace 'com.mergn.reactnative'
17
+ compileSdk safeExtGet('compileSdkVersion', 34)
18
+
19
+ defaultConfig {
20
+ minSdk safeExtGet('minSdkVersion', 24)
21
+ targetSdk safeExtGet('targetSdkVersion', 34)
22
+ }
23
+
24
+ compileOptions {
25
+ sourceCompatibility JavaVersion.VERSION_17
26
+ targetCompatibility JavaVersion.VERSION_17
27
+ }
28
+
29
+ lintOptions { abortOnError false }
30
+ }
31
+
32
+ repositories {
33
+ google()
34
+ mavenCentral()
35
+ // The Mergn Android SDK is published here.
36
+ maven { url 'https://jitpack.io' }
37
+ }
38
+
39
+ dependencies {
40
+ implementation 'com.facebook.react:react-android'
41
+
42
+ // Resolved from JitPack rather than a bundled .aar, so the binary does not
43
+ // ship inside this npm package.
44
+ implementation "com.github.SHamzaHMergn:Mergn_sdk_android:${safeExtGet('mergnSdkVersion', '5.2.4')}"
45
+
46
+ // The SDK's POM was generated by `install:install-file` and declares NO
47
+ // dependencies, so Gradle cannot resolve them transitively - they must be
48
+ // listed here or the app fails at runtime with NoClassDefFoundError.
49
+ // This list was derived by disassembling the .aar (javap over classes.jar):
50
+ // androidx.room + sqlite - local event/attribute persistence
51
+ // androidx.work - periodic upload worker
52
+ // androidx.core - notification building
53
+ // kotlin stdlib/coroutines- the SDK is written in Kotlin
54
+ // gson - payload serialisation (85 references)
55
+ // firebase-messaging - FireBaseMessagingService, declared in our manifest
56
+ implementation "androidx.room:room-runtime:${safeExtGet('roomVersion', '2.6.1')}"
57
+ implementation "androidx.work:work-runtime-ktx:${safeExtGet('workVersion', '2.9.0')}"
58
+ implementation 'androidx.core:core-ktx:1.13.1'
59
+ implementation 'androidx.appcompat:appcompat:1.6.1'
60
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1'
61
+ implementation 'com.google.code.gson:gson:2.10.1'
62
+
63
+ // compileOnly: the host app supplies its own Firebase version via
64
+ // google-services, and pinning one here would risk a conflict.
65
+ compileOnly 'com.google.firebase:firebase-messaging:23.4.1'
66
+ }
@@ -0,0 +1,152 @@
1
+ package com.mergn.reactnative;
2
+
3
+ import android.app.Activity;
4
+ import android.app.Application;
5
+ import android.content.Context;
6
+ import android.util.Log;
7
+
8
+ import com.facebook.react.bridge.Promise;
9
+ import com.facebook.react.bridge.ReactApplicationContext;
10
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
11
+ import com.facebook.react.bridge.ReactMethod;
12
+ import com.mergn.insights.classes.AttributeManager;
13
+ import com.mergn.insights.classes.EventManager;
14
+ import com.mergn.insights.classes.MergnContext;
15
+ import com.mergn.insights.classes.MergnSDK;
16
+
17
+ import org.json.JSONObject;
18
+
19
+ import java.util.HashMap;
20
+ import java.util.Iterator;
21
+ import java.util.Map;
22
+
23
+ public class MergnModule extends ReactContextBaseJavaModule {
24
+ private static final String TAG = "MergnModule";
25
+ private static final String ACTION_REGISTER_API = "register_api";
26
+ private static final String ACTION_PERFORM_EVENT = "perform_event";
27
+ private static final String ACTION_SET_ATTRIBUTE = "add_attribute";
28
+ private static final String ACTION_LOGIN = "login_mergn";
29
+ private static final String ACTION_FIREBASE_TOKEN_MERGN = "firebase_token_mergn";
30
+ private static final String MERGN_APP_CONTEXT = "mergn_app_context";
31
+
32
+ // MergnSDK.initialize registers activity lifecycle callbacks, so calling it on
33
+ // every register_api would stack duplicate listeners.
34
+ private static boolean sdkInitialized = false;
35
+
36
+ private final EventManager eventManager = new EventManager();
37
+ private final AttributeManager attributeManager = new AttributeManager();
38
+
39
+ public MergnModule(ReactApplicationContext reactContext) {
40
+ super(reactContext);
41
+ }
42
+
43
+ @Override
44
+ public String getName() {
45
+ return "MergnModule";
46
+ }
47
+
48
+ @ReactMethod
49
+ public void performAction(String action, String jsonData, Promise promise) {
50
+ try {
51
+ JSONObject options = new JSONObject(jsonData);
52
+
53
+ ReactApplicationContext appCtx = getReactApplicationContext();
54
+ Activity activity = getCurrentActivity();
55
+ Log.d(TAG, "Received Action: " + action
56
+ + " | activity=" + (activity == null ? "NULL" : "present"));
57
+ // The SDK renders in-app popups, which need an Activity. Fall back to the
58
+ // application context so backgrounded calls still record instead of failing.
59
+ Context uiCtx = activity != null ? activity : appCtx;
60
+
61
+ switch (action) {
62
+ case ACTION_REGISTER_API: {
63
+ String apiKey = options.getString("apiKey");
64
+ if (!sdkInitialized) {
65
+ MergnSDK.initialize((Application) appCtx.getApplicationContext());
66
+ sdkInitialized = true;
67
+ }
68
+ if (activity != null) {
69
+ MergnContext.context = activity;
70
+ }
71
+ eventManager.registerApiKey(apiKey, appCtx);
72
+ Log.d(TAG, "Registered API key");
73
+ promise.resolve("API Key Registered");
74
+ break;
75
+ }
76
+
77
+ case ACTION_PERFORM_EVENT: {
78
+ String eventName = options.getString("eventName");
79
+ Map<String, String> eventPropertiesMap = new HashMap<>();
80
+ JSONObject rawProperties = options.optJSONObject("eventPropertiesMap");
81
+ if (rawProperties != null) {
82
+ Iterator<String> keys = rawProperties.keys();
83
+ while (keys.hasNext()) {
84
+ String key = keys.next();
85
+ eventPropertiesMap.put(key, String.valueOf(rawProperties.get(key)));
86
+ }
87
+ }
88
+ // Argument order is load-bearing. The SDK declares:
89
+ // sendEvent(eventName, properties, activityContext, clientAppContext)
90
+ // so the ACTIVITY must be 3rd and the app context 4th.
91
+ //
92
+ // EventManager builds the in-app popup with
93
+ // var dialogContext = activityContext
94
+ // and only swaps to the app context when Settings.canDrawOverlays()
95
+ // is true — which never happens in production, since the SDK does not
96
+ // request SYSTEM_ALERT_WINDOW and users must enable it by hand.
97
+ // So activityContext IS the popup's context. Passing an Application
98
+ // context there makes AlertDialog.show() throw BadTokenException,
99
+ // which CampaignView.show() swallows in an empty catch — the popup
100
+ // silently never appears while the SDK still logs " In App Showed"
101
+ // and sets IS_IN_APP_SHOWN = true.
102
+ eventManager.sendEvent(eventName, eventPropertiesMap, uiCtx, appCtx);
103
+ Log.d(TAG, "Event Sent: " + eventName);
104
+ promise.resolve("Event Performed");
105
+ break;
106
+ }
107
+
108
+ case ACTION_SET_ATTRIBUTE: {
109
+ String attributeName = options.getString("attributeName");
110
+ String attributeValue = options.getString("attributeValue");
111
+ attributeManager.sendAttribute(appCtx, attributeName, attributeValue);
112
+ Log.d(TAG, "Attribute Set: " + attributeName);
113
+ promise.resolve("Attribute Set");
114
+ break;
115
+ }
116
+
117
+ case ACTION_LOGIN: {
118
+ String uniqueIdentifier = options.getString("uniqueIdentifier");
119
+ eventManager.login(uniqueIdentifier, uiCtx);
120
+ Log.d(TAG, "User Logged In");
121
+ promise.resolve("User Logged In");
122
+ break;
123
+ }
124
+
125
+ case ACTION_FIREBASE_TOKEN_MERGN: {
126
+ String fcmTokenMergn = options.getString("fcmTokenMergn");
127
+ eventManager.firebaseToken(fcmTokenMergn, uiCtx);
128
+ Log.d(TAG, "Firebase Token Set");
129
+ promise.resolve("Firebase Token Set");
130
+ break;
131
+ }
132
+
133
+ // TODO: currently identical to firebase_token_mergn. Needs a product
134
+ // decision on what app-context registration should actually do.
135
+ case MERGN_APP_CONTEXT: {
136
+ String contextToken = options.getString("fcmTokenMergn");
137
+ eventManager.firebaseToken(contextToken, uiCtx);
138
+ Log.d(TAG, "Firebase Token in App Context Set");
139
+ promise.resolve("Firebase Token in App Context Set");
140
+ break;
141
+ }
142
+
143
+ default:
144
+ promise.reject("UNSUPPORTED_ACTION", "Action " + action + " is not supported.");
145
+ break;
146
+ }
147
+ } catch (Exception e) {
148
+ Log.e(TAG, "performAction failed for action " + action, e);
149
+ promise.reject("MERGN_ERROR", e);
150
+ }
151
+ }
152
+ }
@@ -0,0 +1,31 @@
1
+ package com.mergn.reactnative;
2
+
3
+ import androidx.annotation.NonNull;
4
+
5
+ import com.facebook.react.ReactPackage;
6
+ import com.facebook.react.bridge.NativeModule;
7
+ import com.facebook.react.bridge.ReactApplicationContext;
8
+ import com.facebook.react.uimanager.ViewManager;
9
+
10
+ import java.util.ArrayList;
11
+ import java.util.Collections;
12
+ import java.util.List;
13
+
14
+ public class MergnPackage implements ReactPackage {
15
+ @NonNull
16
+ @Override
17
+ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactApplicationContext) {
18
+
19
+ List<NativeModule> modules = new ArrayList<>();
20
+
21
+ modules.add(new MergnModule(reactApplicationContext));
22
+
23
+ return modules;
24
+ }
25
+
26
+ @NonNull
27
+ @Override
28
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactApplicationContext) {
29
+ return Collections.emptyList();
30
+ }
31
+ }
package/app.plugin.js ADDED
@@ -0,0 +1,2 @@
1
+ // Expo resolves "mergn-react-native" in app.json plugins to this file.
2
+ module.exports = require("./plugin");
@@ -0,0 +1,147 @@
1
+ # Android setup
2
+
3
+ Most of this is automatic. Autolinking registers the native module, and the
4
+ config plugin adds the manifest entries — so a plain analytics integration needs
5
+ nothing on this page beyond installing.
6
+
7
+ > **Upgrading from a hand-rolled MERGN integration?** Read
8
+ > [MIGRATION.md](./MIGRATION.md) **first** and remove the old pieces. Installing
9
+ > this package on top of a manual integration fails the build, and two of the
10
+ > removal steps fail *silently* if you skip them.
11
+
12
+ ```sh
13
+ npm install mergn-react-native
14
+ ```
15
+
16
+ ```json
17
+ { "expo": { "plugins": ["mergn-react-native"] } }
18
+ ```
19
+
20
+ ```sh
21
+ npx expo prebuild --platform android
22
+ npx expo run:android
23
+ ```
24
+
25
+ ## What the package does for you
26
+
27
+ | | |
28
+ | --- | --- |
29
+ | Native module registration | Autolinking (`react-native.config.js`) |
30
+ | MERGN Android SDK | `com.github.SHamzaHMergn:Mergn_sdk_android:5.2.4` from JitPack |
31
+ | JitPack repository | Declared in the package's own `build.gradle` |
32
+ | `INTERNET`, `POST_NOTIFICATIONS`, `VIBRATE` permissions | Config plugin |
33
+ | MERGN `FireBaseMessagingService` | Config plugin |
34
+
35
+ You do **not** edit `MainApplication`, `settings.gradle`, or `app/build.gradle`.
36
+
37
+ ## Requirements
38
+
39
+ - `minSdkVersion` 24 or higher
40
+ - Java 17 (the Android Gradle Plugin default for AGP 8+)
41
+
42
+ Override the SDK version if MERGN ships a new one before this package updates,
43
+ in `android/build.gradle`:
44
+
45
+ ```gradle
46
+ ext { mergnSdkVersion = "5.2.5" }
47
+ ```
48
+
49
+ ## Push notifications
50
+
51
+ The MERGN SDK receives pushes through its own `FirebaseMessagingService`, which
52
+ the config plugin declares. You still need Firebase in your app:
53
+
54
+ ```sh
55
+ npx expo install @react-native-firebase/app @react-native-firebase/messaging
56
+ ```
57
+
58
+ 1. Put `google-services.json` in your project root.
59
+ 2. Point `app.json` at it and add the Firebase plugin:
60
+ ```json
61
+ {
62
+ "expo": {
63
+ "android": { "googleServicesFile": "./google-services.json" },
64
+ "plugins": [
65
+ "mergn-react-native",
66
+ "@react-native-firebase/app"
67
+ ]
68
+ }
69
+ }
70
+ ```
71
+ 3. Pass the token to MERGN:
72
+ ```js
73
+ import messaging from "@react-native-firebase/messaging";
74
+ import Mergn from "mergn-react-native";
75
+
76
+ const token = await messaging().getToken();
77
+ await Mergn.setFirebaseToken(token);
78
+ ```
79
+
80
+ `google-services.json` is client configuration that ships inside every APK, not
81
+ a server secret — committing it is normal and keeps builds reproducible.
82
+
83
+ ### Android 13+ notification permission
84
+
85
+ `POST_NOTIFICATIONS` is declared for you, but it is a *runtime* permission on
86
+ API 33+, so you must still request it:
87
+
88
+ ```js
89
+ import { PermissionsAndroid, Platform } from "react-native";
90
+
91
+ if (Platform.OS === "android" && Platform.Version >= 33) {
92
+ await PermissionsAndroid.request(
93
+ PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
94
+ );
95
+ }
96
+ ```
97
+
98
+ Without this, pushes are delivered but silently not displayed.
99
+
100
+ ### Notification view / click tracking
101
+
102
+ Automatic. The SDK's own `FirebaseMessagingService` records impressions and taps
103
+ internally — there is no JS API for it, and none is needed.
104
+
105
+ ## In-app popups
106
+
107
+ Triggered by MERGN campaigns in response to events, so nothing to call directly:
108
+
109
+ ```js
110
+ await Mergn.performEvent("Collection Viewed", { title: "Beauty" });
111
+ ```
112
+
113
+ The SDK renders the popup itself using the current Activity. If a popup does not
114
+ appear, check that a campaign is actually configured for that event name in your
115
+ MERGN dashboard.
116
+
117
+ ## Transitive dependencies
118
+
119
+ The SDK's published POM declares no dependencies, so this package declares them
120
+ on the SDK's behalf: `androidx.room`, `androidx.work`, `androidx.core`,
121
+ `androidx.appcompat`, `kotlinx-coroutines-android` and `gson`, plus
122
+ `firebase-messaging` as `compileOnly` so it cannot conflict with your app's own
123
+ Firebase version.
124
+
125
+ If you see `NoClassDefFoundError` from inside `com.mergn.insights` at runtime,
126
+ that list has drifted — please report it.
127
+
128
+ ## Troubleshooting
129
+
130
+ **`Duplicate class com.mergn.insights.*`** — you still have the old `.aar` in
131
+ `android/app/libs/`. See [MIGRATION.md](./MIGRATION.md) — and note that removing
132
+ the `.aar` alone is not sufficient.
133
+
134
+ **`Native module MergnModule tried to override ...`** — your old
135
+ `MergnModule.java` / `MergnPackage.java` are still in the app, so two modules
136
+ claim the same name. See [MIGRATION.md](./MIGRATION.md) steps 2 and 3.
137
+
138
+ **`MergnModule.<method> is unavailable`** — the native module did not load.
139
+ You are probably in Expo Go, which cannot load native code; use
140
+ `npx expo run:android` or an EAS build.
141
+
142
+ **Events send but nothing reaches the dashboard** — confirm `registerApi`
143
+ resolved *before* the events, and that your API key and package name are
144
+ provisioned in your MERGN account.
145
+
146
+ **An attribute does not update** — the SDK de-duplicates: setting the same value
147
+ again for one attribute name is intentionally a no-op. Use a changed value.