sparkling-navigation 2.1.0-rc.2 → 2.1.0-rc.24
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/android/build.gradle.kts +24 -20
- package/android/src/androidTest/java/com/tiktok/sparkling/method/router/ExampleInstrumentedTest.kt +1 -1
- package/android/src/main/java/com/tiktok/sparkling/method/router/close/AbsRouterCloseMethodIDL.kt +2 -12
- package/android/src/main/java/com/tiktok/sparkling/method/router/close/RouterCloseMethod.kt +16 -17
- package/android/src/main/java/com/tiktok/sparkling/method/router/open/AbsRouterOpenMethodIDL.kt +3 -8
- package/android/src/main/java/com/tiktok/sparkling/method/router/open/RouterOpenMethod.kt +57 -53
- package/android/src/main/java/com/tiktok/sparkling/method/router/utils/AbsRouteOpenHandler.kt +7 -2
- package/android/src/main/java/com/tiktok/sparkling/method/router/utils/IHostRouterDepend.kt +19 -4
- package/android/src/main/java/com/tiktok/sparkling/method/router/utils/RouterProvider.kt +1 -2
- package/android/src/test/java/com/tiktok/sparkling/method/router/RouterMethodUnitTest.kt +1 -1
- package/dist/src/devServer.d.ts +10 -0
- package/dist/src/devServer.d.ts.map +1 -0
- package/dist/src/devServer.js +40 -0
- package/dist/src/devServer.js.map +1 -0
- package/dist/src/navigate/navigate.d.ts.map +1 -1
- package/dist/src/navigate/navigate.js +4 -12
- package/dist/src/navigate/navigate.js.map +1 -1
- package/dist/src/open/open.d.ts.map +1 -1
- package/dist/src/open/open.js +20 -1
- package/dist/src/open/open.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/ios/Sources/Core/Methods/Close/CloseMethod+impl.swift +2 -3
- package/ios/Sources/Core/Methods/Close/CloseMethod.swift +7 -8
- package/ios/Sources/Core/Methods/Open/OpenMethod+impl.swift +2 -3
- package/ios/Sources/Core/Methods/Open/OpenMethod.swift +4 -5
- package/ios/Sources/Core/Protocols/RouterService.swift +1 -1
- package/ios/Sparkling-Router.podspec +7 -11
- package/package.json +2 -2
- package/src/__tests__/navigate/navigate.test.ts +70 -1
- package/src/devServer.ts +44 -0
- package/src/navigate/navigate.ts +4 -15
- package/src/open/open.ts +20 -1
- package/ios/SparklingMethodTests/SPKRouterTest.swift +0 -124
package/android/build.gradle.kts
CHANGED
|
@@ -21,7 +21,7 @@ android {
|
|
|
21
21
|
isMinifyEnabled = false
|
|
22
22
|
proguardFiles(
|
|
23
23
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
24
|
-
"proguard-rules.pro"
|
|
24
|
+
"proguard-rules.pro",
|
|
25
25
|
)
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -41,9 +41,10 @@ dependencies {
|
|
|
41
41
|
testImplementation(libs.junit)
|
|
42
42
|
androidTestImplementation(libs.androidx.junit)
|
|
43
43
|
androidTestImplementation(libs.androidx.espresso.core)
|
|
44
|
-
val sparklingVersion =
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
val sparklingVersion =
|
|
45
|
+
(findProperty("SPARKLING_ANDROID_SDK_VERSION") as? String)
|
|
46
|
+
?: System.getenv("SPARKLING_ANDROID_SDK_VERSION")
|
|
47
|
+
?: "2.1.0-rc.12"
|
|
47
48
|
api("com.tiktok.sparkling:sparkling-method:$sparklingVersion")
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -55,28 +56,31 @@ tasks.register<JacocoReport>("jacocoTestReport") {
|
|
|
55
56
|
html.required.set(true)
|
|
56
57
|
}
|
|
57
58
|
|
|
58
|
-
val fileFilter =
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
59
|
+
val fileFilter =
|
|
60
|
+
listOf(
|
|
61
|
+
"**/R.class",
|
|
62
|
+
"**/R$*.class",
|
|
63
|
+
"**/BuildConfig.*",
|
|
64
|
+
"**/Manifest*.*",
|
|
65
|
+
"**/*Test*.*",
|
|
66
|
+
"android/**/*.*",
|
|
67
|
+
)
|
|
66
68
|
|
|
67
69
|
val mainSrc = "${project.projectDir}/src/main/java"
|
|
68
70
|
sourceDirectories.setFrom(files(mainSrc))
|
|
69
71
|
|
|
70
|
-
val debugJavaTree =
|
|
71
|
-
dir.
|
|
72
|
-
|
|
72
|
+
val debugJavaTree =
|
|
73
|
+
layout.buildDirectory.dir("intermediates/javac/debug").map { dir ->
|
|
74
|
+
dir.asFileTree.matching {
|
|
75
|
+
exclude(fileFilter)
|
|
76
|
+
}
|
|
73
77
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
val debugKotlinTree =
|
|
79
|
+
layout.buildDirectory.dir("tmp/kotlin-classes/debug").map { dir ->
|
|
80
|
+
dir.asFileTree.matching {
|
|
81
|
+
exclude(fileFilter)
|
|
82
|
+
}
|
|
78
83
|
}
|
|
79
|
-
}
|
|
80
84
|
classDirectories.setFrom(debugJavaTree, debugKotlinTree)
|
|
81
85
|
|
|
82
86
|
val unitTestCoverageExec = layout.buildDirectory.file("outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec")
|
package/android/src/main/java/com/tiktok/sparkling/method/router/close/AbsRouterCloseMethodIDL.kt
CHANGED
|
@@ -11,29 +11,19 @@ import com.tiktok.sparkling.method.registry.core.base.AbsSparklingIDLMethod
|
|
|
11
11
|
import com.tiktok.sparkling.method.registry.core.model.idl.IDLMethodBaseParamModel
|
|
12
12
|
import com.tiktok.sparkling.method.registry.core.model.idl.IDLMethodBaseResultModel
|
|
13
13
|
|
|
14
|
-
|
|
15
14
|
abstract class AbsRouterCloseMethodIDL : AbsSparklingIDLMethod<AbsRouterCloseMethodIDL.IDLMethodCloseParamModel, AbsRouterCloseMethodIDL.IDLMethodCloseResultModel>() {
|
|
16
|
-
|
|
17
15
|
@IDLMethodName(name = "router.close", params = ["containerID", "animated"])
|
|
18
16
|
final override val name: String = "router.close"
|
|
19
17
|
|
|
20
|
-
|
|
21
18
|
@IDLMethodParamModel
|
|
22
19
|
interface IDLMethodCloseParamModel : IDLMethodBaseParamModel {
|
|
23
|
-
|
|
24
20
|
@get:IDLMethodParamField(required = false, isGetter = true, keyPath = "containerID")
|
|
25
21
|
val containerID: String
|
|
26
22
|
|
|
27
|
-
|
|
28
23
|
@get:IDLMethodParamField(required = false, isGetter = true, keyPath = "animated")
|
|
29
24
|
val animated: Boolean?
|
|
30
|
-
|
|
31
|
-
|
|
32
25
|
}
|
|
33
26
|
|
|
34
27
|
@IDLMethodResultModel
|
|
35
|
-
interface IDLMethodCloseResultModel: IDLMethodBaseResultModel
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
28
|
+
interface IDLMethodCloseResultModel : IDLMethodBaseResultModel
|
|
29
|
+
}
|
|
@@ -16,19 +16,16 @@ import com.tiktok.sparkling.method.router.utils.RouterProvider
|
|
|
16
16
|
* Handles closing pages/containers.
|
|
17
17
|
*/
|
|
18
18
|
class RouterCloseMethod : AbsRouterCloseMethodIDL() {
|
|
19
|
-
|
|
20
19
|
companion object {
|
|
21
20
|
private const val TAG = "RouterCloseMethod"
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
private fun getRouterDependInstance(): IHostRouterDepend?
|
|
25
|
-
return RouterProvider.hostRouterDepend
|
|
26
|
-
}
|
|
23
|
+
private fun getRouterDependInstance(): IHostRouterDepend? = RouterProvider.hostRouterDepend
|
|
27
24
|
|
|
28
25
|
override fun handle(
|
|
29
26
|
params: IDLMethodCloseParamModel,
|
|
30
27
|
callback: CompletionBlock<IDLMethodCloseResultModel>,
|
|
31
|
-
type: BridgePlatformType
|
|
28
|
+
type: BridgePlatformType,
|
|
32
29
|
) {
|
|
33
30
|
// Check if router dependency is available
|
|
34
31
|
val routerDepend = getRouterDependInstance()
|
|
@@ -41,22 +38,24 @@ class RouterCloseMethod : AbsRouterCloseMethodIDL() {
|
|
|
41
38
|
val containerID = params.containerID
|
|
42
39
|
val animated = params.animated ?: true // Default to animated close
|
|
43
40
|
|
|
44
|
-
val success =
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
val success =
|
|
42
|
+
try {
|
|
43
|
+
routerDepend.closeView(getSDKContext(), type, containerID, animated)
|
|
44
|
+
} catch (e: Exception) {
|
|
45
|
+
Log.e(TAG, "Exception while closing container: ${e.message}")
|
|
46
|
+
false
|
|
47
|
+
}
|
|
50
48
|
|
|
51
49
|
if (success) {
|
|
52
50
|
callback.onSuccess(IDLMethodCloseResultModel::class.java.createXModel())
|
|
53
51
|
} else {
|
|
54
|
-
val errorMsg =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
val errorMsg =
|
|
53
|
+
if (containerID.isNullOrBlank()) {
|
|
54
|
+
"Failed to close current container"
|
|
55
|
+
} else {
|
|
56
|
+
"Failed to close container: $containerID"
|
|
57
|
+
}
|
|
59
58
|
callback.onFailure(IDLBridgeMethod.FAIL, errorMsg, null)
|
|
60
59
|
}
|
|
61
60
|
}
|
|
62
|
-
}
|
|
61
|
+
}
|
package/android/src/main/java/com/tiktok/sparkling/method/router/open/AbsRouterOpenMethodIDL.kt
CHANGED
|
@@ -21,14 +21,11 @@ import com.tiktok.sparkling.method.registry.core.model.idl.IDLMethodBaseResultMo
|
|
|
21
21
|
* DO NOT MODIFY!!!
|
|
22
22
|
*/
|
|
23
23
|
abstract class AbsRouterOpenMethodIDL : AbsSparklingIDLMethod<AbsRouterOpenMethodIDL.IDLMethodOpenParamModel, AbsRouterOpenMethodIDL.IDLMethodOpenResultModel>() {
|
|
24
|
-
|
|
25
24
|
@IDLMethodName(name = "router.open", params = ["scheme", "replace", "replaceType", "useSysBrowser", "animated", "interceptor", "extra"])
|
|
26
25
|
final override val name: String = "router.open"
|
|
27
26
|
|
|
28
|
-
|
|
29
27
|
@IDLMethodParamModel
|
|
30
28
|
interface IDLMethodOpenParamModel : IDLMethodBaseParamModel {
|
|
31
|
-
|
|
32
29
|
@get:IDLMethodParamField(required = true, isGetter = true, keyPath = "scheme")
|
|
33
30
|
val scheme: String
|
|
34
31
|
|
|
@@ -52,9 +49,7 @@ abstract class AbsRouterOpenMethodIDL : AbsSparklingIDLMethod<AbsRouterOpenMetho
|
|
|
52
49
|
}
|
|
53
50
|
|
|
54
51
|
@IDLMethodResultModel
|
|
55
|
-
interface IDLMethodOpenResultModel: IDLMethodBaseResultModel
|
|
56
|
-
}
|
|
52
|
+
interface IDLMethodOpenResultModel : IDLMethodBaseResultModel
|
|
57
53
|
|
|
58
|
-
interface IDLMethodOpenExtra : IDLMethodBaseModel
|
|
59
|
-
|
|
60
|
-
}
|
|
54
|
+
interface IDLMethodOpenExtra : IDLMethodBaseModel
|
|
55
|
+
}
|
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
3
|
// LICENSE file in the root directory of this source tree.
|
|
4
4
|
|
|
5
|
-
|
|
6
5
|
package com.tiktok.sparkling.method.router.open
|
|
7
6
|
|
|
8
|
-
|
|
9
7
|
import android.util.Log
|
|
10
8
|
import com.tiktok.sparkling.method.registry.core.IDLBridgeMethod
|
|
11
9
|
import com.tiktok.sparkling.method.registry.core.BridgePlatformType
|
|
@@ -14,25 +12,21 @@ import com.tiktok.sparkling.method.registry.core.utils.createXModel
|
|
|
14
12
|
import com.tiktok.sparkling.method.router.utils.IHostRouterDepend
|
|
15
13
|
import com.tiktok.sparkling.method.router.utils.RouterProvider
|
|
16
14
|
|
|
17
|
-
|
|
18
15
|
/**
|
|
19
16
|
* Router open method implementation.
|
|
20
17
|
* Handles opening new pages/routes with various configuration options.
|
|
21
18
|
*/
|
|
22
19
|
class RouterOpenMethod : AbsRouterOpenMethodIDL() {
|
|
23
|
-
|
|
24
20
|
companion object {
|
|
25
21
|
private const val TAG = "RouterOpenMethod"
|
|
26
22
|
}
|
|
27
23
|
|
|
28
|
-
private fun getRouterDependInstance(): IHostRouterDepend?
|
|
29
|
-
return RouterProvider.hostRouterDepend
|
|
30
|
-
}
|
|
24
|
+
private fun getRouterDependInstance(): IHostRouterDepend? = RouterProvider.hostRouterDepend
|
|
31
25
|
|
|
32
26
|
override fun handle(
|
|
33
27
|
params: IDLMethodOpenParamModel,
|
|
34
28
|
callback: CompletionBlock<IDLMethodOpenResultModel>,
|
|
35
|
-
type: BridgePlatformType
|
|
29
|
+
type: BridgePlatformType,
|
|
36
30
|
) {
|
|
37
31
|
// Validate scheme is not null or empty
|
|
38
32
|
val scheme = params.scheme
|
|
@@ -43,21 +37,22 @@ class RouterOpenMethod : AbsRouterOpenMethodIDL() {
|
|
|
43
37
|
}
|
|
44
38
|
|
|
45
39
|
// Validate replaceType if provided
|
|
46
|
-
val replaceType: ReplaceType? =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
40
|
+
val replaceType: ReplaceType? =
|
|
41
|
+
if (!params.replaceType.isNullOrBlank()) {
|
|
42
|
+
try {
|
|
43
|
+
ReplaceType.valueOf(params.replaceType!!)
|
|
44
|
+
} catch (e: IllegalArgumentException) {
|
|
45
|
+
Log.w(TAG, "Invalid replaceType: ${params.replaceType}")
|
|
46
|
+
callback.onFailure(
|
|
47
|
+
IDLBridgeMethod.INVALID_PARAM,
|
|
48
|
+
"Invalid replaceType: ${params.replaceType}. Valid values are: ${ReplaceType.values().joinToString()}",
|
|
49
|
+
null,
|
|
50
|
+
)
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
ReplaceType.onlyCloseAfterOpenSucceed
|
|
57
55
|
}
|
|
58
|
-
} else {
|
|
59
|
-
ReplaceType.onlyCloseAfterOpenSucceed
|
|
60
|
-
}
|
|
61
56
|
|
|
62
57
|
// Get and validate context
|
|
63
58
|
val context = getSDKContext()?.context
|
|
@@ -79,19 +74,21 @@ class RouterOpenMethod : AbsRouterOpenMethodIDL() {
|
|
|
79
74
|
val useSysBrowser = params.useSysBrowser ?: false
|
|
80
75
|
val extra = params.extra
|
|
81
76
|
|
|
82
|
-
val extraInfo =
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
77
|
+
val extraInfo =
|
|
78
|
+
mutableMapOf<String, Any>(
|
|
79
|
+
"useSysBrowser" to useSysBrowser,
|
|
80
|
+
"extra" to (extra ?: emptyMap<Any, Any>()),
|
|
81
|
+
)
|
|
86
82
|
|
|
87
83
|
// Handle non-replace open
|
|
88
84
|
if (!replace) {
|
|
89
|
-
val success =
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
85
|
+
val success =
|
|
86
|
+
try {
|
|
87
|
+
routerDepend.openScheme(getSDKContext(), scheme, extraInfo, type, context = context)
|
|
88
|
+
} catch (e: Exception) {
|
|
89
|
+
Log.e(TAG, "Exception while opening scheme: ${e.message}")
|
|
90
|
+
false
|
|
91
|
+
}
|
|
95
92
|
|
|
96
93
|
if (success) {
|
|
97
94
|
callback.onSuccess(IDLMethodOpenResultModel::class.java.createXModel())
|
|
@@ -102,30 +99,36 @@ class RouterOpenMethod : AbsRouterOpenMethodIDL() {
|
|
|
102
99
|
}
|
|
103
100
|
|
|
104
101
|
// Handle replace open with different replace types
|
|
105
|
-
val success: Boolean =
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
routerDepend.openScheme(getSDKContext(), scheme, extraInfo, type, context = context)
|
|
110
|
-
}
|
|
111
|
-
ReplaceType.alwaysCloseAfterOpen -> {
|
|
112
|
-
val opened = routerDepend.openScheme(getSDKContext(), scheme, extraInfo, type, context = context)
|
|
113
|
-
routerDepend.closeView(getSDKContext(), type)
|
|
114
|
-
opened
|
|
115
|
-
}
|
|
116
|
-
ReplaceType.onlyCloseAfterOpenSucceed -> {
|
|
117
|
-
val opened = routerDepend.openScheme(getSDKContext(), scheme, extraInfo, type, context = context)
|
|
118
|
-
if (opened) {
|
|
102
|
+
val success: Boolean =
|
|
103
|
+
try {
|
|
104
|
+
when (replaceType) {
|
|
105
|
+
ReplaceType.alwaysCloseBeforeOpen -> {
|
|
119
106
|
routerDepend.closeView(getSDKContext(), type)
|
|
107
|
+
routerDepend.openScheme(getSDKContext(), scheme, extraInfo, type, context = context)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
ReplaceType.alwaysCloseAfterOpen -> {
|
|
111
|
+
val opened = routerDepend.openScheme(getSDKContext(), scheme, extraInfo, type, context = context)
|
|
112
|
+
routerDepend.closeView(getSDKContext(), type)
|
|
113
|
+
opened
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
ReplaceType.onlyCloseAfterOpenSucceed -> {
|
|
117
|
+
val opened = routerDepend.openScheme(getSDKContext(), scheme, extraInfo, type, context = context)
|
|
118
|
+
if (opened) {
|
|
119
|
+
routerDepend.closeView(getSDKContext(), type)
|
|
120
|
+
}
|
|
121
|
+
opened
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
null -> {
|
|
125
|
+
false
|
|
120
126
|
}
|
|
121
|
-
opened
|
|
122
127
|
}
|
|
123
|
-
|
|
128
|
+
} catch (e: Exception) {
|
|
129
|
+
Log.e(TAG, "Exception during replace open: ${e.message}")
|
|
130
|
+
false
|
|
124
131
|
}
|
|
125
|
-
} catch (e: Exception) {
|
|
126
|
-
Log.e(TAG, "Exception during replace open: ${e.message}")
|
|
127
|
-
false
|
|
128
|
-
}
|
|
129
132
|
|
|
130
133
|
if (success) {
|
|
131
134
|
callback.onSuccess(IDLMethodOpenResultModel::class.java.createXModel())
|
|
@@ -134,8 +137,9 @@ class RouterOpenMethod : AbsRouterOpenMethodIDL() {
|
|
|
134
137
|
}
|
|
135
138
|
}
|
|
136
139
|
}
|
|
140
|
+
|
|
137
141
|
enum class ReplaceType {
|
|
138
142
|
alwaysCloseAfterOpen,
|
|
139
143
|
alwaysCloseBeforeOpen,
|
|
140
|
-
onlyCloseAfterOpenSucceed
|
|
144
|
+
onlyCloseAfterOpenSucceed,
|
|
141
145
|
}
|
package/android/src/main/java/com/tiktok/sparkling/method/router/utils/AbsRouteOpenHandler.kt
CHANGED
|
@@ -23,6 +23,11 @@ abstract class AbsRouteOpenHandler {
|
|
|
23
23
|
this.exceptionHandler = handler
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
abstract fun openScheme(
|
|
26
|
+
abstract fun openScheme(
|
|
27
|
+
scheme: String,
|
|
28
|
+
extraInfo: Map<String, Any>,
|
|
29
|
+
context: Context?,
|
|
30
|
+
): Boolean
|
|
31
|
+
|
|
27
32
|
abstract fun getSupportPlatformTypeList(): List<BridgePlatformType>
|
|
28
|
-
}
|
|
33
|
+
}
|
|
@@ -9,7 +9,13 @@ import com.tiktok.sparkling.method.registry.core.BridgePlatformType
|
|
|
9
9
|
import com.tiktok.sparkling.method.registry.core.model.context.ContextProviderFactory
|
|
10
10
|
|
|
11
11
|
interface IHostRouterDepend {
|
|
12
|
-
fun openScheme(
|
|
12
|
+
fun openScheme(
|
|
13
|
+
bridgeContext: IBridgeContext?,
|
|
14
|
+
scheme: String,
|
|
15
|
+
extraParams: Map<String, Any>,
|
|
16
|
+
platformType: BridgePlatformType,
|
|
17
|
+
context: Context?,
|
|
18
|
+
): Boolean {
|
|
13
19
|
var handled = false
|
|
14
20
|
val contextProviderFactory = ContextProviderFactory()
|
|
15
21
|
val headHandlerNode = assembleHandlerChain(contextProviderFactory) ?: return false
|
|
@@ -30,11 +36,20 @@ interface IHostRouterDepend {
|
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
38
|
|
|
33
|
-
return
|
|
39
|
+
return handled
|
|
34
40
|
}
|
|
35
|
-
|
|
41
|
+
|
|
42
|
+
fun closeView(
|
|
43
|
+
bridgeContext: IBridgeContext?,
|
|
44
|
+
type: BridgePlatformType,
|
|
45
|
+
containerID: String? = null,
|
|
46
|
+
animated: Boolean? = false,
|
|
47
|
+
): Boolean
|
|
48
|
+
|
|
36
49
|
fun provideRouteOpenHandlerList(contextProviderFactory: ContextProviderFactory?): List<AbsRouteOpenHandler> = listOf()
|
|
50
|
+
|
|
37
51
|
fun provideRouteOpenExceptionHandler(contextProviderFactory: ContextProviderFactory?): AbsRouteOpenHandler? = null
|
|
52
|
+
|
|
38
53
|
private fun assembleHandlerChain(contextProviderFactory: ContextProviderFactory?): AbsRouteOpenHandler? {
|
|
39
54
|
val chainHandlerList = provideRouteOpenHandlerList(contextProviderFactory)
|
|
40
55
|
val exceptionHandlerNode = provideRouteOpenExceptionHandler(contextProviderFactory)
|
|
@@ -51,4 +66,4 @@ interface IHostRouterDepend {
|
|
|
51
66
|
}
|
|
52
67
|
return headChainNode
|
|
53
68
|
}
|
|
54
|
-
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Derive the dev server base URL from the actual bundle URL that the native
|
|
3
|
+
* side used to load this page. Falls back to __webpack_public_path__.
|
|
4
|
+
*
|
|
5
|
+
* This ensures sub-page navigation uses the same host/port that the entry
|
|
6
|
+
* page was loaded from — critical for real-device debugging where the native
|
|
7
|
+
* side may use a LAN IP while __webpack_public_path__ is baked as localhost.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getDevServerBaseURL(): string | undefined;
|
|
10
|
+
//# sourceMappingURL=devServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devServer.d.ts","sourceRoot":"","sources":["../../src/devServer.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,GAAG,SAAS,CA2BxD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// Copyright (c) 2022 TikTok Pte. Ltd.
|
|
2
|
+
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
+
// LICENSE file in the root directory of this source tree.
|
|
4
|
+
/**
|
|
5
|
+
* Derive the dev server base URL from the actual bundle URL that the native
|
|
6
|
+
* side used to load this page. Falls back to __webpack_public_path__.
|
|
7
|
+
*
|
|
8
|
+
* This ensures sub-page navigation uses the same host/port that the entry
|
|
9
|
+
* page was loaded from — critical for real-device debugging where the native
|
|
10
|
+
* side may use a LAN IP while __webpack_public_path__ is baked as localhost.
|
|
11
|
+
*/
|
|
12
|
+
export function getDevServerBaseURL() {
|
|
13
|
+
var _a, _b;
|
|
14
|
+
try {
|
|
15
|
+
if (typeof __DEV__ === 'undefined' || !__DEV__) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
// Prefer the actual URL the native side used to load this bundle.
|
|
19
|
+
// lynx.__globalProps.queryItems.url is set by the SDK from the scheme's
|
|
20
|
+
// url= parameter (e.g. "http://192.168.1.100:5969/main.lynx.bundle").
|
|
21
|
+
if (typeof lynx !== 'undefined' && ((_b = (_a = lynx === null || lynx === void 0 ? void 0 : lynx.__globalProps) === null || _a === void 0 ? void 0 : _a.queryItems) === null || _b === void 0 ? void 0 : _b.url)) {
|
|
22
|
+
const pageUrl = lynx.__globalProps.queryItems.url;
|
|
23
|
+
if (pageUrl.startsWith('http://') || pageUrl.startsWith('https://')) {
|
|
24
|
+
const lastSlash = pageUrl.lastIndexOf('/');
|
|
25
|
+
if (lastSlash > pageUrl.indexOf('//') + 1) {
|
|
26
|
+
return pageUrl.substring(0, lastSlash + 1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// Fall back to build-time value.
|
|
31
|
+
if (typeof __webpack_public_path__ === 'string' && __webpack_public_path__) {
|
|
32
|
+
return __webpack_public_path__;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (_c) {
|
|
36
|
+
// globals not available
|
|
37
|
+
}
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=devServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devServer.js","sourceRoot":"","sources":["../../src/devServer.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,yEAAyE;AACzE,0DAA0D;AAM1D;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB;;IAC/B,IAAI,CAAC;QACD,IAAI,OAAO,OAAO,KAAK,WAAW,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7C,OAAO,SAAS,CAAC;QACrB,CAAC;QAED,kEAAkE;QAClE,wEAAwE;QACxE,sEAAsE;QACtE,IAAI,OAAO,IAAI,KAAK,WAAW,KAAI,MAAA,MAAA,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,aAAa,0CAAE,UAAU,0CAAE,GAAG,CAAA,EAAE,CAAC;YACtE,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,GAAG,CAAC;YAClD,IAAI,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAClE,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;gBAC3C,IAAI,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;oBACxC,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAC;gBAC/C,CAAC;YACL,CAAC;QACL,CAAC;QAED,iCAAiC;QACjC,IAAI,OAAO,uBAAuB,KAAK,QAAQ,IAAI,uBAAuB,EAAE,CAAC;YACzE,OAAO,uBAAuB,CAAC;QACnC,CAAC;IACL,CAAC;IAAC,WAAM,CAAC;QACL,wBAAwB;IAC5B,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigate.d.ts","sourceRoot":"","sources":["../../../src/navigate/navigate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"navigate.d.ts","sourceRoot":"","sources":["../../../src/navigate/navigate.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACR,eAAe,EACf,gBAAgB,EAGnB,MAAM,cAAc,CAAC;AAyDtB,wBAAgB,QAAQ,CAAC,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,GAAG,IAAI,CAgDpG"}
|
|
@@ -13,6 +13,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
13
13
|
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
14
14
|
// LICENSE file in the root directory of this source tree.
|
|
15
15
|
import { open } from '../open/open';
|
|
16
|
+
import { getDevServerBaseURL } from '../devServer';
|
|
16
17
|
const DEFAULT_ROUTER_SCHEME = 'hybrid://lynxview_page';
|
|
17
18
|
const PROTOCOL_REGEX = /^[a-z][a-z0-9+.-]*:\/\//i;
|
|
18
19
|
function createErrorResponse(msg) {
|
|
@@ -27,17 +28,6 @@ function normalizePath(path) {
|
|
|
27
28
|
normalized = normalized.replace(/^(?:\.\/|\/)+/, '');
|
|
28
29
|
return normalized;
|
|
29
30
|
}
|
|
30
|
-
function getDevServerBaseURL() {
|
|
31
|
-
try {
|
|
32
|
-
if (typeof __DEV__ !== 'undefined' && __DEV__ && typeof __webpack_public_path__ === 'string' && __webpack_public_path__) {
|
|
33
|
-
return __webpack_public_path__;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
catch (_a) {
|
|
37
|
-
// __DEV__ or __webpack_public_path__ not available
|
|
38
|
-
}
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
31
|
function buildScheme(baseScheme, bundlePath, params) {
|
|
42
32
|
const sanitizedBase = (baseScheme || DEFAULT_ROUTER_SCHEME).trim().replace(/[?&]+$/, '') || DEFAULT_ROUTER_SCHEME;
|
|
43
33
|
const searchParams = new URLSearchParams();
|
|
@@ -67,7 +57,9 @@ function buildScheme(baseScheme, bundlePath, params) {
|
|
|
67
57
|
searchParams.append(key, String(value));
|
|
68
58
|
}
|
|
69
59
|
}
|
|
70
|
-
|
|
60
|
+
// URLSearchParams encodes spaces as '+' (x-www-form-urlencoded), but
|
|
61
|
+
// native URL parsers only understand '%20'. Replace to avoid mangled values.
|
|
62
|
+
return `${sanitizedBase}?${searchParams.toString().replace(/\+/g, '%20')}`;
|
|
71
63
|
}
|
|
72
64
|
export function navigate(params, callback) {
|
|
73
65
|
var _a, _b;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"navigate.js","sourceRoot":"","sources":["../../../src/navigate/navigate.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,sCAAsC;AACtC,yEAAyE;AACzE,0DAA0D;AAC1D,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"navigate.js","sourceRoot":"","sources":["../../../src/navigate/navigate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../../src/open/open.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../../src/open/open.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE1D;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI,CA2DxF"}
|
package/dist/src/open/open.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
3
|
// LICENSE file in the root directory of this source tree.
|
|
4
4
|
import pipe from 'sparkling-method';
|
|
5
|
+
import { getDevServerBaseURL } from '../devServer';
|
|
5
6
|
/**
|
|
6
7
|
* Open a new page or route
|
|
7
8
|
* @param params |
|
|
@@ -32,7 +33,25 @@ export function open(params, callback) {
|
|
|
32
33
|
console.error('[sparkling-navigation] open: callback must be a function');
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
+
// In dev mode, rewrite bundle= to url= so the native side loads from the
|
|
37
|
+
// dev server instead of stale local assets.
|
|
38
|
+
let scheme = params.scheme.trim();
|
|
39
|
+
const devBase = getDevServerBaseURL();
|
|
40
|
+
if (devBase) {
|
|
41
|
+
try {
|
|
42
|
+
const u = new URL(scheme);
|
|
43
|
+
const bundle = u.searchParams.get('bundle');
|
|
44
|
+
if (bundle && !u.searchParams.get('url')) {
|
|
45
|
+
u.searchParams.delete('bundle');
|
|
46
|
+
u.searchParams.set('url', `${devBase.replace(/\/+$/, '')}/${bundle.replace(/^(?:\.\/|\/)+/, '')}`);
|
|
47
|
+
scheme = u.toString();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (_a) {
|
|
51
|
+
// scheme is not a valid URL, pass through as-is
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
pipe.call('router.open', Object.assign({ scheme }, params.options), (v) => {
|
|
36
55
|
var _a, _b;
|
|
37
56
|
const response = v;
|
|
38
57
|
const code = (_a = response === null || response === void 0 ? void 0 : response.code) !== null && _a !== void 0 ? _a : -1;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../../src/open/open.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,yEAAyE;AACzE,0DAA0D;AAC1D,OAAO,IAAI,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"open.js","sourceRoot":"","sources":["../../../src/open/open.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,yEAAyE;AACzE,0DAA0D;AAC1D,OAAO,IAAI,MAAM,kBAAkB,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGnD;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,MAAmB,EAAE,QAAwC;IAC9E,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,aAAa,GAAiB;YAChC,IAAI,EAAE,CAAC,CAAC;YACR,GAAG,EAAE,oDAAoD;SAC5D,CAAC;QACF,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;YACjC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO;IACX,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/E,MAAM,aAAa,GAAiB;YAChC,IAAI,EAAE,CAAC,CAAC;YACR,GAAG,EAAE,mDAAmD;SAC3D,CAAC;QACF,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;YACjC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO;IACX,CAAC;IAED,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;QAC1E,OAAO;IACX,CAAC;IAED,yEAAyE;IACzE,4CAA4C;IAC5C,IAAI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAClC,MAAM,OAAO,GAAG,mBAAmB,EAAE,CAAC;IACtC,IAAI,OAAO,EAAE,CAAC;QACV,IAAI,CAAC;YACD,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;YAC1B,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC5C,IAAI,MAAM,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBACvC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;gBAChC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;gBACnG,MAAM,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;YAC1B,CAAC;QACL,CAAC;QAAC,WAAM,CAAC;YACL,gDAAgD;QACpD,CAAC;IACL,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,aAAa,kBACnB,MAAM,IACH,MAAM,CAAC,OAAO,GAClB,CAAC,CAAU,EAAE,EAAE;;QACd,MAAM,QAAQ,GAAG,CAAiB,CAAC;QACnC,MAAM,IAAI,GAAG,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,IAAI,mCAAI,CAAC,CAAC,CAAC;QAClC,2EAA2E;QAC3E,0EAA0E;QAC1E,kDAAkD;QAClD,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,CAAC;QAC7B,MAAM,GAAG,GAAG,MAAA,QAAQ,aAAR,QAAQ,uBAAR,QAAQ,CAAE,GAAG,mCAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;QAClE,QAAQ,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IAC5B,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"fileNames":["../../../../node_modules/.pnpm/typescript@5.
|
|
1
|
+
{"fileNames":["../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.core.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.collection.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.generator.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.iterable.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.promise.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.proxy.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.reflect.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.d.ts","../../../../node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","../src/devServer.ts","../../../sparkling-method/dist/types.d.ts","../../../sparkling-method/dist/index.d.ts","../src/close/close.d.ts","../src/close/close.ts","../src/open/open.d.ts","../src/open/open.ts","../src/navigate/navigate.d.ts","../src/navigate/navigate.ts","../index.ts","../../../../node_modules/.pnpm/@jest+expect-utils@29.7.0/node_modules/@jest/expect-utils/build/index.d.ts","../../../../node_modules/.pnpm/chalk@4.1.2/node_modules/chalk/index.d.ts","../../../../node_modules/.pnpm/@sinclair+typebox@0.27.10/node_modules/@sinclair/typebox/typebox.d.ts","../../../../node_modules/.pnpm/@jest+schemas@29.6.3/node_modules/@jest/schemas/build/index.d.ts","../../../../node_modules/.pnpm/pretty-format@29.7.0/node_modules/pretty-format/build/index.d.ts","../../../../node_modules/.pnpm/jest-diff@29.7.0/node_modules/jest-diff/build/index.d.ts","../../../../node_modules/.pnpm/jest-matcher-utils@29.7.0/node_modules/jest-matcher-utils/build/index.d.ts","../../../../node_modules/.pnpm/expect@29.7.0/node_modules/expect/build/index.d.ts","../../../../node_modules/.pnpm/@types+jest@29.5.14/node_modules/@types/jest/index.d.ts"],"fileIdsList":[[27],[29,32],[25,31],[29],[26,30],[28],[18,19,20,21,22,23],[17,18],[20],[15,21,22],[15,17,20],[16]],"fileInfos":[{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"45b7ab580deca34ae9729e97c13cfd999df04416a79116c3bfb483804f85ded4","impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"c57796738e7f83dbc4b8e65132f11a377649c00dd3eee333f672b8f0a6bea671","affectsGlobalScope":true,"impliedFormat":1},{"version":"dc2df20b1bcdc8c2d34af4926e2c3ab15ffe1160a63e58b7e09833f616efff44","affectsGlobalScope":true,"impliedFormat":1},{"version":"515d0b7b9bea2e31ea4ec968e9edd2c39d3eebf4a2d5cbd04e88639819ae3b71","affectsGlobalScope":true,"impliedFormat":1},{"version":"0559b1f683ac7505ae451f9a96ce4c3c92bdc71411651ca6ddb0e88baaaad6a3","affectsGlobalScope":true,"impliedFormat":1},{"version":"0dc1e7ceda9b8b9b455c3a2d67b0412feab00bd2f66656cd8850e8831b08b537","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce691fb9e5c64efb9547083e4a34091bcbe5bdb41027e310ebba8f7d96a98671","affectsGlobalScope":true,"impliedFormat":1},{"version":"8d697a2a929a5fcb38b7a65594020fcef05ec1630804a33748829c5ff53640d0","affectsGlobalScope":true,"impliedFormat":1},{"version":"4ff2a353abf8a80ee399af572debb8faab2d33ad38c4b4474cff7f26e7653b8d","affectsGlobalScope":true,"impliedFormat":1},{"version":"fb0f136d372979348d59b3f5020b4cdb81b5504192b1cacff5d1fbba29378aa1","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"4fc8c80e3f83b51aa0be32aca09faa0a00968109a8b2f9a1172999ae422f6a58","signature":"51d6a96a88f06928d2bf9400f47a225ab2ca51b0c290f5c5aeb232b04f0aca9d"},"f7633d7fe074d6a4f1d215bbc7a3b27fc0419a5a3bfbbe054ac07f3dbbc68487","bdddec6a06096ab2fc1460e59d0e8c1c954ffe72290bee32bc1ecce28ebe9393","582fe2e974682a46dcee0b08fac869d96c56ec3421ad48633f6289f497acc3fd",{"version":"437d1d1bf67ea36dbf6f48e75dc75f7385e58e91d5a0acc493cbc1cec23c59fa","signature":"f421088758adc5b04e44c1548f2d7ac1cebbdda08458c8e493a490002c8e6f7c"},"a078d8603e9ef86dbed7ba0ff50276734c4cefbc5e64a6ab07144911ff701e3b",{"version":"ad4667e00d7fce51bded3e210d1f271e651ea5516cea8ba121201bc1614e022f","signature":"dd1d64b74f46208aecdee3727641eff5c0262826752e37a19ca6b2eb474d45af"},"e3963382b8a425258f14e665e7a0d39b024f1e71b7c9200096cdc9604ddf5f94",{"version":"712aba6de5cf5a6724f0ecdc5ec1176d35e7ed1071e36fb69d696dabfb1e7088","signature":"e902e6d4f2877e301fa4cf11b50a18c6a1c078bd34edecb15ae62459310004d0"},{"version":"f4ef2dc4d2182f03365773c1c488eb01ebd07186a7d7e3c51eea5eed6c0d5252","signature":"4acdb0a03d91ac0b94410f47337f1dba8f947a74300a305e1e6a14fef3933d07"},{"version":"cdcc132f207d097d7d3aa75615ab9a2e71d6a478162dde8b67f88ea19f3e54de","impliedFormat":1},{"version":"0d14fa22c41fdc7277e6f71473b20ebc07f40f00e38875142335d5b63cdfc9d2","impliedFormat":1},{"version":"e1028394c1cf96d5d057ecc647e31e457b919092f882ed0c7092152b077fed9d","impliedFormat":1},{"version":"f315e1e65a1f80992f0509e84e4ae2df15ecd9ef73df975f7c98813b71e4c8da","impliedFormat":1},{"version":"5b9586e9b0b6322e5bfbd2c29bd3b8e21ab9d871f82346cb71020e3d84bae73e","impliedFormat":1},{"version":"3e70a7e67c2cb16f8cd49097360c0309fe9d1e3210ff9222e9dac1f8df9d4fb6","impliedFormat":1},{"version":"ab68d2a3e3e8767c3fba8f80de099a1cfc18c0de79e42cb02ae66e22dfe14a66","impliedFormat":1},{"version":"d96cc6598148bf1a98fb2e8dcf01c63a4b3558bdaec6ef35e087fd0562eb40ec","impliedFormat":1},{"version":"f8db4fea512ab759b2223b90ecbbe7dae919c02f8ce95ec03f7fb1cf757cfbeb","affectsGlobalScope":true,"impliedFormat":1}],"root":[15,19,21,23,24],"options":{"composite":true,"declaration":true,"declarationMap":true,"emitDeclarationOnly":false,"esModuleInterop":true,"module":5,"outDir":"./","skipLibCheck":true,"sourceMap":true,"strict":true,"target":2},"referencedMap":[[28,1],[33,2],[32,3],[30,4],[31,5],[29,6],[24,7],[19,8],[22,9],[23,10],[21,11],[17,12]],"latestChangedDtsFile":"./index.d.ts","version":"5.9.3"}
|
|
@@ -7,39 +7,38 @@ import SparklingMethod
|
|
|
7
7
|
|
|
8
8
|
@objc(CloseMethod)
|
|
9
9
|
public class CloseMethod: PipeMethod {
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
public override var methodName: String {
|
|
12
12
|
return "router.close"
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
public override class func methodName() -> String {
|
|
16
16
|
return "router.close"
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
@objc public override var paramsModelClass: AnyClass {
|
|
20
20
|
return CloseMethodParamModel.self
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
@objc public override var resultModelClass: AnyClass {
|
|
24
24
|
return EmptyMethodModelClass.self
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
27
|
}
|
|
29
28
|
|
|
30
29
|
@objc(CloseMethodParamModel)
|
|
31
30
|
public class CloseMethodParamModel: SPKMethodModel {
|
|
32
31
|
@objc public var containerID: String?
|
|
33
32
|
@objc public var animated: Bool = false
|
|
34
|
-
|
|
33
|
+
|
|
35
34
|
public override class func requiredKeyPaths() -> Set<String>? {
|
|
36
35
|
return []
|
|
37
36
|
}
|
|
38
|
-
|
|
37
|
+
|
|
39
38
|
@objc public override class func jsonKeyPathsByPropertyKey() -> [AnyHashable: Any] {
|
|
40
39
|
return [
|
|
41
40
|
"containerID": "containerID",
|
|
42
|
-
"animated": "animated"
|
|
41
|
+
"animated": "animated",
|
|
43
42
|
]
|
|
44
43
|
}
|
|
45
44
|
}
|
|
@@ -21,11 +21,10 @@ extension OpenMethod {
|
|
|
21
21
|
completionHandler.handleCompletion(status: .invalidParameter(message: "The schema should not be empty."), result: nil)
|
|
22
22
|
return
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
|
|
25
25
|
routerService.openScheme(withParams: typedParamModel) { status, result in
|
|
26
26
|
completionHandler.handleCompletion(status: status, result: nil)
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
|
|
30
29
|
|
|
31
|
-
}
|
|
30
|
+
}
|
|
@@ -10,20 +10,19 @@ public class OpenMethod: PipeMethod {
|
|
|
10
10
|
public override var methodName: String {
|
|
11
11
|
return "router.open"
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
public override class func methodName() -> String {
|
|
15
15
|
return "router.open"
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
@objc public override var paramsModelClass: AnyClass {
|
|
19
19
|
return OpenMethodParamModel.self
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
@objc public override var resultModelClass: AnyClass {
|
|
23
23
|
return EmptyMethodModelClass.self
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
@objc(OpenMethodParamModel)
|
|
@@ -31,7 +30,7 @@ public class OpenMethodParamModel: SPKMethodModel {
|
|
|
31
30
|
public override class func requiredKeyPaths() -> Set<String>? {
|
|
32
31
|
return ["scheme"]
|
|
33
32
|
}
|
|
34
|
-
|
|
33
|
+
|
|
35
34
|
@objc public var scheme: String?
|
|
36
35
|
@objc public var replace: Bool = false
|
|
37
36
|
@objc public var replaceType: String?
|
|
@@ -8,5 +8,5 @@ import SparklingMethod
|
|
|
8
8
|
public protocol RouterService {
|
|
9
9
|
func openScheme(withParams params: OpenMethodParamModel, completion: @escaping PipeMethod.CompletionBlock)
|
|
10
10
|
func closeContainer(withParams params: CloseMethodParamModel, completion: @escaping PipeMethod.CompletionBlock)
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
|
|
3
|
-
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
-
|
|
5
1
|
Pod::Spec.new do |s|
|
|
6
2
|
s.name = 'Sparkling-Router'
|
|
7
|
-
s.version =
|
|
8
|
-
s.summary =
|
|
9
|
-
s.description =
|
|
10
|
-
s.license =
|
|
11
|
-
s.author =
|
|
3
|
+
s.version = "2.1.0-rc.24"
|
|
4
|
+
s.summary = "iOS navigation router SDK for Sparkling"
|
|
5
|
+
s.description = "iOS navigation router SDK for Sparkling"
|
|
6
|
+
s.license = "Apache-2.0"
|
|
7
|
+
s.author = "TikTok"
|
|
12
8
|
s.homepage = 'https://github.com/tiktok/sparkling'
|
|
13
9
|
s.platforms = {
|
|
14
10
|
:ios => '12.0'
|
|
@@ -21,7 +17,7 @@ Pod::Spec.new do |s|
|
|
|
21
17
|
'DEFINES_MODULE' => 'YES',
|
|
22
18
|
'SWIFT_COMPILATION_MODE' => 'wholemodule'
|
|
23
19
|
}
|
|
24
|
-
|
|
20
|
+
|
|
25
21
|
s.subspec 'Core' do |core|
|
|
26
22
|
core.source_files = [
|
|
27
23
|
'Sources/Core/Methods/**/*.{h,m,swift}',
|
|
@@ -29,7 +25,7 @@ Pod::Spec.new do |s|
|
|
|
29
25
|
'Sources/Core/Utils/*.{h,m,swift}',
|
|
30
26
|
]
|
|
31
27
|
end
|
|
32
|
-
|
|
28
|
+
|
|
33
29
|
s.dependency 'SparklingMethod/Core'
|
|
34
30
|
s.dependency 'SparklingMethod/DIProvider'
|
|
35
31
|
s.dependency 'Mantle', '~> 2.2.0'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sparkling-navigation",
|
|
3
|
-
"version": "2.1.0-rc.
|
|
3
|
+
"version": "2.1.0-rc.24",
|
|
4
4
|
"homepage": "https://tiktok.github.io/sparkling/",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"license": "Apache-2.0",
|
|
25
25
|
"description": "none",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"sparkling-method": "2.1.0-rc.
|
|
27
|
+
"sparkling-method": "2.1.0-rc.24"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/jest": "^29.5.12",
|
|
@@ -127,7 +127,7 @@ expect(consoleErrorSpy).toHaveBeenCalledWith('[sparkling-navigation] navigate: c
|
|
|
127
127
|
|
|
128
128
|
expect(mockOpen).toHaveBeenCalledWith(
|
|
129
129
|
{
|
|
130
|
-
scheme: 'hybrid://lynxview_page?bundle=pages%2Fsecond.lynx.bundle&title=Second
|
|
130
|
+
scheme: 'hybrid://lynxview_page?bundle=pages%2Fsecond.lynx.bundle&title=Second%20Page&screen_orientation=portrait',
|
|
131
131
|
options: { animated: true },
|
|
132
132
|
},
|
|
133
133
|
callback
|
|
@@ -213,4 +213,73 @@ expect(consoleErrorSpy).toHaveBeenCalledWith('[sparkling-navigation] navigate: c
|
|
|
213
213
|
);
|
|
214
214
|
});
|
|
215
215
|
});
|
|
216
|
+
|
|
217
|
+
describe('dev mode with globalProps', () => {
|
|
218
|
+
const savedLynx = (globalThis as any).lynx;
|
|
219
|
+
const savedDev = (globalThis as any).__DEV__;
|
|
220
|
+
const savedPublicPath = (globalThis as any).__webpack_public_path__;
|
|
221
|
+
|
|
222
|
+
beforeEach(() => {
|
|
223
|
+
(globalThis as any).__DEV__ = true;
|
|
224
|
+
(globalThis as any).__webpack_public_path__ = 'http://localhost:5969/';
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
afterEach(() => {
|
|
228
|
+
(globalThis as any).lynx = savedLynx;
|
|
229
|
+
(globalThis as any).__DEV__ = savedDev;
|
|
230
|
+
(globalThis as any).__webpack_public_path__ = savedPublicPath;
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should use base URL from globalProps.queryItems.url over __webpack_public_path__', () => {
|
|
234
|
+
(globalThis as any).lynx = {
|
|
235
|
+
__globalProps: {
|
|
236
|
+
queryItems: { url: 'http://192.168.1.100:5969/main.lynx.bundle' },
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
const callback = jest.fn();
|
|
240
|
+
|
|
241
|
+
navigate({ path: 'second.lynx.bundle' }, callback);
|
|
242
|
+
|
|
243
|
+
expect(mockOpen).toHaveBeenCalledWith(
|
|
244
|
+
expect.objectContaining({
|
|
245
|
+
scheme: expect.stringContaining('url=http%3A%2F%2F192.168.1.100%3A5969%2Fsecond.lynx.bundle'),
|
|
246
|
+
}),
|
|
247
|
+
callback,
|
|
248
|
+
);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
it('should fall back to __webpack_public_path__ when globalProps has no url', () => {
|
|
252
|
+
(globalThis as any).lynx = {
|
|
253
|
+
__globalProps: { queryItems: {} },
|
|
254
|
+
};
|
|
255
|
+
const callback = jest.fn();
|
|
256
|
+
|
|
257
|
+
navigate({ path: 'second.lynx.bundle' }, callback);
|
|
258
|
+
|
|
259
|
+
expect(mockOpen).toHaveBeenCalledWith(
|
|
260
|
+
expect.objectContaining({
|
|
261
|
+
scheme: expect.stringContaining('url=http%3A%2F%2Flocalhost%3A5969%2Fsecond.lynx.bundle'),
|
|
262
|
+
}),
|
|
263
|
+
callback,
|
|
264
|
+
);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should ignore non-HTTP URLs in globalProps', () => {
|
|
268
|
+
(globalThis as any).lynx = {
|
|
269
|
+
__globalProps: {
|
|
270
|
+
queryItems: { url: 'file:///local/main.lynx.bundle' },
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
const callback = jest.fn();
|
|
274
|
+
|
|
275
|
+
navigate({ path: 'second.lynx.bundle' }, callback);
|
|
276
|
+
|
|
277
|
+
expect(mockOpen).toHaveBeenCalledWith(
|
|
278
|
+
expect.objectContaining({
|
|
279
|
+
scheme: expect.stringContaining('url=http%3A%2F%2Flocalhost%3A5969%2Fsecond.lynx.bundle'),
|
|
280
|
+
}),
|
|
281
|
+
callback,
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
216
285
|
});
|
package/src/devServer.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Copyright (c) 2022 TikTok Pte. Ltd.
|
|
2
|
+
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
+
// LICENSE file in the root directory of this source tree.
|
|
4
|
+
|
|
5
|
+
declare const __DEV__: boolean;
|
|
6
|
+
declare const __webpack_public_path__: string;
|
|
7
|
+
declare const lynx: { __globalProps?: { queryItems?: Record<string, string> } } | undefined;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Derive the dev server base URL from the actual bundle URL that the native
|
|
11
|
+
* side used to load this page. Falls back to __webpack_public_path__.
|
|
12
|
+
*
|
|
13
|
+
* This ensures sub-page navigation uses the same host/port that the entry
|
|
14
|
+
* page was loaded from — critical for real-device debugging where the native
|
|
15
|
+
* side may use a LAN IP while __webpack_public_path__ is baked as localhost.
|
|
16
|
+
*/
|
|
17
|
+
export function getDevServerBaseURL(): string | undefined {
|
|
18
|
+
try {
|
|
19
|
+
if (typeof __DEV__ === 'undefined' || !__DEV__) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Prefer the actual URL the native side used to load this bundle.
|
|
24
|
+
// lynx.__globalProps.queryItems.url is set by the SDK from the scheme's
|
|
25
|
+
// url= parameter (e.g. "http://192.168.1.100:5969/main.lynx.bundle").
|
|
26
|
+
if (typeof lynx !== 'undefined' && lynx?.__globalProps?.queryItems?.url) {
|
|
27
|
+
const pageUrl = lynx.__globalProps.queryItems.url;
|
|
28
|
+
if (pageUrl.startsWith('http://') || pageUrl.startsWith('https://')) {
|
|
29
|
+
const lastSlash = pageUrl.lastIndexOf('/');
|
|
30
|
+
if (lastSlash > pageUrl.indexOf('//') + 1) {
|
|
31
|
+
return pageUrl.substring(0, lastSlash + 1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Fall back to build-time value.
|
|
37
|
+
if (typeof __webpack_public_path__ === 'string' && __webpack_public_path__) {
|
|
38
|
+
return __webpack_public_path__;
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
// globals not available
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
package/src/navigate/navigate.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
3
|
// LICENSE file in the root directory of this source tree.
|
|
4
4
|
import { open } from '../open/open';
|
|
5
|
+
import { getDevServerBaseURL } from '../devServer';
|
|
5
6
|
import type {
|
|
6
7
|
NavigateRequest,
|
|
7
8
|
NavigateResponse,
|
|
@@ -9,9 +10,6 @@ import type {
|
|
|
9
10
|
NavigateParams,
|
|
10
11
|
} from './navigate.d';
|
|
11
12
|
|
|
12
|
-
declare const __DEV__: boolean;
|
|
13
|
-
declare const __webpack_public_path__: string;
|
|
14
|
-
|
|
15
13
|
const DEFAULT_ROUTER_SCHEME = 'hybrid://lynxview_page';
|
|
16
14
|
const PROTOCOL_REGEX = /^[a-z][a-z0-9+.-]*:\/\//i;
|
|
17
15
|
|
|
@@ -29,17 +27,6 @@ function normalizePath(path: string): string {
|
|
|
29
27
|
return normalized;
|
|
30
28
|
}
|
|
31
29
|
|
|
32
|
-
function getDevServerBaseURL(): string | undefined {
|
|
33
|
-
try {
|
|
34
|
-
if (typeof __DEV__ !== 'undefined' && __DEV__ && typeof __webpack_public_path__ === 'string' && __webpack_public_path__) {
|
|
35
|
-
return __webpack_public_path__;
|
|
36
|
-
}
|
|
37
|
-
} catch {
|
|
38
|
-
// __DEV__ or __webpack_public_path__ not available
|
|
39
|
-
}
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
30
|
function buildScheme(baseScheme: string, bundlePath: string, params?: NavigateOptions['params']): string {
|
|
44
31
|
const sanitizedBase = (baseScheme || DEFAULT_ROUTER_SCHEME).trim().replace(/[?&]+$/, '') || DEFAULT_ROUTER_SCHEME;
|
|
45
32
|
const searchParams = new URLSearchParams();
|
|
@@ -73,7 +60,9 @@ function buildScheme(baseScheme: string, bundlePath: string, params?: NavigateOp
|
|
|
73
60
|
}
|
|
74
61
|
}
|
|
75
62
|
|
|
76
|
-
|
|
63
|
+
// URLSearchParams encodes spaces as '+' (x-www-form-urlencoded), but
|
|
64
|
+
// native URL parsers only understand '%20'. Replace to avoid mangled values.
|
|
65
|
+
return `${sanitizedBase}?${searchParams.toString().replace(/\+/g, '%20')}`;
|
|
77
66
|
}
|
|
78
67
|
|
|
79
68
|
export function navigate(params: NavigateRequest, callback: (result: NavigateResponse) => void): void {
|
package/src/open/open.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
3
|
// LICENSE file in the root directory of this source tree.
|
|
4
4
|
import pipe from 'sparkling-method';
|
|
5
|
+
import { getDevServerBaseURL } from '../devServer';
|
|
5
6
|
import type { OpenRequest, OpenResponse } from './open.d';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -37,8 +38,26 @@ export function open(params: OpenRequest, callback: (result: OpenResponse) => vo
|
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
// In dev mode, rewrite bundle= to url= so the native side loads from the
|
|
42
|
+
// dev server instead of stale local assets.
|
|
43
|
+
let scheme = params.scheme.trim();
|
|
44
|
+
const devBase = getDevServerBaseURL();
|
|
45
|
+
if (devBase) {
|
|
46
|
+
try {
|
|
47
|
+
const u = new URL(scheme);
|
|
48
|
+
const bundle = u.searchParams.get('bundle');
|
|
49
|
+
if (bundle && !u.searchParams.get('url')) {
|
|
50
|
+
u.searchParams.delete('bundle');
|
|
51
|
+
u.searchParams.set('url', `${devBase.replace(/\/+$/, '')}/${bundle.replace(/^(?:\.\/|\/)+/, '')}`);
|
|
52
|
+
scheme = u.toString();
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
// scheme is not a valid URL, pass through as-is
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
40
59
|
pipe.call('router.open', {
|
|
41
|
-
scheme
|
|
60
|
+
scheme,
|
|
42
61
|
...params.options,
|
|
43
62
|
}, (v: unknown) => {
|
|
44
63
|
const response = v as OpenResponse;
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
// Copyright 2025 The Sparkling Authors. All rights reserved.
|
|
2
|
-
// Licensed under the Apache License Version 2.0 that can be found in the
|
|
3
|
-
// LICENSE file in the root directory of this source tree.
|
|
4
|
-
|
|
5
|
-
import XCTest
|
|
6
|
-
import SparklingMethod
|
|
7
|
-
import SparklingMethodRouter
|
|
8
|
-
|
|
9
|
-
class SPKRouterTest: XCTestCase {
|
|
10
|
-
|
|
11
|
-
// MARK: - CloseMethod Tests
|
|
12
|
-
|
|
13
|
-
func testCloseMethodName() {
|
|
14
|
-
let method = CloseMethod()
|
|
15
|
-
XCTAssertEqual(method.methodName, "router.close")
|
|
16
|
-
XCTAssertEqual(CloseMethod.methodName(), "router.close")
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
func testCloseMethodModels() {
|
|
20
|
-
let method = CloseMethod()
|
|
21
|
-
XCTAssertTrue(method.paramsModelClass is CloseMethodParamModel.Type)
|
|
22
|
-
XCTAssertTrue(method.resultModelClass is EmptyMethodModelClass.Type)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
func testCloseMethodParamModelValidation() {
|
|
26
|
-
let paramModel = CloseMethodParamModel()
|
|
27
|
-
|
|
28
|
-
// Test without required field
|
|
29
|
-
XCTAssertThrowsError(try paramModel.validate())
|
|
30
|
-
|
|
31
|
-
// Test with required field
|
|
32
|
-
paramModel.containerID = "test-container"
|
|
33
|
-
XCTAssertNoThrow(try paramModel.validate())
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
func testCloseMethodParamModelJSONMapping() {
|
|
37
|
-
let paramModel = CloseMethodParamModel()
|
|
38
|
-
paramModel.containerID = "test-container"
|
|
39
|
-
paramModel.animated = true
|
|
40
|
-
|
|
41
|
-
XCTAssertEqual(paramModel.jsonKeyPathsByPropertyKey() as? [String: String], [
|
|
42
|
-
"containerID": "containerID",
|
|
43
|
-
"animated": "animated"
|
|
44
|
-
])
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// MARK: - OpenMethod Tests
|
|
48
|
-
|
|
49
|
-
func testOpenMethodName() {
|
|
50
|
-
let method = OpenMethod()
|
|
51
|
-
XCTAssertEqual(method.methodName, "router.open")
|
|
52
|
-
XCTAssertEqual(OpenMethod.methodName(), "router.open")
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
func testOpenMethodModels() {
|
|
56
|
-
let method = OpenMethod()
|
|
57
|
-
XCTAssertTrue(method.paramsModelClass is OpenMethodParamModel.Type)
|
|
58
|
-
XCTAssertTrue(method.resultModelClass is EmptyMethodModelClass.Type)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
func testOpenMethodParamModelValidation() {
|
|
62
|
-
let paramModel = OpenMethodParamModel()
|
|
63
|
-
|
|
64
|
-
// Test without required field
|
|
65
|
-
XCTAssertThrowsError(try paramModel.validate())
|
|
66
|
-
|
|
67
|
-
// Test with required field
|
|
68
|
-
paramModel.scheme = "https://example.com"
|
|
69
|
-
XCTAssertNoThrow(try paramModel.validate())
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
func testOpenMethodParamModelJSONMapping() {
|
|
73
|
-
let paramModel = OpenMethodParamModel()
|
|
74
|
-
|
|
75
|
-
XCTAssertEqual(paramModel.jsonKeyPathsByPropertyKey() as? [String: String], [
|
|
76
|
-
"scheme": "scheme",
|
|
77
|
-
"replace": "replace",
|
|
78
|
-
"replaceType": "replaceType",
|
|
79
|
-
"useSysBrowser": "useSysBrowser",
|
|
80
|
-
"animated": "animated",
|
|
81
|
-
"interceptor": "interceptor",
|
|
82
|
-
"extra": "extra"
|
|
83
|
-
])
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
func testOpenMethodParamModelDefaultValues() {
|
|
87
|
-
let paramModel = OpenMethodParamModel()
|
|
88
|
-
paramModel.scheme = "test-scheme"
|
|
89
|
-
|
|
90
|
-
XCTAssertFalse(paramModel.replace)
|
|
91
|
-
XCTAssertFalse(paramModel.useSysBrowser)
|
|
92
|
-
XCTAssertFalse(paramModel.animated)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
func testOpenMethodParamModelAllFields() {
|
|
96
|
-
let paramModel = OpenMethodParamModel()
|
|
97
|
-
paramModel.scheme = "test-scheme"
|
|
98
|
-
paramModel.replace = true
|
|
99
|
-
paramModel.replaceType = "all"
|
|
100
|
-
paramModel.useSysBrowser = true
|
|
101
|
-
paramModel.animated = true
|
|
102
|
-
paramModel.interceptor = "test-interceptor"
|
|
103
|
-
let extraDict = NSDictionary(dictionary: ["key": "value"])
|
|
104
|
-
paramModel.extra = extraDict
|
|
105
|
-
|
|
106
|
-
XCTAssertEqual(paramModel.scheme, "test-scheme")
|
|
107
|
-
XCTAssertTrue(paramModel.replace)
|
|
108
|
-
XCTAssertEqual(paramModel.replaceType, "all")
|
|
109
|
-
XCTAssertTrue(paramModel.useSysBrowser)
|
|
110
|
-
XCTAssertTrue(paramModel.animated)
|
|
111
|
-
XCTAssertEqual(paramModel.interceptor, "test-interceptor")
|
|
112
|
-
XCTAssertEqual(paramModel.extra, extraDict)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
func testOpenMethodParamModelFromDictParsesExtraObject() throws {
|
|
116
|
-
let dict: [String: Any] = [
|
|
117
|
-
"scheme": "hybrid://lynxview_page?bundle=a.lynx.bundle",
|
|
118
|
-
"extra": ["foo": "bar"],
|
|
119
|
-
]
|
|
120
|
-
let model = try XCTUnwrap(try OpenMethodParamModel.from(dict: dict))
|
|
121
|
-
XCTAssertNotNil(model.extra)
|
|
122
|
-
XCTAssertEqual(model.extra?["foo"] as? String, "bar")
|
|
123
|
-
}
|
|
124
|
-
}
|