react-native-nami-sdk 3.3.2 → 3.3.3
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/android/build.gradle +2 -2
- package/android/src/main/AndroidManifest.xml +14 -1
- package/android/src/main/java/com/namiml/reactnative/NamiBridgePackage.java +15 -0
- package/android/src/main/java/com/namiml/reactnative/NamiFlowManagerBridge.kt +22 -17
- package/android/src/main/java/com/namiml/reactnative/NamiOverlayControlBridge.kt +171 -0
- package/android/src/main/java/com/namiml/reactnative/ReactOverlayActivity.kt +29 -0
- package/android/src/main/res/values/styles.xml +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/specs/NativeNamiFlowManager.d.ts +1 -0
- package/dist/specs/NativeNamiOverlayControl.d.ts +9 -0
- package/dist/src/NamiOverlayControl.d.ts +9 -0
- package/dist/src/NamiOverlayHost.d.ts +1 -0
- package/dist/src/overlay.d.ts +4 -0
- package/dist/src/registerOverlay.d.ts +1 -0
- package/dist/src/version.d.ts +1 -1
- package/index.ts +1 -0
- package/ios/Nami.swift +21 -8
- package/ios/NamiCampaignManagerBridge.m +3 -2
- package/ios/NamiCampaignManagerBridge.swift +16 -11
- package/ios/NamiCustomerManager.m +3 -2
- package/ios/NamiCustomerManager.swift +44 -21
- package/ios/NamiEntitlementManagerBridge.m +3 -2
- package/ios/NamiEntitlementManagerBridge.swift +14 -12
- package/ios/NamiFlowManagerBridge.m +1 -1
- package/ios/NamiFlowManagerBridge.swift +17 -22
- package/ios/NamiOverlayControlBridge.m +17 -0
- package/ios/NamiOverlayControlBridge.swift +132 -0
- package/ios/NamiPaywallManagerBridge.m +2 -2
- package/ios/NamiPaywallManagerBridge.swift +19 -20
- package/ios/NamiPurchaseManagerBridge.m +2 -2
- package/ios/NamiPurchaseManagerBridge.swift +17 -8
- package/package.json +15 -3
- package/react-native-nami-sdk.podspec +19 -9
- package/specs/NativeNamiFlowManager.ts +1 -0
- package/specs/NativeNamiOverlayControl.ts +9 -0
- package/src/NamiOverlayControl.tsx +48 -0
- package/src/version.ts +1 -1
package/android/build.gradle
CHANGED
|
@@ -85,8 +85,8 @@ dependencies {
|
|
|
85
85
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
86
86
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
|
87
87
|
|
|
88
|
-
playImplementation "com.namiml:sdk-android:3.3.
|
|
89
|
-
amazonImplementation "com.namiml:sdk-amazon:3.3.
|
|
88
|
+
playImplementation "com.namiml:sdk-android:3.3.3"
|
|
89
|
+
amazonImplementation "com.namiml:sdk-amazon:3.3.3"
|
|
90
90
|
|
|
91
91
|
implementation "com.facebook.react:react-native:+" // From node_modules
|
|
92
92
|
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.4"
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
-
<manifest
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
package="com.namiml.reactnative">
|
|
2
3
|
|
|
4
|
+
|
|
5
|
+
<application>
|
|
6
|
+
<activity
|
|
7
|
+
android:name=".ReactOverlayActivity"
|
|
8
|
+
android:theme="@style/Theme.TransparentReact"
|
|
9
|
+
android:exported="false"
|
|
10
|
+
android:launchMode="singleTop"
|
|
11
|
+
android:taskAffinity=""
|
|
12
|
+
android:noHistory="true"
|
|
13
|
+
android:excludeFromRecents="true"
|
|
14
|
+
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" />
|
|
15
|
+
</application>
|
|
3
16
|
</manifest>
|
|
@@ -29,6 +29,8 @@ public class NamiBridgePackage extends TurboReactPackage {
|
|
|
29
29
|
case NamiPaywallManagerBridgeModule.NAME -> new NamiPaywallManagerBridgeModule(context);
|
|
30
30
|
case NamiPurchaseManagerBridgeModule.NAME ->
|
|
31
31
|
new NamiPurchaseManagerBridgeModule(context);
|
|
32
|
+
case NamiOverlayControlBridgeModule.NAME ->
|
|
33
|
+
new NamiOverlayControlBridgeModule(context);
|
|
32
34
|
default -> null;
|
|
33
35
|
};
|
|
34
36
|
}
|
|
@@ -129,6 +131,19 @@ public class NamiBridgePackage extends TurboReactPackage {
|
|
|
129
131
|
BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
|
|
130
132
|
)
|
|
131
133
|
);
|
|
134
|
+
|
|
135
|
+
moduleInfos.put(
|
|
136
|
+
NamiOverlayControlBridgeModule.NAME,
|
|
137
|
+
new ReactModuleInfo(
|
|
138
|
+
NamiOverlayControlBridgeModule.NAME,
|
|
139
|
+
NamiOverlayControlBridgeModule.NAME,
|
|
140
|
+
false,
|
|
141
|
+
false,
|
|
142
|
+
true,
|
|
143
|
+
false,
|
|
144
|
+
BuildConfig.IS_NEW_ARCHITECTURE_ENABLED
|
|
145
|
+
)
|
|
146
|
+
);
|
|
132
147
|
return moduleInfos;
|
|
133
148
|
};
|
|
134
149
|
}
|
|
@@ -4,39 +4,40 @@ import android.os.Handler
|
|
|
4
4
|
import android.os.Looper
|
|
5
5
|
import android.util.Log
|
|
6
6
|
import com.facebook.react.bridge.*
|
|
7
|
-
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
8
7
|
import com.facebook.react.module.annotations.ReactModule
|
|
8
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
9
9
|
import com.facebook.react.turbomodule.core.interfaces.TurboModule
|
|
10
10
|
import com.namiml.flow.NamiFlowManager
|
|
11
11
|
|
|
12
12
|
@ReactModule(name = NamiFlowManagerBridgeModule.NAME)
|
|
13
13
|
class NamiFlowManagerBridgeModule internal constructor(
|
|
14
|
-
reactContext: ReactApplicationContext
|
|
15
|
-
) : ReactContextBaseJavaModule(reactContext),
|
|
16
|
-
|
|
14
|
+
reactContext: ReactApplicationContext,
|
|
15
|
+
) : ReactContextBaseJavaModule(reactContext),
|
|
16
|
+
TurboModule {
|
|
17
17
|
companion object {
|
|
18
18
|
const val NAME = "RNNamiFlowManager"
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
override fun getName(): String
|
|
22
|
-
return NAME
|
|
23
|
-
}
|
|
21
|
+
override fun getName(): String = NAME
|
|
24
22
|
|
|
25
23
|
@ReactMethod
|
|
26
24
|
fun registerStepHandoff() {
|
|
27
25
|
NamiFlowManager.registerStepHandoff { handoffTag, handoffData ->
|
|
28
|
-
val payload =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
26
|
+
val payload =
|
|
27
|
+
Arguments.createMap().apply {
|
|
28
|
+
putString("handoffTag", handoffTag)
|
|
29
|
+
if (handoffData != null) {
|
|
30
|
+
try {
|
|
31
|
+
putMap("handoffData", Arguments.makeNativeMap(handoffData))
|
|
32
|
+
} catch (e: Exception) {
|
|
33
|
+
Log.d(NAME, "Failed to convert handoffData to NativeMap: ${e.localizedMessage}")
|
|
34
|
+
}
|
|
36
35
|
}
|
|
37
36
|
}
|
|
37
|
+
|
|
38
|
+
reactApplicationContext.runOnUiQueueThread {
|
|
39
|
+
sendEvent("Handoff", payload)
|
|
38
40
|
}
|
|
39
|
-
sendEvent("Handoff", payload)
|
|
40
41
|
}
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -74,7 +75,10 @@ class NamiFlowManagerBridgeModule internal constructor(
|
|
|
74
75
|
promise.resolve(NamiFlowManager.isFlowOpen())
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
private fun sendEvent(
|
|
78
|
+
private fun sendEvent(
|
|
79
|
+
eventName: String,
|
|
80
|
+
params: WritableMap?,
|
|
81
|
+
) {
|
|
78
82
|
reactApplicationContext
|
|
79
83
|
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
80
84
|
.emit(eventName, params)
|
|
@@ -82,5 +86,6 @@ class NamiFlowManagerBridgeModule internal constructor(
|
|
|
82
86
|
|
|
83
87
|
// Required for RN EventEmitter support
|
|
84
88
|
@ReactMethod fun addListener(eventName: String?) {}
|
|
89
|
+
|
|
85
90
|
@ReactMethod fun removeListeners(count: Int?) {}
|
|
86
91
|
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
package com.namiml.reactnative
|
|
2
|
+
|
|
3
|
+
import android.app.Activity
|
|
4
|
+
import android.content.Intent
|
|
5
|
+
import android.os.Build
|
|
6
|
+
import android.util.Log
|
|
7
|
+
import com.facebook.react.bridge.*
|
|
8
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
9
|
+
import com.facebook.react.module.annotations.ReactModule
|
|
10
|
+
import com.facebook.react.turbomodule.core.interfaces.TurboModule
|
|
11
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
12
|
+
|
|
13
|
+
@ReactModule(name = NamiOverlayControlBridgeModule.NAME)
|
|
14
|
+
class NamiOverlayControlBridgeModule(private val ctx: ReactApplicationContext)
|
|
15
|
+
: ReactContextBaseJavaModule(ctx), TurboModule {
|
|
16
|
+
|
|
17
|
+
companion object {
|
|
18
|
+
const val NAME = "RNNamiOverlayControl"
|
|
19
|
+
var currentOverlayActivity: ReactOverlayActivity? = null
|
|
20
|
+
var lastValidActivity: Activity? = null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
override fun getName() = NAME
|
|
24
|
+
|
|
25
|
+
@ReactMethod
|
|
26
|
+
fun presentOverlay(promise: Promise) {
|
|
27
|
+
var theActivity: Activity? = null
|
|
28
|
+
if (reactApplicationContext.hasCurrentActivity()) {
|
|
29
|
+
theActivity = reactApplicationContext.currentActivity
|
|
30
|
+
|
|
31
|
+
// Check if it's the overlay activity that's finishing
|
|
32
|
+
if (theActivity is ReactOverlayActivity) {
|
|
33
|
+
if (theActivity.isFinishing || theActivity.isDestroyed) {
|
|
34
|
+
theActivity = lastValidActivity
|
|
35
|
+
if (theActivity == null || theActivity.isFinishing || theActivity.isDestroyed) {
|
|
36
|
+
promise.reject("NO_ACTIVITY", "No valid activity available")
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
lastValidActivity = theActivity
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
lastValidActivity = theActivity
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
theActivity = lastValidActivity
|
|
47
|
+
if (theActivity == null || theActivity.isFinishing || theActivity.isDestroyed) {
|
|
48
|
+
promise.reject("NO_ACTIVITY", "No valid activity available")
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (theActivity == null) {
|
|
54
|
+
promise.reject("NO_ACTIVITY", "No activity available")
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
startOverlayActivity(theActivity, promise)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private fun startOverlayActivity(activity: Activity, promise: Promise) {
|
|
62
|
+
try {
|
|
63
|
+
UiThreadUtil.runOnUiThread {
|
|
64
|
+
try {
|
|
65
|
+
val intent = Intent(activity, ReactOverlayActivity::class.java)
|
|
66
|
+
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
|
|
67
|
+
activity.startActivity(intent)
|
|
68
|
+
// Use modern transition API for Android 14+ (API 34+)
|
|
69
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
70
|
+
activity.overrideActivityTransition(Activity.OVERRIDE_TRANSITION_OPEN, 0, 0)
|
|
71
|
+
} else {
|
|
72
|
+
@Suppress("DEPRECATION")
|
|
73
|
+
activity.overridePendingTransition(0, 0)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Emit ready event after a short delay to ensure activity is started
|
|
77
|
+
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
|
|
78
|
+
try {
|
|
79
|
+
if (ctx.catalystInstance != null) {
|
|
80
|
+
ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
81
|
+
.emit("NamiOverlayReady", null)
|
|
82
|
+
}
|
|
83
|
+
} catch (e: Exception) {
|
|
84
|
+
Log.e(NAME, "Failed to emit NamiOverlayReady: ${e.message}")
|
|
85
|
+
}
|
|
86
|
+
}, 100)
|
|
87
|
+
|
|
88
|
+
promise.resolve(null)
|
|
89
|
+
} catch (uiError: Exception) {
|
|
90
|
+
Log.e(NAME, "Error in UI thread: ${uiError.message}", uiError)
|
|
91
|
+
promise.reject("UI_THREAD_ERROR", "Failed in UI thread: ${uiError.message}", uiError)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} catch (e: Exception) {
|
|
95
|
+
Log.e(NAME, "Error presenting overlay: ${e.message}", e)
|
|
96
|
+
promise.reject("PRESENT_OVERLAY_ERROR", "Failed to present overlay: ${e.message}", e)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@ReactMethod
|
|
101
|
+
fun addListener(eventName: String?) {
|
|
102
|
+
// Required for NativeEventEmitter - no-op since we emit events directly
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@ReactMethod
|
|
106
|
+
fun removeListeners(count: Int?) {
|
|
107
|
+
// Required for NativeEventEmitter - no-op since we emit events directly
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@ReactMethod
|
|
111
|
+
fun finishOverlay(result: ReadableMap?, promise: Promise) {
|
|
112
|
+
try {
|
|
113
|
+
// Emit result to main app listeners
|
|
114
|
+
val payload: WritableMap = Arguments.createMap().apply {
|
|
115
|
+
if (result != null) {
|
|
116
|
+
merge(result)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
if (ctx.catalystInstance != null) {
|
|
121
|
+
ctx.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
122
|
+
.emit("NamiOverlayResult", payload)
|
|
123
|
+
}
|
|
124
|
+
} catch (e: Exception) {
|
|
125
|
+
Log.e(NAME, "Failed to emit NamiOverlayResult: ${e.message}")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
UiThreadUtil.runOnUiThread {
|
|
129
|
+
// Try to finish the tracked overlay activity first
|
|
130
|
+
currentOverlayActivity?.let { overlay ->
|
|
131
|
+
overlay.finish()
|
|
132
|
+
// Use modern transition API for Android 14+ (API 34+)
|
|
133
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
134
|
+
overlay.overrideActivityTransition(Activity.OVERRIDE_TRANSITION_CLOSE, 0, 0)
|
|
135
|
+
} else {
|
|
136
|
+
@Suppress("DEPRECATION")
|
|
137
|
+
overlay.overridePendingTransition(0, 0)
|
|
138
|
+
}
|
|
139
|
+
currentOverlayActivity = null
|
|
140
|
+
|
|
141
|
+
// Wait for activity to actually finish before resolving promise
|
|
142
|
+
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
|
|
143
|
+
promise.resolve(null)
|
|
144
|
+
}, 100)
|
|
145
|
+
} ?: run {
|
|
146
|
+
// Fallback to current activity if it's an overlay
|
|
147
|
+
(ctx.currentActivity as? ReactOverlayActivity)?.apply {
|
|
148
|
+
finish()
|
|
149
|
+
// Use modern transition API for Android 14+ (API 34+)
|
|
150
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
151
|
+
overrideActivityTransition(Activity.OVERRIDE_TRANSITION_CLOSE, 0, 0)
|
|
152
|
+
} else {
|
|
153
|
+
@Suppress("DEPRECATION")
|
|
154
|
+
overridePendingTransition(0, 0)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Wait for activity to actually finish before resolving promise
|
|
158
|
+
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
|
|
159
|
+
promise.resolve(null)
|
|
160
|
+
}, 100)
|
|
161
|
+
} ?: run {
|
|
162
|
+
promise.resolve(null)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
} catch (e: Exception) {
|
|
167
|
+
Log.e(NAME, "Failed to finish overlay: ${e.message}", e)
|
|
168
|
+
promise.reject("FINISH_OVERLAY_ERROR", "Failed to finish overlay", e)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
package com.namiml.reactnative
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import com.facebook.react.ReactActivity
|
|
5
|
+
|
|
6
|
+
class ReactOverlayActivity : ReactActivity() {
|
|
7
|
+
override fun getMainComponentName(): String = "NamiOverlayHost"
|
|
8
|
+
|
|
9
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
10
|
+
super.onCreate(savedInstanceState)
|
|
11
|
+
overridePendingTransition(0, 0)
|
|
12
|
+
|
|
13
|
+
// Register this activity with the bridge module
|
|
14
|
+
NamiOverlayControlBridgeModule.currentOverlayActivity = this
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
override fun onBackPressed() {
|
|
18
|
+
finish()
|
|
19
|
+
overridePendingTransition(0, 0)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
override fun onDestroy() {
|
|
23
|
+
super.onDestroy()
|
|
24
|
+
// Clear the reference when activity is destroyed
|
|
25
|
+
if (NamiOverlayControlBridgeModule.currentOverlayActivity == this) {
|
|
26
|
+
NamiOverlayControlBridgeModule.currentOverlayActivity = null
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<resources>
|
|
3
|
+
<style name="Theme.TransparentReact" parent="Theme.MaterialComponents.DayNight.NoActionBar">
|
|
4
|
+
<item name="android:windowIsTranslucent">true</item>
|
|
5
|
+
<item name="android:windowBackground">@android:color/transparent</item>
|
|
6
|
+
<item name="android:windowNoTitle">true</item>
|
|
7
|
+
<item name="android:statusBarColor">@android:color/transparent</item>
|
|
8
|
+
<item name="android:navigationBarColor">@android:color/transparent</item>
|
|
9
|
+
</style>
|
|
10
|
+
</resources>
|
package/dist/index.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export { NamiEntitlementManager } from './src/NamiEntitlementManager';
|
|
|
5
5
|
export { NamiPurchaseManager } from './src/NamiPurchaseManager';
|
|
6
6
|
export { NamiPaywallManager } from './src/NamiPaywallManager';
|
|
7
7
|
export { NamiFlowManager } from './src/NamiFlowManager';
|
|
8
|
+
export { NamiOverlayControl } from './src/NamiOverlayControl';
|
|
8
9
|
export * from './src/types';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { TurboModule } from 'react-native';
|
|
2
|
+
export interface Spec extends TurboModule {
|
|
3
|
+
presentOverlay(): Promise<void>;
|
|
4
|
+
finishOverlay(result?: {
|
|
5
|
+
[key: string]: unknown;
|
|
6
|
+
} | null): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
declare const _default: Spec;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NativeEventEmitter } from 'react-native';
|
|
2
|
+
export declare const NamiOverlayControl: {
|
|
3
|
+
emitter: NativeEventEmitter;
|
|
4
|
+
presentOverlay(): Promise<void>;
|
|
5
|
+
finishOverlay(result?: any): Promise<void>;
|
|
6
|
+
onOverlayReady(handler: () => void): () => void;
|
|
7
|
+
onOverlayResult(handler: (result: any) => void): () => void;
|
|
8
|
+
};
|
|
9
|
+
export default function NamiOverlayHost(): any;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function NamiOverlayHost(): null;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function presentOverlay(): Promise<void>;
|
|
2
|
+
export declare function finishOverlay(result?: any): Promise<void>;
|
|
3
|
+
export declare function onOverlayReady(handler: () => void): () => void;
|
|
4
|
+
export declare function onOverlayResult(handler: (result: any) => void): () => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/src/version.d.ts
CHANGED
package/index.ts
CHANGED
|
@@ -5,4 +5,5 @@ export { NamiEntitlementManager } from './src/NamiEntitlementManager';
|
|
|
5
5
|
export { NamiPurchaseManager } from './src/NamiPurchaseManager';
|
|
6
6
|
export { NamiPaywallManager } from './src/NamiPaywallManager';
|
|
7
7
|
export { NamiFlowManager } from './src/NamiFlowManager';
|
|
8
|
+
export { NamiOverlayControl } from './src/NamiOverlayControl';
|
|
8
9
|
export * from './src/types';
|
package/ios/Nami.swift
CHANGED
|
@@ -8,10 +8,6 @@ import Foundation
|
|
|
8
8
|
import NamiApple
|
|
9
9
|
import React
|
|
10
10
|
|
|
11
|
-
// #if RCT_NEW_ARCH_ENABLED
|
|
12
|
-
// extension RNNami: RCTTurboModule {}
|
|
13
|
-
// #endif
|
|
14
|
-
|
|
15
11
|
@objc(RNNami)
|
|
16
12
|
class RNNami: NSObject {
|
|
17
13
|
static func moduleName() -> String! {
|
|
@@ -63,20 +59,37 @@ class RNNami: NSObject {
|
|
|
63
59
|
config.initialConfig = initialConfig
|
|
64
60
|
}
|
|
65
61
|
|
|
62
|
+
var didCallBack = false
|
|
66
63
|
Nami.configure(with: config) { sdkConfigured in
|
|
67
|
-
|
|
64
|
+
didCallBack = true
|
|
65
|
+
NSLog("RNNami: configure() completion called, sdkConfigured: \(sdkConfigured)")
|
|
66
|
+
DispatchQueue.main.async {
|
|
67
|
+
resolve(["success": sdkConfigured])
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
|
|
72
|
+
if !didCallBack {
|
|
73
|
+
NSLog("RNNami: configure() completion NEVER CALLED, reporting failure.")
|
|
74
|
+
resolve(["success": false])
|
|
75
|
+
}
|
|
68
76
|
}
|
|
69
77
|
}
|
|
70
78
|
|
|
71
79
|
@objc
|
|
72
|
-
func sdkConfigured(_ resolve: RCTPromiseResolveBlock, rejecter _: RCTPromiseRejectBlock) {
|
|
73
|
-
|
|
80
|
+
func sdkConfigured(_ resolve: @escaping RCTPromiseResolveBlock, rejecter _: RCTPromiseRejectBlock) {
|
|
81
|
+
let sdkConfigured = Nami.sdkConfigured()
|
|
82
|
+
DispatchQueue.main.async {
|
|
83
|
+
resolve(sdkConfigured)
|
|
84
|
+
}
|
|
74
85
|
}
|
|
75
86
|
|
|
76
87
|
@objc(sdkVersion:rejecter:)
|
|
77
88
|
func sdkVersion(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
|
|
78
89
|
let version = Nami.sdkVersion()
|
|
79
|
-
|
|
90
|
+
DispatchQueue.main.async {
|
|
91
|
+
resolve(version)
|
|
92
|
+
}
|
|
80
93
|
}
|
|
81
94
|
|
|
82
95
|
func isNewArchitectureEnabled() -> Bool {
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
#import <React/RCTBridgeModule.h>
|
|
9
|
+
#import <React/RCTEventEmitter.h>
|
|
9
10
|
|
|
10
|
-
@interface RCT_EXTERN_MODULE(RNNamiCampaignManager,
|
|
11
|
+
@interface RCT_EXTERN_MODULE(RNNamiCampaignManager, RCTEventEmitter)
|
|
11
12
|
|
|
12
13
|
RCT_EXTERN_METHOD(launch:(nullable NSString *)label withUrl:(nullable NSString *)withUrl context:(nullable NSDictionary *)context completion:(RCTResponseSenderBlock)callback paywallCompletion:(RCTResponseSenderBlock)paywallCallback);
|
|
13
14
|
|
|
@@ -20,7 +21,7 @@ RCT_EXTERN_METHOD(refresh:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRe
|
|
|
20
21
|
RCT_EXTERN_METHOD(registerAvailableCampaignsHandler)
|
|
21
22
|
|
|
22
23
|
+ (BOOL)requiresMainQueueSetup {
|
|
23
|
-
return
|
|
24
|
+
return YES;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
@end
|
|
@@ -10,17 +10,26 @@ import NamiApple
|
|
|
10
10
|
import os
|
|
11
11
|
import React
|
|
12
12
|
|
|
13
|
-
// #if RCT_NEW_ARCH_ENABLED
|
|
14
|
-
// extension RNNamiCampaignManager: RCTTurboModule {}
|
|
15
|
-
// #endif
|
|
16
|
-
|
|
17
13
|
@objc(RNNamiCampaignManager)
|
|
18
14
|
class RNNamiCampaignManager: RCTEventEmitter {
|
|
19
15
|
public static var shared: RNNamiCampaignManager?
|
|
20
16
|
|
|
21
17
|
override init() {
|
|
22
18
|
super.init()
|
|
23
|
-
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
override class func requiresMainQueueSetup() -> Bool { true }
|
|
22
|
+
|
|
23
|
+
private var hasListeners = false
|
|
24
|
+
override func startObserving() { hasListeners = true }
|
|
25
|
+
override func stopObserving() { hasListeners = false }
|
|
26
|
+
|
|
27
|
+
private func safeSend(withName name: String, body: Any?) {
|
|
28
|
+
guard hasListeners else {
|
|
29
|
+
print("[RNNamiCampaignManager] Warning: no listeners, so event not being sent to JS.")
|
|
30
|
+
return
|
|
31
|
+
} // optional but avoids warnings
|
|
32
|
+
sendEvent(withName: name, body: body)
|
|
24
33
|
}
|
|
25
34
|
|
|
26
35
|
override func supportedEvents() -> [String]! {
|
|
@@ -138,9 +147,7 @@ class RNNamiCampaignManager: RCTEventEmitter {
|
|
|
138
147
|
"timeSpentOnPaywall": paywallEvent.timeSpentOnPaywall,
|
|
139
148
|
]
|
|
140
149
|
|
|
141
|
-
|
|
142
|
-
RNNamiCampaignManager.shared?.sendEvent(withName: "NamiPaywallEvent", body: payload)
|
|
143
|
-
}
|
|
150
|
+
safeSend(withName: "NamiPaywallEvent", body: payload)
|
|
144
151
|
}
|
|
145
152
|
|
|
146
153
|
func handleLaunch(callback: RCTResponseSenderBlock?, success: Bool, error: Error?) {
|
|
@@ -294,9 +301,7 @@ class RNNamiCampaignManager: RCTEventEmitter {
|
|
|
294
301
|
func registerForAvailableCampaigns() {
|
|
295
302
|
NamiCampaignManager.registerAvailableCampaignsHandler { availableCampaigns in
|
|
296
303
|
let dictionaries = availableCampaigns.map { campaign in self.campaignInToDictionary(campaign) }
|
|
297
|
-
|
|
298
|
-
RNNamiCampaignManager.shared?.sendEvent(withName: "AvailableCampaignsChanged", body: dictionaries)
|
|
299
|
-
}
|
|
304
|
+
self.safeSend(withName: "AvailableCampaignsChanged", body: dictionaries)
|
|
300
305
|
}
|
|
301
306
|
}
|
|
302
307
|
}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
#import <React/RCTBridgeModule.h>
|
|
9
|
+
#import <React/RCTEventEmitter.h>
|
|
9
10
|
|
|
10
|
-
@interface RCT_EXTERN_MODULE(RNNamiCustomerManager,
|
|
11
|
+
@interface RCT_EXTERN_MODULE(RNNamiCustomerManager, RCTEventEmitter)
|
|
11
12
|
|
|
12
13
|
RCT_EXTERN_METHOD(setCustomerAttribute:(NSString *)key value:(NSString *)value)
|
|
13
14
|
|
|
@@ -43,7 +44,7 @@ RCT_EXTERN_METHOD(registerAccountStateHandler)
|
|
|
43
44
|
|
|
44
45
|
|
|
45
46
|
+ (BOOL)requiresMainQueueSetup {
|
|
46
|
-
return
|
|
47
|
+
return YES;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
@end
|