@pinwheel/react-native-pinwheel 3.6.1 → 3.7.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/README.md +14 -8
- package/RNPinwheelSDK.podspec +3 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/rtnpinwheel/Pinwheel.kt +14 -1
- package/android/src/main/java/com/rtnpinwheel/PinwheelManager.kt +5 -0
- package/ios/PWPinwheelWrapperVC.swift +97 -0
- package/ios/RTNPinwheelManager.mm +2 -0
- package/ios/RTNPinwheelView.h +14 -4
- package/ios/RTNPinwheelView.mm +29 -14
- package/package.json +3 -2
- package/src/Pinwheel.d.ts +1 -1
- package/src/Pinwheel.tsx +2 -0
- package/src/RTNPinwheelNativeComponent.d.ts +1 -0
- package/src/RTNPinwheelNativeComponent.ts +1 -0
- package/src/client-events/client.d.ts +1 -0
- package/src/client-events/client.ts +11 -10
package/README.md
CHANGED
|
@@ -122,19 +122,25 @@ Enables Link to run with a dark mode theme.
|
|
|
122
122
|
|
|
123
123
|
## Running The Example App Locally
|
|
124
124
|
|
|
125
|
-
You may want to run the example app locally to get started.
|
|
125
|
+
You may want to run the example app locally to get started. The application is located inside of the example_expo directory inside of the repository.
|
|
126
126
|
|
|
127
127
|
#### Dependencies
|
|
128
128
|
|
|
129
|
-
- Node
|
|
130
|
-
-
|
|
131
|
-
-
|
|
132
|
-
- `pod` version 1.11.3 (check with `pod --version`)
|
|
133
|
-
- Add your pinwheel secret to `example/env.js` (create this file) with `export default "<YOUR PINWHEEL SECRET>"`.
|
|
129
|
+
- Node 22.18.0 (check with `node -v` and upgrade versions using `nvm` if needed)
|
|
130
|
+
- Xcode for iOS
|
|
131
|
+
- Android Studio for Android
|
|
134
132
|
|
|
135
133
|
#### Directions
|
|
136
|
-
|
|
137
|
-
- `
|
|
134
|
+
**Enter the `example_expo` directory and run the following commands:**
|
|
135
|
+
- Create a `.env` file with your Pinwheel API secret. An example env file is located at example_repo/.env.example.
|
|
136
|
+
- Directions to run the [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
|
|
137
|
+
- Directions to run the [Android simulator](https://docs.expo.dev/workflow/android-studio-emulator/)
|
|
138
|
+
```
|
|
139
|
+
EXPO_PUBLIC_PINWHEEL_API_KEY=YOUR_API_SECRET
|
|
140
|
+
```
|
|
141
|
+
- `npm i`
|
|
142
|
+
- `npm run ios` (for iOS)
|
|
143
|
+
- `npm run android` (for Android)
|
|
138
144
|
|
|
139
145
|
#### Troubleshooting
|
|
140
146
|
|
package/RNPinwheelSDK.podspec
CHANGED
package/android/build.gradle
CHANGED
|
@@ -21,6 +21,7 @@ class Pinwheel : FrameLayout {
|
|
|
21
21
|
private var pinwheelEventListener: PinwheelEventListener? = null
|
|
22
22
|
private var handleInsets: Boolean = true
|
|
23
23
|
private var useDarkMode: Boolean = false
|
|
24
|
+
private var useSecureOrigin: Boolean = false
|
|
24
25
|
private var fragmentContainer: FrameLayout? = null
|
|
25
26
|
|
|
26
27
|
constructor(context: Context) : super(context) {
|
|
@@ -80,6 +81,10 @@ class Pinwheel : FrameLayout {
|
|
|
80
81
|
this.useDarkMode = useDarkMode
|
|
81
82
|
}
|
|
82
83
|
|
|
84
|
+
fun setUseSecureOrigin(useSecureOrigin: Boolean) {
|
|
85
|
+
this.useSecureOrigin = useSecureOrigin
|
|
86
|
+
}
|
|
87
|
+
|
|
83
88
|
fun getReactNativeVersion(): String {
|
|
84
89
|
val version = ReactNativeVersion.VERSION
|
|
85
90
|
return "${version["major"]}.${version["minor"]}.${version["patch"]}"
|
|
@@ -89,7 +94,15 @@ class Pinwheel : FrameLayout {
|
|
|
89
94
|
Handler(Looper.getMainLooper()).post {
|
|
90
95
|
if (this.pinwheelFragment == null) {
|
|
91
96
|
this.token?.let {
|
|
92
|
-
val pinwheelFragment = PinwheelFragment.newInstanceWithAdvancedOptions(
|
|
97
|
+
val pinwheelFragment = PinwheelFragment.newInstanceWithAdvancedOptions(
|
|
98
|
+
it,
|
|
99
|
+
"react native",
|
|
100
|
+
"3.7.1",
|
|
101
|
+
getReactNativeVersion(),
|
|
102
|
+
this.handleInsets,
|
|
103
|
+
this.useDarkMode,
|
|
104
|
+
this.useSecureOrigin
|
|
105
|
+
)
|
|
93
106
|
pinwheelEventListener?.let { listener ->
|
|
94
107
|
pinwheelFragment.pinwheelEventListener = listener
|
|
95
108
|
}
|
|
@@ -48,6 +48,11 @@ class PinwheelManager(private val reactContext: ReactApplicationContext) :
|
|
|
48
48
|
view.setUseDarkMode(useDarkMode)
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
@ReactProp(name = "useSecureOrigin")
|
|
52
|
+
override fun setUseSecureOrigin(view: Pinwheel, useSecureOrigin: Boolean) {
|
|
53
|
+
view.setUseSecureOrigin(useSecureOrigin)
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
@ReactPropGroup(names = ["width", "height"], customType = "Style")
|
|
52
57
|
fun setStyle(view: Pinwheel, index: Int, value: Int) {
|
|
53
58
|
if (index == 0) propWidth = value
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import PinwheelSDK
|
|
3
|
+
import UIKit
|
|
4
|
+
|
|
5
|
+
@objc public protocol PWPinwheelWrapperDelegate {
|
|
6
|
+
func onEvent(name: String, event: [String: AnyObject])
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@objcMembers
|
|
10
|
+
public final class PWPinwheelWrapperVC: UIViewController {
|
|
11
|
+
private let token: String
|
|
12
|
+
private let delegateBridge: PWPinwheelWrapperDelegate
|
|
13
|
+
|
|
14
|
+
private let useSecureOrigin: Bool
|
|
15
|
+
private let useDarkMode: Bool
|
|
16
|
+
private let sdk: String
|
|
17
|
+
private let version: String
|
|
18
|
+
|
|
19
|
+
private var pinwheelVC: PinwheelViewController?
|
|
20
|
+
|
|
21
|
+
public init(
|
|
22
|
+
token: String,
|
|
23
|
+
delegate: PWPinwheelWrapperDelegate,
|
|
24
|
+
sdk: String,
|
|
25
|
+
version: String,
|
|
26
|
+
useSecureOrigin: Bool,
|
|
27
|
+
useDarkMode: Bool = false,
|
|
28
|
+
useAppBoundDomains: Bool = false,
|
|
29
|
+
useAppBoundDomainsForNativeLink: Bool = false
|
|
30
|
+
) {
|
|
31
|
+
self.token = token
|
|
32
|
+
self.delegateBridge = delegate
|
|
33
|
+
self.sdk = sdk
|
|
34
|
+
self.version = version
|
|
35
|
+
self.useSecureOrigin = useSecureOrigin
|
|
36
|
+
self.useDarkMode = useDarkMode
|
|
37
|
+
super.init(nibName: nil, bundle: nil)
|
|
38
|
+
|
|
39
|
+
var config = PinwheelConfig(mode: .sandbox, environment: .production, sdk: sdk, version: version)
|
|
40
|
+
config.useSecureOrigin = useSecureOrigin
|
|
41
|
+
|
|
42
|
+
let vc = PinwheelViewController(
|
|
43
|
+
token: token,
|
|
44
|
+
delegate: self,
|
|
45
|
+
config: config,
|
|
46
|
+
useDarkMode: useDarkMode,
|
|
47
|
+
useAppBoundDomains: useAppBoundDomains,
|
|
48
|
+
useAppBoundDomainsForNativeLink: useAppBoundDomainsForNativeLink
|
|
49
|
+
)
|
|
50
|
+
self.pinwheelVC = vc
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public required init?(coder: NSCoder) {
|
|
54
|
+
nil
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public override func viewDidLoad() {
|
|
58
|
+
super.viewDidLoad()
|
|
59
|
+
guard let pinwheelVC else { return }
|
|
60
|
+
|
|
61
|
+
addChild(pinwheelVC)
|
|
62
|
+
view.addSubview(pinwheelVC.view)
|
|
63
|
+
pinwheelVC.didMove(toParent: self)
|
|
64
|
+
|
|
65
|
+
pinwheelVC.view.translatesAutoresizingMaskIntoConstraints = false
|
|
66
|
+
NSLayoutConstraint.activate([
|
|
67
|
+
pinwheelVC.view.topAnchor.constraint(equalTo: view.topAnchor),
|
|
68
|
+
pinwheelVC.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
|
|
69
|
+
pinwheelVC.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
|
70
|
+
pinwheelVC.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
|
|
71
|
+
])
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// MARK: - PinwheelDelegate
|
|
76
|
+
|
|
77
|
+
extension PWPinwheelWrapperVC: PinwheelDelegate {
|
|
78
|
+
public func onEvent(name: PinwheelEventType, event: PinwheelEventPayload?) {
|
|
79
|
+
var payload: [String: AnyObject] = [:]
|
|
80
|
+
|
|
81
|
+
if let event {
|
|
82
|
+
do {
|
|
83
|
+
let json = try event.jsonString()
|
|
84
|
+
if let jsonData = json.data(using: .utf8) {
|
|
85
|
+
let jsonObject = try JSONSerialization.jsonObject(with: jsonData)
|
|
86
|
+
if let jsonDictionary = jsonObject as? [String: AnyObject] {
|
|
87
|
+
payload = jsonDictionary
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
} catch {
|
|
91
|
+
// Best-effort payload serialization; still forward event name.
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
delegateBridge.onEvent(name: name.rawValue, event: payload)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -17,6 +17,7 @@ RCT_EXPORT_MODULE(RTNPinwheel)
|
|
|
17
17
|
|
|
18
18
|
RCT_EXPORT_VIEW_PROPERTY(token, NSString);
|
|
19
19
|
RCT_EXPORT_VIEW_PROPERTY(useDarkMode, BOOL);
|
|
20
|
+
RCT_EXPORT_VIEW_PROPERTY(useSecureOrigin, BOOL);
|
|
20
21
|
|
|
21
22
|
@end
|
|
22
23
|
|
|
@@ -34,5 +35,6 @@ RCT_EXPORT_MODULE(RTNPinwheelView)
|
|
|
34
35
|
|
|
35
36
|
RCT_EXPORT_VIEW_PROPERTY(token, NSString);
|
|
36
37
|
RCT_EXPORT_VIEW_PROPERTY(useDarkMode, BOOL);
|
|
38
|
+
RCT_EXPORT_VIEW_PROPERTY(useSecureOrigin, BOOL);
|
|
37
39
|
|
|
38
40
|
@end
|
package/ios/RTNPinwheelView.h
CHANGED
|
@@ -5,25 +5,35 @@
|
|
|
5
5
|
# endif
|
|
6
6
|
|
|
7
7
|
#import <WebKit/WebKit.h>
|
|
8
|
-
#import <PinwheelSDK/PinwheelSDK-Swift.h>
|
|
9
8
|
#import <UIKit/UIKit.h>
|
|
10
9
|
|
|
11
10
|
NS_ASSUME_NONNULL_BEGIN
|
|
12
11
|
|
|
12
|
+
#ifdef __cplusplus
|
|
13
|
+
extern "C" {
|
|
14
|
+
#endif
|
|
15
|
+
@protocol PWPinwheelWrapperDelegate;
|
|
16
|
+
#ifdef __cplusplus
|
|
17
|
+
}
|
|
18
|
+
#endif
|
|
19
|
+
|
|
20
|
+
@class PWPinwheelWrapperVC;
|
|
21
|
+
|
|
13
22
|
#ifdef RCT_NEW_ARCH_ENABLED
|
|
14
23
|
|
|
15
|
-
@interface RTNPinwheelView : RCTViewComponentView <
|
|
24
|
+
@interface RTNPinwheelView : RCTViewComponentView <PWPinwheelWrapperDelegate>
|
|
16
25
|
|
|
17
26
|
#else
|
|
18
27
|
|
|
19
|
-
@interface RTNPinwheelView : UIView <
|
|
28
|
+
@interface RTNPinwheelView : UIView <PWPinwheelWrapperDelegate>
|
|
20
29
|
|
|
21
30
|
#endif
|
|
22
31
|
|
|
23
32
|
|
|
24
|
-
@property (nonatomic, strong, nullable)
|
|
33
|
+
@property (nonatomic, strong, nullable) PWPinwheelWrapperVC *pinwheelWrapperVC;
|
|
25
34
|
@property (nonatomic, strong) NSString *token;
|
|
26
35
|
@property (nonatomic, assign) BOOL useDarkMode;
|
|
36
|
+
@property (nonatomic, assign) BOOL useSecureOrigin;
|
|
27
37
|
|
|
28
38
|
- (instancetype)initWithFrame:(CGRect)frame token:(NSString *)token;
|
|
29
39
|
|
package/ios/RTNPinwheelView.mm
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
#import "RCTFabricComponentsPlugins.h"
|
|
11
11
|
#import "RTNPinwheelEvents.h"
|
|
12
|
+
#import "RNPinwheelSDK-Swift.h"
|
|
12
13
|
|
|
13
14
|
using namespace facebook::react;
|
|
14
15
|
|
|
@@ -71,13 +72,14 @@ using namespace facebook::react;
|
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
self.pinwheelWrapperVC =
|
|
74
|
-
[[
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
[[PWPinwheelWrapperVC alloc] initWithToken:self.token
|
|
76
|
+
delegate:self
|
|
77
|
+
sdk:@"react native"
|
|
78
|
+
version:@"3.7.1"
|
|
79
|
+
useSecureOrigin:self.useSecureOrigin
|
|
80
|
+
useDarkMode:self.useDarkMode
|
|
81
|
+
useAppBoundDomains:NO
|
|
82
|
+
useAppBoundDomainsForNativeLink:NO];
|
|
81
83
|
|
|
82
84
|
// Guard against double-attachment (shouldn’t happen after cleanup, but safe).
|
|
83
85
|
if (self.pinwheelWrapperVC.parentViewController == parentVC) {
|
|
@@ -127,6 +129,10 @@ using namespace facebook::react;
|
|
|
127
129
|
self.useDarkMode = newViewProps.useDarkMode;
|
|
128
130
|
}
|
|
129
131
|
|
|
132
|
+
if (oldViewProps.useSecureOrigin != newViewProps.useSecureOrigin) {
|
|
133
|
+
self.useSecureOrigin = newViewProps.useSecureOrigin;
|
|
134
|
+
}
|
|
135
|
+
|
|
130
136
|
// Ensures that the view is always re-initialized whenever the props change,
|
|
131
137
|
// or the React Native component is re-mounted. On the new architecture, there
|
|
132
138
|
// are optimizations which causes the view to be re-used in these scenarios,
|
|
@@ -181,6 +187,7 @@ Class<RCTComponentViewProtocol> RTNPinwheelCls(void) {
|
|
|
181
187
|
|
|
182
188
|
#import "RTNPinwheelEvents.h"
|
|
183
189
|
#import "RTNPinwheelView.h"
|
|
190
|
+
#import "RNPinwheelSDK-Swift.h"
|
|
184
191
|
|
|
185
192
|
@implementation RTNPinwheelView
|
|
186
193
|
|
|
@@ -234,13 +241,14 @@ Class<RCTComponentViewProtocol> RTNPinwheelCls(void) {
|
|
|
234
241
|
}
|
|
235
242
|
|
|
236
243
|
self.pinwheelWrapperVC =
|
|
237
|
-
[[
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
+
[[PWPinwheelWrapperVC alloc] initWithToken:self.token
|
|
245
|
+
delegate:self
|
|
246
|
+
sdk:@"react native"
|
|
247
|
+
version:@"3.7.1"
|
|
248
|
+
useSecureOrigin:self.useSecureOrigin
|
|
249
|
+
useDarkMode:self.useDarkMode
|
|
250
|
+
useAppBoundDomains:NO
|
|
251
|
+
useAppBoundDomainsForNativeLink:NO];
|
|
244
252
|
|
|
245
253
|
// Guard against double-attachment (shouldn’t happen after cleanup, but safe).
|
|
246
254
|
if (self.pinwheelWrapperVC.parentViewController == parentVC) {
|
|
@@ -281,6 +289,13 @@ Class<RCTComponentViewProtocol> RTNPinwheelCls(void) {
|
|
|
281
289
|
}
|
|
282
290
|
}
|
|
283
291
|
|
|
292
|
+
- (void)setUseSecureOrigin:(BOOL)newUseSecureOrigin {
|
|
293
|
+
if (_useSecureOrigin != newUseSecureOrigin) {
|
|
294
|
+
_useSecureOrigin = newUseSecureOrigin;
|
|
295
|
+
[self initPinwheelWrapperVC];
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
284
299
|
- (void)layoutSubviews {
|
|
285
300
|
[super layoutSubviews];
|
|
286
301
|
self.pinwheelWrapperVC.view.frame = self.bounds;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pinwheel/react-native-pinwheel",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
24
|
"build": "tsc",
|
|
25
|
-
"dev": "./scripts/dev_expo.sh"
|
|
25
|
+
"dev": "./scripts/dev_expo.sh",
|
|
26
|
+
"dev:bare": "./scripts/dev_bare.sh"
|
|
26
27
|
},
|
|
27
28
|
"author": "Pinwheel",
|
|
28
29
|
"license": "MIT",
|
package/src/Pinwheel.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { LinkOptions } from './client-events/client';
|
|
3
|
-
declare const Pinwheel: ({ linkToken, onLogin, onLoginAttempt, onSuccess, onError, onExit, onEvent, handleInsets, useDarkMode, }: LinkOptions & {
|
|
3
|
+
declare const Pinwheel: ({ linkToken, onLogin, onLoginAttempt, onSuccess, onError, onExit, onEvent, handleInsets, useDarkMode, useSecureOrigin, }: LinkOptions & {
|
|
4
4
|
handleInsets?: boolean;
|
|
5
5
|
useDarkMode?: boolean;
|
|
6
6
|
}) => React.JSX.Element;
|
package/src/Pinwheel.tsx
CHANGED
|
@@ -19,6 +19,7 @@ const Pinwheel = ({
|
|
|
19
19
|
onEvent,
|
|
20
20
|
handleInsets,
|
|
21
21
|
useDarkMode,
|
|
22
|
+
useSecureOrigin,
|
|
22
23
|
}: LinkOptions & {
|
|
23
24
|
handleInsets?: boolean;
|
|
24
25
|
useDarkMode?: boolean;
|
|
@@ -83,6 +84,7 @@ const Pinwheel = ({
|
|
|
83
84
|
token={linkToken}
|
|
84
85
|
handleInsets={handleInsets ?? true}
|
|
85
86
|
useDarkMode={useDarkMode ?? false}
|
|
87
|
+
useSecureOrigin={useSecureOrigin ?? false}
|
|
86
88
|
/>
|
|
87
89
|
)}
|
|
88
90
|
</SafeAreaView>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { LoginEventPayload, SuccessEventPayload, EventHandler, ErrorEventPayload, LoginAttemptEventPayload } from './registry/v3';
|
|
2
2
|
export type LinkOptions = {
|
|
3
3
|
linkToken: string;
|
|
4
|
+
useSecureOrigin?: boolean;
|
|
4
5
|
onLogin?: (payload: LoginEventPayload) => void;
|
|
5
6
|
onLoginAttempt?: (payload: LoginAttemptEventPayload) => void;
|
|
6
7
|
onSuccess?: (payload: SuccessEventPayload) => void;
|
|
@@ -3,15 +3,16 @@ import type {
|
|
|
3
3
|
SuccessEventPayload,
|
|
4
4
|
EventHandler,
|
|
5
5
|
ErrorEventPayload,
|
|
6
|
-
LoginAttemptEventPayload
|
|
7
|
-
} from './registry/v3'
|
|
6
|
+
LoginAttemptEventPayload,
|
|
7
|
+
} from './registry/v3';
|
|
8
8
|
|
|
9
9
|
export type LinkOptions = {
|
|
10
|
-
linkToken: string
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
linkToken: string;
|
|
11
|
+
useSecureOrigin?: boolean;
|
|
12
|
+
onLogin?: (payload: LoginEventPayload) => void;
|
|
13
|
+
onLoginAttempt?: (payload: LoginAttemptEventPayload) => void;
|
|
14
|
+
onSuccess?: (payload: SuccessEventPayload) => void;
|
|
15
|
+
onError?: (error: ErrorEventPayload) => void;
|
|
16
|
+
onExit?: (error?: ErrorEventPayload) => void;
|
|
17
|
+
onEvent?: EventHandler;
|
|
18
|
+
};
|