react-native-nami-sdk 1.2.1 → 2.0.2

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.
@@ -0,0 +1,68 @@
1
+ name: Build Bridge
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ ref:
7
+ description: "Git Tag, Branch or SHA to build"
8
+ required: true
9
+ default: "develop"
10
+ earlyaccess:
11
+ description: "Is this a early access build?"
12
+ default: true
13
+ type: boolean
14
+ secrets:
15
+ BUILD_USER_PAT:
16
+ required: true
17
+
18
+ jobs:
19
+ build:
20
+ name: Build Bridge release
21
+ timeout-minutes: 30
22
+ runs-on: ubuntu-latest
23
+ permissions:
24
+ actions: write
25
+ contents: write
26
+ id-token: write
27
+ steps:
28
+
29
+ # clone the repo at a specific version
30
+ - name: Checkout ${{ inputs.ref }}
31
+ uses: actions/checkout@v2
32
+ with:
33
+ ref: ${{ inputs.ref }}
34
+
35
+ # human error checks
36
+ - name: Set up Python
37
+ uses: actions/setup-python@v1
38
+ with:
39
+ python-version: "3.10"
40
+
41
+ - name: Release Preflight Checks
42
+ run: |
43
+ python3 build-utils/preflight.py
44
+ env:
45
+ NAMI_SDK_VERSION: ${{ inputs.version }}
46
+
47
+ - name: Setup .npmrc
48
+ run: |
49
+ cat .npmrc
50
+
51
+ - name: Run Yarn
52
+ run: |
53
+ yarn --frozen-lockfile
54
+ env:
55
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
56
+
57
+ - name: Publish
58
+ run: |
59
+ npm publish --access public
60
+ env:
61
+ NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
62
+
63
+ - name: Create Github Release
64
+ run: |-
65
+ #sh gh-release-command.sh
66
+ echo "Release me"
67
+ env:
68
+ GITHUB_TOKEN: ${{ github.token }}
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ![Nami SDK logo](https://nami-brand.s3.amazonaws.com/images/Nami.SDK.2.0.120x137.png)
1
+ ![Nami SDK logo](https://cdn.namiml.com/brand/sdk/Nami-SDK@0.5x.png)
2
2
 
3
3
  # React Native Bridge for the Nami SDK
4
4
 
@@ -10,10 +10,7 @@ import groovy.json.JsonSlurper
10
10
  // * https://github.com/facebook/react-native/blob/0.60-stable/template/android/app/build.gradle
11
11
  // original location:
12
12
  // - https://github.com/facebook/react-native/blob/0.58-stable/local-cli/templates/HelloWorld/android/app/build.gradle
13
- def DEFAULT_COMPILE_SDK_VERSION = 30
14
- def DEFAULT_BUILD_TOOLS_VERSION = '29.0.3'
15
- def DEFAULT_MIN_SDK_VERSION = 21
16
- def DEFAULT_TARGET_SDK_VERSION = 30
13
+ def DEFAULT_BUILD_TOOLS_VERSION = '30.0.2'
17
14
  def safeExtGet(prop, fallback) {
18
15
  rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
19
16
  }
@@ -28,8 +25,8 @@ buildscript {
28
25
  // ref: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies
29
26
  if (project == rootProject) {
30
27
  repositories {
28
+ mavenCentral()
31
29
  google()
32
- jcenter()
33
30
  }
34
31
  dependencies {
35
32
  classpath 'com.android.tools.build:gradle:4.2.1'
@@ -38,11 +35,11 @@ buildscript {
38
35
  }
39
36
  }
40
37
  android {
41
- compileSdkVersion safeExtGet('compileSdkVersion', DEFAULT_COMPILE_SDK_VERSION)
38
+ compileSdkVersion 31
42
39
  buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION)
43
40
  defaultConfig {
44
- minSdkVersion safeExtGet('minSdkVersion', DEFAULT_MIN_SDK_VERSION)
45
- targetSdkVersion safeExtGet('targetSdkVersion', DEFAULT_TARGET_SDK_VERSION)
41
+ minSdkVersion 26
42
+ targetSdkVersion 31
46
43
  versionCode 1
47
44
  versionName "1.0"
48
45
  }
@@ -58,6 +55,7 @@ android {
58
55
  }
59
56
  }
60
57
  repositories {
58
+ mavenCentral()
61
59
  // ref: https://www.baeldung.com/maven-local-repository
62
60
  maven { url("https://nami-android.s3.amazonaws.com/") }
63
61
  maven {
@@ -69,7 +67,6 @@ repositories {
69
67
  url("$rootDir/../node_modules/jsc-android/dist")
70
68
  }
71
69
  google()
72
- jcenter()
73
70
  }
74
71
 
75
72
  dependencies {
@@ -77,7 +74,7 @@ dependencies {
77
74
  implementation fileTree(dir: 'libs', include: ['*.jar'])
78
75
  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
79
76
 
80
- implementation "com.namiml:sdk-android:1.2.1"
77
+ implementation "com.namiml:sdk-android:2.0.0"
81
78
 
82
79
  implementation 'com.facebook.react:react-native:+' // From node_modules
83
80
  }
@@ -1,4 +1,3 @@
1
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
- package="com.nami.reactlibrary">
1
+ <manifest package="com.nami.reactlibrary">
3
2
 
4
3
  </manifest>
@@ -15,6 +15,7 @@ import com.facebook.react.bridge.WritableNativeArray
15
15
  import com.namiml.Nami
16
16
  import com.namiml.NamiConfiguration
17
17
  import com.namiml.NamiExternalIdentifierType
18
+ import com.namiml.NamiLanguageCode
18
19
  import com.namiml.NamiLogLevel
19
20
 
20
21
  class NamiBridgeModule(reactContext: ReactApplicationContext) :
@@ -26,6 +27,7 @@ class NamiBridgeModule(reactContext: ReactApplicationContext) :
26
27
  private const val CONFIG_MAP_DEVELOPMENT_MODE_KEY = "developmentMode"
27
28
  private const val CONFIG_MAP_BYPASS_STORE_KEY = "bypassStore"
28
29
  private const val CONFIG_MAP_NAMI_COMMANDS_KEY = "namiCommands"
30
+ private const val CONFIG_MAP_LANGUAGE_CODE_KEY = "namiLanguageCode"
29
31
  private const val PLATFORM_ID_ERROR_VALUE = "APPPLATFORMID_NOT_FOUND"
30
32
  }
31
33
 
@@ -33,12 +35,6 @@ class NamiBridgeModule(reactContext: ReactApplicationContext) :
33
35
  return "NamiBridge"
34
36
  }
35
37
 
36
- // @ReactMethod
37
- // public void sampleMethod(String stringArgument, int numberArgument, Callback callback) {
38
- // // TODO: Implement some actually useful functionality
39
- // callback.invoke("Received numberArgument: " + numberArgument + " stringArgument: " + stringArgument);
40
- // }
41
-
42
38
  @ReactMethod
43
39
  fun configure(configDict: ReadableMap) {
44
40
 
@@ -106,13 +102,32 @@ class NamiBridgeModule(reactContext: ReactApplicationContext) :
106
102
  builder.bypassStore = true
107
103
  }
108
104
 
105
+ val languageCode = if (configDict.hasKey(CONFIG_MAP_LANGUAGE_CODE_KEY)) {
106
+ configDict.getString(CONFIG_MAP_LANGUAGE_CODE_KEY)
107
+ } else {
108
+ null
109
+ }
110
+ languageCode?.let { code ->
111
+ NamiLanguageCode.values().find { it.code == code }.let { namiLanguageCode ->
112
+ if (namiLanguageCode == null) {
113
+ Log.w(
114
+ LOG_TAG,
115
+ "Nami language code from config dictionary \"$code\" not " +
116
+ "found in list of available Nami Language Codes:\n"
117
+ )
118
+ } else {
119
+ builder.namiLanguageCode = namiLanguageCode
120
+ }
121
+ }
122
+ }
123
+
109
124
  val namiCommandsReact: ReadableArray? =
110
125
  if (configDict.hasKey(CONFIG_MAP_NAMI_COMMANDS_KEY)) {
111
126
  configDict.getArray(CONFIG_MAP_NAMI_COMMANDS_KEY)
112
127
  } else {
113
128
  Arguments.createArray()
114
129
  }
115
- val settingsList = mutableListOf("extendedClientInfo:react-native:0.3.1")
130
+ val settingsList = mutableListOf("extendedClientInfo:react-native:1.2.1")
116
131
  namiCommandsReact?.toArrayList()?.filterIsInstance<String>()?.let { commandsFromReact ->
117
132
  settingsList.addAll(commandsFromReact)
118
133
  }
@@ -1,10 +1,12 @@
1
1
  package com.nami.reactlibrary
2
2
 
3
+ import android.util.Log
3
4
  import com.facebook.react.bridge.Callback
4
5
  import com.facebook.react.bridge.ReactApplicationContext
5
6
  import com.facebook.react.bridge.ReactContextBaseJavaModule
6
7
  import com.facebook.react.bridge.ReactMethod
7
- import com.facebook.react.bridge.WritableNativeMap
8
+ import com.facebook.react.modules.core.DeviceEventManagerModule
9
+ import com.namiml.customer.CustomerJourneyState
8
10
  import com.namiml.customer.NamiCustomerManager
9
11
 
10
12
  class NamiCustomerManagerBridgeModule(reactContext: ReactApplicationContext) :
@@ -14,24 +16,27 @@ class NamiCustomerManagerBridgeModule(reactContext: ReactApplicationContext) :
14
16
  return "NamiCustomerManagerBridge"
15
17
  }
16
18
 
19
+ init {
20
+ NamiCustomerManager.registerCustomerJourneyChangedListener { customerJourneyState ->
21
+ emitCustomerJourneyChanged(customerJourneyState)
22
+ }
23
+ }
24
+
25
+ private fun emitCustomerJourneyChanged(customerJourneyState: CustomerJourneyState) {
26
+ Log.i(LOG_TAG, "Emitting CustomerJourneyState changed")
27
+ try {
28
+ reactApplicationContext
29
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
30
+ .emit("CustomerJourneyStateChanged", customerJourneyState.toDict())
31
+ } catch (e: Exception) {
32
+ Log.e(LOG_TAG, "Caught Exception: " + e.message)
33
+ }
34
+ }
35
+
17
36
  @ReactMethod
18
37
  fun currentCustomerJourneyState(resultsCallback: Callback) {
19
38
  reactApplicationContext.runOnUiQueueThread {
20
- val journeyState = NamiCustomerManager.currentCustomerJourneyState()
21
-
22
- val formerSubscriber = journeyState?.formerSubscriber ?: false
23
- val inGracePeriod = journeyState?.inGracePeriod ?: false
24
- val inTrialPeriod = journeyState?.inTrialPeriod ?: false
25
- val inIntroOfferPeriod = journeyState?.inIntroOfferPeriod ?: false
26
-
27
- val journeyDict = WritableNativeMap().apply {
28
- putBoolean("formerSubscriber", formerSubscriber)
29
- putBoolean("inGracePeriod", inGracePeriod)
30
- putBoolean("inTrialPeriod", inTrialPeriod)
31
- putBoolean("inIntroOfferPeriod", inIntroOfferPeriod)
32
- }
33
-
34
- resultsCallback.invoke(journeyDict)
39
+ resultsCallback.invoke(NamiCustomerManager.currentCustomerJourneyState().toDict())
35
40
  }
36
41
  }
37
42
  }
@@ -11,7 +11,8 @@ import com.facebook.react.modules.core.DeviceEventManagerModule
11
11
  import com.namiml.billing.NamiPurchase
12
12
  import com.namiml.billing.NamiPurchaseManager
13
13
  import com.namiml.billing.NamiPurchaseState
14
- import com.namiml.entitlement.NamiEntitlement
14
+ import com.namiml.customer.CustomerJourneyState
15
+ import com.namiml.customer.NamiCustomerManager
15
16
  import com.namiml.paywall.NamiPaywall
16
17
  import com.namiml.paywall.NamiPaywallManager
17
18
  import com.namiml.paywall.NamiSKU
@@ -32,15 +33,15 @@ class NamiEmitter(reactContext: ReactApplicationContext) :
32
33
  }
33
34
 
34
35
  override fun initialize() {
35
- NamiPaywallManager.registerSignInListener { context, paywallData, developerPaywallID ->
36
+ NamiPaywallManager.registerSignInListener { _, _, developerPaywallID ->
36
37
  Log.i(LOG_TAG, "Sign in clicked with developerPaywallID $developerPaywallID")
37
38
 
38
- emitSignInActivated(paywallData, developerPaywallID)
39
+ emitSignInActivated(developerPaywallID)
39
40
  }
40
41
 
41
42
  Log.i(LOG_TAG, "In Emitter Initialize()")
42
43
 
43
- NamiPaywallManager.registerPaywallRaiseListener { context, paywallData, products, developerPaywallId ->
44
+ NamiPaywallManager.registerPaywallRaiseListener { _, paywallData, products, developerPaywallId ->
44
45
  Log.i(
45
46
  LOG_TAG,
46
47
  "Products from registerPaywallRaiseListener callback are $products"
@@ -53,28 +54,24 @@ class NamiEmitter(reactContext: ReactApplicationContext) :
53
54
  NamiPurchaseManager.registerPurchasesChangedListener { list, namiPurchaseState, s ->
54
55
  emitPurchaseMade(list, namiPurchaseState, s)
55
56
  }
56
- }
57
-
58
- fun emitEntitlementsChanged(entitlements: List<NamiEntitlement>) {
59
- val map = Arguments.createMap()
60
57
 
61
- val resultArray: WritableArray = WritableNativeArray()
62
- for (entitlement in entitlements) {
63
- resultArray.pushMap(entitlement.toEntitlementDict())
58
+ NamiCustomerManager.registerCustomerJourneyChangedListener {
59
+ emitCustomerJourneyChanged(it)
64
60
  }
65
- map.putArray("entitlements", resultArray)
61
+ }
66
62
 
67
- Log.i(LOG_TAG, "Emitting entitlements changed")
63
+ private fun emitCustomerJourneyChanged(customerJourneyState: CustomerJourneyState) {
64
+ Log.i(LOG_TAG, "Emitting CustomerJourneyChanged $customerJourneyState")
68
65
  try {
69
66
  reactApplicationContext
70
67
  .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
71
- .emit("EntitlementsChanged", map)
68
+ .emit("CustomerJourneyStateChanged", customerJourneyState.toDict())
72
69
  } catch (e: Exception) {
73
70
  Log.e(LOG_TAG, "Caught Exception: " + e.message)
74
71
  }
75
72
  }
76
73
 
77
- fun emitPurchaseMade(
74
+ private fun emitPurchaseMade(
78
75
  purchases: List<NamiPurchase>,
79
76
  purchaseState: NamiPurchaseState,
80
77
  errorString: String?
@@ -117,7 +114,7 @@ class NamiEmitter(reactContext: ReactApplicationContext) :
117
114
  }
118
115
  }
119
116
 
120
- fun emitPaywallRaise(
117
+ private fun emitPaywallRaise(
121
118
  namiPaywall: NamiPaywall,
122
119
  productDicts: List<NamiSKU>,
123
120
  paywallDeveloperID: String?
@@ -139,7 +136,7 @@ class NamiEmitter(reactContext: ReactApplicationContext) :
139
136
  skusArray.pushMap(sku.toSkuDict())
140
137
  }
141
138
 
142
- map.putArray("skus", skusArray)
139
+ map.putArray("namiSkus", skusArray)
143
140
 
144
141
  try {
145
142
  reactApplicationContext
@@ -150,7 +147,7 @@ class NamiEmitter(reactContext: ReactApplicationContext) :
150
147
  }
151
148
  }
152
149
 
153
- fun emitSignInActivated(paywallData: NamiPaywall, paywallDeveloperID: String?) {
150
+ private fun emitSignInActivated(paywallDeveloperID: String?) {
154
151
 
155
152
  val map = Arguments.createMap().apply {
156
153
  putString("developerPaywallID", paywallDeveloperID)
@@ -163,19 +160,4 @@ class NamiEmitter(reactContext: ReactApplicationContext) :
163
160
  Log.e(LOG_TAG, "Caught Exception: " + e.message)
164
161
  }
165
162
  }
166
-
167
- fun emitPurchaseMade(paywallDeveloperID: String) {
168
-
169
- val map = Arguments.createMap().apply {
170
- putString("key1", "Value1")
171
- putString("key1", "Value1")
172
- }
173
- try {
174
- reactApplicationContext
175
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
176
- .emit("customEventName", map)
177
- } catch (e: Exception) {
178
- Log.e(LOG_TAG, "Caught Exception: " + e.message)
179
- }
180
- }
181
163
  }
@@ -70,6 +70,13 @@ class NamiPurchaseManagerBridgeModule(reactContext: ReactApplicationContext) :
70
70
  }
71
71
  }
72
72
 
73
+ @ReactMethod
74
+ fun consumePurchasedSKU(skuRefId: String) {
75
+ reactApplicationContext.runOnUiQueueThread {
76
+ NamiPurchaseManager.consumePurchasedSKU(skuRefId)
77
+ }
78
+ }
79
+
73
80
  @ReactMethod
74
81
  fun anySKUIDPurchased(skuIDs: ReadableArray, resultsCallback: Callback) {
75
82
  reactApplicationContext.runOnUiQueueThread {
@@ -6,12 +6,15 @@ import com.facebook.react.bridge.WritableArray
6
6
  import com.facebook.react.bridge.WritableMap
7
7
  import com.facebook.react.bridge.WritableNativeArray
8
8
  import com.facebook.react.bridge.WritableNativeMap
9
- import com.namiml.api.model.FormattedSku
10
9
  import com.namiml.billing.NamiPurchase
10
+ import com.namiml.customer.CustomerJourneyState
11
11
  import com.namiml.entitlement.NamiEntitlement
12
+ import com.namiml.paywall.LegalCitations
13
+ import com.namiml.paywall.NamiLocaleConfig
12
14
  import com.namiml.paywall.NamiPaywall
13
15
  import com.namiml.paywall.NamiPurchaseSource
14
16
  import com.namiml.paywall.NamiSKU
17
+ import com.namiml.paywall.PaywallDisplayOptions
15
18
  import com.namiml.paywall.PaywallStyleData
16
19
  import com.namiml.paywall.SubscriptionPeriod
17
20
  import com.namiml.util.extensions.getFormattedPrice
@@ -22,19 +25,9 @@ import java.util.Date
22
25
  import java.util.Locale
23
26
  import java.util.TimeZone
24
27
 
25
- fun FormattedSku.toFormattedSkuDict(): WritableMap {
26
- val map: WritableMap = Arguments.createMap()
27
- map.putString("sku_ref_id", this.skuId)
28
- map.putBoolean("featured", this.featured)
29
- return map
30
- }
31
-
32
28
  fun NamiPaywall.toNamiPaywallDict(): WritableMap {
33
29
 
34
30
  val paywallMap: WritableMap = Arguments.createMap()
35
- // These don't seem to exist, inconsistent between Android and iOS, leave in marketing content
36
- //paywallMap.putString("title", title.orEmpty())
37
- //paywallMap.putString("body", body.orEmpty())
38
31
 
39
32
  val marketingContentMap = Arguments.createMap()
40
33
  marketingContentMap.putString("title", title.orEmpty())
@@ -49,37 +42,55 @@ fun NamiPaywall.toNamiPaywallDict(): WritableMap {
49
42
 
50
43
  Log.i(LOG_TAG, "extraData items are $extraDataMap")
51
44
  paywallMap.putString("id", id)
52
- paywallMap.putString("background_image_url_phone", backgroundImageUrlPhone.orEmpty())
53
- paywallMap.putString("background_image_url_tablet", backgroundImageUrlTablet.orEmpty())
54
- paywallMap.putString("privacy_policy", privacyPolicy.orEmpty())
45
+ paywallMap.putMap("backgrounds", Arguments.createMap().apply {
46
+ putString("phone", backgroundImageUrlPhone.orEmpty())
47
+ putString("tablet", backgroundImageUrlTablet.orEmpty())
48
+ })
55
49
  paywallMap.putString("purchase_terms", purchaseTerms.orEmpty())
56
- paywallMap.putString("tos_link", tosLink.orEmpty())
57
50
  paywallMap.putString("name", name.orEmpty())
58
- paywallMap.putString("cta_type", type)
51
+ paywallMap.putString("paywall_type", type)
52
+ paywallMap.putMap("locale_config", localeConfig.toDict())
53
+ paywallMap.putMap("legal_citations", legalCitations?.toDict())
54
+ paywallMap.putMap("display_options", displayOptions.toDict())
59
55
  paywallMap.putString("developer_paywall_id", developerPaywallId.orEmpty())
60
-
61
- val allowClosing = allowClosing
62
- paywallMap.putBoolean("allow_closing", allowClosing)
63
-
64
- val restoreControl = restoreControl
65
- paywallMap.putBoolean("restore_control", restoreControl)
66
-
67
- val signInControl = signInControl
68
- paywallMap.putBoolean("sign_in_control", signInControl)
69
-
70
- val formattedSkusArray: WritableArray = Arguments.createArray()
71
- for (formattedSku in formattedSkus) {
72
- formattedSkusArray.pushMap(formattedSku.toFormattedSkuDict())
73
- }
74
- paywallMap.putArray("formatted_skus", formattedSkusArray)
75
-
76
56
  styleData?.let {
77
57
  paywallMap.putMap("styleData", it.toPaywallStylingDict())
78
58
  }
59
+ return paywallMap
60
+ }
61
+
62
+ private fun NamiLocaleConfig.toDict(): WritableMap {
63
+ return Arguments.createMap().apply {
64
+ putString("close_button_text", closeButtonText)
65
+ putString("sign_in_button_text", signInButtonText)
66
+ putString("restore_purchase_button_text", restorePurchaseButtonText)
67
+ putString("purchase_button_hint_text_to_speech", purchaseButtonHintTextToSpeech)
68
+ putString("purchase_terms_prefix_hint_text_to_speech", purchaseTermsPrefixHintTextToSpeech)
69
+ }
70
+ }
79
71
 
80
- paywallMap.putBoolean("use_bottom_overlay", useBottomOverlay)
72
+ private fun PaywallDisplayOptions.toDict(): WritableMap {
73
+ return Arguments.createMap().apply {
74
+ putBoolean("allow_closing", allowClosing)
75
+ putBoolean("restore_control", restoreControl)
76
+ putBoolean("sign_in_control", signInControl)
77
+ putString("scrollable_region_size", scrollableRegionSize)
78
+ putBoolean("show_nami_purchase_success_message", shouldShowNamiPurchaseSuccessMessage)
79
+ putBoolean("skus_in_scrollable_region", showSkusInScrollableRegion)
80
+ putBoolean("use_bottom_overlay", useBottomOverlay)
81
+ }
82
+ }
81
83
 
82
- return paywallMap
84
+ private fun LegalCitations.toDict(): WritableMap {
85
+ return Arguments.createMap().apply {
86
+ putString("id", id)
87
+ putString("privacy_url", privacyUrl)
88
+ putString("privacy_text", privacyText)
89
+ putString("tos_url", tosUrl)
90
+ putString("tos_text", tosText)
91
+ putString("clickwrap_text", clickWrapText)
92
+ putString("language", language)
93
+ }
83
94
  }
84
95
 
85
96
  fun PaywallStyleData.toPaywallStylingDict(): WritableMap {
@@ -107,6 +118,9 @@ fun PaywallStyleData.toPaywallStylingDict(): WritableMap {
107
118
 
108
119
  styleMap.putString("skuButtonColor", skuButtonColor)
109
120
  styleMap.putString("skuButtonTextColor", skuButtonTextColor)
121
+ styleMap.putString("skuSubDisplayTextColor", skuSubDisplayTextColor)
122
+ styleMap.putString("skuSubDisplayTextShadowColor", skuSubDisplayTextShadowColor)
123
+ styleMap.putDouble("skuSubDisplayTextShadowRadius", skuSubDisplayTextShadowRadius.toDouble())
110
124
 
111
125
  styleMap.putString("featuredSkusButtonColor", featuredSkuButtonColor)
112
126
  styleMap.putString("featuredSkusButtonTextColor", featuredSkuButtonTextColor)
@@ -196,6 +210,7 @@ fun NamiSKU.toSkuDict(): WritableMap {
196
210
  productDict.putString("localizedDescription", skuDetails.description)
197
211
  productDict.putString("localizedPrice", skuDetails.price)
198
212
  productDict.putString("localizedMultipliedPrice", skuDetails.price)
213
+ productDict.putBoolean("featured", featured)
199
214
  productDict.putString("displayText", displayText)
200
215
  productDict.putString("displaySubText", displaySubText)
201
216
  productDict.putString("price", skuDetails.getFormattedPrice().toString())
@@ -219,6 +234,9 @@ fun NamiSKU.toSkuDict(): WritableMap {
219
234
  SubscriptionPeriod.ANNUAL -> {
220
235
  "year"
221
236
  }
237
+ SubscriptionPeriod.FOUR_WEEKS -> {
238
+ "four_weeks"
239
+ }
222
240
  else -> {
223
241
  null
224
242
  }
@@ -267,6 +285,26 @@ fun NamiPurchase.toPurchaseDict(): WritableMap {
267
285
  return purchaseMap
268
286
  }
269
287
 
288
+ fun CustomerJourneyState?.toDict(): WritableMap {
289
+ val formerSubscriber = this?.formerSubscriber ?: false
290
+ val inGracePeriod = this?.inGracePeriod ?: false
291
+ val inTrialPeriod = this?.inTrialPeriod ?: false
292
+ val inIntroOfferPeriod = this?.inIntroOfferPeriod ?: false
293
+ val inPause = this?.inPause ?: false
294
+ val inAccountHold = this?.inAccountHold ?: false
295
+ val isCancelled = this?.isCancelled ?: false
296
+
297
+ return WritableNativeMap().apply {
298
+ putBoolean("formerSubscriber", formerSubscriber)
299
+ putBoolean("inGracePeriod", inGracePeriod)
300
+ putBoolean("inTrialPeriod", inTrialPeriod)
301
+ putBoolean("inIntroOfferPeriod", inIntroOfferPeriod)
302
+ putBoolean("inPause", inPause)
303
+ putBoolean("inAccountHold", inAccountHold)
304
+ putBoolean("isCancelled", isCancelled)
305
+ }
306
+ }
307
+
270
308
  fun NamiEntitlement.toEntitlementDict(): WritableMap? {
271
309
  val resultMap: WritableMap = WritableNativeMap()
272
310
  resultMap.putString("referenceID", referenceId)
@@ -321,4 +359,3 @@ fun Date.toJavascriptDate(): String {
321
359
  }
322
360
  return df.format(this)
323
361
  }
324
-
@@ -0,0 +1,45 @@
1
+ import os
2
+ import json
3
+ import sys
4
+ import re
5
+ import subprocess
6
+
7
+ # Regex to validate version numbers
8
+ PROD_VERSION_RE = re.compile(r"^\d+\.\d+\.\d+$")
9
+ PRERELEASE_VERSION_RE = re.compile(r"^\d+\.\d+\.\d+-(alpha|beta|rc)\.\d{2}$")
10
+
11
+ early_access = str(os.getenv("EARLY_ACCESS"))
12
+
13
+ # get the version out of source of truth
14
+ with open("package.json", "r") as f:
15
+ package = json.load(f)
16
+ nami_sdk_version = package["version"]
17
+
18
+ # Get git version
19
+ git_long_hash = (
20
+ subprocess.check_output(["git", "log", "-1", "--format=%H"]).decode("utf-8").strip()
21
+ )
22
+
23
+ # Check what kind of release this is and guard against non-conforming version numbers
24
+ if PROD_VERSION_RE.match(nami_sdk_version):
25
+ if early_access == "true":
26
+ print(f"Early access value ('{early_access}') is not compatible with production version format '{nami_sdk_version}'")
27
+ sys.exit(1)
28
+ type_mods = ""
29
+ elif PRERELEASE_VERSION_RE.match(nami_sdk_version):
30
+ if early_access == "false":
31
+ print(f"Early access value ('{early_access}') is not compatible with early access version format '{nami_sdk_version}'")
32
+ sys.exit(1)
33
+ type_mods = "--prerelease"
34
+ else:
35
+ print(f"SDK version '{nami_sdk_version}' does not conform to version spec")
36
+ sys.exit(1)
37
+
38
+ # generate a shell command to create a release later
39
+ with open("gh-release-command.sh", "w") as f:
40
+ f.write(
41
+ f"gh release create --generate-notes --title v{nami_sdk_version} {type_mods} --target {git_long_hash} v{nami_sdk_version}"
42
+ )
43
+
44
+ # report our status
45
+ print(f"Identified Version: {nami_sdk_version}")
package/ios/Nami.m CHANGED
@@ -21,7 +21,9 @@
21
21
  @implementation NamiBridge (RCTExternModule)
22
22
 
23
23
  RCT_EXPORT_METHOD(configure: (NSDictionary *)configDict) {
24
-
24
+ if ([configDict count] == 0 || [configDict[@"logLevel"] isEqual: @"DEBUG"] ) {
25
+ NSLog(@"Configure dictionary is %@", configDict);
26
+ }
25
27
  NSString *appID = configDict[@"appPlatformID-apple"];
26
28
 
27
29
  if ([appID length] > 0 ) {
@@ -39,6 +41,17 @@ RCT_EXPORT_METHOD(configure: (NSDictionary *)configDict) {
39
41
  config.logLevel = NamiLogLevelDebug;
40
42
  }
41
43
 
44
+ NSString *languageString = configDict[@"namiLanguageCode"];
45
+ if ([logLevelString length] > 0) {
46
+ NSLog(@"Nami language code from config dictionary is %@", languageString);
47
+ if ([[NamiLanguageCodes allAvailiableNamiLanguageCodes]
48
+ containsObject:[languageString lowercaseString]] ) {
49
+ config.namiLanguageCode = languageString;
50
+ } else {
51
+ NSLog(@"Warning: Nami language code from config dictionary %@ not found in list of available Nami Language Codes:\n%@", languageString, [NamiLanguageCodes allAvailiableNamiLanguageCodes]);
52
+ }
53
+ }
54
+
42
55
  NSObject *bypassString = configDict[@"bypassStore"];
43
56
  if ( bypassString != NULL )
44
57
  {
@@ -70,7 +83,7 @@ RCT_EXPORT_METHOD(configure: (NSDictionary *)configDict) {
70
83
  }
71
84
 
72
85
  // Start commands with header iformation for Nami to let them know this is a React client.
73
- NSMutableArray *namiCommandStrings = [NSMutableArray arrayWithArray:@[@"extendedClientInfo:react-native:0.3.0"]];
86
+ NSMutableArray *namiCommandStrings = [NSMutableArray arrayWithArray:@[@"extendedClientInfo:react-native:2.0.2"]];
74
87
 
75
88
  // Add additional namiCommands app may have sent in.
76
89
  NSObject *appCommandStrings = configDict[@"namiCommands"];
@@ -25,6 +25,8 @@
25
25
 
26
26
  + (NSArray *)stripPresentationPositionFromOrderedMetadataForPaywallMetaDict: (NSDictionary *)paywallMeta;
27
27
 
28
+ + (NSDictionary<NSString *,NSString *> *) customerJourneyStateDict;
29
+
28
30
  + (NSString *)hexStringForColor:(UIColor *)color;
29
31
 
30
32
  @end
@@ -205,6 +205,30 @@
205
205
  return [NSISO8601DateFormatter stringFromDate:purchaseTimestamp timeZone:UTC formatOptions:options];
206
206
  }
207
207
 
208
+
209
+ + (NSDictionary<NSString *,NSString *> *) customerJourneyStateDict {
210
+ CustomerJourneyState *journeyState = [NamiCustomerManager currentCustomerJourneyState];
211
+
212
+ BOOL formerSubscriber = [journeyState formerSubscriber];
213
+ BOOL inGracePeriod = [journeyState inGracePeriod];
214
+ BOOL inTrialPeriod = [journeyState inTrialPeriod];
215
+ BOOL inIntroOfferPeriod = [journeyState inIntroOfferPeriod];
216
+
217
+ BOOL isCancelled = [journeyState isCancelled];
218
+ BOOL inPause = [journeyState inPause];
219
+ BOOL inAccountHold = [journeyState inAccountHold];
220
+
221
+ NSDictionary *journeyDict = @{@"formerSubscriber":@(formerSubscriber),
222
+ @"inGracePeriod":@(inGracePeriod),
223
+ @"inTrialPeriod":@(inTrialPeriod),
224
+ @"inIntroOfferPeriod":@(inIntroOfferPeriod),
225
+ @"isCancelled":@(isCancelled),
226
+ @"inPause":@(inPause),
227
+ @"inAccountHold":@(inAccountHold)
228
+ };
229
+ return journeyDict;
230
+ }
231
+
208
232
  + (NSDictionary<NSString *,NSString *> *) paywallStylingToPaywallStylingDict:(PaywallStyleData *)styling {
209
233
  NSMutableDictionary<NSString *,id> *stylingDict = [NSMutableDictionary new];
210
234
  if (styling != nil) {
@@ -22,18 +22,7 @@
22
22
 
23
23
  RCT_EXPORT_METHOD(currentCustomerJourneyState:(RCTResponseSenderBlock)completion)
24
24
  {
25
- CustomerJourneyState *journeyState = [NamiCustomerManager currentCustomerJourneyState];
26
-
27
- BOOL formerSubscriber = [journeyState formerSubscriber];
28
- BOOL inGracePeriod = [journeyState inGracePeriod];
29
- BOOL inTrialPeriod = [journeyState inTrialPeriod];
30
- BOOL inIntroOfferPeriod = [journeyState inIntroOfferPeriod];
31
-
32
- NSDictionary *journeyDict = @{@"formerSubscriber":@(formerSubscriber),
33
- @"inGracePeriod":@(inGracePeriod),
34
- @"inTrialPeriod":@(inTrialPeriod),
35
- @"inIntroOfferPeriod":@(inIntroOfferPeriod)
36
- };
25
+ NSDictionary *journeyDict = [NamiBridgeUtil customerJourneyStateDict];
37
26
 
38
27
  completion(@[journeyDict]);
39
28
  }
package/ios/NamiEmitter.m CHANGED
@@ -54,6 +54,14 @@ static NamiEmitter *namiEmitter;
54
54
  [NamiPaywallManager registerBlockingPaywallClosedHandler:^{
55
55
  [self sendBlockingPaywallClosed];
56
56
  }];
57
+
58
+ [NamiPurchaseManager registerRestorePurchasesHandlerWithRestorePurchasesStateHandler:^(enum NamiRestorePurchasesState state, NSArray<NamiPurchase *> * _Nonnull newPurchases, NSArray<NamiPurchase *> * _Nonnull oldPurchases, NSError * _Nullable error) {
59
+ [self sendRestorePurchasesStateChanged:state newPurchases:newPurchases oldPurchases:oldPurchases error:error];
60
+ }];
61
+
62
+ [NamiCustomerManager registerJourneyStateChangedHandler:^(CustomerJourneyState * _Nonnull journeyState) {
63
+ [self sendEventCustomerJourneyStateChanged:journeyState];
64
+ }];
57
65
 
58
66
  }
59
67
  namiEmitter = self;
@@ -89,7 +97,7 @@ static NamiEmitter *namiEmitter;
89
97
  }
90
98
 
91
99
  - (NSArray<NSString *> *)supportedEvents {
92
- return @[@"PurchasesChanged", @"SignInActivate", @"AppPaywallActivate", @"EntitlementsChanged", @"BlockingPaywallClosed", @"PreparePaywallFinished" ];
100
+ return @[@"PurchasesChanged", @"SignInActivate", @"AppPaywallActivate", @"EntitlementsChanged", @"BlockingPaywallClosed", @"PreparePaywallFinished", @"RestorePurchasesStateChanged", @"CustomerJourneyStateChanged" ];
93
101
  }
94
102
 
95
103
  - (NSDictionary<NSString *, NSObject *> *)constantsToExport {
@@ -186,6 +194,13 @@ bool hasNamiEmitterListeners;
186
194
  }
187
195
  }
188
196
 
197
+ - (void)sendEventCustomerJourneyStateChanged:(CustomerJourneyState *)journeyState {
198
+ if (hasNamiEmitterListeners) {
199
+ NSDictionary *sendDict = [NamiBridgeUtil customerJourneyStateDict];
200
+ [self sendEventWithName:@"CustomerJourneyStateChanged" body:sendDict];
201
+ }
202
+ }
203
+
189
204
  - (void)sendEventPurchaseMadeWithPurchases:(NSArray<NamiPurchase *>*)purchases withState:(NamiPurchaseState)purchaseState error:(NSError *)error {
190
205
  if (hasNamiEmitterListeners) {
191
206
 
@@ -259,12 +274,73 @@ bool hasNamiEmitterListeners;
259
274
  [paywallMeta removeObjectForKey:@"title"];
260
275
  [paywallMeta removeObjectForKey:@"style"];
261
276
 
262
- [self sendEventWithName:@"AppPaywallActivate" body:@{ @"skus": skuDicts,
277
+ [self sendEventWithName:@"AppPaywallActivate" body:@{ @"namiSkus": skuDicts,
263
278
  @"developerPaywallID": developerPaywallID,
264
279
  @"paywallMetadata": paywallMeta }];
265
280
  }
266
281
  }
267
282
 
283
+ - (NSDictionary *)buildRestorePurchasesStateChangedDict: (enum NamiRestorePurchasesState) state
284
+ newPurchases: (NSArray<NamiPurchase *> * _Nonnull) newPurchases
285
+ oldPurchases: (NSArray<NamiPurchase *> * _Nonnull) oldPurchases
286
+ error: (NSError * _Nullable) error {
287
+ NSString *errorDesc = [error localizedDescription];
288
+ NSDictionary *initialDict;
289
+ if ([errorDesc length] > 0) {
290
+ initialDict = @{@"state": [NSNumber numberWithBool:state], @"stateDesc": [self restorePurchaseStateDescriptionFromCode:state], @"error": [error localizedDescription]};
291
+ } else {
292
+ initialDict = @{@"state": [NSNumber numberWithBool:state], @"stateDesc": [self restorePurchaseStateDescriptionFromCode:state]};
293
+ }
294
+
295
+ NSMutableDictionary *retDict = [NSMutableDictionary dictionary];
296
+ [retDict addEntriesFromDictionary:initialDict];
297
+
298
+ NSMutableArray *newPurchaseDicts = [NSMutableArray array];
299
+ for ( NamiPurchase *purchaseRecord in newPurchases ) {
300
+ if ( purchaseRecord.skuID == nil ) {
301
+ }
302
+ NSDictionary *purchaseDict = [NamiBridgeUtil purchaseToPurchaseDict:purchaseRecord];
303
+ [newPurchaseDicts addObject:purchaseDict];
304
+ }
305
+
306
+ NSMutableArray *oldPurchaseDicts = [NSMutableArray array];
307
+ for ( NamiPurchase *purchaseRecord in oldPurchases ) {
308
+ if ( purchaseRecord.skuID == nil ) {
309
+ }
310
+ NSDictionary *purchaseDict = [NamiBridgeUtil purchaseToPurchaseDict:purchaseRecord];
311
+ [oldPurchaseDicts addObject:purchaseDict];
312
+ }
313
+
314
+ retDict[@"newPurchases"] = newPurchaseDicts;
315
+ retDict[@"oldPurchases"] = oldPurchaseDicts;
316
+
317
+ NSLog(@"NamiBridge: Info: RestorePurchases state change: %@", retDict);
318
+
319
+ return retDict;
320
+ }
321
+
322
+ - (void)sendRestorePurchasesStateChanged: (enum NamiRestorePurchasesState) state
323
+ newPurchases: (NSArray<NamiPurchase *> * _Nonnull) newPurchases
324
+ oldPurchases: (NSArray<NamiPurchase *> * _Nonnull) oldPurchases
325
+ error: (NSError * _Nullable) error {
326
+ NSDictionary * retDict = [self buildRestorePurchasesStateChangedDict:state newPurchases:newPurchases oldPurchases:oldPurchases error:error];
327
+ [self sendEventWithName:@"RestorePurchasesStateChanged" body:retDict];
328
+ }
329
+
330
+ - (NSString *) restorePurchaseStateDescriptionFromCode:(NamiRestorePurchasesState)stateCode {
331
+ switch (stateCode) {
332
+ case NamiRestorePurchasesStateStarted:
333
+ return @"started";
334
+ break;
335
+ case NamiRestorePurchasesStateFinished:
336
+ return @"finished";
337
+ break;
338
+ case NamiRestorePurchasesStateError:
339
+ return @"error";
340
+ break;
341
+ }
342
+ }
343
+
268
344
  - (void) sendBlockingPaywallClosed {
269
345
  // Let system know a blocking paywall has been closed, in case they want to react specifically.
270
346
  if (hasNamiEmitterListeners) {
@@ -95,7 +95,7 @@ RCT_EXPORT_METHOD(fetchCustomPaywallMetaForDeveloperID:(NSString *)developerPayw
95
95
  paywallMeta[@"styleData"] = paywallStylingDict;
96
96
 
97
97
 
98
- NSArray *wrapperArray = @[@{ @"products": productDicts,
98
+ NSArray *wrapperArray = @[@{ @"namiSkus": productDicts,
99
99
  @"developerPaywallID": developerPaywallID,
100
100
  @"paywallMetadata": paywallMeta }];
101
101
  completion(wrapperArray);
@@ -15,6 +15,17 @@
15
15
 
16
16
  #import "React/RCTViewManager.h"
17
17
 
18
+ @interface NamiEmitter : RCTEventEmitter
19
+ - (void)sendRestorePurchasesStateChanged: (enum NamiRestorePurchasesState) state
20
+ newPurchases: (NSArray<NamiPurchase *> * _Nonnull) newPurchases
21
+ oldPurchases: (NSArray<NamiPurchase *> * _Nonnull) oldPurchases
22
+ error: (NSError * _Nullable) error;
23
+ - (NSDictionary *)buildRestorePurchasesStateChangedDict: (enum NamiRestorePurchasesState) state
24
+ newPurchases: (NSArray<NamiPurchase *> * _Nonnull) newPurchases
25
+ oldPurchases: (NSArray<NamiPurchase *> * _Nonnull) oldPurchases
26
+ error: (NSError * _Nullable) error;
27
+ + (NamiEmitter *) reactInstance;
28
+ @end
18
29
 
19
30
  @interface NamiPurchaseManagerBridge : NSObject <RCTBridgeModule>
20
31
  @end
@@ -48,23 +59,26 @@ RCT_EXPORT_METHOD(isSKUIDPurchased:(nonnull NSString*)skuID completion:(RCTRespo
48
59
  completion(@[[NSNumber numberWithBool:active]]);
49
60
  }
50
61
 
51
- RCT_EXPORT_METHOD(restorePurchases:(RCTResponseSenderBlock)completion)
62
+ RCT_EXPORT_METHOD(restorePurchasesWithCompletionHandler:(RCTResponseSenderBlock)completion)
52
63
  {
53
- NSLog(@"NamiBridge: Info: Calling RestorePurchases");
54
- [NamiPurchaseManager restorePurchasesWithHandler:^(BOOL success, NSError * _Nullable error) {
55
- NSString *errorDesc = [error localizedDescription];
56
- NSDictionary *retDict;
57
- if ([errorDesc length] > 0) {
58
- retDict = @{@"success": [NSNumber numberWithBool:success], @"error": [error localizedDescription]};
59
- } else {
60
- retDict = @{@"success": [NSNumber numberWithBool:success]};
61
- }
62
-
63
- NSLog(@"NamiBridge: Info: RestorePurchases Returned %@", retDict);
64
+ NSLog(@"NamiBridge: Info: Calling RestorePurchasesWithCompletionHandler");
65
+
66
+ [NamiPurchaseManager restorePurchasesWithStatehandler:^(enum NamiRestorePurchasesState state, NSArray<NamiPurchase *> * _Nonnull newPurchases, NSArray<NamiPurchase *> * _Nonnull oldPurchases, NSError * _Nullable error) {
67
+ NSDictionary *retDict = [[NamiEmitter reactInstance] buildRestorePurchasesStateChangedDict:state newPurchases:newPurchases oldPurchases:oldPurchases error:error];
64
68
  completion(@[retDict]);
65
69
  }];
66
70
  }
67
71
 
72
+ RCT_EXPORT_METHOD(restorePurchases)
73
+ {
74
+ NSLog(@"NamiBridge: Info: Calling RestorePurchases");
75
+
76
+ [NamiPurchaseManager restorePurchasesWithStatehandler:^(enum NamiRestorePurchasesState state, NSArray<NamiPurchase *> * _Nonnull newPurchases, NSArray<NamiPurchase *> * _Nonnull oldPurchases, NSError * _Nullable error) {
77
+ [[NamiEmitter reactInstance] sendRestorePurchasesStateChanged:state newPurchases:newPurchases oldPurchases:oldPurchases error:error];
78
+ }];
79
+ }
80
+
81
+ /// Determines if any one of the passed in SKUID's have been purchased.
68
82
  RCT_EXPORT_METHOD(anySKUIDPurchased:(nonnull NSArray*)skuIDs completion:(RCTResponseSenderBlock)completion)
69
83
  {
70
84
  BOOL active = false;
@@ -78,6 +92,31 @@ RCT_EXPORT_METHOD(anySKUIDPurchased:(nonnull NSArray*)skuIDs completion:(RCTResp
78
92
  completion(@[[NSNumber numberWithBool:active]]);
79
93
  }
80
94
 
95
+ /// For consumable purchases, removes the SKU from Nami so a product may be purchased again.
96
+ RCT_EXPORT_METHOD(consumePurchasedSKU:(nonnull NSString*)skuID)
97
+ {
98
+ [NamiPurchaseManager consumePurchasedSKUWithSkuID:skuID];
99
+ }
100
+
101
+ /// For consumable purchases, removes the SKU from Nami so a product may be purchased again.
102
+ RCT_EXPORT_METHOD(presentCodeRedemptionSheet)
103
+ {
104
+ if (@available(iOS 14.0, *)) {
105
+ [NamiPurchaseManager presentCodeRedemptionSheet];
106
+ } else {
107
+ NSLog(@"NamiBridge: Warning: presentCodeRedemptionSheet only present in iOS14 and higher");
108
+ }
109
+ }
110
+
111
+ RCT_EXPORT_METHOD(canPresentCodeRedemptionSheet:(RCTResponseSenderBlock)completion)
112
+ {
113
+ if (@available(iOS 14.0, *)) {
114
+ completion(@[[NSNumber numberWithBool:true]]);
115
+ } else {
116
+ completion(@[[NSNumber numberWithBool:false]]);
117
+ }
118
+ }
119
+
81
120
  /// This method does the purchase work, and can optionally be fed a paywall metadata object to pass along to the purchase flow.
82
121
  - (void) doSKUPurchaseWithSKUID:(nonnull NSString*)skuID namiPaywall:(NamiPaywall * _Nullable)namiPaywall completion:(RCTResponseSenderBlock)completion {
83
122
  [NamiPurchaseManager skusForSKUIDsWithSkuIDs:@[skuID] productHandler:^(BOOL success, NSArray<NamiSKU *> * _Nullable products, NSArray<NSString *> * _Nullable invalidProducts, NSError * _Nullable error) {
package/ios/Podfile CHANGED
@@ -1,48 +1,32 @@
1
- platform :ios, '11.0'
1
+
2
+ require_relative '../node_modules/react-native/scripts/react_native_pods'
2
3
  require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
3
4
 
5
+ platform :ios, '11.2'
6
+
4
7
  source 'https://cdn.cocoapods.org/'
5
8
 
6
9
  target 'RNNami' do
7
- # Pods for RNNami
8
- pod 'Nami', '2.7.1'
9
- pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector"
10
- pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec"
11
- pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired"
12
- pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety"
13
- pod 'React', :path => '../node_modules/react-native/'
14
- pod 'React-Core', :path => '../node_modules/react-native/'
15
- pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules'
16
- pod 'React-Core/DevSupport', :path => '../node_modules/react-native/'
17
- pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
18
- pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
19
- pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
20
- pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
21
- pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
22
- pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
23
- pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
24
- pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
25
- pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
26
- pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/'
27
-
28
- pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
29
- pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
30
- pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
31
- pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
32
- pod 'ReactCommon/jscallinvoker', :path => "../node_modules/react-native/ReactCommon"
33
- pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon"
34
- pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
35
-
36
- pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
37
- pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
38
- pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
39
-
40
- use_native_modules!
10
+ config = use_native_modules!
11
+ pod 'Nami', '2.9.5'
41
12
 
42
- end
13
+ use_react_native!(
14
+ :path => config[:reactNativePath],
15
+ # to enable hermes on iOS, change `false` to `true` and then install pods
16
+ :hermes_enabled => false
17
+ )
18
+
19
+ # Enables Flipper.
20
+ #
21
+ # Note that if you have use_frameworks! enabled, Flipper will not work and
22
+ # you should disable the next line.
23
+ use_flipper!()
43
24
 
44
- post_install do |installer|
45
- puts("Attempting to add Nami.xcframework reference to react-native-nami-sdk project.")
25
+ post_install do |installer|
26
+ react_native_post_install(installer)
27
+ #__apply_Xcode_12_5_M1_post_install_workaround(installer)
28
+
29
+ puts("Attempting to add Nami.xcframework reference to react-native-nami-sdk project.")
46
30
  installer.pods_project.targets.each do |target|
47
31
  if target.name == "Pods-RNNami"
48
32
  puts("Found Pods-RNNami target.")
@@ -60,4 +44,28 @@ post_install do |installer|
60
44
  end
61
45
  end
62
46
  end
47
+ ## Fix for XCode 12+, hotpatch of react files should be a great idea
48
+ find_and_replace("../node_modules/react-native/React/CxxBridge/RCTCxxBridge.mm",
49
+ "_initializeModules:(NSArray<id<RCTBridgeModule>> *)modules", "_initializeModules:(NSArray<Class> *)modules")
50
+ find_and_replace("../node_modules/react-native/ReactCommon/turbomodule/core/platform/ios/RCTTurboModuleManager.mm",
51
+ "RCTBridgeModuleNameForClass(module))", "RCTBridgeModuleNameForClass(Class(module)))")
52
+
53
+
54
+ end
55
+ end
56
+
57
+
58
+
59
+
60
+ def find_and_replace(dir, findstr, replacestr)
61
+ Dir[dir].each do |name|
62
+ text = File.read(name)
63
+ replace = text.gsub(findstr,replacestr)
64
+ if text != replace
65
+ puts "Fix: " + name
66
+ File.open(name, "w") { |file| file.puts replace }
67
+ STDOUT.flush
68
+ end
69
+ end
70
+ Dir[dir + '*/'].each(&method(:find_and_replace))
63
71
  end
@@ -230,6 +230,7 @@
230
230
  COPY_PHASE_STRIP = NO;
231
231
  ENABLE_STRICT_OBJC_MSGSEND = YES;
232
232
  ENABLE_TESTABILITY = YES;
233
+ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
233
234
  GCC_C_LANGUAGE_STANDARD = gnu99;
234
235
  GCC_DYNAMIC_NO_PIC = NO;
235
236
  GCC_NO_COMMON_BLOCKS = YES;
@@ -245,7 +246,7 @@
245
246
  GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
246
247
  GCC_WARN_UNUSED_FUNCTION = YES;
247
248
  GCC_WARN_UNUSED_VARIABLE = YES;
248
- IPHONEOS_DEPLOYMENT_TARGET = 10.3;
249
+ IPHONEOS_DEPLOYMENT_TARGET = 11.2;
249
250
  MTL_ENABLE_DEBUG_INFO = YES;
250
251
  ONLY_ACTIVE_ARCH = YES;
251
252
  SDKROOT = iphoneos;
@@ -274,6 +275,7 @@
274
275
  COPY_PHASE_STRIP = YES;
275
276
  ENABLE_NS_ASSERTIONS = NO;
276
277
  ENABLE_STRICT_OBJC_MSGSEND = YES;
278
+ "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = " ";
277
279
  GCC_C_LANGUAGE_STANDARD = gnu99;
278
280
  GCC_NO_COMMON_BLOCKS = YES;
279
281
  GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
@@ -282,7 +284,7 @@
282
284
  GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
283
285
  GCC_WARN_UNUSED_FUNCTION = YES;
284
286
  GCC_WARN_UNUSED_VARIABLE = YES;
285
- IPHONEOS_DEPLOYMENT_TARGET = 10.3;
287
+ IPHONEOS_DEPLOYMENT_TARGET = 11.2;
286
288
  MTL_ENABLE_DEBUG_INFO = NO;
287
289
  SDKROOT = iphoneos;
288
290
  VALIDATE_PRODUCT = YES;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-native-nami-sdk",
3
- "version": "1.2.1",
4
- "description": "React Native Module for Nami - The Smartest Way to Sell Subscriptions.",
3
+ "version": "2.0.2",
4
+ "description": "React Native Module for Nami - Easy subscriptions & in-app purchases, with powerful built-in paywalls and A/B testing.",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
7
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -20,12 +20,15 @@
20
20
  "paywall",
21
21
  "react-native",
22
22
  "storekit",
23
- "subscriptions"
23
+ "subscriptions",
24
+ "iap",
25
+ "play-billing",
26
+ "payments"
24
27
  ],
25
28
  "author": {
26
- "username": "namiml",
27
- "name": "Nami ML, Inc.",
28
- "email": "francisco.pena@namiml.com"
29
+ "username": "hellonami",
30
+ "name": "Nami ML Inc.",
31
+ "email": "hello@namiml.com"
29
32
  },
30
33
  "contributors": [
31
34
  {
@@ -39,18 +42,19 @@
39
42
  ],
40
43
  "license": "SEE LICENSE FILE",
41
44
  "peerDependencies": {
42
- "react": "^16.8.1",
43
- "react-native": ">=0.60.0-rc.0 <1.0.x"
45
+ "react": "^17.0.2",
46
+ "react-native": "^0.65.2"
44
47
  },
45
48
  "devDependencies": {
46
- "react": "^16.9.0",
47
- "react-native": "^0.61.5"
49
+ "react": "^17.0.2",
50
+ "react-native": "^0.65.2",
51
+ "react-native-codegen": "^0.0.12"
48
52
  },
49
53
  "repository": {
50
54
  "type": "git",
51
55
  "url": "git+https://github.com/namiml/react-native-nami-sdk.git"
52
56
  },
53
- "homepage": "https://www.nami.ml",
57
+ "homepage": "https://www.namiml.com",
54
58
  "bugs": {
55
59
  "url": "https://github.com/namiml/react-native-nami-sdk/issues"
56
60
  }
@@ -8,17 +8,17 @@ Pod::Spec.new do |s|
8
8
  s.version = package['version']
9
9
  s.summary = package['description']
10
10
 
11
- s.author = { "Nami ML, Inc." => "info@namiml.com" }
11
+ s.author = { "Nami ML Inc." => "info@namiml.com" }
12
12
 
13
13
  s.homepage = package['homepage']
14
14
  s.license = package['license']
15
15
 
16
- s.platform = :ios, "11.0"
16
+ s.platform = :ios, "11.2"
17
17
  s.source = { :git => "https://github.com/namiml/react-native-nami-sdk.git", :tag => "#{s.version}" }
18
18
  s.source_files = "ios/**/*.{h,m}"
19
19
  s.requires_arc = true
20
20
 
21
- s.dependency 'Nami', '2.7.1'
21
+ s.dependency 'Nami', '2.9.5'
22
22
  s.dependency 'React'
23
23
 
24
24
  end