react-native-nami-sdk 3.3.1 → 3.3.2-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.
@@ -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.1"
89
- amazonImplementation "com.namiml:sdk-amazon:3.3.1"
88
+ playImplementation "com.namiml:sdk-android:3.3.2.2"
89
+ amazonImplementation "com.namiml:sdk-amazon:3.3.2.2"
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"
@@ -55,6 +55,13 @@ class NamiFlowManagerBridgeModule internal constructor(
55
55
  }, 100L)
56
56
  }
57
57
 
58
+ @ReactMethod
59
+ fun pause() {
60
+ Handler(Looper.getMainLooper()).postDelayed({
61
+ NamiFlowManager.pause()
62
+ }, 100L)
63
+ }
64
+
58
65
  @ReactMethod
59
66
  fun finish() {
60
67
  Handler(Looper.getMainLooper()).postDelayed({
@@ -114,7 +114,7 @@ fun NamiSKU.toSkuDict(): WritableMap {
114
114
  productDict.putString("id", this.id)
115
115
  productDict.putString("skuId", this.skuId)
116
116
  productDict.putString("name", this.name ?: "")
117
- productDict.putString("type", this.type?.toString() ?: "unknown")
117
+ productDict.putString("type", this.type.toString().lowercase() ?: "unknown")
118
118
 
119
119
  this.promoId?.let {
120
120
  productDict.putString("promoId", it)
@@ -26,6 +26,9 @@ export interface Spec extends TurboModule {
26
26
  type?: string;
27
27
  promoId?: string;
28
28
  promoToken?: string;
29
+ promoOffer?: {
30
+ [key: string]: string;
31
+ } | null;
29
32
  };
30
33
  purchaseError?: string;
31
34
  purchases?: Array<{
@@ -4,6 +4,7 @@ export interface Spec extends TurboModule {
4
4
  isFlowOpen(): Promise<boolean>;
5
5
  registerStepHandoff(): void;
6
6
  resume(): void;
7
+ pause(): void;
7
8
  registerEventHandler(): void;
8
9
  }
9
10
  declare const _default: Spec;
@@ -7,6 +7,7 @@ export declare const NamiFlowManager: {
7
7
  emitter: NativeEventEmitter;
8
8
  registerStepHandoff: (callback: (handoffTag: string, handoffData?: Record<string, unknown>) => void) => (() => void);
9
9
  resume: () => void;
10
+ pause: () => void;
10
11
  registerEventHandler: (callback: (payload: Record<string, unknown>) => void) => (() => void);
11
12
  finish: () => void;
12
13
  isFlowOpen: () => Promise<boolean>;
@@ -16,6 +16,9 @@ export type NamiSKU = {
16
16
  type: NamiSKUType;
17
17
  promoId?: string | null;
18
18
  promoToken?: string | null;
19
+ promoOffer?: {
20
+ [key: string]: string;
21
+ } | null;
19
22
  };
20
23
  export declare enum NamiPurchaseState {
21
24
  PENDING = "pending",
@@ -2,4 +2,4 @@
2
2
  * Auto-generated file. Do not edit manually.
3
3
  * React Native Nami SDK version.
4
4
  */
5
- export declare const NAMI_REACT_NATIVE_VERSION = "3.3.1";
5
+ export declare const NAMI_REACT_NATIVE_VERSION = "3.3.2-3";
package/ios/Nami.swift CHANGED
@@ -63,20 +63,37 @@ class RNNami: NSObject {
63
63
  config.initialConfig = initialConfig
64
64
  }
65
65
 
66
+ var didCallBack = false
66
67
  Nami.configure(with: config) { sdkConfigured in
67
- resolve(["success": sdkConfigured])
68
+ didCallBack = true
69
+ NSLog("RNNami: configure() completion called, sdkConfigured: \(sdkConfigured)")
70
+ DispatchQueue.main.async {
71
+ resolve(["success": sdkConfigured])
72
+ }
73
+ }
74
+
75
+ DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
76
+ if !didCallBack {
77
+ NSLog("RNNami: configure() completion NEVER CALLED, reporting failure.")
78
+ resolve(["success": false])
79
+ }
68
80
  }
69
81
  }
70
82
 
71
83
  @objc
72
- func sdkConfigured(_ resolve: RCTPromiseResolveBlock, rejecter _: RCTPromiseRejectBlock) {
73
- resolve(Nami.sdkConfigured())
84
+ func sdkConfigured(_ resolve: @escaping RCTPromiseResolveBlock, rejecter _: RCTPromiseRejectBlock) {
85
+ let sdkConfigured = Nami.sdkConfigured()
86
+ DispatchQueue.main.async {
87
+ resolve(sdkConfigured)
88
+ }
74
89
  }
75
90
 
76
91
  @objc(sdkVersion:rejecter:)
77
92
  func sdkVersion(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
78
- let version = Nami.sdkVersion
79
- resolve(version)
93
+ let version = Nami.sdkVersion()
94
+ DispatchQueue.main.async {
95
+ resolve(version)
96
+ }
80
97
  }
81
98
 
82
99
  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, NSObject)
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
 
@@ -95,6 +95,7 @@ class RNNamiCampaignManager: RCTEventEmitter {
95
95
  skuDict["name"] = sku.name
96
96
  skuDict["skuId"] = sku.skuId
97
97
  skuDict["type"] = sku.type.description
98
+ skuDict["promoId"] = sku.promoId
98
99
  }
99
100
 
100
101
  var componentChange: [String: Any?] = [:]
@@ -142,8 +143,22 @@ class RNNamiCampaignManager: RCTEventEmitter {
142
143
  }
143
144
  }
144
145
 
145
- func handleLaunch(callback: @escaping RCTResponseSenderBlock, success: Bool, error: Error?) {
146
- callback([success, error?._code as Any])
146
+ func handleLaunch(callback: RCTResponseSenderBlock?, success: Bool, error: Error?) {
147
+ guard let callback = callback else {
148
+ print("[handleLaunch] callback was nil — possibly already released.")
149
+ return
150
+ }
151
+
152
+ var errorInfo: Any = NSNull()
153
+ if let nsError = error as NSError? {
154
+ errorInfo = [
155
+ "code": nsError.code,
156
+ "domain": nsError.domain,
157
+ "message": nsError.localizedDescription,
158
+ ]
159
+ }
160
+
161
+ callback([success, errorInfo])
147
162
  }
148
163
 
149
164
  @objc(launch:withUrl:context:completion:paywallCompletion:)
@@ -173,55 +188,67 @@ class RNNamiCampaignManager: RCTEventEmitter {
173
188
  }
174
189
 
175
190
  if productGroups != nil || customAttributes != nil || customObject != nil {
176
- paywallLaunchContext = PaywallLaunchContext(productGroups: productGroups, customAttributes: customAttributes, customObject: customObject)
191
+ paywallLaunchContext = PaywallLaunchContext(
192
+ productGroups: productGroups,
193
+ customAttributes: customAttributes,
194
+ customObject: customObject
195
+ )
196
+ }
197
+
198
+ // Wrap the callback to ensure it's only called once
199
+ var callbackOnce: RCTResponseSenderBlock? = callback
200
+ let safeCallback: RCTResponseSenderBlock = { args in
201
+ if let cb = callbackOnce {
202
+ cb(args)
203
+ callbackOnce = nil
204
+ } else {
205
+ print("[RNNamiCampaignManager] Warning: callback already called or cleared")
206
+ }
177
207
  }
178
208
 
179
209
  var launchMethod: (() -> Void)?
180
210
 
181
211
  if let urlString = withUrl, let urlObject = URL(string: urlString) {
182
212
  launchMethod = {
183
- NamiCampaignManager.launch(url: urlObject, context: paywallLaunchContext,
184
- launchHandler: { success, error in
185
- self.handleLaunch(
186
- callback: callback,
187
- success: success,
188
- error: error
189
- )
190
- },
191
- paywallActionHandler: { paywallEvent in
192
- self.handlePaywallAction(paywallEvent: paywallEvent)
193
- })
213
+ NamiCampaignManager.launch(
214
+ url: urlObject,
215
+ context: paywallLaunchContext,
216
+ launchHandler: { [weak self] success, error in
217
+ self?.handleLaunch(callback: safeCallback, success: success, error: error)
218
+ },
219
+ paywallActionHandler: { [weak self] event in
220
+ self?.handlePaywallAction(paywallEvent: event)
221
+ }
222
+ )
194
223
  }
195
224
  } else if let label = label {
196
225
  launchMethod = {
197
- NamiCampaignManager.launch(label: label, context: paywallLaunchContext,
198
- launchHandler: { success, error in
199
- self.handleLaunch(
200
- callback: callback,
201
- success: success,
202
- error: error
203
- )
204
- },
205
- paywallActionHandler: { paywallEvent in
206
- self.handlePaywallAction(paywallEvent: paywallEvent)
207
- })
226
+ NamiCampaignManager.launch(
227
+ label: label,
228
+ context: paywallLaunchContext,
229
+ launchHandler: { [weak self] success, error in
230
+ self?.handleLaunch(callback: safeCallback, success: success, error: error)
231
+ },
232
+ paywallActionHandler: { [weak self] event in
233
+ self?.handlePaywallAction(paywallEvent: event)
234
+ }
235
+ )
208
236
  }
209
237
  } else {
210
238
  print("Neither URL nor label provided calling default launch.")
211
239
  launchMethod = {
212
- NamiCampaignManager.launch(context: paywallLaunchContext,
213
- launchHandler: { success, error in
214
- self.handleLaunch(
215
- callback: callback,
216
- success: success,
217
- error: error
218
- )
219
- },
220
- paywallActionHandler: { paywallEvent in
221
- self.handlePaywallAction(paywallEvent: paywallEvent)
222
- })
240
+ NamiCampaignManager.launch(
241
+ context: paywallLaunchContext,
242
+ launchHandler: { [weak self] success, error in
243
+ self?.handleLaunch(callback: safeCallback, success: success, error: error)
244
+ },
245
+ paywallActionHandler: { [weak self] event in
246
+ self?.handlePaywallAction(paywallEvent: event)
247
+ }
248
+ )
223
249
  }
224
250
  }
251
+
225
252
  DispatchQueue.main.async {
226
253
  launchMethod?()
227
254
  }
@@ -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, NSObject)
11
+ @interface RCT_EXTERN_MODULE(RNNamiCustomerManager, RCTEventEmitter)
11
12
 
12
13
  RCT_EXTERN_METHOD(setCustomerAttribute:(NSString *)key value:(NSString *)value)
13
14
 
@@ -46,8 +46,10 @@ class RNNamiCustomerManager: RCTEventEmitter {
46
46
 
47
47
  @objc(getCustomerAttribute:resolver:rejecter:)
48
48
  func getCustomerAttribute(key: String, resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
49
- let customerAttribute = NamiCustomerManager.getCustomerAttribute(key: key)
50
- resolve(customerAttribute)
49
+ DispatchQueue.main.async {
50
+ let customerAttribute = NamiCustomerManager.getCustomerAttribute(key: key)
51
+ resolve(customerAttribute)
52
+ }
51
53
  }
52
54
 
53
55
  @objc(clearCustomerAttribute:)
@@ -78,45 +80,61 @@ class RNNamiCustomerManager: RCTEventEmitter {
78
80
  @objc(inAnonymousMode:rejecter:)
79
81
  func inAnonymousMode(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
80
82
  let inAnonymousMode: Bool = NamiCustomerManager.inAnonymousMode()
81
- resolve(inAnonymousMode)
83
+ DispatchQueue.main.async {
84
+ resolve(inAnonymousMode)
85
+ }
82
86
  }
83
87
 
84
88
  @objc(journeyState:rejecter:)
85
89
  func journeyState(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
86
90
  if let journeyState = NamiCustomerManager.journeyState() {
87
91
  let dictionary = journeyStateToDictionary(journeyState)
88
- resolve(dictionary)
92
+ DispatchQueue.main.async {
93
+ resolve(dictionary)
94
+ }
89
95
  } else {
90
- resolve(nil)
96
+ DispatchQueue.main.async {
97
+ resolve(nil)
98
+ }
91
99
  }
92
100
  }
93
101
 
94
102
  @objc(isLoggedIn:rejecter:)
95
103
  func isLoggedIn(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
96
104
  let isLoggedIn = NamiCustomerManager.isLoggedIn()
97
- resolve(isLoggedIn)
105
+ DispatchQueue.main.async {
106
+ resolve(isLoggedIn)
107
+ }
98
108
  }
99
109
 
100
110
  @objc(loggedInId:rejecter:)
101
111
  func loggedInId(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
102
112
  let id = NamiCustomerManager.loggedInId()
103
- resolve(id)
113
+ DispatchQueue.main.async {
114
+ resolve(id)
115
+ }
104
116
  }
105
117
 
106
118
  @objc(deviceId:rejecter:)
107
119
  func deviceId(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
108
120
  let id = NamiCustomerManager.deviceId()
109
- resolve(id)
121
+ DispatchQueue.main.async {
122
+ resolve(id)
123
+ }
110
124
  }
111
125
 
112
126
  @objc(login:)
113
127
  func login(customerId: String) {
114
- NamiCustomerManager.login(withId: customerId)
128
+ DispatchQueue.main.async {
129
+ NamiCustomerManager.login(withId: customerId)
130
+ }
115
131
  }
116
132
 
117
133
  @objc(logout)
118
134
  func logout() {
119
- NamiCustomerManager.logout()
135
+ DispatchQueue.main.async {
136
+ NamiCustomerManager.logout()
137
+ }
120
138
  }
121
139
 
122
140
  @objc(registerJourneyStateHandler)
@@ -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(RNNamiEntitlementManager, NSObject)
11
+ @interface RCT_EXTERN_MODULE(RNNamiEntitlementManager, RCTEventEmitter)
11
12
 
12
13
  RCT_EXTERN_METHOD(isEntitlementActive:(nullable NSString *)referenceId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
13
14
 
@@ -12,6 +12,7 @@
12
12
  RCT_EXTERN_METHOD(registerStepHandoff)
13
13
  RCT_EXTERN_METHOD(registerEventHandler)
14
14
  RCT_EXTERN_METHOD(resume)
15
+ RCT_EXTERN_METHOD(pause)
15
16
  RCT_EXTERN_METHOD(finish)
16
17
  RCT_EXTERN_METHOD(isFlowOpen:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
17
18
 
@@ -59,6 +59,12 @@ class RNNamiFlowManager: RCTEventEmitter {
59
59
  }
60
60
  }
61
61
 
62
+ @objc func pause() {
63
+ DispatchQueue.main.async {
64
+ NamiFlowManager.pause()
65
+ }
66
+ }
67
+
62
68
  @objc func finish() {
63
69
  DispatchQueue.main.async {
64
70
  NamiFlowManager.finish()
@@ -13,7 +13,7 @@
13
13
 
14
14
  #import "React/RCTViewManager.h"
15
15
 
16
- @interface RCT_EXTERN_MODULE(RNNamiPaywallManager, NSObject)
16
+ @interface RCT_EXTERN_MODULE(RNNamiPaywallManager, RCTEventEmitter)
17
17
 
18
18
  RCT_EXTERN_METHOD(buySkuComplete:(NSDictionary)dict)
19
19
 
@@ -13,7 +13,7 @@
13
13
 
14
14
  #import "React/RCTViewManager.h"
15
15
 
16
- @interface RCT_EXTERN_MODULE(RNNamiPurchaseManager, NSObject)
16
+ @interface RCT_EXTERN_MODULE(RNNamiPurchaseManager, RCTEventEmitter)
17
17
 
18
18
  RCT_EXTERN_METHOD(allPurchases:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
19
19
 
@@ -69,6 +69,10 @@ class RNNamiPurchaseManager: RCTEventEmitter {
69
69
  skuDict["promoId"] = promoId
70
70
  }
71
71
 
72
+ if let computed = sku.computedSignature {
73
+ skuDict["promoOffer"] = computed
74
+ }
75
+
72
76
  return NSDictionary(dictionary: skuDict.compactMapValues { $0 })
73
77
  }
74
78
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nami-sdk",
3
- "version": "3.3.1",
3
+ "version": "3.3.2-3",
4
4
  "description": "React Native Module for Nami - Easy subscriptions & in-app purchases, with powerful built-in paywalls and A/B testing.",
5
5
  "main": "index.ts",
6
6
  "types": "dist/index.d.ts",
@@ -13,7 +13,7 @@ Pod::Spec.new do |s|
13
13
  s.homepage = package['homepage']
14
14
  s.license = package['license']
15
15
 
16
- s.platforms = { :ios => "14.0", :tvos => "15.0" }
16
+ s.platforms = { :ios => "15.0", :tvos => "15.0" }
17
17
 
18
18
 
19
19
  s.source = { :git => "https://github.com/namiml/react-native-nami-sdk.git", :tag => "#{s.version}" }
@@ -21,7 +21,7 @@ Pod::Spec.new do |s|
21
21
  s.requires_arc = true
22
22
  s.swift_version = '5.0' # or your supported version
23
23
 
24
- s.dependency 'Nami', '3.3.1.1'
24
+ s.dependency 'Nami', '3.3.2.9'
25
25
  s.dependency 'React'
26
26
 
27
27
  s.pod_target_xcconfig = {
@@ -29,6 +29,7 @@ export interface Spec extends TurboModule {
29
29
  type?: string;
30
30
  promoId?: string;
31
31
  promoToken?: string;
32
+ promoOffer?: { [key: string]: string } | null;
32
33
  };
33
34
  purchaseError?: string;
34
35
  purchases?: Array<{
@@ -7,6 +7,7 @@ export interface Spec extends TurboModule {
7
7
 
8
8
  registerStepHandoff(): void;
9
9
  resume(): void;
10
+ pause(): void;
10
11
  registerEventHandler(): void;
11
12
  }
12
13
 
@@ -46,6 +46,11 @@ export const NamiFlowManager = {
46
46
  RNNamiFlowManager.resume?.();
47
47
  },
48
48
 
49
+ pause: (): void => {
50
+ console.info('[NamiFlowManager] pause from handoff requested');
51
+ RNNamiFlowManager.pause();
52
+ },
53
+
49
54
  registerEventHandler: (
50
55
  callback: (payload: Record<string, unknown>) => void,
51
56
  ): (() => void) => {
package/src/types.ts CHANGED
@@ -114,6 +114,7 @@ export type NamiSKU = {
114
114
  type: NamiSKUType;
115
115
  promoId?: string | null;
116
116
  promoToken?: string | null;
117
+ promoOffer?: { [key: string]: string } | null;
117
118
  };
118
119
 
119
120
  export enum NamiPurchaseState {
package/src/version.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * Auto-generated file. Do not edit manually.
3
3
  * React Native Nami SDK version.
4
4
  */
5
- export const NAMI_REACT_NATIVE_VERSION = '3.3.1';
5
+ export const NAMI_REACT_NATIVE_VERSION = '3.3.2-3';