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.
- package/LICENSE +44 -0
- package/README.md +131 -0
- package/android/build.gradle +66 -0
- package/android/src/main/java/com/mergn/reactnative/MergnModule.java +152 -0
- package/android/src/main/java/com/mergn/reactnative/MergnPackage.java +31 -0
- package/app.plugin.js +2 -0
- package/docs/ANDROID.md +147 -0
- package/docs/IOS.md +156 -0
- package/docs/MIGRATION.md +365 -0
- package/ios/MergnModule.swift +149 -0
- package/ios/MergnModuleBridge.m +14 -0
- package/ios/MergnNotificationHandler.swift +160 -0
- package/ios/NotificationService/Info.plist +31 -0
- package/ios/NotificationService/NotificationService.swift +82 -0
- package/mergn-react-native.podspec +32 -0
- package/package.json +49 -0
- package/plugin/index.js +219 -0
- package/react-native.config.js +19 -0
- package/scripts/release-ios.sh +79 -0
- package/scripts/verify-package.js +58 -0
- package/sdk/MergnSDK.podspec +28 -0
- package/sdk/mergn_ios.xcframework/Info.plist +44 -0
- package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/Info.plist +0 -0
- package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios.abi.json +2517 -0
- package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios.private.swiftinterface +82 -0
- package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios.swiftinterface +82 -0
- package/sdk/mergn_ios.xcframework/ios-arm64/mergn_ios.framework/mergn_ios +0 -0
- package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Info.plist +0 -0
- 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
- 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
- package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/Modules/mergn_ios.swiftmodule/arm64-apple-ios-simulator.swiftinterface +82 -0
- 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
- 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
- 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
- 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
- package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/_CodeSignature/CodeResources +101 -0
- package/sdk/mergn_ios.xcframework/ios-arm64_x86_64-simulator/mergn_ios.framework/mergn_ios +0 -0
- package/src/index.d.ts +37 -0
- 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
package/docs/ANDROID.md
ADDED
|
@@ -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.
|