@ionic/portals-react-native 0.5.2 → 0.6.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/ReactNativePortals.podspec +39 -14
- package/android/build.gradle +78 -108
- package/android/gradle.properties +5 -3
- package/android/src/main/java/io/ionic/portals/reactnative/PortalView.kt +11 -8
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalManager.kt +35 -14
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalsModule.kt +2 -3
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativeWebVitalsModule.kt +11 -19
- package/ios/IonicPortals+Codable.swift +77 -0
- package/ios/LiveUpdateManager+Async.swift +16 -46
- package/ios/Podfile +29 -4
- package/ios/Podfile.lock +478 -241
- package/ios/Portal.swift +50 -54
- package/ios/PortalView.swift +26 -8
- package/ios/PortalsConfig.swift +1 -88
- package/ios/PortalsReactNative-Bridging-Header.h +2 -0
- package/ios/PortalsReactNative.swift +41 -36
- package/ios/SyncResult+SyncError+Encodable.swift +55 -0
- package/ios/WebVitals.swift +19 -26
- package/package.json +62 -43
- package/src/{PortalView.android.tsx → BasePortalView.android.tsx} +2 -3
- package/src/{PortalView.tsx → BasePortalView.tsx} +2 -3
- package/src/{index.ts → index.tsx} +77 -39
- package/ios/LiveUpdate+Dict.swift +0 -30
- package/ios/LiveUpdateManagerError+Dict.swift +0 -19
- package/ios/ReactNativePortals.xcodeproj/project.pbxproj +0 -465
- package/ios/ReactNativePortals.xcodeproj/xcshareddata/xcschemes/ReactNativePortals.xcscheme +0 -67
- package/ios/ReactNativePortals.xcworkspace/contents.xcworkspacedata +0 -10
- package/ios/ReactNativePortals.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/ios/SyncResult+Dict.swift +0 -35
- package/lib/commonjs/PortalView.android.js +0 -28
- package/lib/commonjs/PortalView.android.js.map +0 -1
- package/lib/commonjs/PortalView.js +0 -15
- package/lib/commonjs/PortalView.js.map +0 -1
- package/lib/commonjs/index.js +0 -200
- package/lib/commonjs/index.js.map +0 -1
- package/lib/module/PortalView.android.js +0 -20
- package/lib/module/PortalView.android.js.map +0 -1
- package/lib/module/PortalView.js +0 -8
- package/lib/module/PortalView.js.map +0 -1
- package/lib/module/index.js +0 -176
- package/lib/module/index.js.map +0 -1
- package/lib/typescript/PortalView.android.d.ts +0 -4
- package/lib/typescript/PortalView.d.ts +0 -4
- package/lib/typescript/index.d.ts +0 -181
- /package/ios/{PortalManager.m → PortalManager.mm} +0 -0
- /package/ios/{PortalView.m → PortalView.mm} +0 -0
- /package/ios/{PortalWebVitals.m → PortalWebVitals.mm} +0 -0
- /package/ios/{PortalsPubSub.m → PortalsPubSub.mm} +0 -0
|
@@ -1,21 +1,46 @@
|
|
|
1
|
-
require
|
|
1
|
+
require "json"
|
|
2
2
|
|
|
3
|
-
package = JSON.parse(File.read(File.join(__dir__,
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
|
|
4
5
|
|
|
5
6
|
Pod::Spec.new do |s|
|
|
6
|
-
s.name =
|
|
7
|
-
s.version = package[
|
|
8
|
-
s.summary = package[
|
|
9
|
-
s.homepage = package[
|
|
10
|
-
s.license = package[
|
|
11
|
-
s.authors = package[
|
|
7
|
+
s.name = "ReactNativePortals"
|
|
8
|
+
s.version = package["version"]
|
|
9
|
+
s.summary = package["description"]
|
|
10
|
+
s.homepage = package["homepage"]
|
|
11
|
+
s.license = package["license"]
|
|
12
|
+
s.authors = package["author"]
|
|
12
13
|
|
|
13
|
-
s.platforms = { ios
|
|
14
|
-
s.source = { git
|
|
14
|
+
s.platforms = { :ios => min_ios_version_supported }
|
|
15
|
+
s.source = { :git => "https://github.com/ionic-team/ionic-portals-react-native.git", :tag => "#{s.version}" }
|
|
15
16
|
|
|
16
|
-
s.source_files =
|
|
17
|
+
s.source_files = "ios/**/*.{h,m,mm,swift}"
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
# Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
|
|
20
|
+
# See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
|
|
21
|
+
if respond_to?(:install_modules_dependencies, true)
|
|
22
|
+
s.dependency 'IonicPortals', '~> 0.11.0'
|
|
23
|
+
s.dependency 'IonicLiveUpdates', '~> 0.5.2'
|
|
24
|
+
install_modules_dependencies(s)
|
|
25
|
+
|
|
26
|
+
else
|
|
27
|
+
s.dependency "React-Core"
|
|
28
|
+
s.dependency 'IonicPortals', '~> 0.11.0'
|
|
29
|
+
s.dependency 'IonicLiveUpdates', '~> 0.5.2'
|
|
30
|
+
|
|
31
|
+
# Don't install the dependencies when we run `pod install` in the old architecture.
|
|
32
|
+
if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
|
|
33
|
+
s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
|
|
34
|
+
s.pod_target_xcconfig = {
|
|
35
|
+
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
|
|
36
|
+
"OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
|
|
37
|
+
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
|
|
38
|
+
}
|
|
39
|
+
s.dependency "React-Codegen"
|
|
40
|
+
s.dependency "RCT-Folly"
|
|
41
|
+
s.dependency "RCTRequired"
|
|
42
|
+
s.dependency "RCTTypeSafety"
|
|
43
|
+
s.dependency "ReactCommon/turbomodule/core"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
21
46
|
end
|
package/android/build.gradle
CHANGED
|
@@ -1,131 +1,101 @@
|
|
|
1
1
|
buildscript {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
|
|
3
|
+
def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["PortalsReactNative_kotlinVersion"]
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
repositories {
|
|
6
|
+
google()
|
|
7
|
+
mavenCentral()
|
|
8
|
+
}
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
dependencies {
|
|
11
|
+
classpath "com.android.tools.build:gradle:7.2.1"
|
|
12
|
+
// noinspection DifferentKotlinGradleVersion
|
|
13
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
14
|
+
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
def reactNativeArchitectures() {
|
|
18
|
+
def value = rootProject.getProperties().get("reactNativeArchitectures")
|
|
19
|
+
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
|
|
20
|
+
}
|
|
19
21
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
+
def isNewArchitectureEnabled() {
|
|
23
|
+
return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
android
|
|
25
|
-
|
|
26
|
-
defaultConfig {
|
|
27
|
-
minSdkVersion 16
|
|
28
|
-
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
|
|
29
|
-
versionCode 1
|
|
30
|
-
versionName "1.0"
|
|
31
|
-
}
|
|
26
|
+
apply plugin: "com.android.library"
|
|
27
|
+
apply plugin: "kotlin-android"
|
|
32
28
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
minifyEnabled false
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
lintOptions {
|
|
39
|
-
disable 'GradleCompatible'
|
|
40
|
-
}
|
|
29
|
+
if (isNewArchitectureEnabled()) {
|
|
30
|
+
apply plugin: "com.facebook.react"
|
|
41
31
|
}
|
|
42
32
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
33
|
+
def getExtOrDefault(name) {
|
|
34
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["PortalsReactNative_" + name]
|
|
35
|
+
}
|
|
46
36
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
37
|
+
def getExtOrIntegerDefault(name) {
|
|
38
|
+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["PortalsReactNative_" + name]).toInteger()
|
|
50
39
|
}
|
|
51
40
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
def supportsNamespace() {
|
|
42
|
+
def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
|
|
43
|
+
def major = parsed[0].toInteger()
|
|
44
|
+
def minor = parsed[1].toInteger()
|
|
55
45
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
defaultDir = new File(
|
|
64
|
-
projectDir,
|
|
65
|
-
'/../../../node_modules/react-native/android'
|
|
66
|
-
)
|
|
67
|
-
}
|
|
46
|
+
// Namespace support was added in 7.3.0
|
|
47
|
+
return (major == 7 && minor >= 3) || major >= 8
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
android {
|
|
51
|
+
if (supportsNamespace()) {
|
|
52
|
+
namespace "com.ionic.portalsreactnative"
|
|
68
53
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}")
|
|
76
|
-
found = true
|
|
77
|
-
} else {
|
|
78
|
-
def parentDir = rootProject.projectDir
|
|
79
|
-
|
|
80
|
-
1.upto(5, {
|
|
81
|
-
if (found) return true
|
|
82
|
-
parentDir = parentDir.parentFile
|
|
83
|
-
|
|
84
|
-
def androidSourcesDir = new File(
|
|
85
|
-
parentDir,
|
|
86
|
-
'node_modules/react-native'
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
def androidPrebuiltBinaryDir = new File(
|
|
90
|
-
parentDir,
|
|
91
|
-
'node_modules/react-native/android'
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
if (androidPrebuiltBinaryDir.exists()) {
|
|
95
|
-
maven {
|
|
96
|
-
url androidPrebuiltBinaryDir.toString()
|
|
97
|
-
name androidSourcesName
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}")
|
|
101
|
-
found = true
|
|
102
|
-
} else if (androidSourcesDir.exists()) {
|
|
103
|
-
maven {
|
|
104
|
-
url androidSourcesDir.toString()
|
|
105
|
-
name androidSourcesName
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}")
|
|
109
|
-
found = true
|
|
110
|
-
}
|
|
111
|
-
})
|
|
54
|
+
sourceSets {
|
|
55
|
+
main {
|
|
56
|
+
manifest.srcFile "src/main/AndroidManifestNew.xml"
|
|
57
|
+
}
|
|
112
58
|
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
|
|
62
|
+
|
|
63
|
+
defaultConfig {
|
|
64
|
+
minSdkVersion getExtOrIntegerDefault("minSdkVersion")
|
|
65
|
+
targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
|
|
66
|
+
|
|
67
|
+
}
|
|
113
68
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
"Ensure you have you installed React Native as a dependency in your project and try again."
|
|
118
|
-
)
|
|
69
|
+
buildTypes {
|
|
70
|
+
release {
|
|
71
|
+
minifyEnabled false
|
|
119
72
|
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
lintOptions {
|
|
76
|
+
disable "GradleCompatible"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
compileOptions {
|
|
80
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
81
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
82
|
+
}
|
|
120
83
|
}
|
|
121
84
|
|
|
85
|
+
repositories {
|
|
86
|
+
mavenCentral()
|
|
87
|
+
google()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
def kotlin_version = getExtOrDefault("kotlinVersion")
|
|
91
|
+
|
|
122
92
|
dependencies {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.3"
|
|
93
|
+
// For < 0.71, this will be from the local maven repo
|
|
94
|
+
// For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
|
|
95
|
+
//noinspection GradleDynamicVersion
|
|
96
|
+
implementation "com.facebook.react:react-native:+"
|
|
97
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
98
|
+
implementation "io.ionic:portals:0.10.+"
|
|
99
|
+
implementation "io.ionic:liveupdates:0.5.+"
|
|
131
100
|
}
|
|
101
|
+
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
PortalsReactNative_kotlinVersion=1.8.0
|
|
2
|
+
PortalsReactNative_minSdkVersion=21
|
|
3
|
+
PortalsReactNative_targetSdkVersion=33
|
|
4
|
+
PortalsReactNative_compileSdkVersion=33
|
|
5
|
+
PortalsReactNative_ndkversion=21.4.7075529
|
|
4
6
|
android.useAndroidX=true
|
|
@@ -9,6 +9,7 @@ import androidx.fragment.app.FragmentActivity
|
|
|
9
9
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
10
10
|
import com.facebook.react.bridge.ReadableArray
|
|
11
11
|
import com.facebook.react.bridge.ReadableMap
|
|
12
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
12
13
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
13
14
|
import com.facebook.react.uimanager.ViewGroupManager
|
|
14
15
|
import com.facebook.react.uimanager.annotations.ReactProp
|
|
@@ -32,7 +33,7 @@ internal class PortalViewManager(private val context: ReactApplicationContext) :
|
|
|
32
33
|
when (fragmentMap[viewGroup.id]) {
|
|
33
34
|
null -> fragmentMap[viewGroup.id] = PortalViewState(
|
|
34
35
|
fragment = null,
|
|
35
|
-
portal = RNPortalManager.getPortal(name),
|
|
36
|
+
portal = RNPortalManager.getPortal(name) ?: RNPortalManager.createPortal(portal),
|
|
36
37
|
initialContext = portal.getMap("initialContext")?.toHashMap()
|
|
37
38
|
)
|
|
38
39
|
}
|
|
@@ -68,13 +69,15 @@ internal class PortalViewManager(private val context: ReactApplicationContext) :
|
|
|
68
69
|
setupLayout(parentView)
|
|
69
70
|
|
|
70
71
|
val portal = rnPortal.builder.create()
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
72
|
+
val vitals: List<String>? = rnPortal.vitals
|
|
73
|
+
|
|
74
|
+
if (vitals != null) {
|
|
75
|
+
val vitalsPlugin = WebVitals { name, metric, duration ->
|
|
76
|
+
val stringMetric = metric.toString().lowercase()
|
|
77
|
+
if (vitals.contains(stringMetric)) {
|
|
78
|
+
context
|
|
79
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
80
|
+
.emit("vitals:$stringMetric", mapOf("duration" to duration, "portalName" to name).toReadableMap())
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
portal.addPluginInstance(vitalsPlugin)
|
|
@@ -17,9 +17,7 @@ internal data class RNPortal(
|
|
|
17
17
|
val builder: PortalBuilder,
|
|
18
18
|
val index: String?,
|
|
19
19
|
val plugins: List<PortalPlugin>,
|
|
20
|
-
var
|
|
21
|
-
var onTTFB: ((Long) -> Unit)? = null,
|
|
22
|
-
var onFID: ((Long) -> Unit)? = null
|
|
20
|
+
var vitals: MutableList<String>? = null
|
|
23
21
|
)
|
|
24
22
|
|
|
25
23
|
internal data class PortalPlugin(val androidClassPath: String, val iosClassName: String) {
|
|
@@ -43,13 +41,21 @@ internal data class PortalPlugin(val androidClassPath: String, val iosClassName:
|
|
|
43
41
|
|
|
44
42
|
internal object RNPortalManager {
|
|
45
43
|
private val manager = PortalManager
|
|
44
|
+
@Deprecated("Will be removed in the next release.")
|
|
46
45
|
private val portals: ConcurrentHashMap<String, RNPortal> = ConcurrentHashMap()
|
|
47
46
|
private lateinit var reactApplicationContext: ReactApplicationContext
|
|
48
47
|
private var usesSecureLiveUpdates = false
|
|
49
48
|
|
|
50
49
|
fun register(key: String) = manager.register(key)
|
|
51
50
|
|
|
51
|
+
@Deprecated("Will be removed in the next release.")
|
|
52
52
|
fun addPortal(map: ReadableMap): RNPortal? {
|
|
53
|
+
val portal = createPortal(map) ?: return null
|
|
54
|
+
portals[portal.builder.name] = portal
|
|
55
|
+
return portal
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
fun createPortal(map: ReadableMap): RNPortal? {
|
|
53
59
|
val name = map.getString("name") ?: return null
|
|
54
60
|
val portalBuilder = PortalBuilder(name)
|
|
55
61
|
|
|
@@ -60,13 +66,16 @@ internal object RNPortalManager {
|
|
|
60
66
|
?.toHashMap()
|
|
61
67
|
?.let(portalBuilder::setInitialContext)
|
|
62
68
|
|
|
69
|
+
if (map.hasKey("devMode")) {
|
|
70
|
+
map.getBoolean("devMode").let(portalBuilder::setDevMode)
|
|
71
|
+
}
|
|
63
72
|
|
|
64
73
|
val plugins: List<PortalPlugin> = map.getArray("plugins")
|
|
65
74
|
?.let { rnArray ->
|
|
66
75
|
val list = mutableListOf<PortalPlugin>()
|
|
67
76
|
for (idx in 0 until rnArray.size()) {
|
|
68
77
|
rnArray.getMap(idx)
|
|
69
|
-
|
|
78
|
+
.let(PortalPlugin.Companion::fromReadableMap)
|
|
70
79
|
?.let(list::add)
|
|
71
80
|
}
|
|
72
81
|
return@let list
|
|
@@ -84,7 +93,7 @@ internal object RNPortalManager {
|
|
|
84
93
|
|
|
85
94
|
for (idx in 0 until rnArray.size()) {
|
|
86
95
|
rnArray.getMap(idx)
|
|
87
|
-
|
|
96
|
+
.let assetMap@{ map ->
|
|
88
97
|
val name = map.getString("name") ?: return@assetMap null
|
|
89
98
|
AssetMap(
|
|
90
99
|
name = name,
|
|
@@ -105,11 +114,11 @@ internal object RNPortalManager {
|
|
|
105
114
|
val appId = readableMap.getString("appId") ?: return@let null
|
|
106
115
|
val channel = readableMap.getString("channel") ?: return@let null
|
|
107
116
|
val syncOnAdd = readableMap.getBoolean("syncOnAdd")
|
|
108
|
-
Pair(LiveUpdate(appId, channel,
|
|
117
|
+
Pair(LiveUpdate(appId, channel, usesSecureLiveUpdates), syncOnAdd)
|
|
109
118
|
}
|
|
110
119
|
?.let { (liveUpdate, updateOnAppLoad) ->
|
|
111
120
|
portalBuilder.setLiveUpdateConfig(
|
|
112
|
-
context =
|
|
121
|
+
context = reactApplicationContext,
|
|
113
122
|
liveUpdateConfig = liveUpdate,
|
|
114
123
|
updateOnAppLoad = updateOnAppLoad
|
|
115
124
|
)
|
|
@@ -118,18 +127,30 @@ internal object RNPortalManager {
|
|
|
118
127
|
portalBuilder
|
|
119
128
|
.addPlugin(PortalsPlugin::class.java)
|
|
120
129
|
|
|
121
|
-
val
|
|
130
|
+
val vitals = map.getArray("webVitals")
|
|
131
|
+
val maybeList = if (vitals != null) {
|
|
132
|
+
val size = vitals.size()
|
|
133
|
+
(0 until size).fold(mutableListOf<String>()) { list, next ->
|
|
134
|
+
val vital = vitals.getString(next)
|
|
135
|
+
list.add(vital)
|
|
136
|
+
return@fold list
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
null
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return RNPortal(
|
|
122
143
|
builder = portalBuilder,
|
|
123
144
|
index = map.getString("index"),
|
|
124
|
-
plugins = plugins
|
|
145
|
+
plugins = plugins,
|
|
146
|
+
vitals = maybeList
|
|
125
147
|
)
|
|
126
|
-
|
|
127
|
-
portals[name] = rnPortal
|
|
128
|
-
return rnPortal
|
|
129
148
|
}
|
|
130
149
|
|
|
131
|
-
|
|
132
|
-
|
|
150
|
+
@Deprecated("Will be removed in the next release.")
|
|
151
|
+
fun getPortal(name: String): RNPortal? {
|
|
152
|
+
return portals[name]
|
|
153
|
+
}
|
|
133
154
|
|
|
134
155
|
fun enableSecureLiveUpdates(keyPath: String) {
|
|
135
156
|
LiveUpdateManager.secureLiveUpdatePEM = keyPath
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
package io.ionic.portals.reactnative
|
|
2
2
|
|
|
3
3
|
import com.facebook.react.bridge.*
|
|
4
|
-
import io.ionic.portals.Portal
|
|
5
4
|
|
|
6
5
|
internal class PortalManagerModule(reactContext: ReactApplicationContext) :
|
|
7
6
|
ReactContextBaseJavaModule(reactContext) {
|
|
@@ -32,7 +31,7 @@ internal class PortalManagerModule(reactContext: ReactApplicationContext) :
|
|
|
32
31
|
val portals = WritableNativeArray()
|
|
33
32
|
|
|
34
33
|
for (i in 0 until array.size()) {
|
|
35
|
-
val map = array.getMap(i)
|
|
34
|
+
val map = array.getMap(i)
|
|
36
35
|
val portal = RNPortalManager.addPortal(map) ?: continue
|
|
37
36
|
portals.pushMap(portal.toReadableMap())
|
|
38
37
|
}
|
|
@@ -44,7 +43,7 @@ internal class PortalManagerModule(reactContext: ReactApplicationContext) :
|
|
|
44
43
|
fun getPortal(name: String, promise: Promise) {
|
|
45
44
|
try {
|
|
46
45
|
val portal = RNPortalManager.getPortal(name)
|
|
47
|
-
promise.resolve(portal
|
|
46
|
+
promise.resolve(portal?.toReadableMap())
|
|
48
47
|
} catch (e: IllegalStateException) {
|
|
49
48
|
promise.reject(null, "Portal named $name not registered.")
|
|
50
49
|
}
|
|
@@ -4,41 +4,33 @@ import com.facebook.react.bridge.Promise
|
|
|
4
4
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
5
|
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
6
6
|
import com.facebook.react.bridge.ReactMethod
|
|
7
|
-
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
8
7
|
|
|
9
8
|
internal class PortalWebVitalsModule(reactContext: ReactApplicationContext): ReactContextBaseJavaModule(reactContext) {
|
|
10
9
|
override fun getName() = "IONPortalsWebVitals"
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
17
|
-
.emit("vitals:fcp", mapOf("duration" to duration, "portalName" to portalName).toReadableMap())
|
|
11
|
+
private fun registerVital(portalName: String, vitalName: String) {
|
|
12
|
+
val portal = RNPortalManager.getPortal(portalName) ?: return
|
|
13
|
+
if (portal.vitals == null) {
|
|
14
|
+
portal.vitals = mutableListOf()
|
|
18
15
|
}
|
|
16
|
+
portal.vitals?.add(vitalName)
|
|
17
|
+
}
|
|
19
18
|
|
|
19
|
+
@ReactMethod
|
|
20
|
+
fun registerOnFirstContentfulPaint(portalName: String, promise: Promise) {
|
|
21
|
+
registerVital(portalName,"fcp")
|
|
20
22
|
promise.resolve(null)
|
|
21
23
|
}
|
|
22
24
|
|
|
23
25
|
@ReactMethod
|
|
24
26
|
fun registerOnFirstInputDelay(portalName: String, promise: Promise) {
|
|
25
|
-
|
|
26
|
-
reactApplicationContext
|
|
27
|
-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
28
|
-
.emit("vitals:fid", mapOf("duration" to duration, "portalName" to portalName).toReadableMap())
|
|
29
|
-
}
|
|
30
|
-
|
|
27
|
+
registerVital(portalName,"fid")
|
|
31
28
|
promise.resolve(null)
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
@ReactMethod
|
|
35
32
|
fun registerOnTimeToFirstByte(portalName: String, promise: Promise) {
|
|
36
|
-
|
|
37
|
-
reactApplicationContext
|
|
38
|
-
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
39
|
-
.emit("vitals:ttfb", mapOf("duration" to duration, "portalName" to portalName).toReadableMap())
|
|
40
|
-
}
|
|
41
|
-
|
|
33
|
+
registerVital(portalName,"ttfb")
|
|
42
34
|
promise.resolve(null)
|
|
43
35
|
}
|
|
44
36
|
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
//
|
|
2
|
+
// IonicPortals+Codable.swift
|
|
3
|
+
// ReactNativePortals
|
|
4
|
+
//
|
|
5
|
+
// Created by Trevor Lambert on 6/5/24.
|
|
6
|
+
// Copyright © 2024 Facebook. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
import IonicPortals
|
|
11
|
+
|
|
12
|
+
extension AssetMap: Encodable {
|
|
13
|
+
enum CodingKeys: String, CodingKey {
|
|
14
|
+
case startDir, virtualPath, name
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public func encode(to encoder: Encoder) throws {
|
|
18
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
19
|
+
try container.encode(startDir, forKey: .startDir)
|
|
20
|
+
try container.encode(virtualPath, forKey: .virtualPath)
|
|
21
|
+
try container.encode(name, forKey: .name)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
extension AssetMap: Decodable {
|
|
26
|
+
public init(from decoder: Decoder) throws {
|
|
27
|
+
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
28
|
+
let name = try container.decode(String.self, forKey: .name)
|
|
29
|
+
let startDir = try container.decodeIfPresent(String.self, forKey: .startDir) ?? ""
|
|
30
|
+
let virtualPath = try container.decodeIfPresent(String.self, forKey: .virtualPath)
|
|
31
|
+
self.init(name: name, virtualPath: virtualPath, startDir: startDir)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
//export interface Portal {
|
|
36
|
+
// /** The name of the Portal to be referenced. Must be **unique** */
|
|
37
|
+
// name: string;
|
|
38
|
+
// /** Any Capacitor plugins to be made available to the Portal */
|
|
39
|
+
// plugins?: CapacitorPlugin[];
|
|
40
|
+
// /**
|
|
41
|
+
// * The root directory of the web application relative to Bundle.main on iOS
|
|
42
|
+
// * and src/main/assets on Android. If omitted, `name` is used.
|
|
43
|
+
// */
|
|
44
|
+
// startDir?: string;
|
|
45
|
+
// /** The name of the initial file to load. If omitted, 'index.html' is used. */
|
|
46
|
+
// index?: string;
|
|
47
|
+
// /** Any data needed at initial render when a portal is loaded. */
|
|
48
|
+
// initialContext?: {
|
|
49
|
+
// [key: string]: any;
|
|
50
|
+
// };
|
|
51
|
+
// assetMaps?: AssetMap[];
|
|
52
|
+
// liveUpdate?: LiveUpdateConfig;
|
|
53
|
+
//}
|
|
54
|
+
|
|
55
|
+
//export interface LiveUpdate {
|
|
56
|
+
// /** The AppFlow application ID */
|
|
57
|
+
// appId: string;
|
|
58
|
+
// /** The AppFlow distribution channel */
|
|
59
|
+
// channel: string;
|
|
60
|
+
//}
|
|
61
|
+
//
|
|
62
|
+
///** Data needed to register a live update to be managed */
|
|
63
|
+
//export type LiveUpdateConfig = LiveUpdate & { syncOnAdd: boolean };
|
|
64
|
+
|
|
65
|
+
//export interface AssetMap {
|
|
66
|
+
// /** The name to index the asset map by */
|
|
67
|
+
// name: string;
|
|
68
|
+
// /** Any path to match via the web. If omitted, {@link AssetMap#name} will be used. */
|
|
69
|
+
// virtualPath?: string;
|
|
70
|
+
// /** The root directory of the assets relative to Bundle.main on iOS
|
|
71
|
+
// * and src/main/assets on Android. If omitted, the root of Bundle.main
|
|
72
|
+
// * and src/main/assets will be used.
|
|
73
|
+
// */
|
|
74
|
+
// startDir?: string;
|
|
75
|
+
//}
|
|
76
|
+
|
|
77
|
+
|