react-native-nami-sdk 1.0.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,9 +20,8 @@ def safeExtGet(prop, fallback) {
20
20
  apply plugin: 'com.android.library'
21
21
  apply plugin: 'maven'
22
22
  apply plugin: "kotlin-android"
23
- apply plugin: "kotlin-android-extensions"
24
23
  buildscript {
25
- ext.kotlin_version = '1.4.30'
24
+ ext.kotlin_version = '1.4.31'
26
25
  // The Android Gradle plugin is only required when opening the android folder stand-alone.
27
26
  // This avoids unnecessary downloads and potential conflicts when the library is included as a
28
27
  // module dependency in an application project.
@@ -33,7 +32,7 @@ buildscript {
33
32
  jcenter()
34
33
  }
35
34
  dependencies {
36
- classpath 'com.android.tools.build:gradle:4.1.2'
35
+ classpath 'com.android.tools.build:gradle:4.2.1'
37
36
  classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
38
37
  }
39
38
  }
@@ -47,9 +46,16 @@ android {
47
46
  versionCode 1
48
47
  versionName "1.0"
49
48
  }
49
+ compileOptions {
50
+ sourceCompatibility JavaVersion.VERSION_1_8
51
+ targetCompatibility JavaVersion.VERSION_1_8
52
+ }
50
53
  lintOptions {
51
54
  abortOnError false
52
55
  }
56
+ kotlinOptions {
57
+ jvmTarget = "1.8"
58
+ }
53
59
  }
54
60
  repositories {
55
61
  // ref: https://www.baeldung.com/maven-local-repository
@@ -65,12 +71,13 @@ repositories {
65
71
  google()
66
72
  jcenter()
67
73
  }
74
+
68
75
  dependencies {
69
76
  //noinspection GradleDynamicVersion
70
77
  implementation fileTree(dir: 'libs', include: ['*.jar'])
71
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
78
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
72
79
 
73
- implementation "com.namiml:sdk-android:1.0.1"
80
+ implementation "com.namiml:sdk-android:1.2.1"
74
81
 
75
82
  implementation 'com.facebook.react:react-native:+' // From node_modules
76
83
  }
@@ -1,6 +1,6 @@
1
- #Sun Nov 15 19:24:03 EST 2020
1
+ #Wed May 26 17:12:26 EDT 2021
2
2
  distributionBase=GRADLE_USER_HOME
3
+ distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip
3
4
  distributionPath=wrapper/dists
4
- zipStoreBase=GRADLE_USER_HOME
5
5
  zipStorePath=wrapper/dists
6
- distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
6
+ zipStoreBase=GRADLE_USER_HOME
@@ -12,6 +12,7 @@ import com.facebook.react.bridge.ReactMethod
12
12
  import com.facebook.react.bridge.WritableNativeMap
13
13
  import com.facebook.react.modules.core.DeviceEventManagerModule
14
14
  import com.namiml.paywall.NamiPaywallManager
15
+ import com.namiml.paywall.PreparePaywallResult
15
16
 
16
17
  class NamiPaywallManagerBridgeModule(reactContext: ReactApplicationContext) :
17
18
  ReactContextBaseJavaModule(reactContext), ActivityEventListener {
@@ -46,7 +47,7 @@ class NamiPaywallManagerBridgeModule(reactContext: ReactApplicationContext) :
46
47
  }
47
48
  }
48
49
 
49
- fun emitBockedPaywallClosed() {
50
+ private fun emitBockedPaywallClosed() {
50
51
  val map = Arguments.createMap().apply {
51
52
  putBoolean("blockingPaywallClosed", true)
52
53
  }
@@ -99,9 +100,6 @@ class NamiPaywallManagerBridgeModule(reactContext: ReactApplicationContext) :
99
100
 
100
101
  @ReactMethod
101
102
  fun canRaisePaywall(successCallback: Callback) {
102
- // BOOL canRaise = [[NamiPaywallManager shared] canRaisePaywall];
103
- // completion(@[[NSNumber numberWithBool:canRaise]]);
104
-
105
103
  reactApplicationContext.runOnUiQueueThread {
106
104
  val canRaiseResult = NamiPaywallManager.canRaisePaywall()
107
105
  successCallback.invoke(canRaiseResult)
@@ -124,4 +122,80 @@ class NamiPaywallManagerBridgeModule(reactContext: ReactApplicationContext) :
124
122
  fun paywallImpression(developerPaywallID: String) {
125
123
  // TODO: Android SDK paywall impression call.
126
124
  }
125
+
126
+ @ReactMethod
127
+ fun preparePaywallForDisplay(backgroundImageRequired: Boolean, imageFetchTimeout: Double) {
128
+ val imageFetchTimeoutConvertedToLong: Long = imageFetchTimeout.toLong()
129
+ reactApplicationContext.runOnUiQueueThread {
130
+
131
+ NamiPaywallManager.preparePaywallForDisplay(
132
+ backgroundImageRequired,
133
+ imageFetchTimeoutConvertedToLong
134
+ ) { result ->
135
+ when (result) {
136
+ is PreparePaywallResult.Success -> {
137
+ emitPreparePaywallFinished(true, null, null)
138
+ }
139
+ is PreparePaywallResult.Failure -> {
140
+ emitPreparePaywallFinished(false, null, result.error)
141
+ }
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ @ReactMethod
148
+ fun preparePaywallForDisplayByDeveloperPaywallId(
149
+ developerPaywallID: String,
150
+ backgroundImageRequired: Boolean,
151
+ imageFetchTimeout: Double
152
+ ) {
153
+ val imageFetchTimeoutConvertedToLong: Long = imageFetchTimeout.toLong()
154
+ reactApplicationContext.runOnUiQueueThread {
155
+ NamiPaywallManager.preparePaywallForDisplay(
156
+ developerPaywallID,
157
+ backgroundImageRequired,
158
+ imageFetchTimeoutConvertedToLong
159
+ ) { result ->
160
+ when (result) {
161
+ is PreparePaywallResult.Success -> {
162
+ emitPreparePaywallFinished(true, developerPaywallID, null)
163
+ }
164
+ is PreparePaywallResult.Failure -> {
165
+ emitPreparePaywallFinished(false, developerPaywallID, result.error)
166
+ }
167
+ }
168
+ }
169
+ }
170
+ }
171
+
172
+ private fun emitPreparePaywallFinished(
173
+ success: Boolean,
174
+ developerPaywallID: String?,
175
+ error: com.namiml.paywall.PreparePaywallError?
176
+ ) {
177
+ val prepareContentMap = Arguments.createMap()
178
+ prepareContentMap.putBoolean("success", success)
179
+
180
+ if (developerPaywallID != null) {
181
+ prepareContentMap.putString("developerPaywallID", developerPaywallID)
182
+ }
183
+
184
+ if (error != null) {
185
+ prepareContentMap.putInt("errorCode", error.ordinal)
186
+ prepareContentMap.putString("errorMessage", error.toString())
187
+ }
188
+
189
+ Log.i(
190
+ LOG_TAG,
191
+ "Emitting preparePaywallForDisplay finished with result " + success + "error: " + error.toString()
192
+ )
193
+ try {
194
+ reactApplicationContext
195
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
196
+ .emit("PreparePaywallFinished", prepareContentMap)
197
+ } catch (e: Exception) {
198
+ Log.e(LOG_TAG, "Caught Exception: " + e.message)
199
+ }
200
+ }
127
201
  }
@@ -196,6 +196,8 @@ fun NamiSKU.toSkuDict(): WritableMap {
196
196
  productDict.putString("localizedDescription", skuDetails.description)
197
197
  productDict.putString("localizedPrice", skuDetails.price)
198
198
  productDict.putString("localizedMultipliedPrice", skuDetails.price)
199
+ productDict.putString("displayText", displayText)
200
+ productDict.putString("displaySubText", displaySubText)
199
201
  productDict.putString("price", skuDetails.getFormattedPrice().toString())
200
202
  productDict.putString("priceLanguage", Locale.getDefault().language)
201
203
  productDict.putString("priceCountry", Locale.getDefault().country)
@@ -208,9 +210,6 @@ fun NamiSKU.toSkuDict(): WritableMap {
208
210
  SubscriptionPeriod.HALF_YEAR -> {
209
211
  "half_year"
210
212
  }
211
- SubscriptionPeriod.DAY -> {
212
- "day"
213
- }
214
213
  SubscriptionPeriod.WEEKLY -> {
215
214
  "week"
216
215
  }
@@ -28,6 +28,10 @@
28
28
  productDict[@"priceLanguage"] = productInt.priceLocale.languageCode;
29
29
  productDict[@"priceCountry"] = productInt.priceLocale.countryCode;
30
30
  productDict[@"priceCurrency"] = productInt.priceLocale.currencyCode;
31
+
32
+ // Add smart text processed values for sku buttons to sku dictionary
33
+ productDict[@"displayText"] = [sku namiDisplayText];
34
+ productDict[@"displaySubText"] = [sku namiSubDisplayText];
31
35
 
32
36
  if (@available(iOS 12.0, *)) {
33
37
  if (productInt != nil && productInt.subscriptionGroupIdentifier != nil) {
package/ios/NamiEmitter.m CHANGED
@@ -23,6 +23,8 @@ RCT_EXTERN_METHOD(allPurchasedProducts)
23
23
  RCT_EXTERN_METHOD(getPurchasedProducts: (RCTResponseSenderBlock)callback)
24
24
  @end
25
25
 
26
+ static NamiEmitter *namiEmitter;
27
+
26
28
  @implementation NamiEmitter : RCTEventEmitter
27
29
 
28
30
  - (instancetype)init
@@ -54,9 +56,19 @@ RCT_EXTERN_METHOD(getPurchasedProducts: (RCTResponseSenderBlock)callback)
54
56
  }];
55
57
 
56
58
  }
59
+ namiEmitter = self;
57
60
  return self;
58
61
  }
59
62
 
63
+ - (void)dealloc {
64
+ namiEmitter = nil;
65
+ }
66
+
67
+
68
+ + (NamiEmitter *) reactInstance {
69
+ return namiEmitter;
70
+ }
71
+
60
72
  - (void) getPurchasedProducts : (RCTResponseSenderBlock) callback {
61
73
  NSArray *allProducts = [self allPurchasedProducts];
62
74
  callback(allProducts);
@@ -77,7 +89,7 @@ RCT_EXTERN_METHOD(getPurchasedProducts: (RCTResponseSenderBlock)callback)
77
89
  }
78
90
 
79
91
  - (NSArray<NSString *> *)supportedEvents {
80
- return @[@"PurchasesChanged", @"SignInActivate", @"AppPaywallActivate", @"EntitlementsChanged", @"BlockingPaywallClosed" ];
92
+ return @[@"PurchasesChanged", @"SignInActivate", @"AppPaywallActivate", @"EntitlementsChanged", @"BlockingPaywallClosed", @"PreparePaywallFinished" ];
81
93
  }
82
94
 
83
95
  - (NSDictionary<NSString *, NSObject *> *)constantsToExport {
@@ -150,6 +162,30 @@ bool hasNamiEmitterListeners;
150
162
  }
151
163
  }
152
164
 
165
+ - (void)sendEventPreparePaywallForDisplayFinishedWithResult:(BOOL)success developerPaywallID: (NSString * _Nullable) developerPaywallID error:(NSError * _Nullable) error {
166
+ if (hasNamiEmitterListeners) {
167
+
168
+ NSMutableDictionary *sendDict = [NSMutableDictionary dictionaryWithDictionary: @{ @"success": @(success) }];
169
+
170
+ if (developerPaywallID != nil) {
171
+ [sendDict addEntriesFromDictionary:@{
172
+ @"developerPaywallID": developerPaywallID
173
+ }];
174
+ }
175
+
176
+ if (error != nil) {
177
+ [sendDict addEntriesFromDictionary:@{
178
+ @"errorCode": @(error.code),
179
+ @"errorMessage": [error localizedDescription]
180
+ }
181
+ ];
182
+ }
183
+
184
+ NSLog(@"NamiBridge: Info: attempting to send result of preparePaywallForDisplay with result dictionary: %@", sendDict);
185
+ [self sendEventWithName:@"PreparePaywallFinished" body:sendDict];
186
+ }
187
+ }
188
+
153
189
  - (void)sendEventPurchaseMadeWithPurchases:(NSArray<NamiPurchase *>*)purchases withState:(NamiPurchaseState)purchaseState error:(NSError *)error {
154
190
  if (hasNamiEmitterListeners) {
155
191
 
@@ -200,6 +236,14 @@ bool hasNamiEmitterListeners;
200
236
  NSMutableDictionary *paywallMeta = [NSMutableDictionary dictionaryWithDictionary:paywallMetadata.namiPaywallInfoDict];
201
237
  // This part is really meant to be internally facing, scrub from dictionary
202
238
 
239
+ NSMutableDictionary *marketingContentDictionary = [NSMutableDictionary dictionaryWithDictionary:paywallMeta[@"marketing_content"]];
240
+
241
+ // Populated SmartText formatted values in dictioanry to send
242
+ marketingContentDictionary[@"body"] = [paywallMetadata body];
243
+ marketingContentDictionary[@"title"] = [paywallMetadata title];
244
+ paywallMeta[@"marketing_content"] = marketingContentDictionary;
245
+ paywallMeta[@"purchase_terms"] = [paywallMetadata purchaseTerms];
246
+
203
247
  // Strip out presention_position from all listed sku items
204
248
  NSArray *cleanedOrderdMetadata = [NamiBridgeUtil stripPresentationPositionFromOrderedMetadataForPaywallMetaDict:paywallMeta];
205
249
  [paywallMeta setObject:cleanedOrderdMetadata forKey:@"formatted_skus"];
@@ -15,7 +15,10 @@
15
15
 
16
16
  #import "React/RCTViewManager.h"
17
17
 
18
-
18
+ @interface NamiEmitter : RCTEventEmitter
19
+ - (void)sendEventPreparePaywallForDisplayFinishedWithResult:(BOOL)success developerPaywallID: (NSString * _Nullable) developerPaywallID error:(NSError * _Nullable) error;
20
+ + (NamiEmitter *) reactInstance;
21
+ @end
19
22
 
20
23
  @interface NamiPaywallManagerBridge : NSObject <RCTBridgeModule>
21
24
  @property (atomic) BOOL blockPaywallRaise;
@@ -58,6 +61,7 @@ RCT_EXPORT_METHOD(canRaisePaywall:(RCTResponseSenderBlock)completion)
58
61
  completion(@[[NSNumber numberWithBool:canRaise]]);
59
62
  }
60
63
 
64
+
61
65
  RCT_EXPORT_METHOD(presentNamiPaywall:(NSArray *)skuIDs metapaywallDefinition:(NSDictionary *)paywallDict)
62
66
  {
63
67
  NSString *paywallDeveloperID = paywallDict[@"developerPaywallID"];
@@ -104,6 +108,38 @@ RCT_EXPORT_METHOD(paywallImpression:(NSString *)developerPaywallID)
104
108
  [NamiPaywallManager paywallImpressionWithDeveloperID:developerPaywallID];
105
109
  }
106
110
 
111
+ RCT_EXPORT_METHOD( preparePaywallForDisplay:(BOOL)backgroundImageRequired
112
+ imageFetchTimeout:(double)imageFetchTimeout )
113
+ {
114
+ [NamiPaywallManager preparePaywallForDisplayWithBackgroundImageRequired:backgroundImageRequired imageFetchTimeout:imageFetchTimeout prepareHandler:^(BOOL success, NSError * _Nullable error) {
115
+ [[NamiEmitter reactInstance] sendEventPreparePaywallForDisplayFinishedWithResult:success developerPaywallID:nil error:error];
116
+ }];
117
+ }
118
+
119
+ RCT_EXPORT_METHOD(preparePaywallForDisplayByDeveloperPaywallId:(NSString *)developerPaywallID
120
+ backgroundImageRequired: (BOOL)backgroundImageRequired
121
+ imageFetchTimeout:(double)imageFetchTimeout )
122
+ {
123
+ [NamiPaywallManager preparePaywallForDisplayWithDeveloperPaywallID:developerPaywallID backgroundImageRequired:backgroundImageRequired imageFetchTimeout:imageFetchTimeout prepareHandler:^(BOOL success, NSError * _Nullable error) {
124
+ [[NamiEmitter reactInstance] sendEventPreparePaywallForDisplayFinishedWithResult:success developerPaywallID:developerPaywallID error:error];
125
+ }];
126
+ }
127
+
128
+
129
+ RCT_EXPORT_METHOD(processSmartTextForProducts:(NSString *)smartText skuIDs:(NSArray<NSString *> *)skuIDs completion:(RCTResponseSenderBlock)completion)
130
+ {
131
+ [NamiPurchaseManager skusForSKUIDsWithSkuIDs:skuIDs productHandler:^(BOOL success, NSArray<NamiSKU *> * _Nullable skus, NSArray<NSString *> * _Nullable invalidSkuIDs, NSError * _Nullable error) {
132
+ if (skus != NULL) {
133
+ // Found some of the skus they were looking for, process text
134
+ NSString *processedText = [NamiPaywallManager processSmartTextWithText:smartText dataStores:skus];
135
+ completion(@[processedText]);
136
+ } else {
137
+ // No products found so cannot process smart text, just send back.
138
+ completion(@[smartText]);
139
+ }
140
+ }];
141
+ }
142
+
107
143
 
108
144
  @end
109
145
 
package/ios/Podfile CHANGED
@@ -5,7 +5,7 @@ source 'https://cdn.cocoapods.org/'
5
5
 
6
6
  target 'RNNami' do
7
7
  # Pods for RNNami
8
- pod 'Nami', '2.5.2'
8
+ pod 'Nami', '2.7.1'
9
9
  pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
10
10
  pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
11
11
  pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-nami-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.2.1",
4
4
  "description": "React Native Module for Nami - The Smartest Way to Sell Subscriptions.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -18,7 +18,7 @@ Pod::Spec.new do |s|
18
18
  s.source_files = "ios/**/*.{h,m}"
19
19
  s.requires_arc = true
20
20
 
21
- s.dependency 'Nami', '2.5.2'
21
+ s.dependency 'Nami', '2.7.1'
22
22
  s.dependency 'React'
23
23
 
24
24
  end