react-native-nami-sdk 3.3.4 → 3.3.5-1
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/java/com/namiml/reactnative/NamiCampaignManagerBridge.kt +40 -7
- package/android/src/main/java/com/namiml/reactnative/NamiOverlayControlBridge.kt +31 -0
- package/android/src/main/java/com/namiml/reactnative/NamiPaywallManagerBridgeModule.kt +2 -2
- package/android/src/main/java/com/namiml/reactnative/ReactOverlayActivity.kt +2 -0
- package/dist/specs/NativeNamiCampaignManager.d.ts +1 -0
- package/dist/src/NamiCampaignManager.d.ts +1 -0
- package/dist/src/version.d.ts +1 -1
- package/ios/NamiCampaignManagerBridge.m +2 -0
- package/ios/NamiCampaignManagerBridge.swift +16 -0
- package/package.json +1 -1
- package/react-native-nami-sdk.podspec +1 -1
- package/specs/NativeNamiCampaignManager.ts +5 -0
- package/src/NamiCampaignManager.ts +7 -0
- package/src/NamiOverlayControl.tsx +12 -1
- 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.5.1"
|
|
89
|
+
amazonImplementation "com.namiml:sdk-amazon:3.3.5.1"
|
|
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"
|
|
@@ -354,14 +354,17 @@ class NamiCampaignManagerBridgeModule internal constructor(
|
|
|
354
354
|
promise: Promise,
|
|
355
355
|
) {
|
|
356
356
|
try {
|
|
357
|
-
val uri =
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
357
|
+
val uri =
|
|
358
|
+
if (!withUrl.isNullOrEmpty()) {
|
|
359
|
+
val parsedUri = Uri.parse(withUrl)
|
|
360
|
+
if (parsedUri.scheme.isNullOrEmpty()) {
|
|
361
|
+
promise.reject("ISFLOW_ERROR", "Invalid URL format: missing scheme", null)
|
|
362
|
+
return
|
|
363
|
+
}
|
|
364
|
+
parsedUri
|
|
365
|
+
} else {
|
|
366
|
+
null
|
|
362
367
|
}
|
|
363
|
-
parsedUri
|
|
364
|
-
} else null
|
|
365
368
|
val result = NamiCampaignManager.isFlow(label = label, uri = uri)
|
|
366
369
|
promise.resolve(result)
|
|
367
370
|
} catch (e: Exception) {
|
|
@@ -400,4 +403,34 @@ class NamiCampaignManagerBridgeModule internal constructor(
|
|
|
400
403
|
@ReactMethod
|
|
401
404
|
fun removeListeners(count: Int?) {
|
|
402
405
|
}
|
|
406
|
+
|
|
407
|
+
@ReactMethod
|
|
408
|
+
fun productGroups(
|
|
409
|
+
label: String?,
|
|
410
|
+
withUrl: String?,
|
|
411
|
+
promise: Promise,
|
|
412
|
+
) {
|
|
413
|
+
try {
|
|
414
|
+
val uri =
|
|
415
|
+
if (!withUrl.isNullOrEmpty()) {
|
|
416
|
+
val parsedUri = Uri.parse(withUrl)
|
|
417
|
+
if (parsedUri.scheme.isNullOrEmpty()) {
|
|
418
|
+
promise.reject("PRODUCTGROUPS_ERROR", "Invalid URL format: missing scheme", null)
|
|
419
|
+
return
|
|
420
|
+
}
|
|
421
|
+
parsedUri
|
|
422
|
+
} else {
|
|
423
|
+
null
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
val productGroups = NamiCampaignManager.getProductGroups(label = label, uri = uri)
|
|
427
|
+
val array = WritableNativeArray()
|
|
428
|
+
productGroups.forEach { group: String ->
|
|
429
|
+
array.pushString(group)
|
|
430
|
+
}
|
|
431
|
+
promise.resolve(array)
|
|
432
|
+
} catch (e: Exception) {
|
|
433
|
+
promise.reject("PRODUCTGROUPS_ERROR", "Failed to get product groups: ${e.message}", e)
|
|
434
|
+
}
|
|
435
|
+
}
|
|
403
436
|
}
|
|
@@ -18,12 +18,31 @@ class NamiOverlayControlBridgeModule(private val ctx: ReactApplicationContext)
|
|
|
18
18
|
const val NAME = "RNNamiOverlayControl"
|
|
19
19
|
var currentOverlayActivity: ReactOverlayActivity? = null
|
|
20
20
|
var lastValidActivity: Activity? = null
|
|
21
|
+
private var isPresentingOverlay = false
|
|
22
|
+
private val pendingPromises = mutableListOf<Promise>()
|
|
23
|
+
|
|
24
|
+
// Internal method to clear the presenting flag (for use by ReactOverlayActivity)
|
|
25
|
+
internal fun clearPresentingFlag() {
|
|
26
|
+
isPresentingOverlay = false
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Internal method to check if an overlay is currently being presented
|
|
30
|
+
internal fun isOverlayActive(): Boolean {
|
|
31
|
+
return isPresentingOverlay || currentOverlayActivity != null
|
|
32
|
+
}
|
|
21
33
|
}
|
|
22
34
|
|
|
23
35
|
override fun getName() = NAME
|
|
24
36
|
|
|
25
37
|
@ReactMethod
|
|
26
38
|
fun presentOverlay(promise: Promise) {
|
|
39
|
+
// Check if we're already presenting an overlay
|
|
40
|
+
if (isPresentingOverlay || currentOverlayActivity != null) {
|
|
41
|
+
// If there's already an active overlay, reject the new call
|
|
42
|
+
promise.reject("OVERLAY_ALREADY_ACTIVE", "An overlay is already being presented or is currently active")
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
27
46
|
var theActivity: Activity? = null
|
|
28
47
|
if (reactApplicationContext.hasCurrentActivity()) {
|
|
29
48
|
theActivity = reactApplicationContext.currentActivity
|
|
@@ -55,6 +74,8 @@ class NamiOverlayControlBridgeModule(private val ctx: ReactApplicationContext)
|
|
|
55
74
|
return
|
|
56
75
|
}
|
|
57
76
|
|
|
77
|
+
// Set flag to indicate we're presenting an overlay
|
|
78
|
+
isPresentingOverlay = true
|
|
58
79
|
startOverlayActivity(theActivity, promise)
|
|
59
80
|
}
|
|
60
81
|
|
|
@@ -88,11 +109,15 @@ class NamiOverlayControlBridgeModule(private val ctx: ReactApplicationContext)
|
|
|
88
109
|
promise.resolve(null)
|
|
89
110
|
} catch (uiError: Exception) {
|
|
90
111
|
Log.e(NAME, "Error in UI thread: ${uiError.message}", uiError)
|
|
112
|
+
// Clear the presenting flag on error
|
|
113
|
+
isPresentingOverlay = false
|
|
91
114
|
promise.reject("UI_THREAD_ERROR", "Failed in UI thread: ${uiError.message}", uiError)
|
|
92
115
|
}
|
|
93
116
|
}
|
|
94
117
|
} catch (e: Exception) {
|
|
95
118
|
Log.e(NAME, "Error presenting overlay: ${e.message}", e)
|
|
119
|
+
// Clear the presenting flag on error
|
|
120
|
+
isPresentingOverlay = false
|
|
96
121
|
promise.reject("PRESENT_OVERLAY_ERROR", "Failed to present overlay: ${e.message}", e)
|
|
97
122
|
}
|
|
98
123
|
}
|
|
@@ -137,6 +162,8 @@ class NamiOverlayControlBridgeModule(private val ctx: ReactApplicationContext)
|
|
|
137
162
|
overlay.overridePendingTransition(0, 0)
|
|
138
163
|
}
|
|
139
164
|
currentOverlayActivity = null
|
|
165
|
+
// Clear the presenting flag when overlay is finished
|
|
166
|
+
isPresentingOverlay = false
|
|
140
167
|
|
|
141
168
|
// Wait for activity to actually finish before resolving promise
|
|
142
169
|
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
|
|
@@ -153,12 +180,16 @@ class NamiOverlayControlBridgeModule(private val ctx: ReactApplicationContext)
|
|
|
153
180
|
@Suppress("DEPRECATION")
|
|
154
181
|
overridePendingTransition(0, 0)
|
|
155
182
|
}
|
|
183
|
+
// Clear the presenting flag when overlay is finished
|
|
184
|
+
isPresentingOverlay = false
|
|
156
185
|
|
|
157
186
|
// Wait for activity to actually finish before resolving promise
|
|
158
187
|
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
|
|
159
188
|
promise.resolve(null)
|
|
160
189
|
}, 100)
|
|
161
190
|
} ?: run {
|
|
191
|
+
// Clear the presenting flag even if no activity was found
|
|
192
|
+
isPresentingOverlay = false
|
|
162
193
|
promise.resolve(null)
|
|
163
194
|
}
|
|
164
195
|
}
|
|
@@ -68,7 +68,7 @@ class NamiPaywallManagerBridgeModule internal constructor(
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
if (purchaseSuccess != null) {
|
|
71
|
-
val activity = latestPaywallActivity ?:
|
|
71
|
+
val activity = latestPaywallActivity ?: reactApplicationContext.getCurrentActivity()
|
|
72
72
|
if (activity != null) {
|
|
73
73
|
NamiPaywallManager.buySkuComplete(activity, purchaseSuccess)
|
|
74
74
|
} else {
|
|
@@ -166,7 +166,7 @@ class NamiPaywallManagerBridgeModule internal constructor(
|
|
|
166
166
|
reactApplicationContext.runOnUiQueueThread {
|
|
167
167
|
latestPaywallActivity?.let {
|
|
168
168
|
NamiPaywallManager.buySkuCancel(it)
|
|
169
|
-
} ?:
|
|
169
|
+
} ?: reactApplicationContext.getCurrentActivity()?.let {
|
|
170
170
|
NamiPaywallManager.buySkuCancel(it)
|
|
171
171
|
} ?: NamiPaywallManager.buySkuCancel()
|
|
172
172
|
}
|
|
@@ -24,6 +24,8 @@ class ReactOverlayActivity : ReactActivity() {
|
|
|
24
24
|
// Clear the reference when activity is destroyed
|
|
25
25
|
if (NamiOverlayControlBridgeModule.currentOverlayActivity == this) {
|
|
26
26
|
NamiOverlayControlBridgeModule.currentOverlayActivity = null
|
|
27
|
+
// Also clear the presenting flag to prevent stuck states
|
|
28
|
+
NamiOverlayControlBridgeModule.clearPresentingFlag()
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
}
|
|
@@ -81,6 +81,7 @@ export interface Spec extends TurboModule {
|
|
|
81
81
|
value?: string;
|
|
82
82
|
}[]>;
|
|
83
83
|
registerAvailableCampaignsHandler(): void;
|
|
84
|
+
productGroups(label: string | null, withUrl: string | null): Promise<string[]>;
|
|
84
85
|
}
|
|
85
86
|
declare const _default: Spec;
|
|
86
87
|
export default _default;
|
|
@@ -27,4 +27,5 @@ export declare const NamiCampaignManager: {
|
|
|
27
27
|
value?: string;
|
|
28
28
|
}[]>;
|
|
29
29
|
registerAvailableCampaignsHandler: (callback: (campaigns: NamiCampaign[]) => void) => (() => void);
|
|
30
|
+
getProductGroups: (label?: string | null, withUrl?: string | null) => Promise<string[]>;
|
|
30
31
|
};
|
package/dist/src/version.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ RCT_EXTERN_METHOD(refresh:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRe
|
|
|
22
22
|
|
|
23
23
|
RCT_EXTERN_METHOD(registerAvailableCampaignsHandler)
|
|
24
24
|
|
|
25
|
+
RCT_EXTERN_METHOD(productGroups:(nullable NSString *)label withUrl:(nullable NSString *)withUrl resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
26
|
+
|
|
25
27
|
+ (BOOL)requiresMainQueueSetup {
|
|
26
28
|
return YES;
|
|
27
29
|
}
|
|
@@ -320,4 +320,20 @@ class RNNamiCampaignManager: RCTEventEmitter {
|
|
|
320
320
|
self.safeSend(withName: "AvailableCampaignsChanged", body: dictionaries)
|
|
321
321
|
}
|
|
322
322
|
}
|
|
323
|
+
|
|
324
|
+
@objc(productGroups:withUrl:resolver:rejecter:)
|
|
325
|
+
func productGroups(
|
|
326
|
+
label: String?,
|
|
327
|
+
withUrl: String?,
|
|
328
|
+
resolve: @escaping RCTPromiseResolveBlock,
|
|
329
|
+
reject _: @escaping RCTPromiseRejectBlock
|
|
330
|
+
) {
|
|
331
|
+
var url: URL?
|
|
332
|
+
if let withUrl = withUrl {
|
|
333
|
+
url = URL(string: withUrl)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
let productGroups = NamiCampaignManager.productGroups(label: label, url: url)
|
|
337
|
+
resolve(productGroups)
|
|
338
|
+
}
|
|
323
339
|
}
|
package/package.json
CHANGED
|
@@ -92,6 +92,11 @@ export interface Spec extends TurboModule {
|
|
|
92
92
|
>;
|
|
93
93
|
|
|
94
94
|
registerAvailableCampaignsHandler(): void;
|
|
95
|
+
|
|
96
|
+
productGroups(
|
|
97
|
+
label: string | null,
|
|
98
|
+
withUrl: string | null,
|
|
99
|
+
): Promise<string[]>;
|
|
95
100
|
}
|
|
96
101
|
|
|
97
102
|
export default TurboModuleRegistry.getEnforcing<Spec>('RNNamiCampaignManager');
|
|
@@ -115,4 +115,11 @@ export const NamiCampaignManager = {
|
|
|
115
115
|
RNNamiCampaignManager.registerAvailableCampaignsHandler?.();
|
|
116
116
|
return () => sub.remove();
|
|
117
117
|
},
|
|
118
|
+
|
|
119
|
+
getProductGroups: async (label?: string | null, withUrl?: string | null) => {
|
|
120
|
+
return await RNNamiCampaignManager.productGroups(
|
|
121
|
+
label ?? null,
|
|
122
|
+
withUrl ?? null,
|
|
123
|
+
);
|
|
124
|
+
},
|
|
118
125
|
};
|
|
@@ -16,7 +16,18 @@ export const NamiOverlayControl = {
|
|
|
16
16
|
emitter,
|
|
17
17
|
|
|
18
18
|
presentOverlay(): Promise<void> {
|
|
19
|
-
return RNNamiOverlayControl.presentOverlay()
|
|
19
|
+
return RNNamiOverlayControl.presentOverlay().catch((error) => {
|
|
20
|
+
// Handle the case where an overlay is already active
|
|
21
|
+
if (error.code === 'OVERLAY_ALREADY_ACTIVE') {
|
|
22
|
+
console.warn(
|
|
23
|
+
'NamiOverlayControl: An overlay is already being presented. Ignoring duplicate call.',
|
|
24
|
+
);
|
|
25
|
+
// Return a resolved promise to maintain backward compatibility
|
|
26
|
+
return Promise.resolve();
|
|
27
|
+
}
|
|
28
|
+
// Re-throw other errors
|
|
29
|
+
throw error;
|
|
30
|
+
});
|
|
20
31
|
},
|
|
21
32
|
|
|
22
33
|
finishOverlay(result?: any): Promise<void> {
|
package/src/version.ts
CHANGED