@ionic/portals-react-native 0.0.3 → 0.0.4
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 -31
- package/ReactNativePortals.podspec +2 -3
- package/android/build.gradle +15 -5
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativeLiveUpdatesModule.kt +187 -0
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalsModule.kt +96 -36
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalsPackage.kt +2 -1
- package/ios/LiveUpdatesManager.m +16 -0
- package/ios/Podfile +1 -1
- package/ios/Podfile.lock +12 -16
- package/ios/PortalsPubSub.m +1 -1
- package/ios/ReactNativePortals.swift +165 -16
- package/ios/ReactNativePortals.xcodeproj/project.pbxproj +4 -0
- package/lib/commonjs/index.js +26 -7
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +16 -6
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/index.d.ts +24 -1
- package/package.json +1 -1
- package/src/index.ts +41 -6
package/README.md
CHANGED
|
@@ -132,44 +132,24 @@ unsubscribe('channel:topic', subscriptionReference)
|
|
|
132
132
|
To see an example of Portals Pub/Sub in action that manages the lifecycle of a subscription with the lifecycle of a React Native component, refer to the [`PubSubLabel`](https://github.com/ionic-team/react-native-ionic-portals/blob/af19df0d66059d85ab8dde493504368c3bf39127/example/App.tsx#L53) implementation in the example project.
|
|
133
133
|
|
|
134
134
|
### Using Capacitor Plugins
|
|
135
|
-
If you need to use any Capacitor plugins,
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
PortalManager.register("YOUR_PORTAL_KEY_HERE");
|
|
145
|
-
PortalManager.newPortal("hello")
|
|
146
|
-
.addPlugin(MyCapacitorPlugin.class) // Plugin registration
|
|
147
|
-
.setInitialContext(Map.of("greeting", "Hello, world!"))
|
|
148
|
-
.setStartDir("portals/hello")
|
|
149
|
-
.create();
|
|
135
|
+
If you need to use any Capacitor plugins, the classpath of the Android plugins will have to be provided to the `Portal` `androidPlugins` property.
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
const helloPortal = {
|
|
139
|
+
name: 'hello',
|
|
140
|
+
startDir: 'portals/hello',
|
|
141
|
+
androidPlugins: ['com.capacitorjs.plugins.camera.CameraPlugin'],
|
|
142
|
+
initialContext: {
|
|
143
|
+
greeting: 'Hello, world!'
|
|
150
144
|
}
|
|
151
|
-
}
|
|
145
|
+
};
|
|
152
146
|
```
|
|
153
147
|
|
|
154
|
-
|
|
155
|
-
```objective-c
|
|
156
|
-
@implementation RNAppDelegate
|
|
157
|
-
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDicationary *)launchOptions {
|
|
158
|
-
// React Native boilerplate
|
|
159
|
-
[PortalManager register:@"YOUR_PORTAL_KEY_HERE"];
|
|
160
|
-
PortalBuilder *builder = [[PortalBuilder alloc] init:@"hello"];
|
|
161
|
-
[builder setStartDir:@"portals/hello"];
|
|
162
|
-
[builder setInitialContext: @{ @"greeting": @"Hello, world!" }]
|
|
163
|
-
Portal *portal = [builder create];
|
|
164
|
-
[PortalManager addPortal:portal];
|
|
165
|
-
}
|
|
166
|
-
@end
|
|
167
|
-
```
|
|
148
|
+
No configuration for iOS is needed since plugins are automatically registered when the Capacitor bridge initializes on iOS.
|
|
168
149
|
|
|
169
150
|
### Bundling Your Web Apps
|
|
170
151
|
Currently there is no tooling for bundling your web apps directly as part of @ionic/portals-react-native. Please follow the [native guides](https://ionic.io/docs/portals/how-to/pull-in-web-bundle#setup-the-web-asset-directory) to manage this as part of the native build process.
|
|
171
152
|
|
|
172
|
-
|
|
173
153
|
## Registration
|
|
174
154
|
|
|
175
155
|
Ionic Portals for React Native requires a key to use. Once you have integrated Portals into your project, login to your ionic account to get a key. See our doc on [how to register for free and get your Portals license key](https://ionic.io/docs/portals/how-to/get-a-product-key) and refer to the [usage](#Usage) section on how to add your key to your React Native application.
|
|
@@ -10,12 +10,11 @@ Pod::Spec.new do |s|
|
|
|
10
10
|
s.license = package["license"]
|
|
11
11
|
s.authors = package["author"]
|
|
12
12
|
|
|
13
|
-
s.platforms = { :ios => "
|
|
13
|
+
s.platforms = { :ios => "13.0" }
|
|
14
14
|
s.source = { :git => "https://github.com/ionic-team/react-native-ionic-portals.git", :tag => "#{s.version}" }
|
|
15
15
|
|
|
16
16
|
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
17
17
|
|
|
18
18
|
s.dependency "React-Core"
|
|
19
|
-
s.dependency "IonicPortals", "0.
|
|
20
|
-
s.dependency "IonicLiveUpdates", "0.0.5"
|
|
19
|
+
s.dependency "IonicPortals", "~> 0.6.1"
|
|
21
20
|
end
|
package/android/build.gradle
CHANGED
|
@@ -38,9 +38,14 @@ android {
|
|
|
38
38
|
lintOptions {
|
|
39
39
|
disable 'GradleCompatible'
|
|
40
40
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
|
44
|
+
sourceCompatibility = JavaVersion.VERSION_1_8
|
|
45
|
+
targetCompatibility = JavaVersion.VERSION_1_8
|
|
46
|
+
|
|
47
|
+
kotlinOptions {
|
|
48
|
+
freeCompilerArgs += '-Xopt-in=kotlin.RequiresOptIn'
|
|
44
49
|
}
|
|
45
50
|
}
|
|
46
51
|
|
|
@@ -116,7 +121,12 @@ repositories {
|
|
|
116
121
|
}
|
|
117
122
|
|
|
118
123
|
dependencies {
|
|
119
|
-
//
|
|
124
|
+
//noinspection GradleDynamicVersion
|
|
120
125
|
api 'com.facebook.react:react-native:+'
|
|
121
|
-
|
|
126
|
+
//noinspection GradleDynamicVersion
|
|
127
|
+
api "io.ionic:portals:0.6.+"
|
|
128
|
+
//noinspection GradleDynamicVersion
|
|
129
|
+
api "io.ionic:liveupdates:0.0.+"
|
|
130
|
+
|
|
131
|
+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0"
|
|
122
132
|
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
package io.ionic.portals.reactnative
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.*
|
|
4
|
+
import io.ionic.liveupdates.LiveUpdate
|
|
5
|
+
import io.ionic.liveupdates.LiveUpdateManager
|
|
6
|
+
import io.ionic.liveupdates.network.FailStep
|
|
7
|
+
import io.ionic.liveupdates.network.SyncCallback
|
|
8
|
+
import kotlinx.coroutines.*
|
|
9
|
+
import kotlinx.coroutines.channels.awaitClose
|
|
10
|
+
import kotlinx.coroutines.flow.callbackFlow
|
|
11
|
+
import kotlinx.coroutines.flow.fold
|
|
12
|
+
import java.util.concurrent.Executors
|
|
13
|
+
|
|
14
|
+
internal class LiveUpdatesModule(reactContext: ReactApplicationContext) :
|
|
15
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
16
|
+
|
|
17
|
+
override fun getName() = "IONLiveUpdatesManager"
|
|
18
|
+
|
|
19
|
+
private val liveUpdateScope = CoroutineScope(
|
|
20
|
+
Executors.newFixedThreadPool(4)
|
|
21
|
+
.asCoroutineDispatcher()
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
private fun callbackToMap(
|
|
25
|
+
liveUpdate: LiveUpdate,
|
|
26
|
+
failStep: FailStep?,
|
|
27
|
+
failMsg: String?
|
|
28
|
+
): ReadableMap =
|
|
29
|
+
if (failStep != null) {
|
|
30
|
+
val map = WritableNativeMap()
|
|
31
|
+
map.putString("appId", liveUpdate.appId)
|
|
32
|
+
map.putString("failStep", failStep.name)
|
|
33
|
+
map.putString("message", failMsg ?: "Sync failed for unknown reason")
|
|
34
|
+
map
|
|
35
|
+
} else {
|
|
36
|
+
liveUpdate.toReadableMap()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private fun callbackToResult(
|
|
40
|
+
liveUpdate: LiveUpdate,
|
|
41
|
+
failStep: FailStep?,
|
|
42
|
+
failMsg: String?
|
|
43
|
+
): LiveUpdateResult =
|
|
44
|
+
if (failStep != null) {
|
|
45
|
+
LiveUpdateError(
|
|
46
|
+
appId = liveUpdate.appId,
|
|
47
|
+
failStep = failStep.name,
|
|
48
|
+
failMsg = failMsg ?: "Sync failed for unknown reason"
|
|
49
|
+
)
|
|
50
|
+
} else {
|
|
51
|
+
LiveUpdateSuccess(liveUpdate)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@ReactMethod
|
|
56
|
+
fun addLiveUpdate(map: ReadableMap) {
|
|
57
|
+
val appId = map.getString("appId") ?: return
|
|
58
|
+
val channel = map.getString("channel") ?: return
|
|
59
|
+
|
|
60
|
+
LiveUpdateManager.addLiveUpdateInstance(
|
|
61
|
+
context = reactApplicationContext,
|
|
62
|
+
liveUpdate = LiveUpdate(appId, channel)
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
@ReactMethod
|
|
67
|
+
fun syncOne(appId: String, promise: Promise) {
|
|
68
|
+
LiveUpdateManager.sync(
|
|
69
|
+
context = reactApplicationContext,
|
|
70
|
+
appId = appId,
|
|
71
|
+
callback = object : SyncCallback {
|
|
72
|
+
override fun onAppComplete(
|
|
73
|
+
liveUpdate: LiveUpdate,
|
|
74
|
+
failStep: FailStep?,
|
|
75
|
+
failMsg: String?
|
|
76
|
+
) {
|
|
77
|
+
val map = callbackToMap(liveUpdate, failStep, failMsg)
|
|
78
|
+
promise.resolve(map)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
override fun onSyncComplete() {
|
|
82
|
+
// do nothing
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
@ReactMethod
|
|
89
|
+
fun syncSome(appIds: ReadableArray, promise: Promise) {
|
|
90
|
+
@Suppress("NAME_SHADOWING")
|
|
91
|
+
val appIds = (0 until appIds.size())
|
|
92
|
+
.mapNotNull(appIds::getString)
|
|
93
|
+
.toTypedArray()
|
|
94
|
+
|
|
95
|
+
sync(appIds, promise)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
@ReactMethod
|
|
99
|
+
fun syncAll(promise: Promise) {
|
|
100
|
+
sync(emptyArray(), promise)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@OptIn(ExperimentalCoroutinesApi::class)
|
|
104
|
+
private fun sync(appIds: Array<String>, promise: Promise) {
|
|
105
|
+
liveUpdateScope.launch {
|
|
106
|
+
val results = callbackFlow {
|
|
107
|
+
LiveUpdateManager.sync(
|
|
108
|
+
context = reactApplicationContext,
|
|
109
|
+
appIds = appIds,
|
|
110
|
+
callback = object : SyncCallback {
|
|
111
|
+
override fun onAppComplete(
|
|
112
|
+
liveUpdate: LiveUpdate,
|
|
113
|
+
failStep: FailStep?,
|
|
114
|
+
failMsg: String?
|
|
115
|
+
) {
|
|
116
|
+
trySend(callbackToResult(liveUpdate, failStep, failMsg))
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
override fun onSyncComplete() {
|
|
120
|
+
close()
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
awaitClose { cancel() }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
val syncResults = results.fold(SyncResults.empty()) { syncResults, result ->
|
|
129
|
+
when (result) {
|
|
130
|
+
is LiveUpdateSuccess -> syncResults.liveUpdates.add(result.liveUpdate)
|
|
131
|
+
is LiveUpdateError -> syncResults.errors.add(result)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return@fold syncResults
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
promise.resolve(syncResults.asReadableMap)
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
fun LiveUpdate.toReadableMap(): ReadableMap {
|
|
143
|
+
val map = WritableNativeMap()
|
|
144
|
+
map.putString("appId", appId)
|
|
145
|
+
map.putString("channel", channelName)
|
|
146
|
+
return map
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private sealed class LiveUpdateResult
|
|
150
|
+
|
|
151
|
+
private data class LiveUpdateError(val appId: String, val failStep: String, val failMsg: String) :
|
|
152
|
+
LiveUpdateResult() {
|
|
153
|
+
val asReadableMap: ReadableMap
|
|
154
|
+
get() {
|
|
155
|
+
val map = WritableNativeMap()
|
|
156
|
+
map.putString("appId", appId)
|
|
157
|
+
map.putString("failStep", failStep)
|
|
158
|
+
map.putString("message", failMsg)
|
|
159
|
+
return map
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private data class LiveUpdateSuccess(val liveUpdate: LiveUpdate) : LiveUpdateResult()
|
|
164
|
+
|
|
165
|
+
private data class SyncResults(
|
|
166
|
+
val liveUpdates: MutableList<LiveUpdate>,
|
|
167
|
+
val errors: MutableList<LiveUpdateError>
|
|
168
|
+
) {
|
|
169
|
+
val asReadableMap: ReadableMap
|
|
170
|
+
get() {
|
|
171
|
+
val map = WritableNativeMap()
|
|
172
|
+
|
|
173
|
+
val liveUpdatesArray = WritableNativeArray()
|
|
174
|
+
liveUpdates.forEach { liveUpdatesArray.pushMap(it.toReadableMap()) }
|
|
175
|
+
map.putArray("liveUpdates", liveUpdatesArray)
|
|
176
|
+
|
|
177
|
+
val errorsArray = WritableNativeArray()
|
|
178
|
+
errors.forEach { errorsArray.pushMap(it.asReadableMap) }
|
|
179
|
+
map.putArray("errors", errorsArray)
|
|
180
|
+
|
|
181
|
+
return map
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
companion object {
|
|
185
|
+
fun empty() = SyncResults(mutableListOf(), mutableListOf())
|
|
186
|
+
}
|
|
187
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package io.ionic.portals.reactnative
|
|
2
2
|
|
|
3
|
+
import android.util.Log
|
|
3
4
|
import android.view.Choreographer
|
|
4
5
|
import android.view.View
|
|
5
6
|
import android.view.ViewGroup
|
|
@@ -11,16 +12,16 @@ import com.facebook.react.uimanager.ThemedReactContext
|
|
|
11
12
|
import com.facebook.react.uimanager.ViewGroupManager
|
|
12
13
|
import com.facebook.react.uimanager.annotations.ReactProp
|
|
13
14
|
import com.getcapacitor.JSObject
|
|
15
|
+
import com.getcapacitor.Plugin
|
|
16
|
+
import io.ionic.liveupdates.LiveUpdate
|
|
14
17
|
import io.ionic.portals.*
|
|
15
18
|
import org.json.JSONArray
|
|
16
19
|
import org.json.JSONException
|
|
17
20
|
import org.json.JSONObject
|
|
18
21
|
|
|
19
|
-
class PortalManagerModule(reactContext: ReactApplicationContext) :
|
|
22
|
+
internal class PortalManagerModule(reactContext: ReactApplicationContext) :
|
|
20
23
|
ReactContextBaseJavaModule(reactContext) {
|
|
21
|
-
override fun getName()
|
|
22
|
-
return "IONPortalManager"
|
|
23
|
-
}
|
|
24
|
+
override fun getName() = "IONPortalManager"
|
|
24
25
|
|
|
25
26
|
@ReactMethod
|
|
26
27
|
fun register(key: String) {
|
|
@@ -29,35 +30,51 @@ class PortalManagerModule(reactContext: ReactApplicationContext) :
|
|
|
29
30
|
|
|
30
31
|
@ReactMethod
|
|
31
32
|
fun addPortal(map: ReadableMap) {
|
|
32
|
-
map.getString("name")
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
val name = map.getString("name") ?: return
|
|
34
|
+
val portalBuilder = PortalBuilder(name)
|
|
35
|
+
|
|
36
|
+
map.getString("startDir")
|
|
37
|
+
?.let(portalBuilder::setStartDir)
|
|
38
|
+
|
|
39
|
+
map.getMap("initialContext")
|
|
40
|
+
?.toHashMap()
|
|
41
|
+
?.let(portalBuilder::setInitialContext)
|
|
42
|
+
|
|
43
|
+
map.getArray("androidPlugins")
|
|
44
|
+
?.toArrayList()
|
|
45
|
+
?.mapNotNull { it as? String }
|
|
46
|
+
?.map {
|
|
47
|
+
Class.forName(it)
|
|
48
|
+
.asSubclass(Plugin::class.java)
|
|
40
49
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
+
)
|
|
44
65
|
}
|
|
45
66
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.create()
|
|
67
|
+
val portal = portalBuilder
|
|
68
|
+
.addPlugin(PortalsPlugin::class.java)
|
|
69
|
+
.create()
|
|
50
70
|
|
|
51
|
-
|
|
52
|
-
}
|
|
71
|
+
PortalManager.addPortal(portal)
|
|
53
72
|
}
|
|
54
73
|
}
|
|
55
74
|
|
|
56
|
-
class PortalsPubSubModule(reactContext: ReactApplicationContext) :
|
|
75
|
+
internal class PortalsPubSubModule(reactContext: ReactApplicationContext) :
|
|
57
76
|
ReactContextBaseJavaModule(reactContext) {
|
|
58
|
-
override fun getName()
|
|
59
|
-
return "IONPortalsPubSub"
|
|
60
|
-
}
|
|
77
|
+
override fun getName() = "IONPortalPubSub"
|
|
61
78
|
|
|
62
79
|
@ReactMethod
|
|
63
80
|
fun subscribe(topic: String, promise: Promise) {
|
|
@@ -91,7 +108,7 @@ class PortalsPubSubModule(reactContext: ReactApplicationContext) :
|
|
|
91
108
|
}
|
|
92
109
|
}
|
|
93
110
|
|
|
94
|
-
fun JSONObject.toReactMap(): ReadableMap =
|
|
111
|
+
private fun JSONObject.toReactMap(): ReadableMap =
|
|
95
112
|
keys().asSequence().fold(WritableNativeMap()) { map, key ->
|
|
96
113
|
try {
|
|
97
114
|
when (val value = get(key)) {
|
|
@@ -110,7 +127,7 @@ fun JSONObject.toReactMap(): ReadableMap =
|
|
|
110
127
|
return@fold map
|
|
111
128
|
}
|
|
112
129
|
|
|
113
|
-
fun JSONArray.toReactArray(): ReadableArray =
|
|
130
|
+
private fun JSONArray.toReactArray(): ReadableArray =
|
|
114
131
|
(0 until length()).fold(WritableNativeArray()) { array, index ->
|
|
115
132
|
try {
|
|
116
133
|
when (val value = get(index)) {
|
|
@@ -129,26 +146,44 @@ fun JSONArray.toReactArray(): ReadableArray =
|
|
|
129
146
|
return@fold array
|
|
130
147
|
}
|
|
131
148
|
|
|
132
|
-
fun ReadableMap.toJSObject(): JSObject = JSObject.fromJSONObject(JSONObject(toHashMap()))
|
|
149
|
+
private fun ReadableMap.toJSObject(): JSObject = JSObject.fromJSONObject(JSONObject(toHashMap()))
|
|
150
|
+
|
|
151
|
+
private data class PortalViewState(
|
|
152
|
+
var fragment: PortalFragment?,
|
|
153
|
+
var portal: Portal?,
|
|
154
|
+
var initialContext: HashMap<String, Any>?
|
|
155
|
+
)
|
|
133
156
|
|
|
134
|
-
class PortalViewManager(private val context: ReactApplicationContext) :
|
|
157
|
+
internal class PortalViewManager(private val context: ReactApplicationContext) :
|
|
135
158
|
ViewGroupManager<FrameLayout>() {
|
|
136
159
|
private val createId = 1
|
|
137
|
-
private
|
|
160
|
+
private val fragmentMap = mutableMapOf<Int, PortalViewState>()
|
|
138
161
|
|
|
139
162
|
@ReactProp(name = "name")
|
|
140
163
|
fun setPortal(viewGroup: ViewGroup, portalName: String) {
|
|
141
|
-
|
|
164
|
+
when (val viewState = fragmentMap[viewGroup.id]) {
|
|
165
|
+
null -> fragmentMap[viewGroup.id] = PortalViewState(
|
|
166
|
+
fragment = null,
|
|
167
|
+
portal = PortalManager.getPortal(portalName),
|
|
168
|
+
initialContext = null
|
|
169
|
+
)
|
|
170
|
+
else -> viewState.portal = PortalManager.getPortal(portalName)
|
|
171
|
+
}
|
|
142
172
|
}
|
|
143
173
|
|
|
144
174
|
@ReactProp(name = "initialContext")
|
|
145
175
|
fun setInitialContext(viewGroup: ViewGroup, initialContext: ReadableMap) {
|
|
146
|
-
|
|
176
|
+
when (val viewState = fragmentMap[viewGroup.id]) {
|
|
177
|
+
null -> fragmentMap[viewGroup.id] = PortalViewState(
|
|
178
|
+
fragment = null,
|
|
179
|
+
portal = null,
|
|
180
|
+
initialContext = initialContext.toHashMap()
|
|
181
|
+
)
|
|
182
|
+
else -> viewState.initialContext = initialContext.toHashMap()
|
|
183
|
+
}
|
|
147
184
|
}
|
|
148
185
|
|
|
149
|
-
override fun getName()
|
|
150
|
-
return "AndroidPortalView"
|
|
151
|
-
}
|
|
186
|
+
override fun getName() = "AndroidPortalView"
|
|
152
187
|
|
|
153
188
|
override fun createViewInstance(reactContext: ThemedReactContext): FrameLayout {
|
|
154
189
|
return FrameLayout(reactContext)
|
|
@@ -161,6 +196,8 @@ class PortalViewManager(private val context: ReactApplicationContext) :
|
|
|
161
196
|
override fun receiveCommand(root: FrameLayout, commandId: String?, args: ReadableArray?) {
|
|
162
197
|
super.receiveCommand(root, commandId, args)
|
|
163
198
|
val viewId = args?.getInt(0) ?: return
|
|
199
|
+
|
|
200
|
+
@Suppress("NAME_SHADOWING")
|
|
164
201
|
val commandId = commandId?.toIntOrNull() ?: return
|
|
165
202
|
|
|
166
203
|
when (commandId) {
|
|
@@ -169,11 +206,17 @@ class PortalViewManager(private val context: ReactApplicationContext) :
|
|
|
169
206
|
}
|
|
170
207
|
|
|
171
208
|
private fun createFragment(root: FrameLayout, viewId: Int) {
|
|
172
|
-
val
|
|
209
|
+
val viewState = fragmentMap[viewId] ?: return
|
|
210
|
+
val portal = viewState.portal ?: return
|
|
211
|
+
|
|
173
212
|
val parentView = root.findViewById<ViewGroup>(viewId)
|
|
174
213
|
setupLayout(parentView)
|
|
175
214
|
|
|
176
215
|
val portalFragment = PortalFragment(portal)
|
|
216
|
+
viewState.initialContext?.let(portalFragment::setInitialContext)
|
|
217
|
+
|
|
218
|
+
viewState.fragment = portalFragment
|
|
219
|
+
|
|
177
220
|
val fragmentActivity = context.currentActivity as? FragmentActivity ?: return
|
|
178
221
|
fragmentActivity.supportFragmentManager
|
|
179
222
|
.beginTransaction()
|
|
@@ -181,6 +224,23 @@ class PortalViewManager(private val context: ReactApplicationContext) :
|
|
|
181
224
|
.commit()
|
|
182
225
|
}
|
|
183
226
|
|
|
227
|
+
override fun onDropViewInstance(view: FrameLayout) {
|
|
228
|
+
super.onDropViewInstance(view)
|
|
229
|
+
val viewState = fragmentMap[view.id] ?: return
|
|
230
|
+
|
|
231
|
+
try {
|
|
232
|
+
viewState.fragment
|
|
233
|
+
?.parentFragmentManager
|
|
234
|
+
?.beginTransaction()
|
|
235
|
+
?.remove(viewState.fragment!!)
|
|
236
|
+
?.commit()
|
|
237
|
+
} catch (e: IllegalStateException) {
|
|
238
|
+
Log.i("io.ionic.portals.rn", "Parent fragment manager not available")
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
fragmentMap.remove(view.id)
|
|
242
|
+
}
|
|
243
|
+
|
|
184
244
|
private fun setupLayout(view: ViewGroup) {
|
|
185
245
|
Choreographer.getInstance().postFrameCallback {
|
|
186
246
|
layoutChildren(view)
|
|
@@ -10,7 +10,8 @@ class ReactNativePortalsPackage : ReactPackage {
|
|
|
10
10
|
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
11
11
|
return listOf(
|
|
12
12
|
PortalManagerModule(reactContext),
|
|
13
|
-
PortalsPubSubModule(reactContext)
|
|
13
|
+
PortalsPubSubModule(reactContext),
|
|
14
|
+
LiveUpdatesModule(reactContext)
|
|
14
15
|
)
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
package/ios/Podfile
CHANGED
package/ios/Podfile.lock
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
PODS:
|
|
2
2
|
- boost-for-react-native (1.63.0)
|
|
3
|
-
- Capacitor (3.
|
|
3
|
+
- Capacitor (3.6.0):
|
|
4
4
|
- CapacitorCordova
|
|
5
|
-
- CapacitorCordova (3.
|
|
5
|
+
- CapacitorCordova (3.6.0)
|
|
6
6
|
- DoubleConversion (1.1.6)
|
|
7
7
|
- FBLazyVector (0.63.4)
|
|
8
8
|
- FBReactNativeSpec (0.63.4):
|
|
@@ -22,11 +22,10 @@ PODS:
|
|
|
22
22
|
- DoubleConversion
|
|
23
23
|
- glog
|
|
24
24
|
- glog (0.3.5)
|
|
25
|
-
- IonicLiveUpdates (0.
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
- IonicLiveUpdates
|
|
25
|
+
- IonicLiveUpdates (0.1.1)
|
|
26
|
+
- IonicPortals (0.6.1):
|
|
27
|
+
- Capacitor (~> 3.5)
|
|
28
|
+
- IonicLiveUpdates (~> 0.1.0)
|
|
30
29
|
- RCTRequired (0.63.4)
|
|
31
30
|
- RCTTypeSafety (0.63.4):
|
|
32
31
|
- FBLazyVector (= 0.63.4)
|
|
@@ -254,7 +253,6 @@ PODS:
|
|
|
254
253
|
- React-cxxreact (= 0.63.4)
|
|
255
254
|
- React-jsi (= 0.63.4)
|
|
256
255
|
- Yoga (1.14.0)
|
|
257
|
-
- ZIPFoundation (0.9.13)
|
|
258
256
|
|
|
259
257
|
DEPENDENCIES:
|
|
260
258
|
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
|
@@ -262,7 +260,7 @@ DEPENDENCIES:
|
|
|
262
260
|
- FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`)
|
|
263
261
|
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
|
|
264
262
|
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
|
|
265
|
-
- IonicPortals (~> 0.
|
|
263
|
+
- IonicPortals (~> 0.6.1)
|
|
266
264
|
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
|
|
267
265
|
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
|
|
268
266
|
- React (from `../node_modules/react-native/`)
|
|
@@ -294,7 +292,6 @@ SPEC REPOS:
|
|
|
294
292
|
- CapacitorCordova
|
|
295
293
|
- IonicLiveUpdates
|
|
296
294
|
- IonicPortals
|
|
297
|
-
- ZIPFoundation
|
|
298
295
|
|
|
299
296
|
EXTERNAL SOURCES:
|
|
300
297
|
DoubleConversion:
|
|
@@ -352,15 +349,15 @@ EXTERNAL SOURCES:
|
|
|
352
349
|
|
|
353
350
|
SPEC CHECKSUMS:
|
|
354
351
|
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
|
|
355
|
-
Capacitor:
|
|
356
|
-
CapacitorCordova:
|
|
352
|
+
Capacitor: 28d6f7c3b02858b0696c98d27527ffb1ac8aba8f
|
|
353
|
+
CapacitorCordova: 23b4def1cd6a8c463074916376f511d7446d683e
|
|
357
354
|
DoubleConversion: cde416483dac037923206447da6e1454df403714
|
|
358
355
|
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
|
|
359
356
|
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
|
|
360
357
|
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
|
|
361
358
|
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
|
|
362
|
-
IonicLiveUpdates:
|
|
363
|
-
IonicPortals:
|
|
359
|
+
IonicLiveUpdates: 5fb89c6faed266d083691e64f33710211edb3839
|
|
360
|
+
IonicPortals: 17b9ee9ae513fc3906b062bdd0b7492db94e38ce
|
|
364
361
|
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
|
|
365
362
|
RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b
|
|
366
363
|
React: b0a957a2c44da4113b0c4c9853d8387f8e64e615
|
|
@@ -382,8 +379,7 @@ SPEC CHECKSUMS:
|
|
|
382
379
|
React-RCTVibration: ae4f914cfe8de7d4de95ae1ea6cc8f6315d73d9d
|
|
383
380
|
ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
|
|
384
381
|
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
|
|
385
|
-
ZIPFoundation: ae5b4b813d216d3bf0a148773267fff14bd51d37
|
|
386
382
|
|
|
387
|
-
PODFILE CHECKSUM:
|
|
383
|
+
PODFILE CHECKSUM: 67d6b2cc79c25d2c4dcf32d6e3c6d6e6defffdb1
|
|
388
384
|
|
|
389
385
|
COCOAPODS: 1.11.2
|
package/ios/PortalsPubSub.m
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
#import <React/RCTBridgeModule.h>
|
|
10
10
|
#import <React/RCTEventEmitter.h>
|
|
11
11
|
|
|
12
|
-
@interface RCT_EXTERN_MODULE(
|
|
12
|
+
@interface RCT_EXTERN_MODULE(IONPortalPubSub, RCTEventEmitter)
|
|
13
13
|
RCT_EXTERN_METHOD(subscribe: (NSString *) topic resolver: (RCTPromiseResolveBlock) resolver rejector: (RCTPromiseRejectBlock) rejector)
|
|
14
14
|
RCT_EXTERN_METHOD(unsubscribe: (NSString *) topic subscriptionRef: (NSNumber _Nonnull) subscriptionRef)
|
|
15
15
|
RCT_EXTERN_METHOD(publish: (NSString *) topic data: (id) data)
|
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import IonicPortals
|
|
3
|
+
import IonicLiveUpdates
|
|
3
4
|
import React
|
|
4
5
|
import UIKit
|
|
6
|
+
import Capacitor
|
|
5
7
|
|
|
6
8
|
@objc(IONPortalManager)
|
|
7
|
-
class PortalManager: NSObject {
|
|
8
|
-
private
|
|
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] }
|
|
9
21
|
|
|
10
22
|
@objc func register(_ key: String) {
|
|
11
|
-
|
|
23
|
+
Self.register(key)
|
|
12
24
|
}
|
|
13
25
|
|
|
14
26
|
@objc func addPortal(_ portalDict: [String: Any]) {
|
|
15
|
-
guard let
|
|
16
|
-
|
|
17
|
-
portal.initialContext = portalDict["initialContext"] as? [String: Any]
|
|
18
|
-
IonPortalManager.addPortal(portal)
|
|
27
|
+
guard let portal = Portal(portalDict) else { return }
|
|
28
|
+
Self.add(portal)
|
|
19
29
|
}
|
|
20
30
|
|
|
21
31
|
@objc static func requiresMainQueueSetup() -> Bool { true }
|
|
22
32
|
}
|
|
23
33
|
|
|
24
|
-
@objc(
|
|
34
|
+
@objc(IONPortalPubSub)
|
|
25
35
|
class PortalsPubSub: RCTEventEmitter {
|
|
26
36
|
private let eventName = "PortalsSubscription"
|
|
27
37
|
|
|
@@ -30,7 +40,7 @@ class PortalsPubSub: RCTEventEmitter {
|
|
|
30
40
|
}
|
|
31
41
|
|
|
32
42
|
@objc func subscribe(_ topic: String, resolver: RCTPromiseResolveBlock, rejector: RCTPromiseRejectBlock) {
|
|
33
|
-
let subRef =
|
|
43
|
+
let subRef = IonicPortals.PortalsPubSub.subscribe(topic) { [weak self] result in
|
|
34
44
|
guard let self = self else { return }
|
|
35
45
|
self.sendEvent(
|
|
36
46
|
withName: self.eventName,
|
|
@@ -46,11 +56,11 @@ class PortalsPubSub: RCTEventEmitter {
|
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
@objc func unsubscribe(_ topic: String, subscriptionRef: NSNumber) {
|
|
49
|
-
|
|
59
|
+
IonicPortals.PortalsPubSub.unsubscribe(from: topic, subscriptionRef: subscriptionRef.intValue)
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
@objc func publish(_ topic: String, data: Any) {
|
|
53
|
-
|
|
63
|
+
IONPortalsPubSub.publish(message: data, topic: topic)
|
|
54
64
|
}
|
|
55
65
|
|
|
56
66
|
override class func requiresMainQueueSetup() -> Bool { true }
|
|
@@ -63,7 +73,7 @@ class PortalViewManager: RCTViewManager {
|
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
class PortalView: UIView {
|
|
66
|
-
private var webView:
|
|
76
|
+
private var webView: PortalUIView?
|
|
67
77
|
|
|
68
78
|
@objc var name: String? {
|
|
69
79
|
get {
|
|
@@ -73,7 +83,7 @@ class PortalView: UIView {
|
|
|
73
83
|
|
|
74
84
|
set {
|
|
75
85
|
guard let portalName = newValue else { return }
|
|
76
|
-
_portal =
|
|
86
|
+
_portal = PortalManager.getPortal(named: portalName)
|
|
77
87
|
}
|
|
78
88
|
}
|
|
79
89
|
|
|
@@ -85,8 +95,8 @@ class PortalView: UIView {
|
|
|
85
95
|
|
|
86
96
|
set {
|
|
87
97
|
guard let name = name else { return }
|
|
88
|
-
_portal =
|
|
89
|
-
_portal?.initialContext = newValue
|
|
98
|
+
_portal = PortalManager.getPortal(named: name)
|
|
99
|
+
_portal?.initialContext = JSTypes.coerceDictionaryToJSObject(newValue) ?? [:]
|
|
90
100
|
}
|
|
91
101
|
}
|
|
92
102
|
|
|
@@ -96,7 +106,7 @@ class PortalView: UIView {
|
|
|
96
106
|
DispatchQueue.main.async { [weak self] in
|
|
97
107
|
guard let self = self else { return }
|
|
98
108
|
self.webView?.removeFromSuperview()
|
|
99
|
-
let webView =
|
|
109
|
+
let webView = PortalUIView(portal: portal)
|
|
100
110
|
webView.translatesAutoresizingMaskIntoConstraints = false
|
|
101
111
|
self.addSubview(webView)
|
|
102
112
|
NSLayoutConstraint.activate([
|
|
@@ -111,3 +121,142 @@ class PortalView: UIView {
|
|
|
111
121
|
}
|
|
112
122
|
}
|
|
113
123
|
|
|
124
|
+
extension Portal {
|
|
125
|
+
init?(_ dict: [String: Any]) {
|
|
126
|
+
guard let name = dict["name"] as? String else { return nil }
|
|
127
|
+
self.init(
|
|
128
|
+
name: name,
|
|
129
|
+
startDir: dict["startDir"] as? String,
|
|
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
|
+
}
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
A7128A0827F7A16200DADDF3 /* ReactNativePortals-Bridging-Header.h in Headers */ = {isa = PBXBuildFile; fileRef = F4FF95D5245B92E700C19C63 /* ReactNativePortals-Bridging-Header.h */; };
|
|
14
14
|
A7128A0927F7A16200DADDF3 /* PortalsPubSub.m in Sources */ = {isa = PBXBuildFile; fileRef = A71289F827F79D4000DADDF3 /* PortalsPubSub.m */; };
|
|
15
15
|
A7128A0A27F7A16200DADDF3 /* PortalView.m in Sources */ = {isa = PBXBuildFile; fileRef = A71289F727F79CDC00DADDF3 /* PortalView.m */; };
|
|
16
|
+
A748ABFC28626EC300F26852 /* LiveUpdatesManager.m in Sources */ = {isa = PBXBuildFile; fileRef = A748ABFB28626EC300F26852 /* LiveUpdatesManager.m */; };
|
|
16
17
|
/* End PBXBuildFile section */
|
|
17
18
|
|
|
18
19
|
/* Begin PBXFileReference section */
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
A71289F827F79D4000DADDF3 /* PortalsPubSub.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PortalsPubSub.m; sourceTree = "<group>"; };
|
|
22
23
|
A71289F927F79EB200DADDF3 /* PortalManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PortalManager.m; sourceTree = "<group>"; };
|
|
23
24
|
A71289FF27F7A14900DADDF3 /* ReactNativePortals.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ReactNativePortals.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
25
|
+
A748ABFB28626EC300F26852 /* LiveUpdatesManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LiveUpdatesManager.m; sourceTree = "<group>"; };
|
|
24
26
|
CB9439A9444D2E97DA3B8149 /* Pods-ReactNativePortals.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ReactNativePortals.debug.xcconfig"; path = "Target Support Files/Pods-ReactNativePortals/Pods-ReactNativePortals.debug.xcconfig"; sourceTree = "<group>"; };
|
|
25
27
|
F4FF95D5245B92E700C19C63 /* ReactNativePortals-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ReactNativePortals-Bridging-Header.h"; sourceTree = "<group>"; };
|
|
26
28
|
F4FF95D6245B92E800C19C63 /* ReactNativePortals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactNativePortals.swift; sourceTree = "<group>"; };
|
|
@@ -57,6 +59,7 @@
|
|
|
57
59
|
58B511D21A9E6C8500147676 = {
|
|
58
60
|
isa = PBXGroup;
|
|
59
61
|
children = (
|
|
62
|
+
A748ABFB28626EC300F26852 /* LiveUpdatesManager.m */,
|
|
60
63
|
F4FF95D6245B92E800C19C63 /* ReactNativePortals.swift */,
|
|
61
64
|
A71289F727F79CDC00DADDF3 /* PortalView.m */,
|
|
62
65
|
A71289F927F79EB200DADDF3 /* PortalManager.m */,
|
|
@@ -183,6 +186,7 @@
|
|
|
183
186
|
isa = PBXSourcesBuildPhase;
|
|
184
187
|
buildActionMask = 2147483647;
|
|
185
188
|
files = (
|
|
189
|
+
A748ABFC28626EC300F26852 /* LiveUpdatesManager.m in Sources */,
|
|
186
190
|
A7128A0A27F7A16200DADDF3 /* PortalView.m in Sources */,
|
|
187
191
|
A7128A0927F7A16200DADDF3 /* PortalsPubSub.m in Sources */,
|
|
188
192
|
A7128A0627F7A16200DADDF3 /* ReactNativePortals.swift in Sources */,
|
package/lib/commonjs/index.js
CHANGED
|
@@ -9,7 +9,7 @@ Object.defineProperty(exports, "PortalView", {
|
|
|
9
9
|
return _PortalView.default;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
|
-
exports.unsubscribe = exports.subscribe = exports.register = exports.publish = exports.addPortal = void 0;
|
|
12
|
+
exports.unsubscribe = exports.syncSome = exports.syncOne = exports.syncAll = exports.subscribe = exports.register = exports.publish = exports.addPortal = void 0;
|
|
13
13
|
|
|
14
14
|
var _reactNative = require("react-native");
|
|
15
15
|
|
|
@@ -18,14 +18,15 @@ var _PortalView = _interopRequireDefault(require("./PortalView"));
|
|
|
18
18
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
19
|
|
|
20
20
|
const {
|
|
21
|
-
|
|
22
|
-
IONPortalManager
|
|
21
|
+
IONPortalPubSub,
|
|
22
|
+
IONPortalManager,
|
|
23
|
+
IONLiveUpdatesManager
|
|
23
24
|
} = _reactNative.NativeModules;
|
|
24
|
-
const PortalsPubSub = new _reactNative.NativeEventEmitter(
|
|
25
|
+
const PortalsPubSub = new _reactNative.NativeEventEmitter(IONPortalPubSub);
|
|
25
26
|
const subscriptionMap = new Map();
|
|
26
27
|
|
|
27
28
|
const subscribe = async (topic, onMessageReceived) => {
|
|
28
|
-
const subscriptionRef = await
|
|
29
|
+
const subscriptionRef = await IONPortalPubSub.subscribe(topic);
|
|
29
30
|
const subscriber = PortalsPubSub.addListener('PortalsSubscription', message => {
|
|
30
31
|
if (message.subscriptionRef === subscriptionRef) {
|
|
31
32
|
onMessageReceived(message);
|
|
@@ -38,7 +39,7 @@ const subscribe = async (topic, onMessageReceived) => {
|
|
|
38
39
|
exports.subscribe = subscribe;
|
|
39
40
|
|
|
40
41
|
const unsubscribe = (topic, subRef) => {
|
|
41
|
-
|
|
42
|
+
IONPortalPubSub.unsubscribe(topic, subRef);
|
|
42
43
|
const subscription = subscriptionMap.get(subRef);
|
|
43
44
|
|
|
44
45
|
if (subscription !== undefined) {
|
|
@@ -53,7 +54,7 @@ const publish = (topic, data) => {
|
|
|
53
54
|
const msg = {
|
|
54
55
|
message: data
|
|
55
56
|
};
|
|
56
|
-
|
|
57
|
+
IONPortalPubSub.publish(topic, msg);
|
|
57
58
|
};
|
|
58
59
|
|
|
59
60
|
exports.publish = publish;
|
|
@@ -69,4 +70,22 @@ const addPortal = portal => {
|
|
|
69
70
|
};
|
|
70
71
|
|
|
71
72
|
exports.addPortal = addPortal;
|
|
73
|
+
|
|
74
|
+
const syncOne = appId => {
|
|
75
|
+
return IONLiveUpdatesManager.syncOne(appId);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
exports.syncOne = syncOne;
|
|
79
|
+
|
|
80
|
+
const syncSome = appIds => {
|
|
81
|
+
return IONLiveUpdatesManager.syncSome(appIds);
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
exports.syncSome = syncSome;
|
|
85
|
+
|
|
86
|
+
const syncAll = () => {
|
|
87
|
+
return IONLiveUpdatesManager.syncAll();
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
exports.syncAll = syncAll;
|
|
72
91
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["
|
|
1
|
+
{"version":3,"names":["IONPortalPubSub","IONPortalManager","IONLiveUpdatesManager","NativeModules","PortalsPubSub","NativeEventEmitter","subscriptionMap","Map","subscribe","topic","onMessageReceived","subscriptionRef","subscriber","addListener","message","set","unsubscribe","subRef","subscription","get","undefined","remove","delete","publish","data","msg","register","key","addPortal","portal","syncOne","appId","syncSome","appIds","syncAll"],"sources":["index.ts"],"sourcesContent":["import {\n EmitterSubscription,\n NativeEventEmitter,\n NativeModules,\n ViewProps,\n} from 'react-native';\n\nconst { IONPortalPubSub, IONPortalManager, IONLiveUpdatesManager } =\n NativeModules;\n\nexport { default as PortalView } from './PortalView';\n\nexport interface Message {\n subscriptionRef: number;\n data: any;\n topic: string;\n}\n\nconst PortalsPubSub = new NativeEventEmitter(IONPortalPubSub);\n\nconst subscriptionMap = new Map<number, EmitterSubscription>();\n\nexport const subscribe = async (\n topic: string,\n onMessageReceived: (message: Message) => void\n): Promise<number> => {\n const subscriptionRef = await IONPortalPubSub.subscribe(topic);\n\n const subscriber = PortalsPubSub.addListener(\n 'PortalsSubscription',\n (message: Message) => {\n if (message.subscriptionRef === subscriptionRef) {\n onMessageReceived(message);\n }\n }\n );\n\n subscriptionMap.set(subscriptionRef, subscriber);\n\n return subscriptionRef;\n};\n\nexport const unsubscribe = (topic: string, subRef: number) => {\n IONPortalPubSub.unsubscribe(topic, subRef);\n\n const subscription = subscriptionMap.get(subRef);\n if (subscription !== undefined) {\n subscription.remove();\n subscriptionMap.delete(subRef);\n }\n};\n\nexport const publish = (topic: string, data: any) => {\n const msg = { message: data };\n IONPortalPubSub.publish(topic, msg);\n};\n\nexport const register = (key: string) => {\n IONPortalManager.register(key);\n};\n\nexport interface Portal {\n name: string;\n androidPlugins?: string[];\n startDir?: string;\n initialContext?: {\n [key: string]: any;\n };\n liveUpdate?: LiveUpdateConfig;\n}\n\nexport type PortalProps = Pick<Portal, 'name' | 'initialContext'> & ViewProps;\n\nexport const addPortal = (portal: Portal) => {\n IONPortalManager.addPortal(portal);\n};\n\nexport interface LiveUpdate {\n appId: string;\n channel: string;\n}\n\nexport type LiveUpdateConfig = LiveUpdate & { syncOnAdd: boolean };\n\nexport interface LiveUpdateError {\n appId: string;\n failStep: string;\n message: string;\n}\n\nexport interface SyncResults {\n liveUpdates: LiveUpdate[];\n errors: LiveUpdateError[];\n}\n\nexport const syncOne = (appId: string): Promise<LiveUpdate> => {\n return IONLiveUpdatesManager.syncOne(appId);\n};\n\nexport const syncSome = (appIds: string[]): Promise<SyncResults> => {\n return IONLiveUpdatesManager.syncSome(appIds);\n};\n\nexport const syncAll = (): Promise<SyncResults> => {\n return IONLiveUpdatesManager.syncAll();\n};\n"],"mappings":";;;;;;;;;;;;;AAAA;;AAUA;;;;AAHA,MAAM;EAAEA,eAAF;EAAmBC,gBAAnB;EAAqCC;AAArC,IACJC,0BADF;AAWA,MAAMC,aAAa,GAAG,IAAIC,+BAAJ,CAAuBL,eAAvB,CAAtB;AAEA,MAAMM,eAAe,GAAG,IAAIC,GAAJ,EAAxB;;AAEO,MAAMC,SAAS,GAAG,OACvBC,KADuB,EAEvBC,iBAFuB,KAGH;EACpB,MAAMC,eAAe,GAAG,MAAMX,eAAe,CAACQ,SAAhB,CAA0BC,KAA1B,CAA9B;EAEA,MAAMG,UAAU,GAAGR,aAAa,CAACS,WAAd,CACjB,qBADiB,EAEhBC,OAAD,IAAsB;IACpB,IAAIA,OAAO,CAACH,eAAR,KAA4BA,eAAhC,EAAiD;MAC/CD,iBAAiB,CAACI,OAAD,CAAjB;IACD;EACF,CANgB,CAAnB;EASAR,eAAe,CAACS,GAAhB,CAAoBJ,eAApB,EAAqCC,UAArC;EAEA,OAAOD,eAAP;AACD,CAlBM;;;;AAoBA,MAAMK,WAAW,GAAG,CAACP,KAAD,EAAgBQ,MAAhB,KAAmC;EAC5DjB,eAAe,CAACgB,WAAhB,CAA4BP,KAA5B,EAAmCQ,MAAnC;EAEA,MAAMC,YAAY,GAAGZ,eAAe,CAACa,GAAhB,CAAoBF,MAApB,CAArB;;EACA,IAAIC,YAAY,KAAKE,SAArB,EAAgC;IAC9BF,YAAY,CAACG,MAAb;IACAf,eAAe,CAACgB,MAAhB,CAAuBL,MAAvB;EACD;AACF,CARM;;;;AAUA,MAAMM,OAAO,GAAG,CAACd,KAAD,EAAgBe,IAAhB,KAA8B;EACnD,MAAMC,GAAG,GAAG;IAAEX,OAAO,EAAEU;EAAX,CAAZ;EACAxB,eAAe,CAACuB,OAAhB,CAAwBd,KAAxB,EAA+BgB,GAA/B;AACD,CAHM;;;;AAKA,MAAMC,QAAQ,GAAIC,GAAD,IAAiB;EACvC1B,gBAAgB,CAACyB,QAAjB,CAA0BC,GAA1B;AACD,CAFM;;;;AAgBA,MAAMC,SAAS,GAAIC,MAAD,IAAoB;EAC3C5B,gBAAgB,CAAC2B,SAAjB,CAA2BC,MAA3B;AACD,CAFM;;;;AAsBA,MAAMC,OAAO,GAAIC,KAAD,IAAwC;EAC7D,OAAO7B,qBAAqB,CAAC4B,OAAtB,CAA8BC,KAA9B,CAAP;AACD,CAFM;;;;AAIA,MAAMC,QAAQ,GAAIC,MAAD,IAA4C;EAClE,OAAO/B,qBAAqB,CAAC8B,QAAtB,CAA+BC,MAA/B,CAAP;AACD,CAFM;;;;AAIA,MAAMC,OAAO,GAAG,MAA4B;EACjD,OAAOhC,qBAAqB,CAACgC,OAAtB,EAAP;AACD,CAFM"}
|
package/lib/module/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { NativeEventEmitter, NativeModules } from 'react-native';
|
|
2
2
|
const {
|
|
3
|
-
|
|
4
|
-
IONPortalManager
|
|
3
|
+
IONPortalPubSub,
|
|
4
|
+
IONPortalManager,
|
|
5
|
+
IONLiveUpdatesManager
|
|
5
6
|
} = NativeModules;
|
|
6
7
|
export { default as PortalView } from './PortalView';
|
|
7
|
-
const PortalsPubSub = new NativeEventEmitter(
|
|
8
|
+
const PortalsPubSub = new NativeEventEmitter(IONPortalPubSub);
|
|
8
9
|
const subscriptionMap = new Map();
|
|
9
10
|
export const subscribe = async (topic, onMessageReceived) => {
|
|
10
|
-
const subscriptionRef = await
|
|
11
|
+
const subscriptionRef = await IONPortalPubSub.subscribe(topic);
|
|
11
12
|
const subscriber = PortalsPubSub.addListener('PortalsSubscription', message => {
|
|
12
13
|
if (message.subscriptionRef === subscriptionRef) {
|
|
13
14
|
onMessageReceived(message);
|
|
@@ -17,7 +18,7 @@ export const subscribe = async (topic, onMessageReceived) => {
|
|
|
17
18
|
return subscriptionRef;
|
|
18
19
|
};
|
|
19
20
|
export const unsubscribe = (topic, subRef) => {
|
|
20
|
-
|
|
21
|
+
IONPortalPubSub.unsubscribe(topic, subRef);
|
|
21
22
|
const subscription = subscriptionMap.get(subRef);
|
|
22
23
|
|
|
23
24
|
if (subscription !== undefined) {
|
|
@@ -29,7 +30,7 @@ export const publish = (topic, data) => {
|
|
|
29
30
|
const msg = {
|
|
30
31
|
message: data
|
|
31
32
|
};
|
|
32
|
-
|
|
33
|
+
IONPortalPubSub.publish(topic, msg);
|
|
33
34
|
};
|
|
34
35
|
export const register = key => {
|
|
35
36
|
IONPortalManager.register(key);
|
|
@@ -37,4 +38,13 @@ export const register = key => {
|
|
|
37
38
|
export const addPortal = portal => {
|
|
38
39
|
IONPortalManager.addPortal(portal);
|
|
39
40
|
};
|
|
41
|
+
export const syncOne = appId => {
|
|
42
|
+
return IONLiveUpdatesManager.syncOne(appId);
|
|
43
|
+
};
|
|
44
|
+
export const syncSome = appIds => {
|
|
45
|
+
return IONLiveUpdatesManager.syncSome(appIds);
|
|
46
|
+
};
|
|
47
|
+
export const syncAll = () => {
|
|
48
|
+
return IONLiveUpdatesManager.syncAll();
|
|
49
|
+
};
|
|
40
50
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeEventEmitter","NativeModules","
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","NativeModules","IONPortalPubSub","IONPortalManager","IONLiveUpdatesManager","default","PortalView","PortalsPubSub","subscriptionMap","Map","subscribe","topic","onMessageReceived","subscriptionRef","subscriber","addListener","message","set","unsubscribe","subRef","subscription","get","undefined","remove","delete","publish","data","msg","register","key","addPortal","portal","syncOne","appId","syncSome","appIds","syncAll"],"sources":["index.ts"],"sourcesContent":["import {\n EmitterSubscription,\n NativeEventEmitter,\n NativeModules,\n ViewProps,\n} from 'react-native';\n\nconst { IONPortalPubSub, IONPortalManager, IONLiveUpdatesManager } =\n NativeModules;\n\nexport { default as PortalView } from './PortalView';\n\nexport interface Message {\n subscriptionRef: number;\n data: any;\n topic: string;\n}\n\nconst PortalsPubSub = new NativeEventEmitter(IONPortalPubSub);\n\nconst subscriptionMap = new Map<number, EmitterSubscription>();\n\nexport const subscribe = async (\n topic: string,\n onMessageReceived: (message: Message) => void\n): Promise<number> => {\n const subscriptionRef = await IONPortalPubSub.subscribe(topic);\n\n const subscriber = PortalsPubSub.addListener(\n 'PortalsSubscription',\n (message: Message) => {\n if (message.subscriptionRef === subscriptionRef) {\n onMessageReceived(message);\n }\n }\n );\n\n subscriptionMap.set(subscriptionRef, subscriber);\n\n return subscriptionRef;\n};\n\nexport const unsubscribe = (topic: string, subRef: number) => {\n IONPortalPubSub.unsubscribe(topic, subRef);\n\n const subscription = subscriptionMap.get(subRef);\n if (subscription !== undefined) {\n subscription.remove();\n subscriptionMap.delete(subRef);\n }\n};\n\nexport const publish = (topic: string, data: any) => {\n const msg = { message: data };\n IONPortalPubSub.publish(topic, msg);\n};\n\nexport const register = (key: string) => {\n IONPortalManager.register(key);\n};\n\nexport interface Portal {\n name: string;\n androidPlugins?: string[];\n startDir?: string;\n initialContext?: {\n [key: string]: any;\n };\n liveUpdate?: LiveUpdateConfig;\n}\n\nexport type PortalProps = Pick<Portal, 'name' | 'initialContext'> & ViewProps;\n\nexport const addPortal = (portal: Portal) => {\n IONPortalManager.addPortal(portal);\n};\n\nexport interface LiveUpdate {\n appId: string;\n channel: string;\n}\n\nexport type LiveUpdateConfig = LiveUpdate & { syncOnAdd: boolean };\n\nexport interface LiveUpdateError {\n appId: string;\n failStep: string;\n message: string;\n}\n\nexport interface SyncResults {\n liveUpdates: LiveUpdate[];\n errors: LiveUpdateError[];\n}\n\nexport const syncOne = (appId: string): Promise<LiveUpdate> => {\n return IONLiveUpdatesManager.syncOne(appId);\n};\n\nexport const syncSome = (appIds: string[]): Promise<SyncResults> => {\n return IONLiveUpdatesManager.syncSome(appIds);\n};\n\nexport const syncAll = (): Promise<SyncResults> => {\n return IONLiveUpdatesManager.syncAll();\n};\n"],"mappings":"AAAA,SAEEA,kBAFF,EAGEC,aAHF,QAKO,cALP;AAOA,MAAM;EAAEC,eAAF;EAAmBC,gBAAnB;EAAqCC;AAArC,IACJH,aADF;AAGA,SAASI,OAAO,IAAIC,UAApB,QAAsC,cAAtC;AAQA,MAAMC,aAAa,GAAG,IAAIP,kBAAJ,CAAuBE,eAAvB,CAAtB;AAEA,MAAMM,eAAe,GAAG,IAAIC,GAAJ,EAAxB;AAEA,OAAO,MAAMC,SAAS,GAAG,OACvBC,KADuB,EAEvBC,iBAFuB,KAGH;EACpB,MAAMC,eAAe,GAAG,MAAMX,eAAe,CAACQ,SAAhB,CAA0BC,KAA1B,CAA9B;EAEA,MAAMG,UAAU,GAAGP,aAAa,CAACQ,WAAd,CACjB,qBADiB,EAEhBC,OAAD,IAAsB;IACpB,IAAIA,OAAO,CAACH,eAAR,KAA4BA,eAAhC,EAAiD;MAC/CD,iBAAiB,CAACI,OAAD,CAAjB;IACD;EACF,CANgB,CAAnB;EASAR,eAAe,CAACS,GAAhB,CAAoBJ,eAApB,EAAqCC,UAArC;EAEA,OAAOD,eAAP;AACD,CAlBM;AAoBP,OAAO,MAAMK,WAAW,GAAG,CAACP,KAAD,EAAgBQ,MAAhB,KAAmC;EAC5DjB,eAAe,CAACgB,WAAhB,CAA4BP,KAA5B,EAAmCQ,MAAnC;EAEA,MAAMC,YAAY,GAAGZ,eAAe,CAACa,GAAhB,CAAoBF,MAApB,CAArB;;EACA,IAAIC,YAAY,KAAKE,SAArB,EAAgC;IAC9BF,YAAY,CAACG,MAAb;IACAf,eAAe,CAACgB,MAAhB,CAAuBL,MAAvB;EACD;AACF,CARM;AAUP,OAAO,MAAMM,OAAO,GAAG,CAACd,KAAD,EAAgBe,IAAhB,KAA8B;EACnD,MAAMC,GAAG,GAAG;IAAEX,OAAO,EAAEU;EAAX,CAAZ;EACAxB,eAAe,CAACuB,OAAhB,CAAwBd,KAAxB,EAA+BgB,GAA/B;AACD,CAHM;AAKP,OAAO,MAAMC,QAAQ,GAAIC,GAAD,IAAiB;EACvC1B,gBAAgB,CAACyB,QAAjB,CAA0BC,GAA1B;AACD,CAFM;AAgBP,OAAO,MAAMC,SAAS,GAAIC,MAAD,IAAoB;EAC3C5B,gBAAgB,CAAC2B,SAAjB,CAA2BC,MAA3B;AACD,CAFM;AAsBP,OAAO,MAAMC,OAAO,GAAIC,KAAD,IAAwC;EAC7D,OAAO7B,qBAAqB,CAAC4B,OAAtB,CAA8BC,KAA9B,CAAP;AACD,CAFM;AAIP,OAAO,MAAMC,QAAQ,GAAIC,MAAD,IAA4C;EAClE,OAAO/B,qBAAqB,CAAC8B,QAAtB,CAA+BC,MAA/B,CAAP;AACD,CAFM;AAIP,OAAO,MAAMC,OAAO,GAAG,MAA4B;EACjD,OAAOhC,qBAAqB,CAACgC,OAAtB,EAAP;AACD,CAFM"}
|
|
@@ -11,8 +11,31 @@ export declare const publish: (topic: string, data: any) => void;
|
|
|
11
11
|
export declare const register: (key: string) => void;
|
|
12
12
|
export interface Portal {
|
|
13
13
|
name: string;
|
|
14
|
+
androidPlugins?: string[];
|
|
14
15
|
startDir?: string;
|
|
15
|
-
initialContext?:
|
|
16
|
+
initialContext?: {
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
};
|
|
19
|
+
liveUpdate?: LiveUpdateConfig;
|
|
16
20
|
}
|
|
17
21
|
export declare type PortalProps = Pick<Portal, 'name' | 'initialContext'> & ViewProps;
|
|
18
22
|
export declare const addPortal: (portal: Portal) => void;
|
|
23
|
+
export interface LiveUpdate {
|
|
24
|
+
appId: string;
|
|
25
|
+
channel: string;
|
|
26
|
+
}
|
|
27
|
+
export declare type LiveUpdateConfig = LiveUpdate & {
|
|
28
|
+
syncOnAdd: boolean;
|
|
29
|
+
};
|
|
30
|
+
export interface LiveUpdateError {
|
|
31
|
+
appId: string;
|
|
32
|
+
failStep: string;
|
|
33
|
+
message: string;
|
|
34
|
+
}
|
|
35
|
+
export interface SyncResults {
|
|
36
|
+
liveUpdates: LiveUpdate[];
|
|
37
|
+
errors: LiveUpdateError[];
|
|
38
|
+
}
|
|
39
|
+
export declare const syncOne: (appId: string) => Promise<LiveUpdate>;
|
|
40
|
+
export declare const syncSome: (appIds: string[]) => Promise<SyncResults>;
|
|
41
|
+
export declare const syncAll: () => Promise<SyncResults>;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -5,7 +5,8 @@ import {
|
|
|
5
5
|
ViewProps,
|
|
6
6
|
} from 'react-native';
|
|
7
7
|
|
|
8
|
-
const {
|
|
8
|
+
const { IONPortalPubSub, IONPortalManager, IONLiveUpdatesManager } =
|
|
9
|
+
NativeModules;
|
|
9
10
|
|
|
10
11
|
export { default as PortalView } from './PortalView';
|
|
11
12
|
|
|
@@ -15,7 +16,7 @@ export interface Message {
|
|
|
15
16
|
topic: string;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
const PortalsPubSub = new NativeEventEmitter(
|
|
19
|
+
const PortalsPubSub = new NativeEventEmitter(IONPortalPubSub);
|
|
19
20
|
|
|
20
21
|
const subscriptionMap = new Map<number, EmitterSubscription>();
|
|
21
22
|
|
|
@@ -23,7 +24,7 @@ export const subscribe = async (
|
|
|
23
24
|
topic: string,
|
|
24
25
|
onMessageReceived: (message: Message) => void
|
|
25
26
|
): Promise<number> => {
|
|
26
|
-
const subscriptionRef = await
|
|
27
|
+
const subscriptionRef = await IONPortalPubSub.subscribe(topic);
|
|
27
28
|
|
|
28
29
|
const subscriber = PortalsPubSub.addListener(
|
|
29
30
|
'PortalsSubscription',
|
|
@@ -40,7 +41,7 @@ export const subscribe = async (
|
|
|
40
41
|
};
|
|
41
42
|
|
|
42
43
|
export const unsubscribe = (topic: string, subRef: number) => {
|
|
43
|
-
|
|
44
|
+
IONPortalPubSub.unsubscribe(topic, subRef);
|
|
44
45
|
|
|
45
46
|
const subscription = subscriptionMap.get(subRef);
|
|
46
47
|
if (subscription !== undefined) {
|
|
@@ -51,7 +52,7 @@ export const unsubscribe = (topic: string, subRef: number) => {
|
|
|
51
52
|
|
|
52
53
|
export const publish = (topic: string, data: any) => {
|
|
53
54
|
const msg = { message: data };
|
|
54
|
-
|
|
55
|
+
IONPortalPubSub.publish(topic, msg);
|
|
55
56
|
};
|
|
56
57
|
|
|
57
58
|
export const register = (key: string) => {
|
|
@@ -60,8 +61,12 @@ export const register = (key: string) => {
|
|
|
60
61
|
|
|
61
62
|
export interface Portal {
|
|
62
63
|
name: string;
|
|
64
|
+
androidPlugins?: string[];
|
|
63
65
|
startDir?: string;
|
|
64
|
-
initialContext?:
|
|
66
|
+
initialContext?: {
|
|
67
|
+
[key: string]: any;
|
|
68
|
+
};
|
|
69
|
+
liveUpdate?: LiveUpdateConfig;
|
|
65
70
|
}
|
|
66
71
|
|
|
67
72
|
export type PortalProps = Pick<Portal, 'name' | 'initialContext'> & ViewProps;
|
|
@@ -69,3 +74,33 @@ export type PortalProps = Pick<Portal, 'name' | 'initialContext'> & ViewProps;
|
|
|
69
74
|
export const addPortal = (portal: Portal) => {
|
|
70
75
|
IONPortalManager.addPortal(portal);
|
|
71
76
|
};
|
|
77
|
+
|
|
78
|
+
export interface LiveUpdate {
|
|
79
|
+
appId: string;
|
|
80
|
+
channel: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type LiveUpdateConfig = LiveUpdate & { syncOnAdd: boolean };
|
|
84
|
+
|
|
85
|
+
export interface LiveUpdateError {
|
|
86
|
+
appId: string;
|
|
87
|
+
failStep: string;
|
|
88
|
+
message: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export interface SyncResults {
|
|
92
|
+
liveUpdates: LiveUpdate[];
|
|
93
|
+
errors: LiveUpdateError[];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const syncOne = (appId: string): Promise<LiveUpdate> => {
|
|
97
|
+
return IONLiveUpdatesManager.syncOne(appId);
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export const syncSome = (appIds: string[]): Promise<SyncResults> => {
|
|
101
|
+
return IONLiveUpdatesManager.syncSome(appIds);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
export const syncAll = (): Promise<SyncResults> => {
|
|
105
|
+
return IONLiveUpdatesManager.syncAll();
|
|
106
|
+
};
|