react-native-nami-sdk 3.3.2 → 3.3.3-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +2 -2
- package/android/src/main/AndroidManifest.xml +14 -1
- package/android/src/main/java/com/namiml/reactnative/NamiBridgePackage.java +15 -0
- package/android/src/main/java/com/namiml/reactnative/NamiFlowManagerBridge.kt +22 -17
- package/android/src/main/java/com/namiml/reactnative/NamiOverlayControlBridge.kt +171 -0
- package/android/src/main/java/com/namiml/reactnative/ReactOverlayActivity.kt +29 -0
- package/android/src/main/res/values/styles.xml +10 -0
- package/dist/index.d.ts +1 -0
- package/dist/specs/NativeNamiFlowManager.d.ts +1 -0
- package/dist/specs/NativeNamiOverlayControl.d.ts +9 -0
- package/dist/src/NamiOverlayControl.d.ts +9 -0
- package/dist/src/NamiOverlayHost.d.ts +1 -0
- package/dist/src/overlay.d.ts +4 -0
- package/dist/src/registerOverlay.d.ts +1 -0
- package/dist/src/version.d.ts +1 -1
- package/index.ts +1 -0
- package/ios/Nami.swift +21 -8
- package/ios/NamiCampaignManagerBridge.m +3 -2
- package/ios/NamiCampaignManagerBridge.swift +16 -11
- package/ios/NamiCustomerManager.m +3 -2
- package/ios/NamiCustomerManager.swift +44 -21
- package/ios/NamiEntitlementManagerBridge.m +3 -2
- package/ios/NamiEntitlementManagerBridge.swift +14 -12
- package/ios/NamiFlowManagerBridge.m +1 -1
- package/ios/NamiFlowManagerBridge.swift +17 -22
- package/ios/NamiOverlayControlBridge.m +17 -0
- package/ios/NamiOverlayControlBridge.swift +132 -0
- package/ios/NamiPaywallManagerBridge.m +2 -2
- package/ios/NamiPaywallManagerBridge.swift +19 -20
- package/ios/NamiPurchaseManagerBridge.m +2 -2
- package/ios/NamiPurchaseManagerBridge.swift +17 -8
- package/package.json +10 -3
- package/react-native-nami-sdk.podspec +19 -9
- package/specs/NativeNamiFlowManager.ts +1 -0
- package/specs/NativeNamiOverlayControl.ts +9 -0
- package/src/NamiOverlayControl.tsx +48 -0
- package/src/version.ts +1 -1
|
@@ -9,17 +9,26 @@ import Foundation
|
|
|
9
9
|
import NamiApple
|
|
10
10
|
import React
|
|
11
11
|
|
|
12
|
-
// #if RCT_NEW_ARCH_ENABLED
|
|
13
|
-
// extension RNNamiCustomerManager: RCTTurboModule {}
|
|
14
|
-
// #endif
|
|
15
|
-
|
|
16
12
|
@objc(RNNamiCustomerManager)
|
|
17
13
|
class RNNamiCustomerManager: RCTEventEmitter {
|
|
18
14
|
public static var shared: RNNamiCustomerManager?
|
|
19
15
|
|
|
20
16
|
override init() {
|
|
21
17
|
super.init()
|
|
22
|
-
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override class func requiresMainQueueSetup() -> Bool { true }
|
|
21
|
+
|
|
22
|
+
private var hasListeners = false
|
|
23
|
+
override func startObserving() { hasListeners = true }
|
|
24
|
+
override func stopObserving() { hasListeners = false }
|
|
25
|
+
|
|
26
|
+
private func safeSend(withName name: String, body: Any?) {
|
|
27
|
+
guard hasListeners else {
|
|
28
|
+
print("[RNNamiCustomerManager] Warning: no listeners, so event not being sent to JS.")
|
|
29
|
+
return
|
|
30
|
+
} // optional but avoids warnings
|
|
31
|
+
sendEvent(withName: name, body: body)
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
override func supportedEvents() -> [String]! {
|
|
@@ -46,8 +55,10 @@ class RNNamiCustomerManager: RCTEventEmitter {
|
|
|
46
55
|
|
|
47
56
|
@objc(getCustomerAttribute:resolver:rejecter:)
|
|
48
57
|
func getCustomerAttribute(key: String, resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
|
|
49
|
-
|
|
50
|
-
|
|
58
|
+
DispatchQueue.main.async {
|
|
59
|
+
let customerAttribute = NamiCustomerManager.getCustomerAttribute(key: key)
|
|
60
|
+
resolve(customerAttribute)
|
|
61
|
+
}
|
|
51
62
|
}
|
|
52
63
|
|
|
53
64
|
@objc(clearCustomerAttribute:)
|
|
@@ -78,54 +89,68 @@ class RNNamiCustomerManager: RCTEventEmitter {
|
|
|
78
89
|
@objc(inAnonymousMode:rejecter:)
|
|
79
90
|
func inAnonymousMode(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
|
|
80
91
|
let inAnonymousMode: Bool = NamiCustomerManager.inAnonymousMode()
|
|
81
|
-
|
|
92
|
+
DispatchQueue.main.async {
|
|
93
|
+
resolve(inAnonymousMode)
|
|
94
|
+
}
|
|
82
95
|
}
|
|
83
96
|
|
|
84
97
|
@objc(journeyState:rejecter:)
|
|
85
98
|
func journeyState(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
|
|
86
99
|
if let journeyState = NamiCustomerManager.journeyState() {
|
|
87
100
|
let dictionary = journeyStateToDictionary(journeyState)
|
|
88
|
-
|
|
101
|
+
DispatchQueue.main.async {
|
|
102
|
+
resolve(dictionary)
|
|
103
|
+
}
|
|
89
104
|
} else {
|
|
90
|
-
|
|
105
|
+
DispatchQueue.main.async {
|
|
106
|
+
resolve(nil)
|
|
107
|
+
}
|
|
91
108
|
}
|
|
92
109
|
}
|
|
93
110
|
|
|
94
111
|
@objc(isLoggedIn:rejecter:)
|
|
95
112
|
func isLoggedIn(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
|
|
96
113
|
let isLoggedIn = NamiCustomerManager.isLoggedIn()
|
|
97
|
-
|
|
114
|
+
DispatchQueue.main.async {
|
|
115
|
+
resolve(isLoggedIn)
|
|
116
|
+
}
|
|
98
117
|
}
|
|
99
118
|
|
|
100
119
|
@objc(loggedInId:rejecter:)
|
|
101
120
|
func loggedInId(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
|
|
102
121
|
let id = NamiCustomerManager.loggedInId()
|
|
103
|
-
|
|
122
|
+
DispatchQueue.main.async {
|
|
123
|
+
resolve(id)
|
|
124
|
+
}
|
|
104
125
|
}
|
|
105
126
|
|
|
106
127
|
@objc(deviceId:rejecter:)
|
|
107
128
|
func deviceId(resolve: @escaping RCTPromiseResolveBlock, reject _: @escaping RCTPromiseRejectBlock) {
|
|
108
129
|
let id = NamiCustomerManager.deviceId()
|
|
109
|
-
|
|
130
|
+
DispatchQueue.main.async {
|
|
131
|
+
resolve(id)
|
|
132
|
+
}
|
|
110
133
|
}
|
|
111
134
|
|
|
112
135
|
@objc(login:)
|
|
113
136
|
func login(customerId: String) {
|
|
114
|
-
|
|
137
|
+
DispatchQueue.main.async {
|
|
138
|
+
NamiCustomerManager.login(withId: customerId)
|
|
139
|
+
}
|
|
115
140
|
}
|
|
116
141
|
|
|
117
142
|
@objc(logout)
|
|
118
143
|
func logout() {
|
|
119
|
-
|
|
144
|
+
DispatchQueue.main.async {
|
|
145
|
+
NamiCustomerManager.logout()
|
|
146
|
+
}
|
|
120
147
|
}
|
|
121
148
|
|
|
122
149
|
@objc(registerJourneyStateHandler)
|
|
123
150
|
func registerJourneyStateHandler() {
|
|
124
151
|
NamiCustomerManager.registerJourneyStateHandler { journeyState in
|
|
125
152
|
let dictionary = self.journeyStateToDictionary(journeyState)
|
|
126
|
-
|
|
127
|
-
RNNamiCustomerManager.shared?.sendEvent(withName: "JourneyStateChanged", body: dictionary)
|
|
128
|
-
}
|
|
153
|
+
self.safeSend(withName: "JourneyStateChanged", body: dictionary)
|
|
129
154
|
}
|
|
130
155
|
}
|
|
131
156
|
|
|
@@ -166,9 +191,7 @@ class RNNamiCustomerManager: RCTEventEmitter {
|
|
|
166
191
|
"success": success,
|
|
167
192
|
"error": error?._code as Any,
|
|
168
193
|
]
|
|
169
|
-
|
|
170
|
-
RNNamiCustomerManager.shared?.sendEvent(withName: "AccountStateChanged", body: payload)
|
|
171
|
-
}
|
|
194
|
+
self.safeSend(withName: "AccountStateChanged", body: payload)
|
|
172
195
|
}
|
|
173
196
|
}
|
|
174
197
|
}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
//
|
|
7
7
|
|
|
8
8
|
#import <React/RCTBridgeModule.h>
|
|
9
|
+
#import <React/RCTEventEmitter.h>
|
|
9
10
|
|
|
10
|
-
@interface RCT_EXTERN_MODULE(RNNamiEntitlementManager,
|
|
11
|
+
@interface RCT_EXTERN_MODULE(RNNamiEntitlementManager, RCTEventEmitter)
|
|
11
12
|
|
|
12
13
|
RCT_EXTERN_METHOD(isEntitlementActive:(nullable NSString *)referenceId resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
13
14
|
|
|
@@ -20,7 +21,7 @@ RCT_EXTERN_METHOD(registerActiveEntitlementsHandler)
|
|
|
20
21
|
RCT_EXTERN_METHOD(clearProvisionalEntitlementGrants)
|
|
21
22
|
|
|
22
23
|
+ (BOOL)requiresMainQueueSetup {
|
|
23
|
-
return
|
|
24
|
+
return YES;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
@end
|
|
@@ -9,10 +9,6 @@ import Foundation
|
|
|
9
9
|
import NamiApple
|
|
10
10
|
import React
|
|
11
11
|
|
|
12
|
-
// #if RCT_NEW_ARCH_ENABLED
|
|
13
|
-
// extension RNNamiEntitlementManager: RCTTurboModule {}
|
|
14
|
-
// #endif
|
|
15
|
-
|
|
16
12
|
@objc(RNNamiEntitlementManager)
|
|
17
13
|
class RNNamiEntitlementManager: RCTEventEmitter {
|
|
18
14
|
public static var shared: RNNamiEntitlementManager?
|
|
@@ -22,8 +18,18 @@ class RNNamiEntitlementManager: RCTEventEmitter {
|
|
|
22
18
|
RNNamiEntitlementManager.shared = self
|
|
23
19
|
}
|
|
24
20
|
|
|
25
|
-
override
|
|
26
|
-
|
|
21
|
+
override class func requiresMainQueueSetup() -> Bool { true }
|
|
22
|
+
|
|
23
|
+
private var hasListeners = false
|
|
24
|
+
override func startObserving() { hasListeners = true }
|
|
25
|
+
override func stopObserving() { hasListeners = false }
|
|
26
|
+
|
|
27
|
+
private func safeSend(withName name: String, body: Any?) {
|
|
28
|
+
guard hasListeners else {
|
|
29
|
+
print("[RNNamiEntitlementManager] Warning: no listeners, so event not being sent to JS.")
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
sendEvent(withName: name, body: body)
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
override func supportedEvents() -> [String]! {
|
|
@@ -74,9 +80,7 @@ class RNNamiEntitlementManager: RCTEventEmitter {
|
|
|
74
80
|
func refresh() {
|
|
75
81
|
NamiEntitlementManager.refresh { entitlements in
|
|
76
82
|
let dicts = entitlements.map { self.entitlementToDictionary($0) }
|
|
77
|
-
|
|
78
|
-
RNNamiEntitlementManager.shared?.sendEvent(withName: "EntitlementsChanged", body: dicts)
|
|
79
|
-
}
|
|
83
|
+
self.safeSend(withName: "EntitlementsChanged", body: dicts)
|
|
80
84
|
}
|
|
81
85
|
}
|
|
82
86
|
|
|
@@ -84,9 +88,7 @@ class RNNamiEntitlementManager: RCTEventEmitter {
|
|
|
84
88
|
func registerActiveEntitlementsHandler() {
|
|
85
89
|
NamiEntitlementManager.registerActiveEntitlementsHandler { entitlements in
|
|
86
90
|
let dicts = entitlements.map { self.entitlementToDictionary($0) }
|
|
87
|
-
|
|
88
|
-
RNNamiEntitlementManager.shared?.sendEvent(withName: "EntitlementsChanged", body: dicts)
|
|
89
|
-
}
|
|
91
|
+
self.safeSend(withName: "EntitlementsChanged", body: dicts)
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
|
|
@@ -9,21 +9,26 @@ import Foundation
|
|
|
9
9
|
import NamiApple
|
|
10
10
|
import React
|
|
11
11
|
|
|
12
|
-
// #if RCT_NEW_ARCH_ENABLED
|
|
13
|
-
// extension RNNamiFlowManager: RCTTurboModule {}
|
|
14
|
-
// #endif
|
|
15
|
-
|
|
16
12
|
@objc(RNNamiFlowManager)
|
|
17
13
|
class RNNamiFlowManager: RCTEventEmitter {
|
|
18
14
|
public static var shared: RNNamiFlowManager?
|
|
19
15
|
|
|
20
16
|
override init() {
|
|
21
17
|
super.init()
|
|
22
|
-
RNNamiFlowManager.shared = self
|
|
23
18
|
}
|
|
24
19
|
|
|
25
|
-
override
|
|
26
|
-
|
|
20
|
+
override class func requiresMainQueueSetup() -> Bool { true }
|
|
21
|
+
|
|
22
|
+
private var hasListeners = false
|
|
23
|
+
override func startObserving() { hasListeners = true }
|
|
24
|
+
override func stopObserving() { hasListeners = false }
|
|
25
|
+
|
|
26
|
+
private func safeSend(withName name: String, body: Any?) {
|
|
27
|
+
guard hasListeners else {
|
|
28
|
+
print("[RNNamiFlowManager] Warning: no listeners, so event not being sent to JS.")
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
sendEvent(withName: name, body: body)
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
override func supportedEvents() -> [String]! {
|
|
@@ -39,36 +44,26 @@ class RNNamiFlowManager: RCTEventEmitter {
|
|
|
39
44
|
payload["handoffData"] = data
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
RNNamiFlowManager.shared?.sendEvent(withName: "Handoff", body: payload)
|
|
44
|
-
}
|
|
47
|
+
self.safeSend(withName: "Handoff", body: payload)
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
@objc func registerEventHandler() {
|
|
49
52
|
NamiFlowManager.registerEventHandler { payload in
|
|
50
|
-
|
|
51
|
-
RNNamiFlowManager.shared?.sendEvent(withName: "FlowEvent", body: payload)
|
|
52
|
-
}
|
|
53
|
+
self.safeSend(withName: "FlowEvent", body: payload)
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
@objc func resume() {
|
|
57
|
-
|
|
58
|
-
NamiFlowManager.resume()
|
|
59
|
-
}
|
|
58
|
+
NamiFlowManager.resume()
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
@objc func pause() {
|
|
63
|
-
|
|
64
|
-
NamiFlowManager.pause()
|
|
65
|
-
}
|
|
62
|
+
NamiFlowManager.pause()
|
|
66
63
|
}
|
|
67
64
|
|
|
68
65
|
@objc func finish() {
|
|
69
|
-
|
|
70
|
-
NamiFlowManager.finish()
|
|
71
|
-
}
|
|
66
|
+
NamiFlowManager.finish()
|
|
72
67
|
}
|
|
73
68
|
|
|
74
69
|
@objc func isFlowOpen(_ resolve: @escaping RCTPromiseResolveBlock, rejecter _: @escaping RCTPromiseRejectBlock) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#import <React/RCTBridgeModule.h>
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
3
|
+
|
|
4
|
+
@interface RCT_EXTERN_MODULE(RNNamiOverlayControl, RCTEventEmitter)
|
|
5
|
+
|
|
6
|
+
RCT_EXTERN_METHOD(presentOverlay:(RCTPromiseResolveBlock)resolve
|
|
7
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
8
|
+
|
|
9
|
+
RCT_EXTERN_METHOD(finishOverlay:(NSDictionary *)result
|
|
10
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
11
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
12
|
+
|
|
13
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
14
|
+
return YES;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@end
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import React
|
|
3
|
+
import UIKit
|
|
4
|
+
|
|
5
|
+
@objc(RNNamiOverlayControl)
|
|
6
|
+
class NamiOverlayControlBridge: RCTEventEmitter {
|
|
7
|
+
private var overlayViewController: UIViewController?
|
|
8
|
+
private var hasListeners = false
|
|
9
|
+
private var isPresenting = false
|
|
10
|
+
private var isDismissing = false
|
|
11
|
+
|
|
12
|
+
override static func requiresMainQueueSetup() -> Bool {
|
|
13
|
+
return true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
override func supportedEvents() -> [String]! {
|
|
17
|
+
return ["NamiOverlayReady", "NamiOverlayResult"]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override func startObserving() { hasListeners = true }
|
|
21
|
+
override func stopObserving() { hasListeners = false }
|
|
22
|
+
|
|
23
|
+
private func safeSend(withName name: String, body: Any?) {
|
|
24
|
+
guard hasListeners else {
|
|
25
|
+
print("[RNNamiOverlayControl] Warning: no listeners, so event not being sent to JS.")
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
sendEvent(withName: name, body: body)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@objc func presentOverlay(_ resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
32
|
+
DispatchQueue.main.async {
|
|
33
|
+
// If we're already presenting or dismissing, wait and retry
|
|
34
|
+
if self.isPresenting || self.isDismissing {
|
|
35
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
|
|
36
|
+
self.presentOverlay(resolve, rejecter: reject)
|
|
37
|
+
}
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Find the root view controller more reliably
|
|
42
|
+
var rootViewController: UIViewController?
|
|
43
|
+
|
|
44
|
+
if #available(iOS 13.0, *) {
|
|
45
|
+
rootViewController = UIApplication.shared.connectedScenes
|
|
46
|
+
.compactMap { $0 as? UIWindowScene }
|
|
47
|
+
.flatMap { $0.windows }
|
|
48
|
+
.first(where: { $0.isKeyWindow })?.rootViewController
|
|
49
|
+
} else {
|
|
50
|
+
rootViewController = UIApplication.shared.keyWindow?.rootViewController
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
guard let rootVC = rootViewController else {
|
|
54
|
+
reject("NO_ROOT_VIEW_CONTROLLER", "No root view controller available", nil)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Create a React Native view controller for the overlay
|
|
59
|
+
guard let bridge = self.bridge else {
|
|
60
|
+
reject("NO_BRIDGE", "React Native bridge not available", nil)
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let rootView = RCTRootView(
|
|
65
|
+
bridge: bridge,
|
|
66
|
+
moduleName: "NamiOverlayHost",
|
|
67
|
+
initialProperties: [:]
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
let overlayViewController = UIViewController()
|
|
71
|
+
overlayViewController.view = rootView
|
|
72
|
+
overlayViewController.modalPresentationStyle = .overFullScreen
|
|
73
|
+
overlayViewController.modalTransitionStyle = .crossDissolve
|
|
74
|
+
overlayViewController.view.backgroundColor = UIColor.clear
|
|
75
|
+
|
|
76
|
+
self.overlayViewController = overlayViewController
|
|
77
|
+
|
|
78
|
+
// Find the top-most presented view controller
|
|
79
|
+
var topController = rootVC
|
|
80
|
+
while let presented = topController.presentedViewController {
|
|
81
|
+
topController = presented
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Check if the top controller can present (not already in the process of presenting/dismissing)
|
|
85
|
+
if topController.isBeingPresented || topController.isBeingDismissed {
|
|
86
|
+
// Wait longer and try again
|
|
87
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
88
|
+
self.presentOverlay(resolve, rejecter: reject)
|
|
89
|
+
}
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
self.isPresenting = true
|
|
94
|
+
|
|
95
|
+
topController.present(overlayViewController, animated: false) {
|
|
96
|
+
self.isPresenting = false
|
|
97
|
+
// Emit ready event after presentation completes
|
|
98
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
|
99
|
+
if self.hasListeners {
|
|
100
|
+
self.safeSend(withName: "NamiOverlayReady", body: nil)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
resolve(nil)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
@objc func finishOverlay(_ result: NSDictionary?, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter _: @escaping RCTPromiseRejectBlock) {
|
|
109
|
+
DispatchQueue.main.async {
|
|
110
|
+
guard let overlayViewController = self.overlayViewController else {
|
|
111
|
+
resolve(nil)
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Emit result to listeners
|
|
116
|
+
if self.hasListeners {
|
|
117
|
+
self.safeSend(withName: "NamiOverlayResult", body: result)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
self.isDismissing = true
|
|
121
|
+
|
|
122
|
+
overlayViewController.dismiss(animated: false) {
|
|
123
|
+
self.overlayViewController = nil
|
|
124
|
+
self.isDismissing = false
|
|
125
|
+
// Add a longer delay before resolving to ensure the view controller is fully dismissed
|
|
126
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
|
127
|
+
resolve(nil)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
#import "React/RCTViewManager.h"
|
|
15
15
|
|
|
16
|
-
@interface RCT_EXTERN_MODULE(RNNamiPaywallManager,
|
|
16
|
+
@interface RCT_EXTERN_MODULE(RNNamiPaywallManager, RCTEventEmitter)
|
|
17
17
|
|
|
18
18
|
RCT_EXTERN_METHOD(buySkuComplete:(NSDictionary)dict)
|
|
19
19
|
|
|
@@ -46,7 +46,7 @@ RCT_EXTERN_METHOD(setAppSuppliedVideoDetails:(NSString *)url name:(nullable NSSt
|
|
|
46
46
|
RCT_EXTERN_METHOD(allowUserInteraction:(BOOL *)allowed)
|
|
47
47
|
|
|
48
48
|
+ (BOOL)requiresMainQueueSetup {
|
|
49
|
-
return
|
|
49
|
+
return YES;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
@end
|
|
@@ -9,17 +9,26 @@ import Foundation
|
|
|
9
9
|
import NamiApple
|
|
10
10
|
import React
|
|
11
11
|
|
|
12
|
-
// #if RCT_NEW_ARCH_ENABLED
|
|
13
|
-
// extension RNNamiPaywallManager: RCTTurboModule {}
|
|
14
|
-
// #endif
|
|
15
|
-
|
|
16
12
|
@objc(RNNamiPaywallManager)
|
|
17
13
|
class RNNamiPaywallManager: RCTEventEmitter {
|
|
18
14
|
public static var shared: RNNamiPaywallManager?
|
|
19
15
|
|
|
20
16
|
override init() {
|
|
21
17
|
super.init()
|
|
22
|
-
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override class func requiresMainQueueSetup() -> Bool { true }
|
|
21
|
+
|
|
22
|
+
private var hasListeners = false
|
|
23
|
+
override func startObserving() { hasListeners = true }
|
|
24
|
+
override func stopObserving() { hasListeners = false }
|
|
25
|
+
|
|
26
|
+
private func safeSend(withName name: String, body: Any?) {
|
|
27
|
+
guard hasListeners else {
|
|
28
|
+
print("[RNNamiPaywallManager] Warning: no listeners, so event not being sent to JS.")
|
|
29
|
+
return
|
|
30
|
+
} // optional but avoids warnings
|
|
31
|
+
sendEvent(withName: name, body: body)
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
override func supportedEvents() -> [String]! {
|
|
@@ -80,9 +89,7 @@ class RNNamiPaywallManager: RCTEventEmitter {
|
|
|
80
89
|
func registerBuySkuHandler() {
|
|
81
90
|
NamiPaywallManager.registerBuySkuHandler { sku in
|
|
82
91
|
let dictionary = RNNamiPurchaseManager.skuToSKUDict(sku)
|
|
83
|
-
|
|
84
|
-
RNNamiPaywallManager.shared?.sendEvent(withName: "RegisterBuySKU", body: dictionary)
|
|
85
|
-
}
|
|
92
|
+
self.safeSend(withName: "RegisterBuySKU", body: dictionary)
|
|
86
93
|
}
|
|
87
94
|
}
|
|
88
95
|
|
|
@@ -90,9 +97,7 @@ class RNNamiPaywallManager: RCTEventEmitter {
|
|
|
90
97
|
func registerCloseHandler() {
|
|
91
98
|
NamiPaywallManager.registerCloseHandler { _ in
|
|
92
99
|
let dictionary = NSDictionary(dictionary: ["PaywallCloseRequested": true].compactMapValues { $0 })
|
|
93
|
-
|
|
94
|
-
RNNamiPaywallManager.shared?.sendEvent(withName: "PaywallCloseRequested", body: dictionary)
|
|
95
|
-
}
|
|
100
|
+
self.safeSend(withName: "PaywallCloseRequested", body: dictionary)
|
|
96
101
|
}
|
|
97
102
|
}
|
|
98
103
|
|
|
@@ -100,9 +105,7 @@ class RNNamiPaywallManager: RCTEventEmitter {
|
|
|
100
105
|
func registerSignInHandler() {
|
|
101
106
|
NamiPaywallManager.registerSignInHandler { _ in
|
|
102
107
|
let dictionary = NSDictionary(dictionary: ["PaywallSignInRequested": true].compactMapValues { $0 })
|
|
103
|
-
|
|
104
|
-
RNNamiPaywallManager.shared?.sendEvent(withName: "PaywallSignInRequested", body: dictionary)
|
|
105
|
-
}
|
|
108
|
+
self.safeSend(withName: "PaywallSignInRequested", body: dictionary)
|
|
106
109
|
}
|
|
107
110
|
}
|
|
108
111
|
|
|
@@ -110,18 +113,14 @@ class RNNamiPaywallManager: RCTEventEmitter {
|
|
|
110
113
|
func registerRestoreHandler() {
|
|
111
114
|
NamiPaywallManager.registerRestoreHandler {
|
|
112
115
|
let dictionary = NSDictionary(dictionary: ["PaywallRestoreRequested": true].compactMapValues { $0 })
|
|
113
|
-
|
|
114
|
-
RNNamiPaywallManager.shared?.sendEvent(withName: "PaywallRestoreRequested", body: dictionary)
|
|
115
|
-
}
|
|
116
|
+
self.safeSend(withName: "PaywallRestoreRequested", body: dictionary)
|
|
116
117
|
}
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
@objc(registerDeeplinkActionHandler)
|
|
120
121
|
func registerDeeplinkActionHandler() {
|
|
121
122
|
NamiPaywallManager.registerDeeplinkActionHandler { url in
|
|
122
|
-
|
|
123
|
-
RNNamiPaywallManager.shared?.sendEvent(withName: "PaywallDeeplinkAction", body: url)
|
|
124
|
-
}
|
|
123
|
+
self.safeSend(withName: "PaywallDeeplinkAction", body: url)
|
|
125
124
|
}
|
|
126
125
|
}
|
|
127
126
|
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
#import "React/RCTViewManager.h"
|
|
15
15
|
|
|
16
|
-
@interface RCT_EXTERN_MODULE(RNNamiPurchaseManager,
|
|
16
|
+
@interface RCT_EXTERN_MODULE(RNNamiPurchaseManager, RCTEventEmitter)
|
|
17
17
|
|
|
18
18
|
RCT_EXTERN_METHOD(allPurchases:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
|
|
19
19
|
|
|
@@ -30,7 +30,7 @@ RCT_EXTERN_METHOD(presentCodeRedemptionSheet)
|
|
|
30
30
|
RCT_EXTERN_METHOD(restorePurchases)
|
|
31
31
|
|
|
32
32
|
+ (BOOL)requiresMainQueueSetup {
|
|
33
|
-
return
|
|
33
|
+
return YES;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
@end
|
|
@@ -9,17 +9,26 @@ import Foundation
|
|
|
9
9
|
import NamiApple
|
|
10
10
|
import React
|
|
11
11
|
|
|
12
|
-
// #if RCT_NEW_ARCH_ENABLED
|
|
13
|
-
// extension RNNamiPurchaseManager: RCTTurboModule {}
|
|
14
|
-
// #endif
|
|
15
|
-
|
|
16
12
|
@objc(RNNamiPurchaseManager)
|
|
17
13
|
class RNNamiPurchaseManager: RCTEventEmitter {
|
|
18
14
|
public static var shared: RNNamiPurchaseManager?
|
|
19
15
|
|
|
20
16
|
override init() {
|
|
21
17
|
super.init()
|
|
22
|
-
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
override class func requiresMainQueueSetup() -> Bool { true }
|
|
21
|
+
|
|
22
|
+
private var hasListeners = false
|
|
23
|
+
override func startObserving() { hasListeners = true }
|
|
24
|
+
override func stopObserving() { hasListeners = false }
|
|
25
|
+
|
|
26
|
+
private func safeSend(withName name: String, body: Any?) {
|
|
27
|
+
guard hasListeners else {
|
|
28
|
+
print("[RNNamiPurchaseManager] Warning: no listeners, so event not being sent to JS.")
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
sendEvent(withName: name, body: body)
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
override func supportedEvents() -> [String]! {
|
|
@@ -158,7 +167,7 @@ class RNNamiPurchaseManager: RCTEventEmitter {
|
|
|
158
167
|
"purchaseState": stateString,
|
|
159
168
|
"error": error?.localizedDescription,
|
|
160
169
|
]
|
|
161
|
-
self.
|
|
170
|
+
self.safeSend(withName: "PurchasesChanged", body: payload)
|
|
162
171
|
}
|
|
163
172
|
}
|
|
164
173
|
|
|
@@ -187,7 +196,7 @@ class RNNamiPurchaseManager: RCTEventEmitter {
|
|
|
187
196
|
"newPurchases": newPurchasesDictionaries,
|
|
188
197
|
"oldPurchases": oldPurchasesDictionaries,
|
|
189
198
|
]
|
|
190
|
-
|
|
199
|
+
self.safeSend(withName: "RestorePurchasesStateChanged", body: payload)
|
|
191
200
|
}
|
|
192
201
|
}
|
|
193
202
|
|
|
@@ -216,7 +225,7 @@ class RNNamiPurchaseManager: RCTEventEmitter {
|
|
|
216
225
|
"newPurchases": newPurchasesDictionaries,
|
|
217
226
|
"oldPurchases": oldPurchasesDictionaries,
|
|
218
227
|
]
|
|
219
|
-
|
|
228
|
+
self.safeSend(withName: "RestorePurchasesStateChanged", body: payload)
|
|
220
229
|
}
|
|
221
230
|
}
|
|
222
231
|
|
package/package.json
CHANGED
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-nami-sdk",
|
|
3
|
-
"version": "3.3.
|
|
4
|
-
"description": "React Native
|
|
3
|
+
"version": "3.3.3-1",
|
|
4
|
+
"description": "React Native SDK for Nami - No-code paywall management with A/B testing.",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"codegenConfig": {
|
|
8
|
-
"name": "
|
|
8
|
+
"name": "NativeNamiSpec",
|
|
9
9
|
"type": "modules",
|
|
10
10
|
"jsSrcsDir": "./specs",
|
|
11
11
|
"android": {
|
|
12
12
|
"javaPackageName": "com.namiml.reactnative"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
+
"react-native": {
|
|
16
|
+
"android": {
|
|
17
|
+
"sourceDir": "android",
|
|
18
|
+
"packageImportPath": "com.namiml.reactnative.NamiBridgePackage",
|
|
19
|
+
"libraryName": "react-native-nami-sdk"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
15
22
|
"scripts": {
|
|
16
23
|
"build": "tsc",
|
|
17
24
|
"generate:version": "ts-node scripts/generate-version.ts",
|