@ionic/portals-react-native 0.1.0 → 0.2.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 +11 -159
- package/ReactNativePortals.podspec +2 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/io/ionic/portals/reactnative/PortalView.kt +132 -0
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativeLiveUpdatesModule.kt +10 -28
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalManager.kt +149 -0
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalsModule.kt +73 -232
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalsPackage.kt +0 -1
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalsPubSub.kt +45 -0
- package/ios/LiveUpdate+Dict.swift +30 -0
- package/ios/LiveUpdateManager+Async.swift +69 -0
- package/ios/LiveUpdateManagerError+Dict.swift +19 -0
- package/ios/Podfile +2 -1
- package/ios/Podfile.lock +8 -7
- package/ios/Portal+Dict.swift +35 -0
- package/ios/PortalManager.m +10 -4
- package/ios/PortalView.m +1 -1
- package/ios/PortalView.swift +67 -0
- package/ios/PortalsConfig.swift +92 -0
- package/ios/PortalsPubSub.m +3 -3
- package/ios/PortalsPubSub.swift +47 -0
- package/ios/PortalsReactNative.swift +104 -0
- package/ios/ReactNativePortals.xcodeproj/project.pbxproj +32 -8
- package/lib/commonjs/PortalView.android.js +2 -10
- package/lib/commonjs/PortalView.android.js.map +1 -1
- package/lib/commonjs/PortalView.js +0 -6
- package/lib/commonjs/PortalView.js.map +1 -1
- package/lib/commonjs/index.js +54 -38
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/PortalView.android.js +2 -5
- package/lib/module/PortalView.android.js.map +1 -1
- package/lib/module/PortalView.js +0 -2
- package/lib/module/PortalView.js.map +1 -1
- package/lib/module/index.js +52 -19
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/index.d.ts +27 -2
- package/package.json +3 -1
- package/src/index.ts +47 -12
- package/ios/LiveUpdatesManager.m +0 -16
- package/ios/ReactNativePortals.swift +0 -262
package/src/index.ts
CHANGED
|
@@ -5,8 +5,7 @@ import {
|
|
|
5
5
|
ViewProps,
|
|
6
6
|
} from 'react-native';
|
|
7
7
|
|
|
8
|
-
const { IONPortalPubSub,
|
|
9
|
-
NativeModules;
|
|
8
|
+
const { IONPortalPubSub, IONPortalsReactNative } = NativeModules;
|
|
10
9
|
|
|
11
10
|
export { default as PortalView } from './PortalView';
|
|
12
11
|
|
|
@@ -82,9 +81,10 @@ export const publish = (topic: string, data: any) => {
|
|
|
82
81
|
/**
|
|
83
82
|
* Validates that a valid registration key has been procured from http://ionic.io/register-portals
|
|
84
83
|
* @param key The registration key
|
|
84
|
+
* @returns Promise<void>
|
|
85
85
|
*/
|
|
86
|
-
export const register = (key: string) => {
|
|
87
|
-
|
|
86
|
+
export const register = async (key: string): Promise<void> => {
|
|
87
|
+
return IONPortalsReactNative.register(key);
|
|
88
88
|
};
|
|
89
89
|
|
|
90
90
|
/**
|
|
@@ -126,9 +126,30 @@ export type PortalProps = PortalProp & ViewProps;
|
|
|
126
126
|
* Adds a Portal to an internal registry. Must be called before attempting to render a {@link PortalView}.
|
|
127
127
|
*
|
|
128
128
|
* @param portal The portal to add to the internal registry.
|
|
129
|
+
* @returns Promise containing the Portal that was added to the registry.
|
|
129
130
|
*/
|
|
130
|
-
export const addPortal = (portal: Portal) => {
|
|
131
|
-
|
|
131
|
+
export const addPortal = async (portal: Portal): Promise<Portal> => {
|
|
132
|
+
return IONPortalsReactNative.addPortal(portal);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Adds all portals to an internal registry. This or {@link addPortal} must be called before attempting to render a {@link PortalView}
|
|
137
|
+
*
|
|
138
|
+
* @param portals The portals to add to the internal registry.
|
|
139
|
+
* @returns Promise containing the Portals that were added to the registry.
|
|
140
|
+
*/
|
|
141
|
+
export const addPortals = async (portals: Portal[]): Promise<Portal[]> => {
|
|
142
|
+
return IONPortalsReactNative.addPortals(portals);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Gets a {@link Portal} previously registered via {@link addPortal} or {@link addPortals}.
|
|
147
|
+
*
|
|
148
|
+
* @param name The portal name to retrieve from the internal registry.
|
|
149
|
+
* @returns Promise containing the registered {@link Portal}. If the {@link Portal} was not registered, the Promise will fail.
|
|
150
|
+
*/
|
|
151
|
+
export const getPortal = async (name: string): Promise<Portal> => {
|
|
152
|
+
return IONPortalsReactNative.getPortal(name);
|
|
132
153
|
};
|
|
133
154
|
|
|
134
155
|
export interface LiveUpdate {
|
|
@@ -156,14 +177,28 @@ export interface SyncResults {
|
|
|
156
177
|
errors: LiveUpdateError[];
|
|
157
178
|
}
|
|
158
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Configures LiveUpdates to cyrptographically verify the contents of the downloaded bundles.
|
|
182
|
+
* This method must be called before any LiveUpdates are registered otherwise they will no longer be tracked.
|
|
183
|
+
*
|
|
184
|
+
* @param pathToKey The *relative* path to the public key for verification.
|
|
185
|
+
* This path should be the same relatibe to the main application bundle on iOS and the assets directory on Android.
|
|
186
|
+
* @returns Promise<void>
|
|
187
|
+
*/
|
|
188
|
+
export const enableSecureLiveUpdates = async (
|
|
189
|
+
pathToKey: string
|
|
190
|
+
): Promise<void> => {
|
|
191
|
+
return IONPortalsReactNative.enableSecureLiveUpdates(pathToKey);
|
|
192
|
+
};
|
|
193
|
+
|
|
159
194
|
/**
|
|
160
195
|
* Syncs a single live update.
|
|
161
196
|
*
|
|
162
197
|
* @param appId The AppFlow application ID to sync.
|
|
163
198
|
* @returns A Promise<LiveUpdate>. A failure should result in a {@link LiveUpdateError}.
|
|
164
199
|
*/
|
|
165
|
-
export const syncOne = (appId: string): Promise<LiveUpdate> => {
|
|
166
|
-
return
|
|
200
|
+
export const syncOne = async (appId: string): Promise<LiveUpdate> => {
|
|
201
|
+
return IONPortalsReactNative.syncOne(appId);
|
|
167
202
|
};
|
|
168
203
|
|
|
169
204
|
/**
|
|
@@ -172,14 +207,14 @@ export const syncOne = (appId: string): Promise<LiveUpdate> => {
|
|
|
172
207
|
* @param appIds The AppFlow application IDs to sync.
|
|
173
208
|
* @returns Promise<SyncResults>
|
|
174
209
|
*/
|
|
175
|
-
export const syncSome = (appIds: string[]): Promise<SyncResults> => {
|
|
176
|
-
return
|
|
210
|
+
export const syncSome = async (appIds: string[]): Promise<SyncResults> => {
|
|
211
|
+
return IONPortalsReactNative.syncSome(appIds);
|
|
177
212
|
};
|
|
178
213
|
|
|
179
214
|
/**
|
|
180
215
|
* Syncs all registered LiveUpdates
|
|
181
216
|
* @returns Promise<SyncResults>
|
|
182
217
|
*/
|
|
183
|
-
export const syncAll = (): Promise<SyncResults> => {
|
|
184
|
-
return
|
|
218
|
+
export const syncAll = async (): Promise<SyncResults> => {
|
|
219
|
+
return IONPortalsReactNative.syncAll();
|
|
185
220
|
};
|
package/ios/LiveUpdatesManager.m
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// LiveUpdatesManager.m
|
|
3
|
-
// ReactNativePortals
|
|
4
|
-
//
|
|
5
|
-
// Created by Steven Sherry on 6/21/22.
|
|
6
|
-
// Copyright © 2022 Facebook. All rights reserved.
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
#import <React/RCTBridgeModule.h>
|
|
10
|
-
|
|
11
|
-
@interface RCT_EXTERN_MODULE(IONLiveUpdatesManager, NSObject)
|
|
12
|
-
RCT_EXTERN_METHOD(addLiveUpdate: (NSDictionary) liveUpdate)
|
|
13
|
-
RCT_EXTERN_METHOD(syncOne: (NSString *) appId resolver: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
14
|
-
RCT_EXTERN_METHOD(syncSome: (NSArray) appIds resolver: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
15
|
-
RCT_EXTERN_METHOD(syncAll: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
16
|
-
@end
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
import Foundation
|
|
2
|
-
import IonicPortals
|
|
3
|
-
import IonicLiveUpdates
|
|
4
|
-
import React
|
|
5
|
-
import UIKit
|
|
6
|
-
import Capacitor
|
|
7
|
-
|
|
8
|
-
@objc(IONPortalManager)
|
|
9
|
-
public class PortalManager: NSObject {
|
|
10
|
-
private static var portals: [String: Portal] = [:]
|
|
11
|
-
|
|
12
|
-
public static func register(_ key: String) {
|
|
13
|
-
PortalsRegistrationManager.shared.register(key: key)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
public static func add(_ portal: Portal) {
|
|
17
|
-
portals[portal.name] = portal
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static func getPortal(named name: String) -> Portal? { portals[name] }
|
|
21
|
-
|
|
22
|
-
@objc func register(_ key: String) {
|
|
23
|
-
Self.register(key)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
@objc func addPortal(_ portalDict: [String: Any]) {
|
|
27
|
-
guard let portal = Portal(portalDict) else { return }
|
|
28
|
-
Self.add(portal)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@objc static func requiresMainQueueSetup() -> Bool { true }
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
@objc(IONPortalPubSub)
|
|
35
|
-
class PortalsPubSub: RCTEventEmitter {
|
|
36
|
-
private let eventName = "PortalsSubscription"
|
|
37
|
-
|
|
38
|
-
override func supportedEvents() -> [String]! {
|
|
39
|
-
[eventName]
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@objc func subscribe(_ topic: String, resolver: RCTPromiseResolveBlock, rejector: RCTPromiseRejectBlock) {
|
|
43
|
-
let subRef = IonicPortals.PortalsPubSub.subscribe(topic) { [weak self] result in
|
|
44
|
-
guard let self = self else { return }
|
|
45
|
-
self.sendEvent(
|
|
46
|
-
withName: self.eventName,
|
|
47
|
-
body: [
|
|
48
|
-
"subscriptionRef": result.subscriptionRef,
|
|
49
|
-
"topic": result.topic,
|
|
50
|
-
"data": result.data
|
|
51
|
-
]
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
resolver(subRef)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
@objc func unsubscribe(_ topic: String, subscriptionRef: NSNumber) {
|
|
59
|
-
IonicPortals.PortalsPubSub.unsubscribe(from: topic, subscriptionRef: subscriptionRef.intValue)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
@objc func publish(_ topic: String, data: Any) {
|
|
63
|
-
IONPortalsPubSub.publish(message: data, topic: topic)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
override class func requiresMainQueueSetup() -> Bool { true }
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
@objc(IONPortalViewManager)
|
|
70
|
-
class PortalViewManager: RCTViewManager {
|
|
71
|
-
override class func requiresMainQueueSetup() -> Bool { true }
|
|
72
|
-
override func view() -> UIView! { PortalView() }
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
class PortalView: UIView {
|
|
76
|
-
private var webView: PortalUIView?
|
|
77
|
-
|
|
78
|
-
@objc var portal: [String: Any]? {
|
|
79
|
-
get {
|
|
80
|
-
guard let _portal = _portal else { return nil }
|
|
81
|
-
return [
|
|
82
|
-
"name": _portal.name,
|
|
83
|
-
"initialContext": _portal.initialContext
|
|
84
|
-
]
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
set {
|
|
88
|
-
guard let portalDict = newValue,
|
|
89
|
-
let name = portalDict["name"] as? String
|
|
90
|
-
else { return }
|
|
91
|
-
|
|
92
|
-
var portal = PortalManager.getPortal(named: name)
|
|
93
|
-
if let initialContext = portalDict["initialContext"] as? [String: Any] {
|
|
94
|
-
portal?.initialContext = JSTypes.coerceDictionaryToJSObject(initialContext) ?? [:]
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
_portal = portal
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
private var _portal: Portal? {
|
|
102
|
-
didSet {
|
|
103
|
-
guard let portal = _portal else { return }
|
|
104
|
-
|
|
105
|
-
DispatchQueue.main.async { [weak self] in
|
|
106
|
-
guard let self = self else { return }
|
|
107
|
-
self.webView?.removeFromSuperview()
|
|
108
|
-
let webView = PortalUIView(portal: portal)
|
|
109
|
-
webView.translatesAutoresizingMaskIntoConstraints = false
|
|
110
|
-
self.addSubview(webView)
|
|
111
|
-
NSLayoutConstraint.activate([
|
|
112
|
-
webView.topAnchor.constraint(equalTo: self.topAnchor),
|
|
113
|
-
webView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
|
|
114
|
-
webView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
|
115
|
-
webView.trailingAnchor.constraint(equalTo: self.trailingAnchor)
|
|
116
|
-
])
|
|
117
|
-
self.webView = webView
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
extension Portal {
|
|
124
|
-
init?(_ dict: [String: Any]) {
|
|
125
|
-
guard let name = dict["name"] as? String else { return nil }
|
|
126
|
-
self.init(
|
|
127
|
-
name: name,
|
|
128
|
-
startDir: dict["startDir"] as? String,
|
|
129
|
-
index: dict["index"] as? String ?? "index.html",
|
|
130
|
-
initialContext: JSTypes.coerceDictionaryToJSObject(dict["initialContext"] as? [String: Any]) ?? [:],
|
|
131
|
-
liveUpdateConfig: (dict["liveUpdate"] as? [String: Any]).flatMap(LiveUpdate.init)
|
|
132
|
-
)
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
extension LiveUpdate {
|
|
137
|
-
init?(_ dict: [String: Any]) {
|
|
138
|
-
guard let appId = dict["appId"] as? String,
|
|
139
|
-
let channel = dict["channel"] as? String,
|
|
140
|
-
let syncOnAdd = dict["syncOnAdd"] as? Bool
|
|
141
|
-
else { return nil }
|
|
142
|
-
|
|
143
|
-
self.init(appId: appId, channel: channel, syncOnAdd: syncOnAdd)
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
extension LiveUpdate {
|
|
148
|
-
var dict: [String: Any] {
|
|
149
|
-
return [
|
|
150
|
-
"appId": appId,
|
|
151
|
-
"channel": channel,
|
|
152
|
-
"syncOnAdd": syncOnAdd
|
|
153
|
-
]
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
extension LiveUpdateManager.Error {
|
|
158
|
-
var dict: [String: Any] {
|
|
159
|
-
return [
|
|
160
|
-
"appId": appId,
|
|
161
|
-
"failStep": failStep.rawValue.uppercased(),
|
|
162
|
-
"message": localizedDescription
|
|
163
|
-
]
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
private struct SyncResults {
|
|
168
|
-
var liveUpdates: [LiveUpdate]
|
|
169
|
-
var errors: [LiveUpdateManager.Error]
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
extension SyncResults {
|
|
173
|
-
var dict: [String: Any] {
|
|
174
|
-
return [
|
|
175
|
-
"liveUpdates": liveUpdates.map(\.dict),
|
|
176
|
-
"errors": errors.map(\.dict)
|
|
177
|
-
]
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
@objc(IONLiveUpdatesManager)
|
|
182
|
-
public class LiveUpdatesManager: NSObject {
|
|
183
|
-
private var lum = LiveUpdateManager.shared
|
|
184
|
-
|
|
185
|
-
@objc func addLiveUpdate(_ dict: [String: Any]) {
|
|
186
|
-
guard let liveUpdate = LiveUpdate(dict) else { return }
|
|
187
|
-
try? lum.add(liveUpdate)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
@objc func syncOne(_ appId: String, resolver: @escaping RCTPromiseResolveBlock, rejector: @escaping RCTPromiseRejectBlock) {
|
|
191
|
-
lum.sync(appId: appId, isParallel: true) { result in
|
|
192
|
-
switch result {
|
|
193
|
-
case .success(let update):
|
|
194
|
-
resolver(update.dict)
|
|
195
|
-
case .failure(let error):
|
|
196
|
-
rejector(nil, nil, error)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
@objc func syncSome(_ appIds: [String], resolver: @escaping RCTPromiseResolveBlock, rejector: RCTPromiseRejectBlock) {
|
|
202
|
-
Task {
|
|
203
|
-
let syncResult = await lum.syncSome(appIds)
|
|
204
|
-
resolver(syncResult.dict)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
@objc func syncAll(_ resolver: @escaping RCTPromiseResolveBlock, rejector: RCTPromiseRejectBlock) {
|
|
209
|
-
Task {
|
|
210
|
-
let syncResult = await lum.syncAll()
|
|
211
|
-
resolver(syncResult.dict)
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
@objc static func requiresMainQueueSetup() -> Bool { true }
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
extension LiveUpdateManager {
|
|
219
|
-
fileprivate func syncSome(_ appIds: [String]) async -> SyncResults {
|
|
220
|
-
await _syncSome(appIds).syncResults
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
private func _syncSome(_ appIds: [String]) -> AsyncStream<Result<LiveUpdate, LiveUpdateManager.Error>> {
|
|
224
|
-
AsyncStream { continuation in
|
|
225
|
-
sync(appIds: appIds, isParallel: true) {
|
|
226
|
-
continuation.finish()
|
|
227
|
-
} appComplete: { result in
|
|
228
|
-
continuation.yield(result)
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
fileprivate func syncAll() async -> SyncResults {
|
|
234
|
-
await _syncAll().syncResults
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
private func _syncAll() -> AsyncStream<Result<LiveUpdate, LiveUpdateManager.Error>> {
|
|
239
|
-
AsyncStream { continuation in
|
|
240
|
-
sync(isParallel: true) {
|
|
241
|
-
continuation.finish()
|
|
242
|
-
} appComplete: { result in
|
|
243
|
-
continuation.yield(result)
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
extension AsyncStream where Element == Result<LiveUpdate, LiveUpdateManager.Error> {
|
|
250
|
-
fileprivate var syncResults: SyncResults {
|
|
251
|
-
get async {
|
|
252
|
-
await reduce(into: SyncResults(liveUpdates: [], errors: [])) { acc, next in
|
|
253
|
-
switch next {
|
|
254
|
-
case .success(let liveUpdate):
|
|
255
|
-
acc.liveUpdates.append(liveUpdate)
|
|
256
|
-
case .failure(let error):
|
|
257
|
-
acc.errors.append(error)
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
}
|