react-native-nami-sdk 2.0.4 → 3.0.8

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 (59) hide show
  1. package/.github/workflows/app_stg.yaml +203 -0
  2. package/.github/workflows/build.yml +2 -2
  3. package/.pre-commit-config.yaml +25 -0
  4. package/android/build.gradle +24 -13
  5. package/android/gradle/wrapper/gradle-wrapper.properties +5 -1
  6. package/android/src/main/java/com/nami/reactlibrary/Constants.kt +1 -1
  7. package/android/src/main/java/com/nami/reactlibrary/NamiBridgeModule.kt +6 -50
  8. package/android/src/main/java/com/nami/reactlibrary/NamiBridgePackage.java +1 -3
  9. package/android/src/main/java/com/nami/reactlibrary/NamiCampaignManagerBridge.kt +133 -0
  10. package/android/src/main/java/com/nami/reactlibrary/NamiCustomerManagerBridge.kt +89 -20
  11. package/android/src/main/java/com/nami/reactlibrary/NamiEmitter.kt +25 -25
  12. package/android/src/main/java/com/nami/reactlibrary/NamiEntitlementManagerBridgeModule.kt +31 -130
  13. package/android/src/main/java/com/nami/reactlibrary/NamiMLManagerBridgeModule.kt +1 -1
  14. package/android/src/main/java/com/nami/reactlibrary/NamiPaywallManagerBridgeModule.kt +36 -147
  15. package/android/src/main/java/com/nami/reactlibrary/NamiPurchaseManagerBridge.kt +37 -39
  16. package/android/src/main/java/com/nami/reactlibrary/NamiUtil.kt +50 -180
  17. package/build-utils/get_version_code.py +140 -0
  18. package/index.d.ts +20 -0
  19. package/index.js +7 -6
  20. package/ios/Nami.m +18 -72
  21. package/ios/NamiBridgeUtil.h +4 -6
  22. package/ios/NamiBridgeUtil.m +37 -99
  23. package/ios/NamiCampaignManagerBridge.m +26 -0
  24. package/ios/NamiCampaignManagerBridge.swift +107 -0
  25. package/ios/NamiCustomerManager.m +19 -24
  26. package/ios/NamiCustomerManager.swift +122 -0
  27. package/ios/NamiEmitter.m +85 -95
  28. package/ios/NamiEntitlementManagerBridge.m +7 -107
  29. package/ios/NamiEntitlementManagerBridge.swift +74 -0
  30. package/ios/NamiMLManagerBridge.m +2 -2
  31. package/ios/NamiPaywallManagerBridge.m +22 -94
  32. package/ios/NamiPaywallManagerBridge.swift +93 -0
  33. package/ios/NamiPurchaseManagerBridge.m +40 -71
  34. package/ios/NamiPurchaseManagerBridge.swift +174 -0
  35. package/ios/Podfile +2 -2
  36. package/ios/RNNami-Bridging-Header.h +5 -0
  37. package/ios/RNNami.h +0 -1
  38. package/ios/RNNami.m +1 -1
  39. package/ios/RNNami.xcodeproj/project.pbxproj +84 -8
  40. package/ios/RNNami.xcodeproj/xcshareddata/xcschemes/RNNami.xcscheme +67 -0
  41. package/package.json +1 -1
  42. package/react-native-nami-sdk.podspec +3 -3
  43. package/src/Nami.d.ts +112 -0
  44. package/src/Nami.js +10 -0
  45. package/src/NamiCampaignManager.d.ts +54 -0
  46. package/src/NamiCampaignManager.js +43 -0
  47. package/src/NamiCustomerManager.d.ts +39 -0
  48. package/src/NamiCustomerManager.js +43 -0
  49. package/src/NamiEntitlementManager.d.ts +24 -0
  50. package/src/NamiEntitlementManager.js +23 -0
  51. package/src/NamiMLManager.d.ts +5 -0
  52. package/src/NamiMLManager.js +7 -0
  53. package/src/NamiPaywallManager.d.ts +57 -0
  54. package/src/NamiPaywallManager.js +28 -0
  55. package/src/NamiPurchaseManager.d.ts +57 -0
  56. package/src/NamiPurchaseManager.js +37 -0
  57. package/src/types.ts +36 -0
  58. package/android/src/main/java/com/nami/reactlibrary/NamiAnalyticsEmitter.kt +0 -121
  59. package/ios/NamiAnalyticsEmitter.m +0 -146
@@ -0,0 +1,122 @@
1
+ //
2
+ // NamiCustomerManager.swift
3
+ // RNNami
4
+ //
5
+ // Copyright © 2023 Nami ML INc.. All rights reserved.
6
+ //
7
+
8
+ import Foundation
9
+ import NamiApple
10
+ import React
11
+
12
+ @objc(RNNamiCustomerManager)
13
+ class RNNamiCustomerManager: RCTEventEmitter {
14
+ override func supportedEvents() -> [String]! {
15
+ return ["JourneyStateChanged", "AccountStateChanged"]
16
+ }
17
+
18
+ private func journeyStateToDictionary(_ journeyState: CustomerJourneyState) -> NSDictionary {
19
+ let dictionary: [String: Any?] = [
20
+ "formerSubscriber": journeyState.formerSubscriber,
21
+ "inGracePeriod": journeyState.inGracePeriod,
22
+ "inTrialPeriod": journeyState.inTrialPeriod,
23
+ "inIntroOfferPeriod": journeyState.inIntroOfferPeriod,
24
+ "isCancelled": journeyState.isCancelled,
25
+ "inPause": journeyState.inPause,
26
+ "inAccountHold": journeyState.inAccountHold,
27
+ ]
28
+ return NSDictionary(dictionary: dictionary.compactMapValues { $0 })
29
+ }
30
+
31
+ @objc(setCustomerAttribute:value:)
32
+ func setCustomerAttribute(key: String, value: String) {
33
+ NamiCustomerManager.setCustomerAttribute(key, value)
34
+ }
35
+
36
+ @objc(getCustomerAttribute:resolver:rejecter:)
37
+ func getCustomerAttribute(key: String, resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
38
+ let customerAttribute = NamiCustomerManager.getCustomerAttribute(key: key)
39
+ resolve(customerAttribute)
40
+ }
41
+
42
+ @objc(clearCustomerAttribute:)
43
+ func clearCustomerAttribute(key: String) {
44
+ NamiCustomerManager.clearCustomerAttribute(key)
45
+ }
46
+
47
+ @objc(clearAllCustomerAttributes)
48
+ func clearAllCustomerAttributes() {
49
+ NamiCustomerManager.clearAllCustomerAttributes()
50
+ }
51
+
52
+ @objc(journeyState:rejecter:)
53
+ func journeyState(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
54
+ if let journeyState = NamiCustomerManager.journeyState() {
55
+ let dictionary = journeyStateToDictionary(journeyState)
56
+ resolve(dictionary)
57
+ } else {
58
+ resolve(nil)
59
+ }
60
+ }
61
+
62
+ @objc(isLoggedIn:rejecter:)
63
+ func isLoggedIn(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
64
+ let isLoggedIn = NamiCustomerManager.isLoggedIn()
65
+ resolve(isLoggedIn)
66
+ }
67
+
68
+ @objc(loggedInId:rejecter:)
69
+ func loggedInId(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
70
+ let id = NamiCustomerManager.loggedInId()
71
+ resolve(id)
72
+ }
73
+
74
+ @objc(deviceId:rejecter:)
75
+ func deviceId(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
76
+ let id = NamiCustomerManager.deviceId()
77
+ resolve(id)
78
+ }
79
+
80
+ @objc(login:completion:)
81
+ func login(customerId: String, callback: @escaping RCTResponseSenderBlock) {
82
+ NamiCustomerManager.login(withId: customerId, loginCompleteHandler: { success, error in
83
+ callback([success, error?._code as Any])
84
+ })
85
+ }
86
+
87
+ @objc(logout:)
88
+ func logout(callback: @escaping RCTResponseSenderBlock) {
89
+ NamiCustomerManager.logout(logoutCompleteHandler: { success, error in
90
+ callback([success, error?._code as Any])
91
+ })
92
+ }
93
+
94
+ @objc(registerJourneyStateHandler)
95
+ func registerJourneyStateHandler() {
96
+ NamiCustomerManager.registerJourneyStateHandler { journeyState in
97
+ let dictionary = self.journeyStateToDictionary(journeyState)
98
+ self.sendEvent(withName: "JourneyStateChanged", body: dictionary)
99
+ }
100
+ }
101
+
102
+ @objc(registerAccountStateHandler)
103
+ func registerAccountStateHandler() {
104
+ NamiCustomerManager.registerAccountStateHandler({action, success, error in
105
+ let actionString: String
106
+ switch action {
107
+ case .login:
108
+ actionString = "login"
109
+ case .logout:
110
+ actionString = "logout"
111
+ @unknown default:
112
+ actionString = "unknown"
113
+ }
114
+ let payload: [String: Any?] = [
115
+ "action": actionString,
116
+ "success": success,
117
+ "error": error?._code as Any
118
+ ]
119
+ self.sendEvent(withName: "AccountStateChanged", body: payload)
120
+ })
121
+ }
122
+ }
package/ios/NamiEmitter.m CHANGED
@@ -2,13 +2,12 @@
2
2
  // NamiEmitter.m
3
3
  // namiReactNative
4
4
  //
5
- // Created by Kendall Helmstetter Gelner on 12/11/19.
6
5
  // Copyright © 2019 Nami ML Inc. All rights reserved.
7
6
  //
8
7
 
9
8
  #import <Foundation/Foundation.h>
10
9
 
11
- #import <Nami/Nami.h>
10
+ #import <NamiApple/NamiApple.h>
12
11
 
13
12
  #import <React/RCTBridgeModule.h>
14
13
  #import <React/RCTEventEmitter.h>
@@ -32,37 +31,31 @@ static NamiEmitter *namiEmitter;
32
31
  self = [super init];
33
32
  if (self) {
34
33
  hasNamiEmitterListeners = NO;
35
-
34
+
36
35
  // Tell Nami to listen for purchases and we'll forward them on to listeners
37
36
  [NamiPurchaseManager registerPurchasesChangedHandler:^(NSArray<NamiPurchase *> * _Nonnull purchases, enum NamiPurchaseState purchaseState, NSError * _Nullable error) {
38
37
  [self sendEventPurchaseMadeWithPurchases:purchases withState:purchaseState error:error];
39
38
  }];
40
-
41
- [NamiEntitlementManager registerEntitlementsChangedHandler:^(NSArray<NamiEntitlement *> * _Nonnull entitlements) {
39
+
40
+ [NamiEntitlementManager registerActiveEntitlementsHandler:^(NSArray<NamiEntitlement *> * _Nonnull entitlements) {
42
41
  [self sendEventEntitlementsChangedWithEntitlements:entitlements];
43
42
  }];
44
-
45
-
46
- [NamiPaywallManager registerSignInHandler:^(UIViewController * _Nullable fromVC, NSString * _Nonnull developerPaywallID, NamiPaywall * _Nonnull paywallMetadata) {
47
- [self sendSignInActivateFromVC:fromVC forPaywall:developerPaywallID paywallMetadata:paywallMetadata];
48
- }];
49
-
50
- [NamiPaywallManager registerPaywallRaiseHandler:^(UIViewController * _Nullable fromVC, NSArray<NamiSKU *> * _Nullable products, NSString * _Nonnull developerPaywallID, NamiPaywall * _Nonnull paywallMetadata) {
51
- [self sendPaywallActivatedFromVC:fromVC forPaywall:developerPaywallID withProducts:products paywallMetadata:paywallMetadata];
52
- }];
53
-
54
- [NamiPaywallManager registerBlockingPaywallClosedHandler:^{
55
- [self sendBlockingPaywallClosed];
43
+
44
+ [NamiPaywallManager registerSignInHandler:^(UIViewController * _Nullable fromVC) {
45
+ [self sendSignInActivateFromVC:fromVC];
56
46
  }];
57
-
47
+
48
+ // [NamiPaywallManager registerCloseHandler:^(UIViewController * _Nullable fromVC) {
49
+ // [self sendBlockingPaywallClosed];
50
+ // }];
51
+
58
52
  [NamiPurchaseManager registerRestorePurchasesHandlerWithRestorePurchasesStateHandler:^(enum NamiRestorePurchasesState state, NSArray<NamiPurchase *> * _Nonnull newPurchases, NSArray<NamiPurchase *> * _Nonnull oldPurchases, NSError * _Nullable error) {
59
53
  [self sendRestorePurchasesStateChanged:state newPurchases:newPurchases oldPurchases:oldPurchases error:error];
60
54
  }];
61
-
62
- [NamiCustomerManager registerJourneyStateChangedHandler:^(CustomerJourneyState * _Nonnull journeyState) {
55
+
56
+ [NamiCustomerManager registerJourneyStateHandler:^(CustomerJourneyState * _Nonnull journeyState) {
63
57
  [self sendEventCustomerJourneyStateChanged:journeyState];
64
58
  }];
65
-
66
59
  }
67
60
  namiEmitter = self;
68
61
  return self;
@@ -86,9 +79,9 @@ static NamiEmitter *namiEmitter;
86
79
  NSArray<NamiPurchase *> *purchases = NamiPurchaseManager.allPurchases;
87
80
  NSMutableArray<NSString *> *productIDs = [NSMutableArray new];
88
81
  for (NamiPurchase *purchase in purchases) {
89
- [productIDs addObject:purchase.skuID];
82
+ [productIDs addObject:purchase.skuId];
90
83
  }
91
-
84
+
92
85
  return productIDs;
93
86
  }
94
87
 
@@ -118,7 +111,7 @@ bool hasNamiEmitterListeners;
118
111
 
119
112
  -(NSString *)purchaseStateToString:(NamiPurchaseState)purchaseState {
120
113
  switch (purchaseState) {
121
-
114
+
122
115
  case NamiPurchaseStatePending:
123
116
  return @"PENDING";
124
117
  break;
@@ -133,7 +126,7 @@ bool hasNamiEmitterListeners;
133
126
  break;
134
127
  case NamiPurchaseStateUnsubscribed:
135
128
  return @"UNSUBSCRIBED";
136
- break;
129
+ break;
137
130
  case NamiPurchaseStateDeferred:
138
131
  return @"DEFERRED";
139
132
  break;
@@ -142,7 +135,7 @@ bool hasNamiEmitterListeners;
142
135
  break;
143
136
  case NamiPurchaseStateCancelled:
144
137
  return @"CANCELLED";
145
- break;
138
+ break;
146
139
  case NamiPurchaseStateUnknown:
147
140
  return @"UNKNOWN";
148
141
  break;
@@ -154,33 +147,33 @@ bool hasNamiEmitterListeners;
154
147
 
155
148
  - (void)sendEventEntitlementsChangedWithEntitlements:(NSArray<NamiEntitlement *>*)entitlements {
156
149
  if (hasNamiEmitterListeners) {
157
-
150
+
158
151
  NSMutableArray *convertedEntitlementDicts = [NSMutableArray new];
159
152
  for ( NamiEntitlement *entitlementRecord in entitlements ) {
160
- if ( entitlementRecord.referenceID != nil ) {
153
+ if ( entitlementRecord.referenceId != nil ) {
161
154
  NSDictionary *entitlementDict = [NamiBridgeUtil entitlementToEntitlementDict:entitlementRecord];
162
155
  [convertedEntitlementDicts addObject:entitlementDict];
163
156
  }
164
157
  }
165
-
158
+
166
159
  NSMutableDictionary *sendDict = [NSMutableDictionary dictionary];
167
160
  sendDict[@"activeEntitlements"] = convertedEntitlementDicts;
168
-
161
+
169
162
  [self sendEventWithName:@"EntitlementsChanged" body:sendDict];
170
163
  }
171
164
  }
172
165
 
173
166
  - (void)sendEventPreparePaywallForDisplayFinishedWithResult:(BOOL)success developerPaywallID: (NSString * _Nullable) developerPaywallID error:(NSError * _Nullable) error {
174
167
  if (hasNamiEmitterListeners) {
175
-
168
+
176
169
  NSMutableDictionary *sendDict = [NSMutableDictionary dictionaryWithDictionary: @{ @"success": @(success) }];
177
-
170
+
178
171
  if (developerPaywallID != nil) {
179
172
  [sendDict addEntriesFromDictionary:@{
180
173
  @"developerPaywallID": developerPaywallID
181
174
  }];
182
175
  }
183
-
176
+
184
177
  if (error != nil) {
185
178
  [sendDict addEntriesFromDictionary:@{
186
179
  @"errorCode": @(error.code),
@@ -188,7 +181,7 @@ bool hasNamiEmitterListeners;
188
181
  }
189
182
  ];
190
183
  }
191
-
184
+
192
185
  NSLog(@"NamiBridge: Info: attempting to send result of preparePaywallForDisplay with result dictionary: %@", sendDict);
193
186
  [self sendEventWithName:@"PreparePaywallFinished" body:sendDict];
194
187
  }
@@ -203,82 +196,79 @@ bool hasNamiEmitterListeners;
203
196
 
204
197
  - (void)sendEventPurchaseMadeWithPurchases:(NSArray<NamiPurchase *>*)purchases withState:(NamiPurchaseState)purchaseState error:(NSError *)error {
205
198
  if (hasNamiEmitterListeners) {
206
-
207
-
199
+
200
+
208
201
  NSString *convertedState = [self purchaseStateToString:purchaseState];
209
-
202
+
210
203
  NSMutableArray *convertedPurchaseDicts = [NSMutableArray new];
211
204
  for ( NamiPurchase *purchaseRecord in purchases ) {
212
- if ( purchaseRecord.skuID != nil ) {
205
+ if ( purchaseRecord.skuId != nil ) {
213
206
  NSDictionary *purchaseDict = [NamiBridgeUtil purchaseToPurchaseDict:purchaseRecord];
214
207
  [convertedPurchaseDicts addObject:purchaseDict];
215
208
  }
216
209
  }
217
-
210
+
218
211
  NSString *localizedErrorDescription = [error localizedDescription];
219
-
212
+
220
213
  NSMutableDictionary *sendDict = [NSMutableDictionary dictionary];
221
214
  sendDict[@"purchases"] = convertedPurchaseDicts;
222
215
  sendDict[@"purchaseState"] = convertedState;
223
216
  if (localizedErrorDescription != nil) {
224
217
  sendDict[@"error"] = localizedErrorDescription;
225
218
  }
226
-
219
+
227
220
  [self sendEventWithName:@"PurchasesChanged" body:sendDict];
228
221
  }
229
222
  }
230
223
 
231
224
 
232
- - (void) sendSignInActivateFromVC:(UIViewController * _Nullable) fromVC
233
- forPaywall:(NSString * _Nonnull) developerPaywallID
234
- paywallMetadata:(NamiPaywall * _Nonnull) paywallMetadata {
225
+ - (void) sendSignInActivateFromVC:(UIViewController * _Nullable) fromVC {
235
226
  if (hasNamiEmitterListeners) {
236
227
  // Pass along paywall ID use in sign-in provider.
237
- [self sendEventWithName:@"SignInActivate" body:@{ @"developerPaywallID": developerPaywallID }];
228
+ [self sendEventWithName:@"SignInActivate" body:@{ }];
238
229
  }
239
230
  }
240
231
 
241
- - (void)sendPaywallActivatedFromVC:(UIViewController * _Nullable) fromVC
242
- forPaywall:(NSString * _Nonnull) developerPaywallID
243
- withProducts:(NSArray<NamiSKU *> * _Nullable) products
244
- paywallMetadata:(NamiPaywall * _Nonnull) paywallMetadata {
245
- if (hasNamiEmitterListeners) {
246
- NSMutableArray<NSDictionary<NSString *,NSString *> *> *skuDicts = [NSMutableArray new];
247
- for (NamiSKU *sku in products) {
248
- [skuDicts addObject:[NamiBridgeUtil skuToSKUDict:sku]];
249
- }
250
-
251
- NSMutableDictionary *paywallMeta = [NSMutableDictionary dictionaryWithDictionary:paywallMetadata.namiPaywallInfoDict];
252
- // This part is really meant to be internally facing, scrub from dictionary
253
-
254
- NSMutableDictionary *marketingContentDictionary = [NSMutableDictionary dictionaryWithDictionary:paywallMeta[@"marketing_content"]];
255
-
256
- // Populated SmartText formatted values in dictioanry to send
257
- marketingContentDictionary[@"body"] = [paywallMetadata body];
258
- marketingContentDictionary[@"title"] = [paywallMetadata title];
259
- paywallMeta[@"marketing_content"] = marketingContentDictionary;
260
- paywallMeta[@"purchase_terms"] = [paywallMetadata purchaseTerms];
261
-
262
- // Strip out presention_position from all listed sku items
263
- NSArray *cleanedOrderdMetadata = [NamiBridgeUtil stripPresentationPositionFromOrderedMetadataForPaywallMetaDict:paywallMeta];
264
- [paywallMeta setObject:cleanedOrderdMetadata forKey:@"formatted_skus"];
265
-
266
- [paywallMeta removeObjectForKey:@"sku_ordered_metadata"];
267
- [paywallMeta removeObjectForKey:@"skus"];
268
-
269
- NSDictionary *paywallStylingDict = [NamiBridgeUtil paywallStylingToPaywallStylingDict:[paywallMetadata styleData]];
270
- paywallMeta[@"styleData"] = paywallStylingDict;
271
-
272
- // remove keys that are inconsistent with android
273
- [paywallMeta removeObjectForKey:@"body"];
274
- [paywallMeta removeObjectForKey:@"title"];
275
- [paywallMeta removeObjectForKey:@"style"];
276
-
277
- [self sendEventWithName:@"AppPaywallActivate" body:@{ @"namiSkus": skuDicts,
278
- @"developerPaywallID": developerPaywallID,
279
- @"paywallMetadata": paywallMeta }];
280
- }
281
- }
232
+ //- (void)sendPaywallActivatedForPaywall:(NSString * _Nonnull) developerPaywallID
233
+ // withProducts:(NSArray<NamiSKU *> * _Nullable) products
234
+ // paywallMetadata:(NamiPaywall * _Nonnull) paywallMetadata {
235
+ // if (hasNamiEmitterListeners) {
236
+ // NSMutableArray<NSDictionary<NSString *,NSString *> *> *skuDicts = [NSMutableArray new];
237
+ // for (NamiSKU *sku in products) {
238
+ // [skuDicts addObject:[NamiBridgeUtil skuToSKUDict:sku]];
239
+ // }
240
+ //
241
+ // NSMutableDictionary *paywallMeta = [NSMutableDictionary dictionaryWithDictionary:paywallMetadata.namiPaywallInfoDict];
242
+ // // This part is really meant to be internally facing, scrub from dictionary
243
+ //
244
+ // NSMutableDictionary *marketingContentDictionary = [NSMutableDictionary dictionaryWithDictionary:paywallMeta[@"marketing_content"]];
245
+ //
246
+ // // Populated SmartText formatted values in dictioanry to send
247
+ // marketingContentDictionary[@"body"] = [paywallMetadata body];
248
+ // marketingContentDictionary[@"title"] = [paywallMetadata title];
249
+ // paywallMeta[@"marketing_content"] = marketingContentDictionary;
250
+ // paywallMeta[@"purchase_terms"] = [paywallMetadata purchaseTerms];
251
+ //
252
+ // // Strip out presention_position from all listed sku items
253
+ // NSArray *cleanedOrderdMetadata = [NamiBridgeUtil stripPresentationPositionFromOrderedMetadataForPaywallMetaDict:paywallMeta];
254
+ // [paywallMeta setObject:cleanedOrderdMetadata forKey:@"formatted_skus"];
255
+ //
256
+ // [paywallMeta removeObjectForKey:@"sku_ordered_metadata"];
257
+ // [paywallMeta removeObjectForKey:@"skus"];
258
+ //
259
+ // NSDictionary *paywallStylingDict = [NamiBridgeUtil paywallStylingToPaywallStylingDict:[paywallMetadata styleData]];
260
+ // paywallMeta[@"styleData"] = paywallStylingDict;
261
+ //
262
+ // // remove keys that are inconsistent with android
263
+ // [paywallMeta removeObjectForKey:@"body"];
264
+ // [paywallMeta removeObjectForKey:@"title"];
265
+ // [paywallMeta removeObjectForKey:@"style"];
266
+ //
267
+ // [self sendEventWithName:@"AppPaywallActivate" body:@{ @"namiSkus": skuDicts,
268
+ // @"developerPaywallID": developerPaywallID,
269
+ // @"paywallMetadata": paywallMeta }];
270
+ // }
271
+ //}
282
272
 
283
273
  - (NSDictionary *)buildRestorePurchasesStateChangedDict: (enum NamiRestorePurchasesState) state
284
274
  newPurchases: (NSArray<NamiPurchase *> * _Nonnull) newPurchases
@@ -291,13 +281,13 @@ bool hasNamiEmitterListeners;
291
281
  } else {
292
282
  initialDict = @{@"state": [NSNumber numberWithBool:state], @"stateDesc": [self restorePurchaseStateDescriptionFromCode:state]};
293
283
  }
294
-
284
+
295
285
  NSMutableDictionary *retDict = [NSMutableDictionary dictionary];
296
286
  [retDict addEntriesFromDictionary:initialDict];
297
-
287
+
298
288
  NSMutableArray *newPurchaseDicts = [NSMutableArray array];
299
289
  for ( NamiPurchase *purchaseRecord in newPurchases ) {
300
- if ( purchaseRecord.skuID == nil ) {
290
+ if ( purchaseRecord.skuId == nil ) {
301
291
  }
302
292
  NSDictionary *purchaseDict = [NamiBridgeUtil purchaseToPurchaseDict:purchaseRecord];
303
293
  [newPurchaseDicts addObject:purchaseDict];
@@ -305,15 +295,15 @@ bool hasNamiEmitterListeners;
305
295
 
306
296
  NSMutableArray *oldPurchaseDicts = [NSMutableArray array];
307
297
  for ( NamiPurchase *purchaseRecord in oldPurchases ) {
308
- if ( purchaseRecord.skuID == nil ) {
298
+ if ( purchaseRecord.skuId == nil ) {
309
299
  }
310
300
  NSDictionary *purchaseDict = [NamiBridgeUtil purchaseToPurchaseDict:purchaseRecord];
311
301
  [oldPurchaseDicts addObject:purchaseDict];
312
302
  }
313
-
303
+
314
304
  retDict[@"newPurchases"] = newPurchaseDicts;
315
305
  retDict[@"oldPurchases"] = oldPurchaseDicts;
316
-
306
+
317
307
  NSLog(@"NamiBridge: Info: RestorePurchases state change: %@", retDict);
318
308
 
319
309
  return retDict;
@@ -345,14 +335,14 @@ bool hasNamiEmitterListeners;
345
335
  // Let system know a blocking paywall has been closed, in case they want to react specifically.
346
336
  if (hasNamiEmitterListeners) {
347
337
  NSMutableDictionary *paywallMeta = [NSMutableDictionary dictionary];
348
-
338
+
349
339
  // Strip out presention_position from all listed sku items
350
340
  NSArray *cleanedOrderdMetadata = [NamiBridgeUtil stripPresentationPositionFromOrderedMetadataForPaywallMetaDict:paywallMeta];
351
341
  [paywallMeta setObject:cleanedOrderdMetadata forKey:@"formatted_skus"];
352
-
342
+
353
343
  [paywallMeta removeObjectForKey:@"sku_ordered_metadata"];
354
344
  [paywallMeta removeObjectForKey:@"skus"];
355
-
345
+
356
346
  [self sendEventWithName:@"BlockingPaywallClosed" body:@{ @"blockingPaywallClosed": @true }];
357
347
  }
358
348
  }
@@ -3,123 +3,23 @@
3
3
  // RNNami
4
4
  //
5
5
  // Created by Kendall Gelner on 4/8/20.
6
- // Copyright © 2020 Facebook. All rights reserved.
6
+ // Copyright © 2020-2023 Nami ML Inc. All rights reserved.
7
7
  //
8
8
 
9
- #import <Foundation/Foundation.h>
10
- #import <Nami/Nami.h>
11
- #import "NamiBridgeUtil.h"
12
-
13
9
  #import <React/RCTBridgeModule.h>
14
- #import <React/RCTEventEmitter.h>
15
-
16
- #import "React/RCTViewManager.h"
17
10
 
11
+ @interface RCT_EXTERN_MODULE(RNNamiEntitlementManager, NSObject)
18
12
 
13
+ RCT_EXTERN_METHOD(isEntitlementActive:(nullable NSString *)referenceId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
19
14
 
15
+ RCT_EXTERN_METHOD(active:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
20
16
 
21
- @interface NamiEntitlementManagerBridge : NSObject <RCTBridgeModule>
22
- @end
23
- @implementation NamiEntitlementManagerBridge (RCTExternModule)
24
-
25
-
26
- RCT_EXPORT_METHOD(isEntitlementActive:(nonnull NSString*)entitlementRefID completion:(RCTResponseSenderBlock)completion)
27
- {
28
- BOOL active = [NamiEntitlementManager isEntitlementActive:entitlementRefID];
29
- NSLog(@"Checking for %@ entitlement active, result was %@", entitlementRefID, [NSNumber numberWithBool:active] );
30
- completion(@[[NSNumber numberWithBool:active]]);
31
- }
32
-
33
-
34
- RCT_EXPORT_METHOD(getEntitlements:(RCTResponseSenderBlock)completion)
35
- {
36
- NSArray<NamiEntitlement *> *entitlements = [NamiEntitlementManager getEntitlements];
37
-
38
- NSMutableArray *entitlementDicts = [NSMutableArray new];
39
-
40
- for (NamiEntitlement *entitlement in entitlements) {
41
- NSDictionary *entitlementDict = [NamiBridgeUtil entitlementToEntitlementDict:entitlement];
42
- if ([entitlementDict count] > 0) {
43
- [entitlementDicts addObject:entitlementDict];
44
- }
45
- }
46
-
47
- completion(@[entitlementDicts]);
48
- }
49
-
50
-
51
- RCT_EXPORT_METHOD(activeEntitlements:(RCTResponseSenderBlock)completion)
52
- {
53
- NSArray<NamiEntitlement *> *entitlements = [NamiEntitlementManager activeEntitlements];
54
-
55
- NSMutableArray *entitlementDicts = [NSMutableArray new];
56
-
57
- for (NamiEntitlement *entitlement in entitlements) {
58
- NSDictionary *entitlementDict = [NamiBridgeUtil entitlementToEntitlementDict:entitlement];
59
- if ([entitlementDict count] > 0) {
60
- [entitlementDicts addObject:entitlementDict];
61
- }
62
- }
63
-
64
- completion(@[entitlementDicts]);
65
- }
66
-
67
- RCT_EXPORT_METHOD(setEntitlements:(NSArray *)entitlementSetterDicts)
68
- {
17
+ RCT_EXTERN_METHOD(refresh)
69
18
 
70
- NSMutableArray<NamiEntitlementSetter *> *entitlementSetters = [NSMutableArray array];
71
-
72
- for (NSDictionary *entitlementSetterDict in entitlementSetterDicts) {
73
- NSString *referenceID = entitlementSetterDict[@"referenceID"];
74
- NSLog(@"Entitlement to set, referenceID is %@, whole entitlement %@", referenceID, entitlementSetterDict);
75
- if (referenceID != NULL && [referenceID length] > 0) {
76
- NSString *purchasedSKUid = entitlementSetterDict[@"purchasedSKUid"];
77
- NSString *expiresStr = entitlementSetterDict[@"expires"];
78
- // TODO: figure out reverse parsing of date string passed in
79
- NSDate* expires = NULL;
80
-
81
- NSString *platormStr = entitlementSetterDict[@"platform"];
82
-
83
- NamiPlatformType platform = NamiPlatformTypeOther;
84
- if ([platormStr isEqualToString:@"android"]) {
85
- platform = NamiPlatformTypeAndroid;
86
- } else if ([platormStr isEqualToString:@"apple"]) {
87
- platform = NamiPlatformTypeApple;
88
- } else if ([platormStr isEqualToString:@"roku"]) {
89
- platform = NamiPlatformTypeRoku;
90
- } else if ([platormStr isEqualToString:@"web"]) {
91
- platform = NamiPlatformTypeWeb;
92
- }
93
-
94
- NamiEntitlementSetter *setter = [NamiEntitlementSetter alloc];
95
- setter = [setter initWithId:referenceID platform:platform purchasedSKUid:purchasedSKUid expires:expires];
96
-
97
- [entitlementSetters addObject:setter];
98
- } else {
99
- NSLog(@"Warning, entitlement to set had empty referenceID, whole entitlement is \n %@", entitlementSetterDict);
100
- }
101
- }
102
-
103
- [NamiEntitlementManager setEntitlements:entitlementSetters];
104
- }
105
-
106
- RCT_EXPORT_METHOD(clearAllEntitlements) {
107
- [NamiEntitlementManager clearAllEntitlements];
108
- }
109
-
110
-
111
- @end
112
-
113
-
114
- @implementation NamiEntitlementManagerBridge
115
- RCT_EXPORT_MODULE_NO_LOAD(NamiEntitlementManagerBridge, NamiEntitlementManagerBridge)
116
-
117
- - (dispatch_queue_t)methodQueue
118
- {
119
- return dispatch_get_main_queue();
120
- }
19
+ RCT_EXTERN_METHOD(registerActiveEntitlementsHandler)
121
20
 
122
21
  + (BOOL)requiresMainQueueSetup {
123
22
  return YES;
124
23
  }
24
+
125
25
  @end
@@ -0,0 +1,74 @@
1
+ //
2
+ // NamiEntitlementManagerBridge.swift
3
+ // RNNami
4
+ //
5
+ // Copyright © 2023 Nami ML Inc.. All rights reserved.
6
+ //
7
+
8
+ import Foundation
9
+ import NamiApple
10
+ import React
11
+
12
+ @objc(RNNamiEntitlementManager)
13
+ class RNNamiEntitlementManager: RCTEventEmitter {
14
+ override func supportedEvents() -> [String]! {
15
+ return ["EntitlementsChanged"]
16
+ }
17
+
18
+ private func entitlementInToDictionary(_ entitlement: NamiEntitlement) -> NSDictionary {
19
+ let activePurchasesDict: [NSDictionary] = entitlement.activePurchases.map { purchase in
20
+ let dictionary = RNNamiPurchaseManager.purchaseToPurchaseDict(purchase)
21
+ return dictionary
22
+ }
23
+
24
+ let purchasedSkusDict: [NSDictionary] = entitlement.purchasedSkus.map { sku in
25
+ let dictionary = RNNamiPurchaseManager.skuToSKUDict(sku)
26
+ return dictionary
27
+ }
28
+ let relatedSkusDict: [NSDictionary] = entitlement.relatedSkus.map { sku in
29
+ let dictionary = RNNamiPurchaseManager.skuToSKUDict(sku)
30
+ return dictionary
31
+ }
32
+ let dictionary: [String: Any?] = [
33
+ "name": entitlement.name,
34
+ "desc": entitlement.desc,
35
+ "namiId": entitlement.namiId,
36
+ "referenceId": entitlement.referenceId,
37
+ "activePurchases": activePurchasesDict,
38
+ "relatedSkus": relatedSkusDict,
39
+ "purchasedSkus": purchasedSkusDict,
40
+ ]
41
+ return NSDictionary(dictionary: dictionary.compactMapValues { $0 })
42
+ }
43
+ @objc(isEntitlementActive:resolver:rejecter:)
44
+ func isEntitlementActive(referenceId: String, resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
45
+ let isEntitlementActive = NamiEntitlementManager.isEntitlementActive(referenceId)
46
+ resolve(isEntitlementActive)
47
+ }
48
+
49
+ @objc(active:rejecter:)
50
+ func active(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
51
+ let entitlements = NamiEntitlementManager.active()
52
+ let dictionaries: [NSDictionary] = entitlements.map { entitlement in
53
+ let dictionary = self.entitlementInToDictionary(entitlement)
54
+ return dictionary
55
+ }
56
+ resolve(dictionaries)
57
+ }
58
+
59
+ @objc(refresh)
60
+ func refresh() {
61
+ NamiEntitlementManager.refresh()
62
+ }
63
+
64
+ @objc(registerActiveEntitlementsHandler)
65
+ func registerActiveEntitlementsHandler() {
66
+ NamiEntitlementManager.registerActiveEntitlementsHandler { activeEntitlements in
67
+ let dictionaries: [NSDictionary] = activeEntitlements.map { entitlement in
68
+ let dictionary = self.entitlementInToDictionary(entitlement)
69
+ return dictionary
70
+ }
71
+ self.sendEvent(withName: "EntitlementsChanged", body: dictionaries)
72
+ }
73
+ }
74
+ }