expo-dev-launcher 6.0.12 → 6.1.0-canary-20250919-7a31b96
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/CHANGELOG.md +3 -9
- package/android/build.gradle +2 -2
- package/android/src/debug/java/expo/modules/devlauncher/DevLauncherController.kt +1 -10
- package/android/src/debug/java/expo/modules/devlauncher/compose/DevLauncherBottomTabsNavigator.kt +0 -83
- package/android/src/debug/java/expo/modules/devlauncher/compose/primitives/CircularProgressBar.kt +2 -3
- package/android/src/debug/java/expo/modules/devlauncher/compose/ui/ServerUrlInput.kt +10 -18
- package/android/src/debug/java/expo/modules/devlauncher/compose/utils/UrlUtils.kt +4 -23
- package/expo-dev-launcher-gradle-plugin/build.gradle.kts +3 -2
- package/ios/ReactDelegateHandler/ExpoDevLauncherReactDelegateHandler.swift +6 -6
- package/ios/SwiftUI/DevServersView.swift +13 -20
- package/package.json +5 -6
package/CHANGELOG.md
CHANGED
|
@@ -6,19 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
### 🎉 New features
|
|
8
8
|
|
|
9
|
+
- Remove `ExpoAppDelegate` inheritance requirement ([#39417](https://github.com/expo/expo/pull/39417) by [@gabrieldonadel](https://github.com/gabrieldonadel))
|
|
10
|
+
|
|
9
11
|
### 🐛 Bug fixes
|
|
10
12
|
|
|
11
13
|
### 💡 Others
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
### 🎉 New features
|
|
16
|
-
|
|
17
|
-
- [Android] Adds loading state when connecting to a development server. ([#39873](https://github.com/expo/expo/pull/39873) by [@lukmccall](https://github.com/lukmccall))
|
|
18
|
-
|
|
19
|
-
### 🐛 Bug fixes
|
|
20
|
-
|
|
21
|
-
- [expo-dev-launcher] Fix manual URL entry: decode percent-encoded URLs, enable return key submit, and support dark mode text. ([#39840](https://github.com/expo/expo/pull/39840) by [@blazejkustra](https://github.com/blazejkustra))
|
|
15
|
+
- [Android] Migrated from `kotlinOptions` to `compilerOptions` DSL. ([#39794](https://github.com/expo/expo/pull/39794) by [@huextrat](https://github.com/huextrat))
|
|
22
16
|
|
|
23
17
|
## 6.0.11 — 2025-09-11
|
|
24
18
|
|
package/android/build.gradle
CHANGED
|
@@ -20,13 +20,13 @@ expoModule {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
group = "host.exp.exponent"
|
|
23
|
-
version = "6.0
|
|
23
|
+
version = "6.1.0-canary-20250919-7a31b96"
|
|
24
24
|
|
|
25
25
|
android {
|
|
26
26
|
namespace "expo.modules.devlauncher"
|
|
27
27
|
defaultConfig {
|
|
28
28
|
versionCode 9
|
|
29
|
-
versionName "6.0
|
|
29
|
+
versionName "6.1.0-canary-20250919-7a31b96"
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
buildTypes {
|
|
@@ -7,8 +7,6 @@ import android.net.Uri
|
|
|
7
7
|
import android.os.Bundle
|
|
8
8
|
import android.util.Log
|
|
9
9
|
import androidx.annotation.UiThread
|
|
10
|
-
import androidx.compose.runtime.State
|
|
11
|
-
import androidx.compose.runtime.mutableStateOf
|
|
12
10
|
import androidx.core.net.toUri
|
|
13
11
|
import com.facebook.react.ReactActivity
|
|
14
12
|
import com.facebook.react.ReactActivityDelegate
|
|
@@ -109,10 +107,6 @@ class DevLauncherController private constructor() :
|
|
|
109
107
|
|
|
110
108
|
private var appIsLoading = false
|
|
111
109
|
|
|
112
|
-
private val _isLoadingToBundler = mutableStateOf(false)
|
|
113
|
-
val isLoadingToBundler: State<Boolean>
|
|
114
|
-
get() = _isLoadingToBundler
|
|
115
|
-
|
|
116
110
|
private var networkInterceptor: DevLauncherNetworkInterceptor? = null
|
|
117
111
|
private var pendingIntentExtras: Bundle? = null
|
|
118
112
|
|
|
@@ -136,7 +130,6 @@ class DevLauncherController private constructor() :
|
|
|
136
130
|
return
|
|
137
131
|
}
|
|
138
132
|
appIsLoading = true
|
|
139
|
-
_isLoadingToBundler.value = true
|
|
140
133
|
}
|
|
141
134
|
|
|
142
135
|
try {
|
|
@@ -170,7 +163,6 @@ class DevLauncherController private constructor() :
|
|
|
170
163
|
lifecycle.addListener(appLoaderListener)
|
|
171
164
|
mode = Mode.APP
|
|
172
165
|
|
|
173
|
-
_isLoadingToBundler.value = false
|
|
174
166
|
// Note that `launch` method is a suspend one. So the execution will be stopped here until the method doesn't finish.
|
|
175
167
|
if (appLoader.launch(appIntent)) {
|
|
176
168
|
recentlyOpedAppsRegistry.appWasOpened(parsedUrl.toString(), devLauncherUrl.queryParams, manifest)
|
|
@@ -187,7 +179,6 @@ class DevLauncherController private constructor() :
|
|
|
187
179
|
} catch (e: Exception) {
|
|
188
180
|
synchronized(this) {
|
|
189
181
|
appIsLoading = false
|
|
190
|
-
_isLoadingToBundler.value = false
|
|
191
182
|
}
|
|
192
183
|
throw e
|
|
193
184
|
}
|
|
@@ -243,7 +234,7 @@ class DevLauncherController private constructor() :
|
|
|
243
234
|
// used by appetize for snack
|
|
244
235
|
if (intent.getBooleanExtra("EXDevMenuDisableAutoLaunch", false)) {
|
|
245
236
|
canLaunchDevMenuOnStart = false
|
|
246
|
-
this.devMenuManager.setCanLaunchDevMenuOnStart(
|
|
237
|
+
this.devMenuManager.setCanLaunchDevMenuOnStart(canLaunchDevMenuOnStart)
|
|
247
238
|
}
|
|
248
239
|
|
|
249
240
|
if (!isDevLauncherUrl(uri)) {
|
package/android/src/debug/java/expo/modules/devlauncher/compose/DevLauncherBottomTabsNavigator.kt
CHANGED
|
@@ -1,40 +1,14 @@
|
|
|
1
1
|
package expo.modules.devlauncher.compose
|
|
2
2
|
|
|
3
3
|
import androidx.compose.animation.AnimatedContentTransitionScope
|
|
4
|
-
import androidx.compose.animation.AnimatedVisibility
|
|
5
4
|
import androidx.compose.animation.EnterTransition
|
|
6
5
|
import androidx.compose.animation.ExitTransition
|
|
7
6
|
import androidx.compose.animation.core.tween
|
|
8
|
-
import androidx.compose.animation.fadeIn
|
|
9
|
-
import androidx.compose.animation.fadeOut
|
|
10
|
-
import androidx.compose.animation.slideIn
|
|
11
|
-
import androidx.compose.animation.slideOut
|
|
12
|
-
import androidx.compose.foundation.background
|
|
13
|
-
import androidx.compose.foundation.clickable
|
|
14
|
-
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
15
|
-
import androidx.compose.foundation.layout.Arrangement
|
|
16
|
-
import androidx.compose.foundation.layout.Box
|
|
17
|
-
import androidx.compose.foundation.layout.Row
|
|
18
|
-
import androidx.compose.foundation.layout.fillMaxSize
|
|
19
|
-
import androidx.compose.foundation.layout.fillMaxWidth
|
|
20
|
-
import androidx.compose.foundation.layout.navigationBarsPadding
|
|
21
|
-
import androidx.compose.foundation.layout.padding
|
|
22
|
-
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
23
7
|
import androidx.compose.runtime.Composable
|
|
24
|
-
import androidx.compose.runtime.getValue
|
|
25
8
|
import androidx.compose.runtime.remember
|
|
26
|
-
import androidx.compose.ui.Alignment
|
|
27
|
-
import androidx.compose.ui.Modifier
|
|
28
|
-
import androidx.compose.ui.draw.clip
|
|
29
|
-
import androidx.compose.ui.graphics.Color
|
|
30
|
-
import androidx.compose.ui.text.font.FontWeight
|
|
31
|
-
import androidx.compose.ui.unit.IntOffset
|
|
32
|
-
import androidx.compose.ui.unit.dp
|
|
33
9
|
import androidx.navigation.compose.NavHost
|
|
34
10
|
import androidx.navigation.compose.composable
|
|
35
11
|
import androidx.navigation.compose.rememberNavController
|
|
36
|
-
import expo.modules.devlauncher.DevLauncherController
|
|
37
|
-
import expo.modules.devlauncher.compose.primitives.CircularProgressBar
|
|
38
12
|
import expo.modules.devlauncher.compose.primitives.DefaultScaffold
|
|
39
13
|
import expo.modules.devlauncher.compose.routes.CrashReport
|
|
40
14
|
import expo.modules.devlauncher.compose.routes.CrashReportRoute
|
|
@@ -47,8 +21,6 @@ import expo.modules.devlauncher.compose.routes.UpdatesRoute
|
|
|
47
21
|
import expo.modules.devlauncher.compose.ui.BottomTabBar
|
|
48
22
|
import expo.modules.devlauncher.compose.ui.Full
|
|
49
23
|
import expo.modules.devlauncher.compose.ui.rememberBottomSheetState
|
|
50
|
-
import expo.modules.devmenu.compose.newtheme.NewAppTheme
|
|
51
|
-
import expo.modules.devmenu.compose.primitives.NewText
|
|
52
24
|
|
|
53
25
|
@Composable
|
|
54
26
|
fun DevLauncherBottomTabsNavigator() {
|
|
@@ -134,59 +106,4 @@ fun DevLauncherBottomTabsNavigator() {
|
|
|
134
106
|
ProfileRoute(profileBottomSheetState)
|
|
135
107
|
|
|
136
108
|
DevelopmentServersRoute(developmentServersBottomSheetState)
|
|
137
|
-
|
|
138
|
-
val isVisible by (DevLauncherController.instance as DevLauncherController).isLoadingToBundler
|
|
139
|
-
|
|
140
|
-
AnimatedVisibility(
|
|
141
|
-
visible = isVisible,
|
|
142
|
-
enter = fadeIn(animationSpec = tween(durationMillis = 300)),
|
|
143
|
-
exit = fadeOut(animationSpec = tween(durationMillis = 300))
|
|
144
|
-
) {
|
|
145
|
-
Box(
|
|
146
|
-
modifier = Modifier
|
|
147
|
-
.fillMaxSize()
|
|
148
|
-
.background(Color.Black.copy(alpha = 0.6f))
|
|
149
|
-
.clickable(
|
|
150
|
-
interactionSource = remember { MutableInteractionSource() },
|
|
151
|
-
indication = null,
|
|
152
|
-
onClick = {
|
|
153
|
-
// Captures all clicks to block interaction with the underlying screen
|
|
154
|
-
}
|
|
155
|
-
)
|
|
156
|
-
) {
|
|
157
|
-
Row(
|
|
158
|
-
horizontalArrangement = Arrangement.SpaceBetween,
|
|
159
|
-
verticalAlignment = Alignment.CenterVertically,
|
|
160
|
-
modifier = Modifier
|
|
161
|
-
.align(Alignment.BottomStart)
|
|
162
|
-
.animateEnterExit(
|
|
163
|
-
enter = slideIn(
|
|
164
|
-
animationSpec = tween(durationMillis = 300),
|
|
165
|
-
initialOffset = { fullSize -> IntOffset(-fullSize.height, fullSize.width) }
|
|
166
|
-
),
|
|
167
|
-
exit = slideOut(
|
|
168
|
-
animationSpec = tween(durationMillis = 300),
|
|
169
|
-
targetOffset = { fullSize -> IntOffset(fullSize.height, fullSize.width) }
|
|
170
|
-
)
|
|
171
|
-
)
|
|
172
|
-
.clip(RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp))
|
|
173
|
-
.background(NewAppTheme.colors.background.element)
|
|
174
|
-
.fillMaxWidth()
|
|
175
|
-
.navigationBarsPadding()
|
|
176
|
-
.padding(NewAppTheme.spacing.`3`)
|
|
177
|
-
.padding(top = NewAppTheme.spacing.`1`)
|
|
178
|
-
) {
|
|
179
|
-
NewText(
|
|
180
|
-
"Connecting to the development server...",
|
|
181
|
-
style = NewAppTheme.font.md.copy(
|
|
182
|
-
fontWeight = FontWeight.SemiBold
|
|
183
|
-
)
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
CircularProgressBar(
|
|
187
|
-
size = 20.dp
|
|
188
|
-
)
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
109
|
}
|
package/android/src/debug/java/expo/modules/devlauncher/compose/primitives/CircularProgressBar.kt
CHANGED
|
@@ -25,14 +25,13 @@ import kotlin.time.Duration.Companion.seconds
|
|
|
25
25
|
|
|
26
26
|
@Composable
|
|
27
27
|
fun CircularProgressBar(
|
|
28
|
-
modifier: Modifier = Modifier,
|
|
29
28
|
startAngle: Float = 270f,
|
|
30
29
|
size: Dp = 96.dp,
|
|
31
30
|
strokeWidth: Dp = size / 8,
|
|
32
31
|
duration: Duration = 1.seconds
|
|
33
32
|
) {
|
|
34
33
|
val backgroundColor = NewAppTheme.pallet.gray.`3`
|
|
35
|
-
val progressColor = NewAppTheme.pallet.blue.`
|
|
34
|
+
val progressColor = NewAppTheme.pallet.blue.`5`
|
|
36
35
|
|
|
37
36
|
val transition = rememberInfiniteTransition(label = "infiniteSpinningTransition")
|
|
38
37
|
|
|
@@ -45,7 +44,7 @@ fun CircularProgressBar(
|
|
|
45
44
|
label = "Progress Animation"
|
|
46
45
|
)
|
|
47
46
|
|
|
48
|
-
Canvas(modifier = Modifier.size(size)
|
|
47
|
+
Canvas(modifier = Modifier.size(size)) {
|
|
49
48
|
val strokeWidthPx = strokeWidth.toPx()
|
|
50
49
|
val arcSize = size.toPx() - strokeWidthPx
|
|
51
50
|
drawArc(
|
|
@@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|
|
9
9
|
import androidx.compose.foundation.layout.padding
|
|
10
10
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
11
11
|
import androidx.compose.foundation.text.KeyboardOptions
|
|
12
|
-
import androidx.compose.foundation.text.KeyboardActions
|
|
13
12
|
import androidx.compose.runtime.Composable
|
|
14
13
|
import androidx.compose.runtime.getValue
|
|
15
14
|
import androidx.compose.runtime.mutableStateOf
|
|
@@ -27,7 +26,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|
|
27
26
|
import androidx.compose.ui.unit.dp
|
|
28
27
|
import com.composeunstyled.TextField
|
|
29
28
|
import com.composeunstyled.TextInput
|
|
30
|
-
import expo.modules.devlauncher.compose.utils.
|
|
29
|
+
import expo.modules.devlauncher.compose.utils.validateUrl
|
|
31
30
|
import expo.modules.devmenu.compose.newtheme.NewAppTheme
|
|
32
31
|
import expo.modules.devmenu.compose.primitives.NewText
|
|
33
32
|
|
|
@@ -38,18 +37,6 @@ fun ServerUrlInput(
|
|
|
38
37
|
var url by remember { mutableStateOf("") }
|
|
39
38
|
val context = LocalContext.current
|
|
40
39
|
|
|
41
|
-
fun connectToURL() {
|
|
42
|
-
val sanitizedURL = sanitizeUrlString(url)
|
|
43
|
-
if (sanitizedURL != null) {
|
|
44
|
-
openApp(sanitizedURL)
|
|
45
|
-
url = ""
|
|
46
|
-
} else {
|
|
47
|
-
Toast
|
|
48
|
-
.makeText(context, "Invalid URL", Toast.LENGTH_SHORT)
|
|
49
|
-
.show()
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
40
|
Column(
|
|
54
41
|
verticalArrangement = Arrangement.spacedBy(NewAppTheme.spacing.`2`)
|
|
55
42
|
) {
|
|
@@ -76,9 +63,6 @@ fun ServerUrlInput(
|
|
|
76
63
|
autoCorrectEnabled = false,
|
|
77
64
|
keyboardType = KeyboardType.Uri
|
|
78
65
|
),
|
|
79
|
-
keyboardActions = KeyboardActions(
|
|
80
|
-
onDone = { connectToURL() }
|
|
81
|
-
),
|
|
82
66
|
cursorBrush = SolidColor(NewAppTheme.colors.text.default.copy(alpha = 0.9f))
|
|
83
67
|
) {
|
|
84
68
|
TextInput(
|
|
@@ -101,7 +85,15 @@ fun ServerUrlInput(
|
|
|
101
85
|
textStyle = NewAppTheme.font.md.merge(
|
|
102
86
|
fontWeight = FontWeight.SemiBold
|
|
103
87
|
),
|
|
104
|
-
onClick = {
|
|
88
|
+
onClick = {
|
|
89
|
+
if (validateUrl(url)) {
|
|
90
|
+
openApp(url)
|
|
91
|
+
} else {
|
|
92
|
+
Toast
|
|
93
|
+
.makeText(context, "Invalid URL", Toast.LENGTH_SHORT)
|
|
94
|
+
.show()
|
|
95
|
+
}
|
|
96
|
+
}
|
|
105
97
|
)
|
|
106
98
|
}
|
|
107
99
|
}
|
|
@@ -1,31 +1,12 @@
|
|
|
1
1
|
package expo.modules.devlauncher.compose.utils
|
|
2
2
|
|
|
3
3
|
import androidx.core.net.toUri
|
|
4
|
-
import java.net.URLDecoder
|
|
5
|
-
import java.nio.charset.StandardCharsets
|
|
6
|
-
|
|
7
|
-
fun sanitizeUrlString(urlString: String): String? {
|
|
8
|
-
var sanitizedUrl = urlString.trim()
|
|
9
|
-
|
|
10
|
-
val decodedUrl = try {
|
|
11
|
-
URLDecoder.decode(sanitizedUrl, StandardCharsets.UTF_8.toString())
|
|
12
|
-
} catch (_: Exception) {
|
|
13
|
-
sanitizedUrl
|
|
14
|
-
}
|
|
15
|
-
sanitizedUrl = decodedUrl
|
|
16
|
-
|
|
17
|
-
if (!sanitizedUrl.contains("://")) {
|
|
18
|
-
sanitizedUrl = "http://$sanitizedUrl"
|
|
19
|
-
}
|
|
20
4
|
|
|
5
|
+
fun validateUrl(url: String): Boolean {
|
|
21
6
|
return try {
|
|
22
|
-
val uri =
|
|
23
|
-
|
|
24
|
-
sanitizedUrl
|
|
25
|
-
} else {
|
|
26
|
-
null
|
|
27
|
-
}
|
|
7
|
+
val uri = url.toUri()
|
|
8
|
+
uri.scheme != null && uri.host != null
|
|
28
9
|
} catch (_: Throwable) {
|
|
29
|
-
|
|
10
|
+
false
|
|
30
11
|
}
|
|
31
12
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
|
1
2
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|
2
3
|
|
|
3
4
|
plugins {
|
|
@@ -22,8 +23,8 @@ java {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
tasks.withType<KotlinCompile> {
|
|
25
|
-
|
|
26
|
-
jvmTarget
|
|
26
|
+
compilerOptions {
|
|
27
|
+
jvmTarget.set(JvmTarget.JVM_11)
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -50,21 +50,21 @@ public class ExpoDevLauncherReactDelegateHandler: ExpoReactDelegateHandler, EXDe
|
|
|
50
50
|
// MARK: EXDevelopmentClientControllerDelegate implementations
|
|
51
51
|
|
|
52
52
|
public func devLauncherController(_ developmentClientController: EXDevLauncherController, didStartWithSuccess success: Bool) {
|
|
53
|
-
guard let
|
|
54
|
-
(
|
|
55
|
-
fatalError("`UIApplication.shared.delegate` must be an `ExpoAppDelegate` or `EXAppDelegateWrapper`")
|
|
53
|
+
guard let reactDelegate = self.reactDelegate else {
|
|
54
|
+
fatalError("`reactDelegate` should not be nil")
|
|
56
55
|
}
|
|
57
|
-
|
|
56
|
+
|
|
57
|
+
self.reactNativeFactory = reactDelegate.reactNativeFactory as? RCTReactNativeFactory
|
|
58
58
|
|
|
59
59
|
// Reset rctAppDelegate so we can relaunch the app
|
|
60
|
-
if
|
|
60
|
+
if RCTIsNewArchEnabled() {
|
|
61
61
|
self.reactNativeFactory?.rootViewFactory.setValue(nil, forKey: "_reactHost")
|
|
62
62
|
} else {
|
|
63
63
|
self.reactNativeFactory?.bridge = nil
|
|
64
64
|
self.reactNativeFactory?.rootViewFactory.bridge = nil
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
let rootView =
|
|
67
|
+
let rootView = reactDelegate.reactNativeFactory.recreateRootView(
|
|
68
68
|
withBundleURL: developmentClientController.sourceUrl(),
|
|
69
69
|
moduleName: self.rootViewModuleName,
|
|
70
70
|
initialProps: self.rootViewInitialProperties,
|
|
@@ -8,10 +8,6 @@ import Combine
|
|
|
8
8
|
private func sanitizeUrlString(_ urlString: String) -> String? {
|
|
9
9
|
var sanitizedUrl = urlString.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
10
10
|
|
|
11
|
-
if let decodedUrl = sanitizedUrl.removingPercentEncoding {
|
|
12
|
-
sanitizedUrl = decodedUrl
|
|
13
|
-
}
|
|
14
|
-
|
|
15
11
|
if !sanitizedUrl.contains("://") {
|
|
16
12
|
sanitizedUrl = "http://" + sanitizedUrl
|
|
17
13
|
}
|
|
@@ -30,19 +26,6 @@ struct DevServersView: View {
|
|
|
30
26
|
@State private var urlText = ""
|
|
31
27
|
@State private var cancellables = Set<AnyCancellable>()
|
|
32
28
|
|
|
33
|
-
private func connectToURL() {
|
|
34
|
-
if !urlText.isEmpty {
|
|
35
|
-
let sanitizedURL = sanitizeUrlString(urlText)
|
|
36
|
-
if let validURL = sanitizedURL {
|
|
37
|
-
viewModel.openApp(url: validURL)
|
|
38
|
-
withAnimation(.easeInOut(duration: 0.3)) {
|
|
39
|
-
showingURLInput = false
|
|
40
|
-
}
|
|
41
|
-
urlText = ""
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
29
|
var body: some View {
|
|
47
30
|
VStack(alignment: .leading, spacing: 12) {
|
|
48
31
|
header
|
|
@@ -98,8 +81,7 @@ struct DevServersView: View {
|
|
|
98
81
|
.disableAutocorrection(true)
|
|
99
82
|
.padding(.horizontal, 16)
|
|
100
83
|
.padding(.vertical, 12)
|
|
101
|
-
.foregroundColor(.
|
|
102
|
-
.onSubmit(connectToURL)
|
|
84
|
+
.foregroundColor(.black)
|
|
103
85
|
#if !os(tvOS)
|
|
104
86
|
.overlay(
|
|
105
87
|
RoundedRectangle(cornerRadius: 5)
|
|
@@ -142,7 +124,18 @@ struct DevServersView: View {
|
|
|
142
124
|
}
|
|
143
125
|
|
|
144
126
|
private var connectButton: some View {
|
|
145
|
-
Button
|
|
127
|
+
Button {
|
|
128
|
+
if !urlText.isEmpty {
|
|
129
|
+
let sanitizedURL = sanitizeUrlString(urlText)
|
|
130
|
+
if let validURL = sanitizedURL {
|
|
131
|
+
viewModel.openApp(url: validURL)
|
|
132
|
+
withAnimation(.easeInOut(duration: 0.3)) {
|
|
133
|
+
showingURLInput = false
|
|
134
|
+
}
|
|
135
|
+
urlText = ""
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
} label: {
|
|
146
139
|
Text("Connect")
|
|
147
140
|
.font(.headline)
|
|
148
141
|
.foregroundColor(.white)
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-dev-launcher",
|
|
3
3
|
"title": "Expo Development Launcher",
|
|
4
|
-
"version": "6.0
|
|
4
|
+
"version": "6.1.0-canary-20250919-7a31b96",
|
|
5
5
|
"description": "Pre-release version of the Expo development launcher package for testing.",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -15,11 +15,10 @@
|
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"homepage": "https://docs.expo.dev",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"expo-dev-menu": "7.0.12",
|
|
19
|
-
"expo-manifests": "
|
|
18
|
+
"expo-dev-menu": "7.0.12-canary-20250919-7a31b96",
|
|
19
|
+
"expo-manifests": "1.0.9-canary-20250919-7a31b96"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"expo": "
|
|
23
|
-
}
|
|
24
|
-
"gitHead": "6523053d0d997d2a21f580d2752b2f873c122038"
|
|
22
|
+
"expo": "55.0.0-canary-20250919-7a31b96"
|
|
23
|
+
}
|
|
25
24
|
}
|