react-native-nami-sdk 1.0.1 → 2.0.0
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/README.md +1 -1
- package/android/build.gradle +18 -14
- package/android/gradle/wrapper/gradle-wrapper.properties +3 -3
- package/android/src/main/AndroidManifest.xml +1 -2
- package/android/src/main/java/com/nami/reactlibrary/NamiBridgeModule.kt +22 -7
- package/android/src/main/java/com/nami/reactlibrary/NamiCustomerManagerBridge.kt +21 -16
- package/android/src/main/java/com/nami/reactlibrary/NamiEmitter.kt +15 -33
- package/android/src/main/java/com/nami/reactlibrary/NamiPaywallManagerBridgeModule.kt +78 -4
- package/android/src/main/java/com/nami/reactlibrary/NamiPurchaseManagerBridge.kt +7 -0
- package/android/src/main/java/com/nami/reactlibrary/NamiUtil.kt +74 -38
- package/ios/Nami.m +15 -2
- package/ios/NamiBridgeUtil.h +2 -0
- package/ios/NamiBridgeUtil.m +28 -0
- package/ios/NamiCustomerManager.m +1 -12
- package/ios/NamiEmitter.m +122 -2
- package/ios/NamiPaywallManagerBridge.m +38 -2
- package/ios/NamiPurchaseManagerBridge.m +51 -12
- package/ios/Podfile +46 -38
- package/ios/RNNami.xcodeproj/project.pbxproj +4 -2
- package/package.json +6 -5
- package/react-native-nami-sdk.podspec +2 -2
package/README.md
CHANGED
package/android/build.gradle
CHANGED
|
@@ -10,48 +10,52 @@ 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
|
|
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
|
}
|
|
20
17
|
apply plugin: 'com.android.library'
|
|
21
18
|
apply plugin: 'maven'
|
|
22
19
|
apply plugin: "kotlin-android"
|
|
23
|
-
apply plugin: "kotlin-android-extensions"
|
|
24
20
|
buildscript {
|
|
25
|
-
ext.kotlin_version = '1.4.
|
|
21
|
+
ext.kotlin_version = '1.4.31'
|
|
26
22
|
// The Android Gradle plugin is only required when opening the android folder stand-alone.
|
|
27
23
|
// This avoids unnecessary downloads and potential conflicts when the library is included as a
|
|
28
24
|
// module dependency in an application project.
|
|
29
25
|
// ref: https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies
|
|
30
26
|
if (project == rootProject) {
|
|
31
27
|
repositories {
|
|
28
|
+
mavenCentral()
|
|
32
29
|
google()
|
|
33
|
-
jcenter()
|
|
34
30
|
}
|
|
35
31
|
dependencies {
|
|
36
|
-
classpath 'com.android.tools.build:gradle:4.1
|
|
32
|
+
classpath 'com.android.tools.build:gradle:4.2.1'
|
|
37
33
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
38
34
|
}
|
|
39
35
|
}
|
|
40
36
|
}
|
|
41
37
|
android {
|
|
42
|
-
compileSdkVersion
|
|
38
|
+
compileSdkVersion 31
|
|
43
39
|
buildToolsVersion safeExtGet('buildToolsVersion', DEFAULT_BUILD_TOOLS_VERSION)
|
|
44
40
|
defaultConfig {
|
|
45
|
-
minSdkVersion
|
|
46
|
-
targetSdkVersion
|
|
41
|
+
minSdkVersion 26
|
|
42
|
+
targetSdkVersion 31
|
|
47
43
|
versionCode 1
|
|
48
44
|
versionName "1.0"
|
|
49
45
|
}
|
|
46
|
+
compileOptions {
|
|
47
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
48
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
49
|
+
}
|
|
50
50
|
lintOptions {
|
|
51
51
|
abortOnError false
|
|
52
52
|
}
|
|
53
|
+
kotlinOptions {
|
|
54
|
+
jvmTarget = "1.8"
|
|
55
|
+
}
|
|
53
56
|
}
|
|
54
57
|
repositories {
|
|
58
|
+
mavenCentral()
|
|
55
59
|
// ref: https://www.baeldung.com/maven-local-repository
|
|
56
60
|
maven { url("https://nami-android.s3.amazonaws.com/") }
|
|
57
61
|
maven {
|
|
@@ -63,14 +67,14 @@ repositories {
|
|
|
63
67
|
url("$rootDir/../node_modules/jsc-android/dist")
|
|
64
68
|
}
|
|
65
69
|
google()
|
|
66
|
-
jcenter()
|
|
67
70
|
}
|
|
71
|
+
|
|
68
72
|
dependencies {
|
|
69
73
|
//noinspection GradleDynamicVersion
|
|
70
74
|
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
71
|
-
implementation "org.jetbrains.kotlin:kotlin-stdlib-
|
|
75
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
|
72
76
|
|
|
73
|
-
implementation "com.namiml:sdk-android:
|
|
77
|
+
implementation "com.namiml:sdk-android:2.0.0"
|
|
74
78
|
|
|
75
79
|
implementation 'com.facebook.react:react-native:+' // From node_modules
|
|
76
80
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
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
|
-
|
|
6
|
+
zipStoreBase=GRADLE_USER_HOME
|
|
@@ -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:
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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 {
|
|
36
|
+
NamiPaywallManager.registerSignInListener { _, _, developerPaywallID ->
|
|
36
37
|
Log.i(LOG_TAG, "Sign in clicked with developerPaywallID $developerPaywallID")
|
|
37
38
|
|
|
38
|
-
emitSignInActivated(
|
|
39
|
+
emitSignInActivated(developerPaywallID)
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
Log.i(LOG_TAG, "In Emitter Initialize()")
|
|
42
43
|
|
|
43
|
-
NamiPaywallManager.registerPaywallRaiseListener {
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
resultArray.pushMap(entitlement.toEntitlementDict())
|
|
58
|
+
NamiCustomerManager.registerCustomerJourneyChangedListener {
|
|
59
|
+
emitCustomerJourneyChanged(it)
|
|
64
60
|
}
|
|
65
|
-
|
|
61
|
+
}
|
|
66
62
|
|
|
67
|
-
|
|
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("
|
|
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("
|
|
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(
|
|
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
|
}
|
|
@@ -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
|
}
|
|
@@ -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.
|
|
53
|
-
|
|
54
|
-
|
|
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("
|
|
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
|
+
}
|
|
79
61
|
|
|
80
|
-
|
|
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
|
+
}
|
|
81
71
|
|
|
82
|
-
|
|
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
|
+
}
|
|
83
|
+
|
|
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,9 @@ 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)
|
|
214
|
+
productDict.putString("displayText", displayText)
|
|
215
|
+
productDict.putString("displaySubText", displaySubText)
|
|
199
216
|
productDict.putString("price", skuDetails.getFormattedPrice().toString())
|
|
200
217
|
productDict.putString("priceLanguage", Locale.getDefault().language)
|
|
201
218
|
productDict.putString("priceCountry", Locale.getDefault().country)
|
|
@@ -208,9 +225,6 @@ fun NamiSKU.toSkuDict(): WritableMap {
|
|
|
208
225
|
SubscriptionPeriod.HALF_YEAR -> {
|
|
209
226
|
"half_year"
|
|
210
227
|
}
|
|
211
|
-
SubscriptionPeriod.DAY -> {
|
|
212
|
-
"day"
|
|
213
|
-
}
|
|
214
228
|
SubscriptionPeriod.WEEKLY -> {
|
|
215
229
|
"week"
|
|
216
230
|
}
|
|
@@ -220,6 +234,9 @@ fun NamiSKU.toSkuDict(): WritableMap {
|
|
|
220
234
|
SubscriptionPeriod.ANNUAL -> {
|
|
221
235
|
"year"
|
|
222
236
|
}
|
|
237
|
+
SubscriptionPeriod.FOUR_WEEKS -> {
|
|
238
|
+
"four_weeks"
|
|
239
|
+
}
|
|
223
240
|
else -> {
|
|
224
241
|
null
|
|
225
242
|
}
|
|
@@ -268,6 +285,26 @@ fun NamiPurchase.toPurchaseDict(): WritableMap {
|
|
|
268
285
|
return purchaseMap
|
|
269
286
|
}
|
|
270
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
|
+
|
|
271
308
|
fun NamiEntitlement.toEntitlementDict(): WritableMap? {
|
|
272
309
|
val resultMap: WritableMap = WritableNativeMap()
|
|
273
310
|
resultMap.putString("referenceID", referenceId)
|
|
@@ -322,4 +359,3 @@ fun Date.toJavascriptDate(): String {
|
|
|
322
359
|
}
|
|
323
360
|
return df.format(this)
|
|
324
361
|
}
|
|
325
|
-
|
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.
|
|
86
|
+
NSMutableArray *namiCommandStrings = [NSMutableArray arrayWithArray:@[@"extendedClientInfo:react-native:2.0.0"]];
|
|
74
87
|
|
|
75
88
|
// Add additional namiCommands app may have sent in.
|
|
76
89
|
NSObject *appCommandStrings = configDict[@"namiCommands"];
|
package/ios/NamiBridgeUtil.h
CHANGED
package/ios/NamiBridgeUtil.m
CHANGED
|
@@ -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) {
|
|
@@ -201,6 +205,30 @@
|
|
|
201
205
|
return [NSISO8601DateFormatter stringFromDate:purchaseTimestamp timeZone:UTC formatOptions:options];
|
|
202
206
|
}
|
|
203
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
|
+
|
|
204
232
|
+ (NSDictionary<NSString *,NSString *> *) paywallStylingToPaywallStylingDict:(PaywallStyleData *)styling {
|
|
205
233
|
NSMutableDictionary<NSString *,id> *stylingDict = [NSMutableDictionary new];
|
|
206
234
|
if (styling != nil) {
|
|
@@ -22,18 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
RCT_EXPORT_METHOD(currentCustomerJourneyState:(RCTResponseSenderBlock)completion)
|
|
24
24
|
{
|
|
25
|
-
|
|
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
|
@@ -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
|
|
@@ -52,11 +54,29 @@ RCT_EXTERN_METHOD(getPurchasedProducts: (RCTResponseSenderBlock)callback)
|
|
|
52
54
|
[NamiPaywallManager registerBlockingPaywallClosedHandler:^{
|
|
53
55
|
[self sendBlockingPaywallClosed];
|
|
54
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
|
+
}];
|
|
55
65
|
|
|
56
66
|
}
|
|
67
|
+
namiEmitter = self;
|
|
57
68
|
return self;
|
|
58
69
|
}
|
|
59
70
|
|
|
71
|
+
- (void)dealloc {
|
|
72
|
+
namiEmitter = nil;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
+ (NamiEmitter *) reactInstance {
|
|
77
|
+
return namiEmitter;
|
|
78
|
+
}
|
|
79
|
+
|
|
60
80
|
- (void) getPurchasedProducts : (RCTResponseSenderBlock) callback {
|
|
61
81
|
NSArray *allProducts = [self allPurchasedProducts];
|
|
62
82
|
callback(allProducts);
|
|
@@ -77,7 +97,7 @@ RCT_EXTERN_METHOD(getPurchasedProducts: (RCTResponseSenderBlock)callback)
|
|
|
77
97
|
}
|
|
78
98
|
|
|
79
99
|
- (NSArray<NSString *> *)supportedEvents {
|
|
80
|
-
return @[@"PurchasesChanged", @"SignInActivate", @"AppPaywallActivate", @"EntitlementsChanged", @"BlockingPaywallClosed" ];
|
|
100
|
+
return @[@"PurchasesChanged", @"SignInActivate", @"AppPaywallActivate", @"EntitlementsChanged", @"BlockingPaywallClosed", @"PreparePaywallFinished", @"RestorePurchasesStateChanged", @"CustomerJourneyStateChanged" ];
|
|
81
101
|
}
|
|
82
102
|
|
|
83
103
|
- (NSDictionary<NSString *, NSObject *> *)constantsToExport {
|
|
@@ -150,6 +170,37 @@ bool hasNamiEmitterListeners;
|
|
|
150
170
|
}
|
|
151
171
|
}
|
|
152
172
|
|
|
173
|
+
- (void)sendEventPreparePaywallForDisplayFinishedWithResult:(BOOL)success developerPaywallID: (NSString * _Nullable) developerPaywallID error:(NSError * _Nullable) error {
|
|
174
|
+
if (hasNamiEmitterListeners) {
|
|
175
|
+
|
|
176
|
+
NSMutableDictionary *sendDict = [NSMutableDictionary dictionaryWithDictionary: @{ @"success": @(success) }];
|
|
177
|
+
|
|
178
|
+
if (developerPaywallID != nil) {
|
|
179
|
+
[sendDict addEntriesFromDictionary:@{
|
|
180
|
+
@"developerPaywallID": developerPaywallID
|
|
181
|
+
}];
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (error != nil) {
|
|
185
|
+
[sendDict addEntriesFromDictionary:@{
|
|
186
|
+
@"errorCode": @(error.code),
|
|
187
|
+
@"errorMessage": [error localizedDescription]
|
|
188
|
+
}
|
|
189
|
+
];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
NSLog(@"NamiBridge: Info: attempting to send result of preparePaywallForDisplay with result dictionary: %@", sendDict);
|
|
193
|
+
[self sendEventWithName:@"PreparePaywallFinished" body:sendDict];
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
- (void)sendEventCustomerJourneyStateChanged:(CustomerJourneyState *)journeyState {
|
|
198
|
+
if (hasNamiEmitterListeners) {
|
|
199
|
+
NSDictionary *sendDict = [NamiBridgeUtil customerJourneyStateDict];
|
|
200
|
+
[self sendEventWithName:@"CustomerJourneyStateChanged" body:sendDict];
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
153
204
|
- (void)sendEventPurchaseMadeWithPurchases:(NSArray<NamiPurchase *>*)purchases withState:(NamiPurchaseState)purchaseState error:(NSError *)error {
|
|
154
205
|
if (hasNamiEmitterListeners) {
|
|
155
206
|
|
|
@@ -200,6 +251,14 @@ bool hasNamiEmitterListeners;
|
|
|
200
251
|
NSMutableDictionary *paywallMeta = [NSMutableDictionary dictionaryWithDictionary:paywallMetadata.namiPaywallInfoDict];
|
|
201
252
|
// This part is really meant to be internally facing, scrub from dictionary
|
|
202
253
|
|
|
254
|
+
NSMutableDictionary *marketingContentDictionary = [NSMutableDictionary dictionaryWithDictionary:paywallMeta[@"marketing_content"]];
|
|
255
|
+
|
|
256
|
+
// Populated SmartText formatted values in dictioanry to send
|
|
257
|
+
marketingContentDictionary[@"body"] = [paywallMetadata body];
|
|
258
|
+
marketingContentDictionary[@"title"] = [paywallMetadata title];
|
|
259
|
+
paywallMeta[@"marketing_content"] = marketingContentDictionary;
|
|
260
|
+
paywallMeta[@"purchase_terms"] = [paywallMetadata purchaseTerms];
|
|
261
|
+
|
|
203
262
|
// Strip out presention_position from all listed sku items
|
|
204
263
|
NSArray *cleanedOrderdMetadata = [NamiBridgeUtil stripPresentationPositionFromOrderedMetadataForPaywallMetaDict:paywallMeta];
|
|
205
264
|
[paywallMeta setObject:cleanedOrderdMetadata forKey:@"formatted_skus"];
|
|
@@ -215,12 +274,73 @@ bool hasNamiEmitterListeners;
|
|
|
215
274
|
[paywallMeta removeObjectForKey:@"title"];
|
|
216
275
|
[paywallMeta removeObjectForKey:@"style"];
|
|
217
276
|
|
|
218
|
-
[self sendEventWithName:@"AppPaywallActivate" body:@{ @"
|
|
277
|
+
[self sendEventWithName:@"AppPaywallActivate" body:@{ @"namiSkus": skuDicts,
|
|
219
278
|
@"developerPaywallID": developerPaywallID,
|
|
220
279
|
@"paywallMetadata": paywallMeta }];
|
|
221
280
|
}
|
|
222
281
|
}
|
|
223
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
|
+
|
|
224
344
|
- (void) sendBlockingPaywallClosed {
|
|
225
345
|
// Let system know a blocking paywall has been closed, in case they want to react specifically.
|
|
226
346
|
if (hasNamiEmitterListeners) {
|
|
@@ -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"];
|
|
@@ -91,7 +95,7 @@ RCT_EXPORT_METHOD(fetchCustomPaywallMetaForDeveloperID:(NSString *)developerPayw
|
|
|
91
95
|
paywallMeta[@"styleData"] = paywallStylingDict;
|
|
92
96
|
|
|
93
97
|
|
|
94
|
-
NSArray *wrapperArray = @[@{ @"
|
|
98
|
+
NSArray *wrapperArray = @[@{ @"namiSkus": productDicts,
|
|
95
99
|
@"developerPaywallID": developerPaywallID,
|
|
96
100
|
@"paywallMetadata": paywallMeta }];
|
|
97
101
|
completion(wrapperArray);
|
|
@@ -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
|
|
|
@@ -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(
|
|
62
|
+
RCT_EXPORT_METHOD(restorePurchasesWithCompletionHandler:(RCTResponseSenderBlock)completion)
|
|
52
63
|
{
|
|
53
|
-
NSLog(@"NamiBridge: Info: Calling
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
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
|
-
|
|
8
|
-
pod 'Nami', '2.
|
|
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.3'
|
|
41
12
|
|
|
42
|
-
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-nami-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "React Native Module for Nami - The Smartest Way to Sell Subscriptions.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -39,12 +39,13 @@
|
|
|
39
39
|
],
|
|
40
40
|
"license": "SEE LICENSE FILE",
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"react": "^
|
|
43
|
-
"react-native": "
|
|
42
|
+
"react": "^17.0.2",
|
|
43
|
+
"react-native": "^0.65.2"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
-
"react": "^
|
|
47
|
-
"react-native": "^0.
|
|
46
|
+
"react": "^17.0.2",
|
|
47
|
+
"react-native": "^0.65.2",
|
|
48
|
+
"react-native-codegen": "^0.0.12"
|
|
48
49
|
},
|
|
49
50
|
"repository": {
|
|
50
51
|
"type": "git",
|
|
@@ -13,12 +13,12 @@ Pod::Spec.new do |s|
|
|
|
13
13
|
s.homepage = package['homepage']
|
|
14
14
|
s.license = package['license']
|
|
15
15
|
|
|
16
|
-
s.platform = :ios, "11.
|
|
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.
|
|
21
|
+
s.dependency 'Nami', '2.9.3'
|
|
22
22
|
s.dependency 'React'
|
|
23
23
|
|
|
24
24
|
end
|