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.
- package/.github/workflows/app_stg.yaml +203 -0
- package/.github/workflows/build.yml +2 -2
- package/.pre-commit-config.yaml +25 -0
- package/android/build.gradle +24 -13
- package/android/gradle/wrapper/gradle-wrapper.properties +5 -1
- package/android/src/main/java/com/nami/reactlibrary/Constants.kt +1 -1
- package/android/src/main/java/com/nami/reactlibrary/NamiBridgeModule.kt +6 -50
- package/android/src/main/java/com/nami/reactlibrary/NamiBridgePackage.java +1 -3
- package/android/src/main/java/com/nami/reactlibrary/NamiCampaignManagerBridge.kt +133 -0
- package/android/src/main/java/com/nami/reactlibrary/NamiCustomerManagerBridge.kt +89 -20
- package/android/src/main/java/com/nami/reactlibrary/NamiEmitter.kt +25 -25
- package/android/src/main/java/com/nami/reactlibrary/NamiEntitlementManagerBridgeModule.kt +31 -130
- package/android/src/main/java/com/nami/reactlibrary/NamiMLManagerBridgeModule.kt +1 -1
- package/android/src/main/java/com/nami/reactlibrary/NamiPaywallManagerBridgeModule.kt +36 -147
- package/android/src/main/java/com/nami/reactlibrary/NamiPurchaseManagerBridge.kt +37 -39
- package/android/src/main/java/com/nami/reactlibrary/NamiUtil.kt +50 -180
- package/build-utils/get_version_code.py +140 -0
- package/index.d.ts +20 -0
- package/index.js +7 -6
- package/ios/Nami.m +18 -72
- package/ios/NamiBridgeUtil.h +4 -6
- package/ios/NamiBridgeUtil.m +37 -99
- package/ios/NamiCampaignManagerBridge.m +26 -0
- package/ios/NamiCampaignManagerBridge.swift +107 -0
- package/ios/NamiCustomerManager.m +19 -24
- package/ios/NamiCustomerManager.swift +122 -0
- package/ios/NamiEmitter.m +85 -95
- package/ios/NamiEntitlementManagerBridge.m +7 -107
- package/ios/NamiEntitlementManagerBridge.swift +74 -0
- package/ios/NamiMLManagerBridge.m +2 -2
- package/ios/NamiPaywallManagerBridge.m +22 -94
- package/ios/NamiPaywallManagerBridge.swift +93 -0
- package/ios/NamiPurchaseManagerBridge.m +40 -71
- package/ios/NamiPurchaseManagerBridge.swift +174 -0
- package/ios/Podfile +2 -2
- package/ios/RNNami-Bridging-Header.h +5 -0
- package/ios/RNNami.h +0 -1
- package/ios/RNNami.m +1 -1
- package/ios/RNNami.xcodeproj/project.pbxproj +84 -8
- package/ios/RNNami.xcodeproj/xcshareddata/xcschemes/RNNami.xcscheme +67 -0
- package/package.json +1 -1
- package/react-native-nami-sdk.podspec +3 -3
- package/src/Nami.d.ts +112 -0
- package/src/Nami.js +10 -0
- package/src/NamiCampaignManager.d.ts +54 -0
- package/src/NamiCampaignManager.js +43 -0
- package/src/NamiCustomerManager.d.ts +39 -0
- package/src/NamiCustomerManager.js +43 -0
- package/src/NamiEntitlementManager.d.ts +24 -0
- package/src/NamiEntitlementManager.js +23 -0
- package/src/NamiMLManager.d.ts +5 -0
- package/src/NamiMLManager.js +7 -0
- package/src/NamiPaywallManager.d.ts +57 -0
- package/src/NamiPaywallManager.js +28 -0
- package/src/NamiPurchaseManager.d.ts +57 -0
- package/src/NamiPurchaseManager.js +37 -0
- package/src/types.ts +36 -0
- package/android/src/main/java/com/nami/reactlibrary/NamiAnalyticsEmitter.kt +0 -121
- 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 <
|
|
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
|
|
39
|
+
|
|
40
|
+
[NamiEntitlementManager registerActiveEntitlementsHandler:^(NSArray<NamiEntitlement *> * _Nonnull entitlements) {
|
|
42
41
|
[self sendEventEntitlementsChangedWithEntitlements:entitlements];
|
|
43
42
|
}];
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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:@{
|
|
228
|
+
[self sendEventWithName:@"SignInActivate" body:@{ }];
|
|
238
229
|
}
|
|
239
230
|
}
|
|
240
231
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
marketingContentDictionary[@"
|
|
258
|
-
|
|
259
|
-
paywallMeta[@"
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
[paywallMeta removeObjectForKey:@"
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
[paywallMeta removeObjectForKey:@"
|
|
274
|
-
[paywallMeta removeObjectForKey:@"
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
@"
|
|
279
|
-
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
}
|