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
package/ios/Nami.m
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
// Nami.m
|
|
3
3
|
// RNNami
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
// Copyright © 2020 Nami ML Inc. All rights reserved.
|
|
5
|
+
// Copyright © 2020-2023 Nami ML Inc. All rights reserved.
|
|
7
6
|
//
|
|
8
7
|
|
|
9
8
|
#import <Foundation/Foundation.h>
|
|
10
|
-
#import <
|
|
9
|
+
#import <NamiApple/NamiApple.h>
|
|
11
10
|
|
|
12
11
|
#import <React/RCTBridgeModule.h>
|
|
13
12
|
#import <React/RCTEventEmitter.h>
|
|
@@ -20,15 +19,15 @@
|
|
|
20
19
|
@end
|
|
21
20
|
@implementation NamiBridge (RCTExternModule)
|
|
22
21
|
|
|
23
|
-
RCT_EXPORT_METHOD(configure: (NSDictionary *)configDict) {
|
|
22
|
+
RCT_EXPORT_METHOD(configure: (NSDictionary *)configDict completion: (RCTResponseSenderBlock) completion) {
|
|
24
23
|
if ([configDict count] == 0 || [configDict[@"logLevel"] isEqual: @"DEBUG"] ) {
|
|
25
24
|
NSLog(@"Configure dictionary is %@", configDict);
|
|
26
25
|
}
|
|
27
26
|
NSString *appID = configDict[@"appPlatformID-apple"];
|
|
28
|
-
|
|
27
|
+
|
|
29
28
|
if ([appID length] > 0 ) {
|
|
30
|
-
NamiConfiguration *config = [NamiConfiguration
|
|
31
|
-
|
|
29
|
+
NamiConfiguration *config = [NamiConfiguration configurationForAppPlatformId:appID];
|
|
30
|
+
|
|
32
31
|
NSString *logLevelString = configDict[@"logLevel"];
|
|
33
32
|
if ([logLevelString isEqualToString:@"ERROR" ]) {
|
|
34
33
|
config.logLevel = NamiLogLevelError;
|
|
@@ -40,18 +39,18 @@ RCT_EXPORT_METHOD(configure: (NSDictionary *)configDict) {
|
|
|
40
39
|
// If they messed up the params, just set logging to full.
|
|
41
40
|
config.logLevel = NamiLogLevelDebug;
|
|
42
41
|
}
|
|
43
|
-
|
|
42
|
+
|
|
44
43
|
NSString *languageString = configDict[@"namiLanguageCode"];
|
|
45
44
|
if ([logLevelString length] > 0) {
|
|
46
45
|
NSLog(@"Nami language code from config dictionary is %@", languageString);
|
|
47
|
-
if ([[NamiLanguageCodes
|
|
46
|
+
if ([[NamiLanguageCodes allAvailableNamiLanguageCodes]
|
|
48
47
|
containsObject:[languageString lowercaseString]] ) {
|
|
49
48
|
config.namiLanguageCode = languageString;
|
|
50
49
|
} else {
|
|
51
|
-
NSLog(@"Warning: Nami language code from config dictionary %@ not found in list of available Nami Language Codes:\n%@", languageString, [NamiLanguageCodes
|
|
50
|
+
NSLog(@"Warning: Nami language code from config dictionary %@ not found in list of available Nami Language Codes:\n%@", languageString, [NamiLanguageCodes allAvailableNamiLanguageCodes]);
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
|
-
|
|
53
|
+
|
|
55
54
|
NSObject *bypassString = configDict[@"bypassStore"];
|
|
56
55
|
if ( bypassString != NULL )
|
|
57
56
|
{
|
|
@@ -66,25 +65,10 @@ RCT_EXPORT_METHOD(configure: (NSDictionary *)configDict) {
|
|
|
66
65
|
}
|
|
67
66
|
}
|
|
68
67
|
}
|
|
69
|
-
|
|
70
|
-
NSObject *developmentModeString = configDict[@"developmentMode"];
|
|
71
|
-
if ( developmentModeString != NULL )
|
|
72
|
-
{
|
|
73
|
-
NSLog(@"bypassStore from dictionary is %@", configDict[@"developmentMode"]);
|
|
74
|
-
if ([developmentModeString isKindOfClass:[NSNumber class]]) {
|
|
75
|
-
config.developmentMode = [((NSNumber *)developmentModeString) boolValue];
|
|
76
|
-
} else if ([developmentModeString isKindOfClass:[NSString class]] ) {
|
|
77
|
-
if ([[((NSString *)developmentModeString) lowercaseString] hasPrefix:@"t"] )
|
|
78
|
-
{
|
|
79
|
-
// bypass is false by default, so we only worry about checking for enabling bypass
|
|
80
|
-
config.developmentMode = true;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
68
|
+
|
|
85
69
|
// Start commands with header iformation for Nami to let them know this is a React client.
|
|
86
|
-
NSMutableArray *namiCommandStrings = [NSMutableArray arrayWithArray:@[@"extendedClientInfo:react-native:
|
|
87
|
-
|
|
70
|
+
NSMutableArray *namiCommandStrings = [NSMutableArray arrayWithArray:@[@"extendedClientInfo:react-native:3.0.0"]];
|
|
71
|
+
|
|
88
72
|
// Add additional namiCommands app may have sent in.
|
|
89
73
|
NSObject *appCommandStrings = configDict[@"namiCommands"];
|
|
90
74
|
if ( appCommandStrings != NULL ) {
|
|
@@ -97,11 +81,13 @@ RCT_EXPORT_METHOD(configure: (NSDictionary *)configDict) {
|
|
|
97
81
|
}
|
|
98
82
|
}
|
|
99
83
|
}
|
|
100
|
-
|
|
84
|
+
|
|
101
85
|
config.namiCommands = namiCommandStrings;
|
|
102
86
|
|
|
103
|
-
|
|
104
|
-
[Nami
|
|
87
|
+
|
|
88
|
+
[Nami configureWith:config];
|
|
89
|
+
NSDictionary *dict = @{@"success": @YES};
|
|
90
|
+
completion(@[dict]);
|
|
105
91
|
}
|
|
106
92
|
}
|
|
107
93
|
|
|
@@ -109,46 +95,6 @@ RCT_EXPORT_METHOD(performNamiCommand: (NSString *)command) {
|
|
|
109
95
|
[NamiCommand performCommand:command];
|
|
110
96
|
}
|
|
111
97
|
|
|
112
|
-
RCT_EXPORT_METHOD(setExternalIdentifier: (NSString *)externalIdentifier type:(NSString *)type completion: (RCTResponseSenderBlock) completion) {
|
|
113
|
-
|
|
114
|
-
NamiExternalIdentifierType useType;
|
|
115
|
-
|
|
116
|
-
if ( [type isEqualToString:@"sha256"] ) {
|
|
117
|
-
useType = NamiExternalIdentifierTypeSha256;
|
|
118
|
-
} else {
|
|
119
|
-
useType = NamiExternalIdentifierTypeUuid;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
NSLog(@"NamiBridge: Setting external identifier %@ of type %@", externalIdentifier, type);
|
|
123
|
-
|
|
124
|
-
[Nami setExternalIdentifierWithExternalIdentifier:externalIdentifier type:useType completion:^(BOOL success, NSError * _Nullable error) {
|
|
125
|
-
if (error) {
|
|
126
|
-
completion(@[error]);
|
|
127
|
-
}
|
|
128
|
-
completion(nil);
|
|
129
|
-
}];
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
RCT_EXPORT_METHOD(getExternalIdentifier:(RCTResponseSenderBlock)completion)
|
|
133
|
-
{
|
|
134
|
-
NSString *externalIdentifier = [Nami getExternalIdentifier];
|
|
135
|
-
|
|
136
|
-
if (externalIdentifier == NULL || [externalIdentifier length] == 0) {
|
|
137
|
-
completion(@[]);
|
|
138
|
-
} else {
|
|
139
|
-
completion(@[externalIdentifier]);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
RCT_EXPORT_METHOD(clearExternalIdentifier:(RCTResponseSenderBlock)completion) {
|
|
144
|
-
NSLog(@"NamiBridge: Clearing external identifier.");
|
|
145
|
-
[Nami clearExternalIdentifierWithCompletion:^(BOOL success, NSError * _Nullable error) {
|
|
146
|
-
if (error) {
|
|
147
|
-
success }
|
|
148
|
-
completion(nil);
|
|
149
|
-
}];
|
|
150
|
-
}
|
|
151
|
-
|
|
152
98
|
@end
|
|
153
99
|
|
|
154
100
|
@implementation NamiBridge
|
package/ios/NamiBridgeUtil.h
CHANGED
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
// NamiBridgeUtil.h
|
|
3
3
|
// RNNami
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
// Copyright © 2020 Nami ML Inc. All rights reserved.
|
|
5
|
+
// Copyright © 2020-2023 Nami ML Inc. All rights reserved.
|
|
7
6
|
//
|
|
8
7
|
|
|
8
|
+
#import <Foundation/Foundation.h>
|
|
9
|
+
#import <NamiApple/NamiApple.h>
|
|
10
|
+
|
|
9
11
|
#ifndef NamiBridgeUtil_h
|
|
10
12
|
#define NamiBridgeUtil_h
|
|
11
13
|
|
|
@@ -21,14 +23,10 @@
|
|
|
21
23
|
|
|
22
24
|
+ (NSDictionary<NSString *,NSString *> *) entitlementToEntitlementDict:(NamiEntitlement *)entitlement;
|
|
23
25
|
|
|
24
|
-
+ (NSDictionary<NSString *,NSString *> *) paywallStylingToPaywallStylingDict:(PaywallStyleData *)styling;
|
|
25
|
-
|
|
26
26
|
+ (NSArray *)stripPresentationPositionFromOrderedMetadataForPaywallMetaDict: (NSDictionary *)paywallMeta;
|
|
27
27
|
|
|
28
28
|
+ (NSDictionary<NSString *,NSString *> *) customerJourneyStateDict;
|
|
29
29
|
|
|
30
|
-
+ (NSString *)hexStringForColor:(UIColor *)color;
|
|
31
|
-
|
|
32
30
|
@end
|
|
33
31
|
|
|
34
32
|
#endif /* NamiBridgeUtil_h */
|
package/ios/NamiBridgeUtil.m
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
// NamiBridgeUtil.m
|
|
3
3
|
// RNNami
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
// Copyright © 2020 Nami ML Inc. All rights reserved.
|
|
5
|
+
// Copyright © 2020-2023 Nami ML Inc. All rights reserved.
|
|
7
6
|
//
|
|
8
7
|
|
|
9
8
|
#import <Foundation/Foundation.h>
|
|
10
|
-
#import <
|
|
9
|
+
#import <NamiApple/NamiApple.h>
|
|
11
10
|
|
|
12
11
|
#import "NamiBridgeUtil.h"
|
|
13
12
|
|
|
@@ -17,7 +16,7 @@
|
|
|
17
16
|
+ (NSDictionary<NSString *,NSString *> *) skuToSKUDict:(NamiSKU *)sku {
|
|
18
17
|
NSMutableDictionary<NSString *,NSString *> *productDict = [NSMutableDictionary new];
|
|
19
18
|
|
|
20
|
-
productDict[@"skuIdentifier"] = sku.
|
|
19
|
+
productDict[@"skuIdentifier"] = sku.platformId;
|
|
21
20
|
|
|
22
21
|
SKProduct *productInt = sku.product;
|
|
23
22
|
productDict[@"localizedTitle"] = productInt.localizedTitle;
|
|
@@ -28,10 +27,10 @@
|
|
|
28
27
|
productDict[@"priceLanguage"] = productInt.priceLocale.languageCode;
|
|
29
28
|
productDict[@"priceCountry"] = productInt.priceLocale.countryCode;
|
|
30
29
|
productDict[@"priceCurrency"] = productInt.priceLocale.currencyCode;
|
|
31
|
-
|
|
30
|
+
|
|
32
31
|
// Add smart text processed values for sku buttons to sku dictionary
|
|
33
|
-
productDict[@"displayText"] = [sku
|
|
34
|
-
productDict[@"displaySubText"] = [sku
|
|
32
|
+
// productDict[@"displayText"] = [sku localizedDisplayText];
|
|
33
|
+
// productDict[@"displaySubText"] = [sku localizedSubDisplayText];
|
|
35
34
|
|
|
36
35
|
if (@available(iOS 12.0, *)) {
|
|
37
36
|
if (productInt != nil && productInt.subscriptionGroupIdentifier != nil) {
|
|
@@ -71,18 +70,18 @@
|
|
|
71
70
|
|
|
72
71
|
+ (NSDictionary<NSString *,NSString *> *) purchaseToPurchaseDict:(NamiPurchase *)purchase {
|
|
73
72
|
NSMutableDictionary<NSString *,id> *purchaseDict = [NSMutableDictionary new];
|
|
74
|
-
|
|
75
|
-
purchaseDict[@"skuIdentifier"] = purchase.
|
|
73
|
+
|
|
74
|
+
purchaseDict[@"skuIdentifier"] = purchase.skuId;
|
|
76
75
|
purchaseDict[@"transactionIdentifier"] = purchase.transactionIdentifier;
|
|
77
76
|
|
|
78
77
|
// Removed, not sure why, should add back in when possible.
|
|
79
78
|
// purchaseDict[@"purchaseInitiatedTimestamp"] = [self javascriptDateFromNSDate:purchase.purchaseInitiatedTimestamp];
|
|
80
|
-
|
|
79
|
+
|
|
81
80
|
NSDate *subscriptionExpirationDate = purchase.expires;
|
|
82
81
|
if (subscriptionExpirationDate != nil) {
|
|
83
82
|
purchaseDict[@"subscriptionExpirationDate"] = [self javascriptDateFromNSDate:subscriptionExpirationDate];
|
|
84
83
|
}
|
|
85
|
-
|
|
84
|
+
|
|
86
85
|
NSString *convertedSourceString = @"UNKNOWN";
|
|
87
86
|
switch (purchase.purchaseSource) {
|
|
88
87
|
case 0:
|
|
@@ -98,9 +97,9 @@
|
|
|
98
97
|
break;
|
|
99
98
|
}
|
|
100
99
|
purchaseDict[@"purchaseSource"] = convertedSourceString;
|
|
101
|
-
|
|
100
|
+
|
|
102
101
|
// NamiSKU *purchaseSku = [purchase ]
|
|
103
|
-
|
|
102
|
+
|
|
104
103
|
return purchaseDict;
|
|
105
104
|
}
|
|
106
105
|
|
|
@@ -109,7 +108,7 @@
|
|
|
109
108
|
+ (NSArray *)stripPresentationPositionFromOrderedMetadataForPaywallMetaDict: (NSDictionary *)paywallMeta {
|
|
110
109
|
NSArray *baseSkuArray = [paywallMeta objectForKey:@"sku_ordered_metadata"];
|
|
111
110
|
NSMutableArray *newOrderedMetadata = [NSMutableArray new];
|
|
112
|
-
|
|
111
|
+
|
|
113
112
|
if ( [baseSkuArray isKindOfClass:[NSArray class]] ) {
|
|
114
113
|
for (NSDictionary *baseSkuDict in baseSkuArray) {
|
|
115
114
|
NSMutableDictionary *skuFormattingDict = [NSMutableDictionary dictionaryWithDictionary:baseSkuDict];
|
|
@@ -123,16 +122,16 @@
|
|
|
123
122
|
+ (NSDictionary<NSString *,NSString *> *) entitlementToEntitlementDict:(NamiEntitlement *)entitlement {
|
|
124
123
|
NSMutableDictionary<NSString *,id> *entitlementDict = [NSMutableDictionary new];
|
|
125
124
|
NSLog(@"Converting entitlement %@", entitlement);
|
|
126
|
-
entitlementDict[@"referenceID"] = [entitlement
|
|
127
|
-
entitlementDict[@"namiID"] = [entitlement
|
|
125
|
+
entitlementDict[@"referenceID"] = [entitlement referenceId];
|
|
126
|
+
entitlementDict[@"namiID"] = [entitlement namiId] ? [entitlement namiId] : @"";
|
|
128
127
|
entitlementDict[@"desc"] = [entitlement desc] ? [entitlement desc] : @"";
|
|
129
128
|
entitlementDict[@"name"] = [entitlement name] ? [entitlement name] : @"";
|
|
130
|
-
|
|
131
|
-
if (entitlementDict[@"referenceID"] == nil || [[entitlement
|
|
129
|
+
|
|
130
|
+
if (entitlementDict[@"referenceID"] == nil || [[entitlement referenceId] length] == 0) {
|
|
132
131
|
NSLog(@"NamiBridge: Bad entitlement in system, empty referenceID.");
|
|
133
132
|
return nil;
|
|
134
133
|
}
|
|
135
|
-
|
|
134
|
+
|
|
136
135
|
NSArray <NamiPurchase *>*activePurchases = [entitlement activePurchases];
|
|
137
136
|
NSMutableArray *convertedActivePurchases = [NSMutableArray array];
|
|
138
137
|
for (NamiPurchase *purchase in activePurchases) {
|
|
@@ -142,8 +141,8 @@
|
|
|
142
141
|
}
|
|
143
142
|
}
|
|
144
143
|
entitlementDict[@"activePurchases"] = convertedActivePurchases;
|
|
145
|
-
|
|
146
|
-
NSArray <NamiSKU *>*purchasedSKUs = [entitlement
|
|
144
|
+
|
|
145
|
+
NSArray <NamiSKU *>*purchasedSKUs = [entitlement purchasedSkus];
|
|
147
146
|
NSMutableArray *convertedPurchasedSKUs = [NSMutableArray array];
|
|
148
147
|
for (NamiSKU *sku in purchasedSKUs) {
|
|
149
148
|
NSDictionary *skuDict = [NamiBridgeUtil skuToSKUDict:sku];
|
|
@@ -152,9 +151,9 @@
|
|
|
152
151
|
}
|
|
153
152
|
}
|
|
154
153
|
entitlementDict[@"purchasedSKUs"] = convertedPurchasedSKUs;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
NSArray <NamiSKU *>*relatedSKUs = [entitlement
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
NSArray <NamiSKU *>*relatedSKUs = [entitlement relatedSkus];
|
|
158
157
|
NSMutableArray *convertedRelatedSKUs = [NSMutableArray array];
|
|
159
158
|
for (NamiSKU *sku in relatedSKUs) {
|
|
160
159
|
NSDictionary *skuDict = [NamiBridgeUtil skuToSKUDict:sku];
|
|
@@ -163,7 +162,7 @@
|
|
|
163
162
|
}
|
|
164
163
|
}
|
|
165
164
|
entitlementDict[@"relatedSKUs"] = convertedRelatedSKUs;
|
|
166
|
-
|
|
165
|
+
|
|
167
166
|
NamiPurchase *lastPurchase;
|
|
168
167
|
for (NamiPurchase *purchase in [entitlement activePurchases]) {
|
|
169
168
|
if (lastPurchase == NULL || ([lastPurchase purchaseInitiatedTimestamp] < [purchase purchaseInitiatedTimestamp])) {
|
|
@@ -173,26 +172,26 @@
|
|
|
173
172
|
if (lastPurchase != NULL) {
|
|
174
173
|
// entitlementDict[@"latestPurchase"] = [NamiBridgeUtil purchaseToPurchaseDict:lastPurchase];
|
|
175
174
|
}
|
|
176
|
-
|
|
177
|
-
NSString *lastPurchaseSKUID = [lastPurchase
|
|
178
|
-
|
|
175
|
+
|
|
176
|
+
NSString *lastPurchaseSKUID = [lastPurchase skuId];
|
|
177
|
+
|
|
179
178
|
NamiSKU *lastPurchasedSKU;
|
|
180
179
|
if (lastPurchaseSKUID != NULL ) {
|
|
181
|
-
for (NamiSKU *sku in [entitlement
|
|
182
|
-
if ( [[sku
|
|
180
|
+
for (NamiSKU *sku in [entitlement purchasedSkus]) {
|
|
181
|
+
if ( [[sku platformId] isEqualToString:lastPurchaseSKUID] ) {
|
|
183
182
|
lastPurchasedSKU = sku;
|
|
184
183
|
}
|
|
185
184
|
}
|
|
186
185
|
}
|
|
187
|
-
|
|
186
|
+
|
|
188
187
|
if (lastPurchasedSKU != NULL) {
|
|
189
|
-
lastPurchasedSKU = [[entitlement
|
|
188
|
+
lastPurchasedSKU = [[entitlement purchasedSkus] lastObject];
|
|
190
189
|
}
|
|
191
190
|
|
|
192
191
|
if (lastPurchasedSKU != NULL) {
|
|
193
192
|
// entitlementDict[@"lastPurchasedSKU"] = [NamiBridgeUtil skuToSKUDict:lastPurchasedSKU];
|
|
194
193
|
}
|
|
195
|
-
|
|
194
|
+
|
|
196
195
|
return entitlementDict;
|
|
197
196
|
}
|
|
198
197
|
|
|
@@ -201,23 +200,23 @@
|
|
|
201
200
|
+ (NSString *)javascriptDateFromNSDate:(NSDate *)purchaseTimestamp {
|
|
202
201
|
NSTimeZone *UTC = [NSTimeZone timeZoneWithAbbreviation: @"UTC"];
|
|
203
202
|
NSISO8601DateFormatOptions options = NSISO8601DateFormatWithInternetDateTime | NSISO8601DateFormatWithDashSeparatorInDate | NSISO8601DateFormatWithColonSeparatorInTime | NSISO8601DateFormatWithTimeZone;
|
|
204
|
-
|
|
203
|
+
|
|
205
204
|
return [NSISO8601DateFormatter stringFromDate:purchaseTimestamp timeZone:UTC formatOptions:options];
|
|
206
205
|
}
|
|
207
206
|
|
|
208
207
|
|
|
209
208
|
+ (NSDictionary<NSString *,NSString *> *) customerJourneyStateDict {
|
|
210
|
-
CustomerJourneyState *journeyState = [NamiCustomerManager
|
|
211
|
-
|
|
209
|
+
CustomerJourneyState *journeyState = [NamiCustomerManager journeyState];
|
|
210
|
+
|
|
212
211
|
BOOL formerSubscriber = [journeyState formerSubscriber];
|
|
213
212
|
BOOL inGracePeriod = [journeyState inGracePeriod];
|
|
214
213
|
BOOL inTrialPeriod = [journeyState inTrialPeriod];
|
|
215
214
|
BOOL inIntroOfferPeriod = [journeyState inIntroOfferPeriod];
|
|
216
|
-
|
|
215
|
+
|
|
217
216
|
BOOL isCancelled = [journeyState isCancelled];
|
|
218
217
|
BOOL inPause = [journeyState inPause];
|
|
219
218
|
BOOL inAccountHold = [journeyState inAccountHold];
|
|
220
|
-
|
|
219
|
+
|
|
221
220
|
NSDictionary *journeyDict = @{@"formerSubscriber":@(formerSubscriber),
|
|
222
221
|
@"inGracePeriod":@(inGracePeriod),
|
|
223
222
|
@"inTrialPeriod":@(inTrialPeriod),
|
|
@@ -229,65 +228,4 @@
|
|
|
229
228
|
return journeyDict;
|
|
230
229
|
}
|
|
231
230
|
|
|
232
|
-
+ (NSDictionary<NSString *,NSString *> *) paywallStylingToPaywallStylingDict:(PaywallStyleData *)styling {
|
|
233
|
-
NSMutableDictionary<NSString *,id> *stylingDict = [NSMutableDictionary new];
|
|
234
|
-
if (styling != nil) {
|
|
235
|
-
stylingDict[@"backgroundColor"] = [NamiBridgeUtil hexStringForColor: styling.backgroundColor];
|
|
236
|
-
|
|
237
|
-
stylingDict[@"bodyFontSize"] = @(styling.bodyFontSize);
|
|
238
|
-
stylingDict[@"bodyTextColor"] = [NamiBridgeUtil hexStringForColor: styling.bodyTextColor];
|
|
239
|
-
stylingDict[@"bodyShadowColor"] = [NamiBridgeUtil hexStringForColor: styling.bodyShadowColor];
|
|
240
|
-
stylingDict[@"bodyShadowRadius"] = @(styling.bodyShadowRadius);
|
|
241
|
-
|
|
242
|
-
stylingDict[@"titleFontSize"] = @(styling.titleFontSize);
|
|
243
|
-
stylingDict[@"titleTextColor"] = [NamiBridgeUtil hexStringForColor: styling.titleTextColor];
|
|
244
|
-
stylingDict[@"titleShadowColor"] = [NamiBridgeUtil hexStringForColor: styling.titleShadowColor];
|
|
245
|
-
stylingDict[@"titleShadowRadius"] = @(styling.titleShadowRadius);
|
|
246
|
-
|
|
247
|
-
stylingDict[@"closeButtonFontSize"] = @(styling.closeButtonFontSize);
|
|
248
|
-
stylingDict[@"closeButtonTextColor"] = [NamiBridgeUtil hexStringForColor: styling.closeButtonTextColor];
|
|
249
|
-
stylingDict[@"closeButtonShadowColor"] = [NamiBridgeUtil hexStringForColor: styling.closeButtonShadowColor];
|
|
250
|
-
stylingDict[@"closeButtonShadowRadius"] = @(styling.closeButtonShadowRadius);
|
|
251
|
-
|
|
252
|
-
stylingDict[@"bottomOverlayColor"] = [NamiBridgeUtil hexStringForColor: styling.bottomOverlayColor];
|
|
253
|
-
stylingDict[@"bottomOverlayCornerRadius"] = @(styling.bottomOverlayCornerRadius);
|
|
254
|
-
|
|
255
|
-
stylingDict[@"skuButtonColor"] = [NamiBridgeUtil hexStringForColor: styling.skuButtonColor];
|
|
256
|
-
stylingDict[@"skuButtonTextColor"] = [NamiBridgeUtil hexStringForColor: styling.skuButtonTextColor];
|
|
257
|
-
|
|
258
|
-
stylingDict[@"featuredSkusButtonColor"] = [NamiBridgeUtil hexStringForColor: styling.featuredSkusButtonColor];
|
|
259
|
-
stylingDict[@"featuredSkusButtonTextColor"] = [NamiBridgeUtil hexStringForColor: styling.featuredSkusButtonTextColor];
|
|
260
|
-
|
|
261
|
-
stylingDict[@"signinButtonFontSize"] = @(styling.signinButtonFontSize);
|
|
262
|
-
stylingDict[@"signinButtonTextColor"] = [NamiBridgeUtil hexStringForColor: styling.signinButtonTextColor];
|
|
263
|
-
stylingDict[@"signinButtonShadowColor"] = [NamiBridgeUtil hexStringForColor: styling.signinButtonShadowColor];
|
|
264
|
-
stylingDict[@"signinButtonShadowRadius"] = @(styling.signinButtonShadowRadius);
|
|
265
|
-
|
|
266
|
-
stylingDict[@"restoreButtonFontSize"] = @(styling.restoreButtonFontSize);
|
|
267
|
-
stylingDict[@"restoreButtonTextColor"] = [NamiBridgeUtil hexStringForColor: styling.restoreButtonTextColor];
|
|
268
|
-
stylingDict[@"restoreButtonShadowColor"] = [NamiBridgeUtil hexStringForColor: styling.restoreButtonShadowColor];
|
|
269
|
-
stylingDict[@"restoreButtonShadowRadius"] = @(styling.restoreButtonShadowRadius);
|
|
270
|
-
|
|
271
|
-
stylingDict[@"purchaseTermsFontSize"] = @(styling.purchaseTermsFontSize);
|
|
272
|
-
stylingDict[@"purchaseTermsTextColor"] = [NamiBridgeUtil hexStringForColor: styling.purchaseTermsTextColor];
|
|
273
|
-
stylingDict[@"purchaseTermsShadowColor"] = [NamiBridgeUtil hexStringForColor: styling.purchaseTermsShadowColor];
|
|
274
|
-
stylingDict[@"purchaseTermsShadowRadius"] = @(styling.purchaseTermsShadowRadius);
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
stylingDict[@"termsLinkColor"] = styling.termsLinkColor;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return stylingDict;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
+ (NSString *)hexStringForColor:(UIColor *)color {
|
|
284
|
-
CGFloat r;
|
|
285
|
-
CGFloat g;
|
|
286
|
-
CGFloat b;
|
|
287
|
-
CGFloat a;
|
|
288
|
-
[color getRed:&r green:&g blue:&b alpha:&a];
|
|
289
|
-
NSString *hexString=[NSString stringWithFormat:@"#%02X%02X%02X", (int)(r * 255), (int)(g * 255), (int)(b * 255)];
|
|
290
|
-
return hexString;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
231
|
@end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NamiCampaignManager.m
|
|
3
|
+
// RNNami
|
|
4
|
+
//
|
|
5
|
+
// Copyright © 2023 Nami ML INc.. All rights reserved.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
#import <React/RCTBridgeModule.h>
|
|
9
|
+
|
|
10
|
+
@interface RCT_EXTERN_MODULE(RNNamiCampaignManager, NSObject)
|
|
11
|
+
|
|
12
|
+
RCT_EXTERN_METHOD(launch:(nullable NSString *)label completion:(RCTResponseSenderBlock)callback paywallCompletion:(RCTResponseSenderBlock)cpaywallCallback)
|
|
13
|
+
|
|
14
|
+
RCT_EXTERN_METHOD(allCampaigns:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
15
|
+
|
|
16
|
+
RCT_EXTERN_METHOD(isCampaignAvailable:(nullable NSString *)label resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
17
|
+
|
|
18
|
+
RCT_EXTERN_METHOD(refresh)
|
|
19
|
+
|
|
20
|
+
RCT_EXTERN_METHOD(registerAvailableCampaignsHandler)
|
|
21
|
+
|
|
22
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
23
|
+
return YES;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//
|
|
2
|
+
// NamiCampaignManagerBridge.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(RNNamiCampaignManager)
|
|
13
|
+
class RNNamiCampaignManager: RCTEventEmitter {
|
|
14
|
+
override func supportedEvents() -> [String]! {
|
|
15
|
+
return ["AvailableCampaignsChanged", "ResultCampaign"]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
private func campaignInToDictionary(_ campaign: NamiCampaign) -> NSDictionary {
|
|
19
|
+
let dictionary: [String: Any?] = [
|
|
20
|
+
"id": campaign.id,
|
|
21
|
+
"rule": campaign.rule,
|
|
22
|
+
"segment": campaign.segment,
|
|
23
|
+
"paywall": campaign.paywall,
|
|
24
|
+
"type": campaign.type.rawValue,
|
|
25
|
+
"value": campaign.value,
|
|
26
|
+
]
|
|
27
|
+
return NSDictionary(dictionary: dictionary.compactMapValues { $0 })
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@objc(launch:completion:paywallCompletion:)
|
|
31
|
+
func launch(label: String?, callback: @escaping RCTResponseSenderBlock, paywallCallback _: @escaping RCTResponseSenderBlock) {
|
|
32
|
+
NamiCampaignManager.launch(label: label, launchHandler: { success, error in
|
|
33
|
+
callback([success, error?._code as Any])
|
|
34
|
+
}, paywallActionHandler: { action, sku, purchaseError, purchases in
|
|
35
|
+
let actionString: String
|
|
36
|
+
switch action {
|
|
37
|
+
case .show_paywall:
|
|
38
|
+
actionString = "SHOW_PAYWALL"
|
|
39
|
+
case .close_paywall:
|
|
40
|
+
actionString = "CLOSE_PAYWALL"
|
|
41
|
+
case .restore_purchases:
|
|
42
|
+
actionString = "RESTORE_PURCHASES"
|
|
43
|
+
case .sign_in:
|
|
44
|
+
actionString = "SIGN_IN"
|
|
45
|
+
case .buy_sku:
|
|
46
|
+
actionString = "BUY_SKU"
|
|
47
|
+
case .select_sku:
|
|
48
|
+
actionString = "SELECT_SKU"
|
|
49
|
+
case .purchase_selected_sku:
|
|
50
|
+
actionString = "PURCHASE_SELECTED_SKU"
|
|
51
|
+
case .purchase_success:
|
|
52
|
+
actionString = "PURCHASE_SUCCESS"
|
|
53
|
+
case .purchase_deferred:
|
|
54
|
+
actionString = "PURCHASE_DEFERRED"
|
|
55
|
+
case .purchase_failed:
|
|
56
|
+
actionString = "PURCHASE_FAILED"
|
|
57
|
+
case .purchase_cancelled:
|
|
58
|
+
actionString = "PURCHASE_CANCELLED"
|
|
59
|
+
case .purchase_unknown:
|
|
60
|
+
actionString = "PURCHASE_UNKNOWN"
|
|
61
|
+
@unknown default:
|
|
62
|
+
actionString = "PURCHASE_UNKNOWN"
|
|
63
|
+
}
|
|
64
|
+
let skuId = sku?.skuId
|
|
65
|
+
let errorSting = purchaseError?.localizedDescription
|
|
66
|
+
let dictionaries = purchases.map { purchase in NamiBridgeUtil.purchase(toPurchaseDict: purchase) }
|
|
67
|
+
let payload: [String: Any?] = [
|
|
68
|
+
"action": actionString,
|
|
69
|
+
"skuId": skuId,
|
|
70
|
+
"purchaseError": errorSting,
|
|
71
|
+
"purchases": dictionaries
|
|
72
|
+
]
|
|
73
|
+
self.sendEvent(withName: "ResultCampaign", body: payload)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@objc(allCampaigns:rejecter:)
|
|
78
|
+
func allCampaigns(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
|
|
79
|
+
let campaigns = NamiCampaignManager.allCampaigns()
|
|
80
|
+
let dictionaries = campaigns.map { campaign in self.campaignInToDictionary(campaign) }
|
|
81
|
+
resolve(dictionaries)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@objc(isCampaignAvailable:resolver:rejecter:)
|
|
85
|
+
func isCampaignAvailable(label: String?, resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
|
|
86
|
+
let isCampaignAvailable: Bool
|
|
87
|
+
if let label = label {
|
|
88
|
+
isCampaignAvailable = NamiCampaignManager.isCampaignAvailable(label: label)
|
|
89
|
+
} else {
|
|
90
|
+
isCampaignAvailable = NamiCampaignManager.isCampaignAvailable()
|
|
91
|
+
}
|
|
92
|
+
resolve(isCampaignAvailable)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@objc(refresh)
|
|
96
|
+
func refresh() {
|
|
97
|
+
NamiCampaignManager.refresh()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@objc(registerAvailableCampaignsHandler)
|
|
101
|
+
func registerForAvailableCampaigns() {
|
|
102
|
+
NamiCampaignManager.registerAvailableCampaignsHandler { availableCampaigns in
|
|
103
|
+
let dictionaries = availableCampaigns.map { campaign in self.campaignInToDictionary(campaign) }
|
|
104
|
+
self.sendEvent(withName: "AvailableCampaignsChanged", body: dictionaries)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -2,42 +2,37 @@
|
|
|
2
2
|
// NamiCustomerManager.m
|
|
3
3
|
// RNNami
|
|
4
4
|
//
|
|
5
|
-
//
|
|
6
|
-
// Copyright © 2020 Nami ML Inc. All rights reserved.
|
|
5
|
+
// Copyright © 2020-2023 Nami ML Inc. All rights reserved.
|
|
7
6
|
//
|
|
8
7
|
|
|
9
|
-
#import <Foundation/Foundation.h>
|
|
10
|
-
#import <Nami/Nami.h>
|
|
11
|
-
#import "NamiBridgeUtil.h"
|
|
12
|
-
|
|
13
8
|
#import <React/RCTBridgeModule.h>
|
|
14
|
-
#import <React/RCTEventEmitter.h>
|
|
15
9
|
|
|
16
|
-
|
|
10
|
+
@interface RCT_EXTERN_MODULE(RNNamiCustomerManager, NSObject)
|
|
17
11
|
|
|
18
|
-
|
|
19
|
-
@end
|
|
20
|
-
@implementation NamiCustomerManagerBridge (RCTExternModule)
|
|
12
|
+
RCT_EXTERN_METHOD(setCustomerAttribute:(NSString *)key value:(NSString *)value)
|
|
21
13
|
|
|
14
|
+
RCT_EXTERN_METHOD(getCustomerAttribute:(NSString *)key resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
22
15
|
|
|
23
|
-
|
|
24
|
-
{
|
|
25
|
-
NSDictionary *journeyDict = [NamiBridgeUtil customerJourneyStateDict];
|
|
26
|
-
|
|
27
|
-
completion(@[journeyDict]);
|
|
28
|
-
}
|
|
16
|
+
RCT_EXTERN_METHOD(clearCustomerAttribute:(NSString *)key)
|
|
29
17
|
|
|
18
|
+
RCT_EXTERN_METHOD(clearAllCustomerAttributes)
|
|
30
19
|
|
|
31
|
-
|
|
20
|
+
RCT_EXTERN_METHOD(journeyState:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
32
21
|
|
|
22
|
+
RCT_EXTERN_METHOD(isLoggedIn:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
33
23
|
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
RCT_EXTERN_METHOD(loggedInId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
25
|
+
|
|
26
|
+
RCT_EXTERN_METHOD(deviceId:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
27
|
+
|
|
28
|
+
RCT_EXTERN_METHOD(login:(NSString *)customerId completion:(RCTResponseSenderBlock)callback)
|
|
29
|
+
|
|
30
|
+
RCT_EXTERN_METHOD(logout:(RCTResponseSenderBlock)callback)
|
|
31
|
+
|
|
32
|
+
RCT_EXTERN_METHOD(registerJourneyStateHandler)
|
|
33
|
+
|
|
34
|
+
RCT_EXTERN_METHOD(registerAccountStateHandler)
|
|
36
35
|
|
|
37
|
-
- (dispatch_queue_t)methodQueue
|
|
38
|
-
{
|
|
39
|
-
return dispatch_get_main_queue();
|
|
40
|
-
}
|
|
41
36
|
|
|
42
37
|
+ (BOOL)requiresMainQueueSetup {
|
|
43
38
|
return YES;
|