@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
|
@@ -1,282 +1,123 @@
|
|
|
1
1
|
package io.ionic.portals.reactnative
|
|
2
2
|
|
|
3
|
-
import android.util.Log
|
|
4
|
-
import android.view.Choreographer
|
|
5
|
-
import android.view.View
|
|
6
|
-
import android.view.ViewGroup
|
|
7
|
-
import android.widget.FrameLayout
|
|
8
|
-
import androidx.fragment.app.FragmentActivity
|
|
9
3
|
import com.facebook.react.bridge.*
|
|
10
|
-
import
|
|
11
|
-
import com.facebook.react.uimanager.ThemedReactContext
|
|
12
|
-
import com.facebook.react.uimanager.ViewGroupManager
|
|
13
|
-
import com.facebook.react.uimanager.annotations.ReactProp
|
|
14
|
-
import com.getcapacitor.CapConfig
|
|
15
|
-
import com.getcapacitor.JSObject
|
|
16
|
-
import com.getcapacitor.Plugin
|
|
17
|
-
import io.ionic.liveupdates.LiveUpdate
|
|
18
|
-
import io.ionic.portals.*
|
|
19
|
-
import org.json.JSONArray
|
|
20
|
-
import org.json.JSONException
|
|
21
|
-
import org.json.JSONObject
|
|
22
|
-
|
|
23
|
-
internal object RNPortalManager {
|
|
24
|
-
private val manager = PortalManager
|
|
25
|
-
internal var indexMap: MutableMap<String, String> = mutableMapOf()
|
|
26
|
-
lateinit var reactApplicationContext: ReactApplicationContext
|
|
27
|
-
|
|
28
|
-
fun register(key: String) = manager.register(key)
|
|
29
|
-
fun addPortal(map: ReadableMap) {
|
|
30
|
-
val name = map.getString("name") ?: return
|
|
31
|
-
val portalBuilder = PortalBuilder(name)
|
|
32
|
-
|
|
33
|
-
map.getString("startDir")
|
|
34
|
-
?.let(portalBuilder::setStartDir)
|
|
35
|
-
|
|
36
|
-
map.getMap("initialContext")
|
|
37
|
-
?.toHashMap()
|
|
38
|
-
?.let(portalBuilder::setInitialContext)
|
|
39
|
-
|
|
40
|
-
map.getString("index")
|
|
41
|
-
?.let { indexMap[name] = "/$it" }
|
|
42
|
-
|
|
43
|
-
map.getArray("androidPlugins")
|
|
44
|
-
?.toArrayList()
|
|
45
|
-
?.mapNotNull { it as? String }
|
|
46
|
-
?.map {
|
|
47
|
-
Class.forName(it)
|
|
48
|
-
.asSubclass(Plugin::class.java)
|
|
49
|
-
}
|
|
50
|
-
?.forEach(portalBuilder::addPlugin)
|
|
51
|
-
|
|
52
|
-
map.getMap("liveUpdate")
|
|
53
|
-
?.let { readableMap ->
|
|
54
|
-
val appId = readableMap.getString("appId") ?: return@let null
|
|
55
|
-
val channel = readableMap.getString("channel") ?: return@let null
|
|
56
|
-
val syncOnAdd = readableMap.getBoolean("syncOnAdd")
|
|
57
|
-
Pair(LiveUpdate(appId, channel), syncOnAdd)
|
|
58
|
-
}
|
|
59
|
-
?.let { pair ->
|
|
60
|
-
portalBuilder.setLiveUpdateConfig(
|
|
61
|
-
context = reactApplicationContext,
|
|
62
|
-
liveUpdateConfig = pair.first,
|
|
63
|
-
updateOnAppLoad = pair.second
|
|
64
|
-
)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
val portal = portalBuilder
|
|
68
|
-
.addPlugin(PortalsPlugin::class.java)
|
|
69
|
-
.create()
|
|
70
|
-
|
|
71
|
-
PortalManager.addPortal(portal)
|
|
72
|
-
}
|
|
73
|
-
}
|
|
4
|
+
import io.ionic.portals.Portal
|
|
74
5
|
|
|
75
6
|
internal class PortalManagerModule(reactContext: ReactApplicationContext) :
|
|
76
7
|
ReactContextBaseJavaModule(reactContext) {
|
|
77
|
-
override fun getName() = "
|
|
8
|
+
override fun getName() = "IONPortalsReactNative"
|
|
78
9
|
|
|
79
10
|
init {
|
|
80
|
-
RNPortalManager.
|
|
11
|
+
RNPortalManager.registerFromConfigIfAvailable(reactContext)
|
|
81
12
|
}
|
|
82
13
|
|
|
83
14
|
@ReactMethod
|
|
84
|
-
fun register(key: String) {
|
|
15
|
+
fun register(key: String, promise: Promise) {
|
|
85
16
|
RNPortalManager.register(key)
|
|
17
|
+
promise.resolve(null)
|
|
86
18
|
}
|
|
87
19
|
|
|
88
20
|
@ReactMethod
|
|
89
|
-
fun addPortal(map: ReadableMap) {
|
|
90
|
-
RNPortalManager.addPortal(map)
|
|
21
|
+
fun addPortal(map: ReadableMap, promise: Promise) {
|
|
22
|
+
val portal = RNPortalManager.addPortal(map)
|
|
23
|
+
if (portal == null) {
|
|
24
|
+
promise.reject(null, "Invalid Portal configuration.")
|
|
25
|
+
} else {
|
|
26
|
+
promise.resolve(portal.toReadableMap())
|
|
27
|
+
}
|
|
91
28
|
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
internal class PortalsPubSubModule(reactContext: ReactApplicationContext) :
|
|
95
|
-
ReactContextBaseJavaModule(reactContext) {
|
|
96
|
-
override fun getName() = "IONPortalPubSub"
|
|
97
29
|
|
|
98
30
|
@ReactMethod
|
|
99
|
-
fun
|
|
100
|
-
val
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
31
|
+
fun addPortals(array: ReadableArray, promise: Promise) {
|
|
32
|
+
val portals = WritableNativeArray()
|
|
33
|
+
|
|
34
|
+
for (i in 0 until array.size()) {
|
|
35
|
+
val map = array.getMap(i) ?: continue
|
|
36
|
+
val portal = RNPortalManager.addPortal(map) ?: continue
|
|
37
|
+
portals.pushMap(portal.toReadableMap())
|
|
104
38
|
}
|
|
105
39
|
|
|
106
|
-
promise.resolve(
|
|
40
|
+
promise.resolve(portals)
|
|
107
41
|
}
|
|
108
42
|
|
|
109
43
|
@ReactMethod
|
|
110
|
-
fun
|
|
111
|
-
|
|
44
|
+
fun getPortal(name: String, promise: Promise) {
|
|
45
|
+
try {
|
|
46
|
+
val portal = RNPortalManager.getPortal(name)
|
|
47
|
+
promise.resolve(portal.toReadableMap())
|
|
48
|
+
} catch (e: IllegalStateException) {
|
|
49
|
+
promise.reject(null, "Portal named $name not registered.")
|
|
50
|
+
}
|
|
112
51
|
}
|
|
113
52
|
|
|
114
53
|
@ReactMethod
|
|
115
|
-
fun
|
|
116
|
-
|
|
54
|
+
fun enableSecureLiveUpdates(keyPath: String, promise: Promise) {
|
|
55
|
+
RNPortalManager.enableSecureLiveUpdates(keyPath)
|
|
56
|
+
promise.resolve(null)
|
|
117
57
|
}
|
|
118
58
|
|
|
119
|
-
|
|
59
|
+
@ReactMethod
|
|
60
|
+
fun syncOne(appId: String, promise: Promise) {
|
|
61
|
+
LiveUpdatesModule.syncOne(appId, reactApplicationContext, promise)
|
|
62
|
+
}
|
|
120
63
|
|
|
121
64
|
@ReactMethod
|
|
122
|
-
fun
|
|
65
|
+
fun syncSome(appIds: ReadableArray, promise: Promise) {
|
|
66
|
+
LiveUpdatesModule.syncSome(appIds, reactApplicationContext, promise)
|
|
123
67
|
}
|
|
124
68
|
|
|
125
69
|
@ReactMethod
|
|
126
|
-
fun
|
|
70
|
+
fun syncAll(promise: Promise) {
|
|
71
|
+
LiveUpdatesModule.syncAll(reactApplicationContext, promise)
|
|
127
72
|
}
|
|
128
73
|
}
|
|
129
74
|
|
|
130
|
-
|
|
131
|
-
keys
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
} catch (_: JSONException) {
|
|
75
|
+
fun Map<*, *>.toReadableMap(): ReadableMap {
|
|
76
|
+
return keys.fold(WritableNativeMap()) { map, key ->
|
|
77
|
+
val key = key as String
|
|
78
|
+
when (val value = get(key)) {
|
|
79
|
+
is String -> map.putString(key, value)
|
|
80
|
+
is Boolean -> map.putBoolean(key, value)
|
|
81
|
+
is Int -> map.putInt(key, value)
|
|
82
|
+
is Double -> map.putDouble(key, value)
|
|
83
|
+
is Map<*, *> -> map.putMap(key, value.toReadableMap())
|
|
84
|
+
is List<*> -> map.putArray(key, value.toReadableArray())
|
|
85
|
+
null -> map.putNull(key)
|
|
86
|
+
else -> map.putString(key, value.toString())
|
|
144
87
|
}
|
|
145
|
-
|
|
146
88
|
return@fold map
|
|
147
89
|
}
|
|
90
|
+
}
|
|
148
91
|
|
|
149
|
-
|
|
150
|
-
(0 until
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
else -> array.pushString(value.toString())
|
|
161
|
-
}
|
|
162
|
-
} catch (_: JSONException) {
|
|
92
|
+
fun List<*>.toReadableArray(): ReadableArray {
|
|
93
|
+
return (0 until size).fold(WritableNativeArray()) { array, index ->
|
|
94
|
+
when (val value = get(index)) {
|
|
95
|
+
is String -> array.pushString(value)
|
|
96
|
+
is Boolean -> array.pushBoolean(value)
|
|
97
|
+
is Int -> array.pushInt(value)
|
|
98
|
+
is Double -> array.pushDouble(value)
|
|
99
|
+
is Map<*, *> -> array.pushMap(value.toReadableMap())
|
|
100
|
+
is List<*> -> array.pushArray(value.toReadableArray())
|
|
101
|
+
null -> array.pushNull()
|
|
102
|
+
else -> array.pushString(value.toString())
|
|
163
103
|
}
|
|
164
104
|
|
|
165
105
|
return@fold array
|
|
166
106
|
}
|
|
107
|
+
}
|
|
167
108
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
internal class PortalViewManager(private val context: ReactApplicationContext) :
|
|
177
|
-
ViewGroupManager<FrameLayout>() {
|
|
178
|
-
private val createId = 1
|
|
179
|
-
private val fragmentMap = mutableMapOf<Int, PortalViewState>()
|
|
180
|
-
|
|
181
|
-
@ReactProp(name = "portal")
|
|
182
|
-
fun setPortal(viewGroup: ViewGroup, portal: ReadableMap) {
|
|
183
|
-
val name = portal.getString("name") ?: return
|
|
184
|
-
when (val viewState = fragmentMap[viewGroup.id]) {
|
|
185
|
-
null -> fragmentMap[viewGroup.id] = PortalViewState(
|
|
186
|
-
fragment = null,
|
|
187
|
-
portal = PortalManager.getPortal(name),
|
|
188
|
-
initialContext = portal.getMap("initialContext")?.toHashMap()
|
|
189
|
-
)
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
override fun getName() = "AndroidPortalView"
|
|
194
|
-
|
|
195
|
-
override fun createViewInstance(reactContext: ThemedReactContext): FrameLayout {
|
|
196
|
-
return FrameLayout(reactContext)
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
override fun getCommandsMap(): MutableMap<String, Int> {
|
|
200
|
-
return mutableMapOf("create" to createId)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
override fun receiveCommand(root: FrameLayout, commandId: String?, args: ReadableArray?) {
|
|
204
|
-
super.receiveCommand(root, commandId, args)
|
|
205
|
-
val viewId = args?.getInt(0) ?: return
|
|
206
|
-
|
|
207
|
-
@Suppress("NAME_SHADOWING")
|
|
208
|
-
val commandId = commandId?.toIntOrNull() ?: return
|
|
209
|
-
|
|
210
|
-
when (commandId) {
|
|
211
|
-
createId -> createFragment(root, viewId)
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
private fun createFragment(root: FrameLayout, viewId: Int) {
|
|
216
|
-
val viewState = fragmentMap[viewId] ?: return
|
|
217
|
-
val portal = viewState.portal ?: return
|
|
218
|
-
|
|
219
|
-
val parentView = root.findViewById<ViewGroup>(viewId)
|
|
220
|
-
setupLayout(parentView)
|
|
221
|
-
|
|
222
|
-
val portalFragment = PortalFragment(portal)
|
|
223
|
-
|
|
224
|
-
val configBuilder = CapConfig.Builder(context)
|
|
225
|
-
.setInitialFocus(false)
|
|
226
|
-
|
|
227
|
-
RNPortalManager.indexMap[portal.name]
|
|
228
|
-
?.let(configBuilder::setStartPath)
|
|
229
|
-
|
|
230
|
-
portalFragment.setConfig(configBuilder.create())
|
|
231
|
-
|
|
232
|
-
viewState.initialContext?.let(portalFragment::setInitialContext)
|
|
233
|
-
|
|
234
|
-
viewState.fragment = portalFragment
|
|
235
|
-
|
|
236
|
-
val fragmentActivity = context.currentActivity as? FragmentActivity ?: return
|
|
237
|
-
fragmentActivity.supportFragmentManager
|
|
238
|
-
.beginTransaction()
|
|
239
|
-
.replace(viewId, portalFragment, "$viewId")
|
|
240
|
-
.commit()
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
override fun onDropViewInstance(view: FrameLayout) {
|
|
244
|
-
super.onDropViewInstance(view)
|
|
245
|
-
val viewState = fragmentMap[view.id] ?: return
|
|
246
|
-
|
|
247
|
-
try {
|
|
248
|
-
viewState.fragment
|
|
249
|
-
?.parentFragmentManager
|
|
250
|
-
?.beginTransaction()
|
|
251
|
-
?.remove(viewState.fragment!!)
|
|
252
|
-
?.commit()
|
|
253
|
-
} catch (e: IllegalStateException) {
|
|
254
|
-
Log.i("io.ionic.portals.rn", "Parent fragment manager not available")
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
fragmentMap.remove(view.id)
|
|
258
|
-
}
|
|
109
|
+
@Suppress("UNCHECKED_CAST")
|
|
110
|
+
fun Portal.toReadableMap(): ReadableMap {
|
|
111
|
+
val map = WritableNativeMap()
|
|
112
|
+
map.putString("name", name)
|
|
113
|
+
map.putString("startDir", startDir)
|
|
114
|
+
RNPortalManager.indexMap[name]?.let { map.putString("index", it) }
|
|
259
115
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
override fun doFrame(frameTimeNanos: Long) {
|
|
263
|
-
layoutPortal(view)
|
|
264
|
-
view.viewTreeObserver.dispatchOnGlobalLayout()
|
|
265
|
-
Choreographer.getInstance().postFrameCallback(this)
|
|
266
|
-
}
|
|
267
|
-
})
|
|
116
|
+
initialContext?.let {
|
|
117
|
+
if (it is Map<*, *>) map.putMap("initialContext", it.toReadableMap())
|
|
268
118
|
}
|
|
269
119
|
|
|
270
|
-
|
|
271
|
-
for (i in 0 until view.childCount) {
|
|
272
|
-
val child = view.getChildAt(i)
|
|
120
|
+
liveUpdateConfig?.let { map.putMap("liveUpdate", it.toReadableMap()) }
|
|
273
121
|
|
|
274
|
-
|
|
275
|
-
View.MeasureSpec.makeMeasureSpec(view.measuredWidth, View.MeasureSpec.EXACTLY),
|
|
276
|
-
View.MeasureSpec.makeMeasureSpec(view.measuredHeight, View.MeasureSpec.EXACTLY)
|
|
277
|
-
)
|
|
278
|
-
|
|
279
|
-
child.layout(0, 0, child.measuredWidth, child.measuredHeight)
|
|
280
|
-
}
|
|
281
|
-
}
|
|
122
|
+
return map
|
|
282
123
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
package io.ionic.portals.reactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.*
|
|
4
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
5
|
+
import com.getcapacitor.JSObject
|
|
6
|
+
import io.ionic.portals.PortalsPlugin
|
|
7
|
+
import org.json.JSONObject
|
|
8
|
+
|
|
9
|
+
internal class PortalsPubSubModule(reactContext: ReactApplicationContext) :
|
|
10
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
11
|
+
override fun getName() = "IONPortalPubSub"
|
|
12
|
+
|
|
13
|
+
@ReactMethod
|
|
14
|
+
fun subscribe(topic: String, promise: Promise) {
|
|
15
|
+
val reference = PortalsPlugin.subscribe(topic) { result ->
|
|
16
|
+
reactApplicationContext
|
|
17
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
18
|
+
.emit("PortalsSubscription", result.toJSObject().toReactMap())
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
promise.resolve(reference)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@ReactMethod
|
|
25
|
+
fun publish(topic: String, data: ReadableMap) {
|
|
26
|
+
PortalsPlugin.publish(topic, data.toJSObject())
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@ReactMethod
|
|
30
|
+
fun unsubscribe(topic: String, reference: Int) {
|
|
31
|
+
PortalsPlugin.unsubscribe(topic, reference)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// These are required to be an EventEmitter in javascript
|
|
35
|
+
|
|
36
|
+
@ReactMethod
|
|
37
|
+
fun addListener(eventName: String) {
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@ReactMethod
|
|
41
|
+
fun removeListeners(count: Int) {
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private fun ReadableMap.toJSObject(): JSObject = JSObject.fromJSONObject(JSONObject(toHashMap()))
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//
|
|
2
|
+
// LiveUpdate+Dict.swift
|
|
3
|
+
// ReactNativePortals
|
|
4
|
+
//
|
|
5
|
+
// Created by Steven Sherry on 10/5/22.
|
|
6
|
+
// Copyright © 2022 Ionic. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import IonicLiveUpdates
|
|
10
|
+
|
|
11
|
+
extension LiveUpdate {
|
|
12
|
+
init?(_ dict: [String: Any]) {
|
|
13
|
+
guard let appId = dict["appId"] as? String,
|
|
14
|
+
let channel = dict["channel"] as? String,
|
|
15
|
+
let syncOnAdd = dict["syncOnAdd"] as? Bool
|
|
16
|
+
else { return nil }
|
|
17
|
+
|
|
18
|
+
self.init(appId: appId, channel: channel, syncOnAdd: syncOnAdd)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
extension LiveUpdate {
|
|
23
|
+
var dict: [String: Any] {
|
|
24
|
+
return [
|
|
25
|
+
"appId": appId,
|
|
26
|
+
"channel": channel,
|
|
27
|
+
"syncOnAdd": syncOnAdd
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
//
|
|
2
|
+
// LiveUpdateManager+Async.swift
|
|
3
|
+
// ReactNativePortals
|
|
4
|
+
//
|
|
5
|
+
// Created by Steven Sherry on 10/5/22.
|
|
6
|
+
// Copyright © 2022 Ionic. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import IonicLiveUpdates
|
|
10
|
+
|
|
11
|
+
struct SyncResults {
|
|
12
|
+
var liveUpdates: [LiveUpdate]
|
|
13
|
+
var errors: [LiveUpdateManager.Error]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
extension SyncResults {
|
|
17
|
+
var dict: [String: Any] {
|
|
18
|
+
return [
|
|
19
|
+
"liveUpdates": liveUpdates.map(\.dict),
|
|
20
|
+
"errors": errors.map(\.dict)
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
extension LiveUpdateManager {
|
|
26
|
+
func syncSome(_ appIds: [String]) async -> SyncResults {
|
|
27
|
+
await _syncSome(appIds).syncResults
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private func _syncSome(_ appIds: [String]) -> AsyncStream<Result<LiveUpdate, LiveUpdateManager.Error>> {
|
|
31
|
+
AsyncStream { continuation in
|
|
32
|
+
sync(appIds: appIds, isParallel: true) {
|
|
33
|
+
continuation.finish()
|
|
34
|
+
} appComplete: { result in
|
|
35
|
+
continuation.yield(result)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
func syncAll() async -> SyncResults {
|
|
41
|
+
await _syncAll().syncResults
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
private func _syncAll() -> AsyncStream<Result<LiveUpdate, LiveUpdateManager.Error>> {
|
|
46
|
+
AsyncStream { continuation in
|
|
47
|
+
sync(isParallel: true) {
|
|
48
|
+
continuation.finish()
|
|
49
|
+
} appComplete: { result in
|
|
50
|
+
continuation.yield(result)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
extension AsyncStream where Element == Result<LiveUpdate, LiveUpdateManager.Error> {
|
|
57
|
+
var syncResults: SyncResults {
|
|
58
|
+
get async {
|
|
59
|
+
await reduce(into: SyncResults(liveUpdates: [], errors: [])) { acc, next in
|
|
60
|
+
switch next {
|
|
61
|
+
case .success(let liveUpdate):
|
|
62
|
+
acc.liveUpdates.append(liveUpdate)
|
|
63
|
+
case .failure(let error):
|
|
64
|
+
acc.errors.append(error)
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//
|
|
2
|
+
// LiveUpdateManagerError+Dict.swift
|
|
3
|
+
// ReactNativePortals
|
|
4
|
+
//
|
|
5
|
+
// Created by Steven Sherry on 10/5/22.
|
|
6
|
+
// Copyright © 2022 Ionic. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import IonicLiveUpdates
|
|
10
|
+
|
|
11
|
+
extension LiveUpdateManager.Error {
|
|
12
|
+
var dict: [String: Any] {
|
|
13
|
+
return [
|
|
14
|
+
"appId": appId,
|
|
15
|
+
"failStep": failStep.rawValue.uppercased(),
|
|
16
|
+
"message": localizedDescription
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
}
|
package/ios/Podfile
CHANGED
package/ios/Podfile.lock
CHANGED
|
@@ -22,10 +22,10 @@ PODS:
|
|
|
22
22
|
- DoubleConversion
|
|
23
23
|
- glog
|
|
24
24
|
- glog (0.3.5)
|
|
25
|
-
- IonicLiveUpdates (0.
|
|
26
|
-
- IonicPortals (0.6.
|
|
25
|
+
- IonicLiveUpdates (0.2.0)
|
|
26
|
+
- IonicPortals (0.6.4):
|
|
27
27
|
- Capacitor (~> 3.7)
|
|
28
|
-
- IonicLiveUpdates (
|
|
28
|
+
- IonicLiveUpdates (< 0.3.0, >= 0.1.2)
|
|
29
29
|
- RCTRequired (0.63.4)
|
|
30
30
|
- RCTTypeSafety (0.63.4):
|
|
31
31
|
- FBLazyVector (= 0.63.4)
|
|
@@ -260,7 +260,8 @@ DEPENDENCIES:
|
|
|
260
260
|
- FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`)
|
|
261
261
|
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
|
|
262
262
|
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
|
263
|
-
-
|
|
263
|
+
- IonicLiveUpdates (~> 0.2.0)
|
|
264
|
+
- IonicPortals (~> 0.6.4)
|
|
264
265
|
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
|
|
265
266
|
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
|
|
266
267
|
- React (from `../node_modules/react-native/`)
|
|
@@ -356,8 +357,8 @@ SPEC CHECKSUMS:
|
|
|
356
357
|
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
|
|
357
358
|
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
|
358
359
|
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
|
|
359
|
-
IonicLiveUpdates:
|
|
360
|
-
IonicPortals:
|
|
360
|
+
IonicLiveUpdates: e9cfcb6cbcf67d7b171eae417fa2802cc5826d72
|
|
361
|
+
IonicPortals: 50634da3bd7a3cf9127bbad5f21fd23afde4f0ff
|
|
361
362
|
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
|
|
362
363
|
RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b
|
|
363
364
|
React: b0a957a2c44da4113b0c4c9853d8387f8e64e615
|
|
@@ -380,6 +381,6 @@ SPEC CHECKSUMS:
|
|
|
380
381
|
ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
|
|
381
382
|
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
|
|
382
383
|
|
|
383
|
-
PODFILE CHECKSUM:
|
|
384
|
+
PODFILE CHECKSUM: 9dce8640a99e055a2e7fad56d00e49829114eae1
|
|
384
385
|
|
|
385
386
|
COCOAPODS: 1.11.2
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Portal+Dict.swift
|
|
3
|
+
// ReactNativePortals
|
|
4
|
+
//
|
|
5
|
+
// Created by Steven Sherry on 10/5/22.
|
|
6
|
+
// Copyright © 2022 Ionic. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Capacitor
|
|
10
|
+
import IonicLiveUpdates
|
|
11
|
+
import IonicPortals
|
|
12
|
+
|
|
13
|
+
extension Portal {
|
|
14
|
+
init?(_ dict: [String: Any], _ liveUpdateManager: LiveUpdateManager) {
|
|
15
|
+
guard let name = dict["name"] as? String else { return nil }
|
|
16
|
+
self.init(
|
|
17
|
+
name: name,
|
|
18
|
+
startDir: dict["startDir"] as? String,
|
|
19
|
+
index: dict["index"] as? String ?? "index.html",
|
|
20
|
+
initialContext: JSTypes.coerceDictionaryToJSObject(dict["initialContext"] as? [String: Any]) ?? [:],
|
|
21
|
+
liveUpdateManager: liveUpdateManager,
|
|
22
|
+
liveUpdateConfig: (dict["liveUpdate"] as? [String: Any]).flatMap(LiveUpdate.init)
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var dict: [String: Any] {
|
|
27
|
+
return [
|
|
28
|
+
"name": name,
|
|
29
|
+
"startDir": startDir,
|
|
30
|
+
"index": index,
|
|
31
|
+
"initialContext": initialContext,
|
|
32
|
+
"liveUpdateConfig": liveUpdateConfig?.dict as Any
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
}
|
package/ios/PortalManager.m
CHANGED
|
@@ -3,12 +3,18 @@
|
|
|
3
3
|
// ReactNativePortals
|
|
4
4
|
//
|
|
5
5
|
// Created by Steven Sherry on 4/1/22.
|
|
6
|
-
// Copyright © 2022
|
|
6
|
+
// Copyright © 2022 Ionic. All rights reserved.
|
|
7
7
|
//
|
|
8
8
|
|
|
9
9
|
#import <React/RCTBridgeModule.h>
|
|
10
10
|
|
|
11
|
-
@interface RCT_EXTERN_MODULE(
|
|
12
|
-
RCT_EXTERN_METHOD(register: (NSString *) key)
|
|
13
|
-
RCT_EXTERN_METHOD(
|
|
11
|
+
@interface RCT_EXTERN_MODULE(IONPortalsReactNative, NSObject)
|
|
12
|
+
RCT_EXTERN_METHOD(register: (NSString *) key resolver: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
13
|
+
RCT_EXTERN_METHOD(enableSecureLiveUpdates: (NSString *) publicKeyPath resolver: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
14
|
+
RCT_EXTERN_METHOD(addPortal: (NSDictionary) portal resolver: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
15
|
+
RCT_EXTERN_METHOD(addPortals: (NSArray) portals resolver: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
16
|
+
RCT_EXTERN_METHOD(getPortal: (NSString *) name resolver: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
17
|
+
RCT_EXTERN_METHOD(syncOne: (NSString *) appId resolver: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
18
|
+
RCT_EXTERN_METHOD(syncSome: (NSArray) appIds resolver: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
19
|
+
RCT_EXTERN_METHOD(syncAll: (RCTPromiseResolveBlock) resolver)
|
|
14
20
|
@end
|