diff --git a/apps/bare-expo/e2e/TestSuite-test.native.js b/apps/bare-expo/e2e/TestSuite-test.native.js index 1101ade208e07..d38f7b8754535 100644 --- a/apps/bare-expo/e2e/TestSuite-test.native.js +++ b/apps/bare-expo/e2e/TestSuite-test.native.js @@ -40,6 +40,9 @@ describe('test-suite', () => { await device.launchApp({ newInstance: true, url: `bareexpo://test-suite/run?tests=${testName}`, + launchArgs: { + EXDevMenuIsOnboardingFinished: true, + }, }); const launchWaitingTime = platform === 'ios' ? 100 : 3000; diff --git a/apps/bare-expo/e2e/Utils.js b/apps/bare-expo/e2e/Utils.js index cf448e524ae5c..902e8f8657503 100644 --- a/apps/bare-expo/e2e/Utils.js +++ b/apps/bare-expo/e2e/Utils.js @@ -23,6 +23,9 @@ export async function launchWithPermissionsAsync(config, permissions, options) { } }, {}), newInstance: true, + launchArgs: { + EXDevMenuIsOnboardingFinished: true, + }, }); } else { await init(config, options); diff --git a/packages/expo-dev-launcher/CHANGELOG.md b/packages/expo-dev-launcher/CHANGELOG.md index 21fa11adaf913..09b91c12ba94e 100644 --- a/packages/expo-dev-launcher/CHANGELOG.md +++ b/packages/expo-dev-launcher/CHANGELOG.md @@ -19,6 +19,7 @@ - Refactored inline Android emulator checks to use enhanced checking in `EmulatorUtilities.isRunningOnEmulator()`. ([#16177](https://github.com/expo/expo/pull/16177)) by [@kbrandwijk](https://github.com/kbrandwijk), [@keith-kurak](https://github.com/keith-kurak)) - Switched uncaught exception logging to use metro websocket instead of expo-cli logUrl. ([#18787](https://github.com/expo/expo/pull/18787) by [@esamelson](https://github.com/esamelson)) +- Disable onboarding popup with URL query param. ([#19024](https://github.com/expo/expo/pull/19024) by [@douglowder](https://github.com/douglowder)) ## 1.2.1 — 2022-08-16 diff --git a/packages/expo-dev-launcher/ios/EXDevLauncherController.m b/packages/expo-dev-launcher/ios/EXDevLauncherController.m index 2fc50e2bfcad3..e02d908792d60 100644 --- a/packages/expo-dev-launcher/ios/EXDevLauncherController.m +++ b/packages/expo-dev-launcher/ios/EXDevLauncherController.m @@ -404,6 +404,9 @@ - (void)loadApp:(NSURL *)url withProjectUrl:(NSURL * _Nullable)projectUrl onSucc projectUrl = expoUrl; } + // Disable onboarding popup if "&disableOnboarding=1" is a param + [EXDevLauncherURLHelper disableOnboardingPopupIfNeeded:expoUrl]; + NSString *installationID = [_installationIDHelper getOrCreateInstallationID]; NSDictionary *updatesConfiguration = [EXDevLauncherUpdatesHelper createUpdatesConfigurationWithURL:expoUrl diff --git a/packages/expo-dev-launcher/ios/EXDevLauncherURLHelper.swift b/packages/expo-dev-launcher/ios/EXDevLauncherURLHelper.swift index 9c4aa67c09bec..a1d2a30d5a256 100644 --- a/packages/expo-dev-launcher/ios/EXDevLauncherURLHelper.swift +++ b/packages/expo-dev-launcher/ios/EXDevLauncherURLHelper.swift @@ -1,21 +1,22 @@ - // Copyright 2015-present 650 Industries. All rights reserved. +// Copyright 2015-present 650 Industries. All rights reserved. import Foundation +import EXDevMenu @objc public class EXDevLauncherUrl: NSObject { @objc public var url: URL - + @objc public var queryParams: [String: String] - + @objc public init(_ url: URL) { self.queryParams = EXDevLauncherURLHelper.getQueryParamsForUrl(url) self.url = url - - if (EXDevLauncherURLHelper.isDevLauncherURL(url)) { + + if EXDevLauncherURLHelper.isDevLauncherURL(url) { if let urlParam = self.queryParams["url"] { if let urlFromParam = URL.init(string: urlParam) { self.url = EXDevLauncherURLHelper.replaceEXPScheme(urlFromParam, to: "http") @@ -24,7 +25,7 @@ public class EXDevLauncherUrl: NSObject { } else { self.url = EXDevLauncherURLHelper.replaceEXPScheme(self.url, to: "http") } - + super.init() } } @@ -35,41 +36,51 @@ public class EXDevLauncherURLHelper: NSObject { public static func isDevLauncherURL(_ url: URL?) -> Bool { return url?.host == "expo-development-client" } - + @objc public static func hasUrlQueryParam(_ url: URL) -> Bool { var hasUrlQueryParam = false - + let components = URLComponents.init(url: url, resolvingAgainstBaseURL: false) - - for queryItem in components?.queryItems ?? [] { - if queryItem.name == "url" && queryItem.value != nil { - hasUrlQueryParam = true - break - } + + if ((components?.queryItems?.contains(where: { + $0.name == "url" && $0.value != nil + })) ?? false) { + hasUrlQueryParam = true } - + return hasUrlQueryParam } + @objc + public static func disableOnboardingPopupIfNeeded(_ url: URL) { + let components = URLComponents.init(url: url, resolvingAgainstBaseURL: false) + + if ((components?.queryItems?.contains(where: { + $0.name == "disableOnboarding" && ($0.value ?? "") == "1" + })) ?? false) { + DevMenuPreferences.isOnboardingFinished = true + } + } + @objc public static func replaceEXPScheme(_ url: URL, to scheme: String) -> URL { var components = URLComponents.init(url: url, resolvingAgainstBaseURL: false)! - if (components.scheme == "exp") { + if components.scheme == "exp" { components.scheme = scheme } return components.url! } - + @objc public static func getQueryParamsForUrl(_ url: URL) -> [String: String] { let components = URLComponents.init(url: url, resolvingAgainstBaseURL: false) var dict: [String: String] = [:] - + for parameter in components?.queryItems ?? [] { dict[parameter.name] = parameter.value?.removingPercentEncoding ?? "" } - + return dict } } diff --git a/packages/expo-dev-menu/CHANGELOG.md b/packages/expo-dev-menu/CHANGELOG.md index 8447c351f35d9..0ed2062910f9b 100644 --- a/packages/expo-dev-menu/CHANGELOG.md +++ b/packages/expo-dev-menu/CHANGELOG.md @@ -12,6 +12,8 @@ ### 💡 Others +- Disable onboarding popup with URL query param. ([#19024](https://github.com/expo/expo/pull/19024) by [@douglowder](https://github.com/douglowder)) + ## 1.2.1 — 2022-08-16 ### 🐛 Bug fixes diff --git a/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/DevMenuDevSettings.kt b/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/DevMenuDevSettings.kt index 6066a7de330cc..117dbf418530a 100644 --- a/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/DevMenuDevSettings.kt +++ b/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/DevMenuDevSettings.kt @@ -23,15 +23,18 @@ object DevMenuDevSettings { putBoolean("isElementInspectorAvailable", devSettings.isJSDevModeEnabled) putBoolean("isHotLoadingAvailable", devSettings.isJSDevModeEnabled) putBoolean("isPerfMonitorAvailable", devSettings.isJSDevModeEnabled) - putBoolean("isJSInspectorAvailable", run { - val packageName = reactInstanceManager.currentReactContext?.packageName - ?: return@run false - val metroHost = "http://${devSettings.packagerConnectionSettings.debugServerHost}" - runBlocking { - DevMenuManager.metroClient - .queryJSInspectorAvailability(metroHost, packageName) + putBoolean( + "isJSInspectorAvailable", + run { + val packageName = reactInstanceManager.currentReactContext?.packageName + ?: return@run false + val metroHost = "http://${devSettings.packagerConnectionSettings.debugServerHost}" + runBlocking { + DevMenuManager.metroClient + .queryJSInspectorAvailability(metroHost, packageName) + } } - }) + ) } } diff --git a/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/DevMenuManager.kt b/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/DevMenuManager.kt index 9f790f0cca4da..b4a9fe861e335 100644 --- a/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/DevMenuManager.kt +++ b/packages/expo-dev-menu/android/src/debug/java/expo/modules/devmenu/DevMenuManager.kt @@ -206,6 +206,10 @@ object DevMenuManager : DevMenuManagerInterface, LifecycleEventListener { } } + private fun hasDisableOnboardingQueryParam(urlString: String): Boolean { + return urlString.contains("disableOnboarding=1") + } + /** * Starts dev menu if wasn't initialized, prepares for opening menu at launch if needed and gets [DevMenuPreferences]. * We can't open dev menu here, cause then the app will crash - two react instance try to render. @@ -227,6 +231,10 @@ object DevMenuManager : DevMenuManagerInterface, LifecycleEventListener { DevMenuDefaultPreferences() } ).also { + if (hasDisableOnboardingQueryParam(currentManifestURL.orEmpty())) { + it.isOnboardingFinished = true + } + }.also { shouldLaunchDevMenuOnStart = canLaunchDevMenuOnStart && (it.showsAtLaunch || !it.isOnboardingFinished) if (shouldLaunchDevMenuOnStart) { reactContext.addLifecycleEventListener(this) diff --git a/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/DevMenuActivity.kt b/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/DevMenuActivity.kt index 280f6ea6327d1..45530801541e4 100644 --- a/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/DevMenuActivity.kt +++ b/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/DevMenuActivity.kt @@ -1,7 +1,5 @@ package expo.modules.devmenu -import android.content.Context -import android.content.pm.ActivityInfo import android.os.Build import android.os.Bundle import android.view.KeyEvent diff --git a/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/extensions/DevMenuExtension.kt b/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/extensions/DevMenuExtension.kt index fda70a435fb89..fe0b5882f45d0 100644 --- a/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/extensions/DevMenuExtension.kt +++ b/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/extensions/DevMenuExtension.kt @@ -15,7 +15,6 @@ import expo.interfaces.devmenu.items.KeyCommand import expo.modules.devmenu.DEV_MENU_TAG import expo.modules.devmenu.DevMenuManager import expo.modules.devmenu.devtools.DevMenuDevToolsDelegate -import kotlinx.coroutines.runBlocking class DevMenuExtension(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext), DevMenuExtensionInterface { diff --git a/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/modules/DevMenuInternalModule.kt b/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/modules/DevMenuInternalModule.kt index d0b574f11c86d..69f66aa4e2d34 100644 --- a/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/modules/DevMenuInternalModule.kt +++ b/packages/expo-dev-menu/android/src/main/java/expo/modules/devmenu/modules/DevMenuInternalModule.kt @@ -1,6 +1,5 @@ package expo.modules.devmenu.modules -import android.os.Build import com.facebook.react.bridge.Promise import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule diff --git a/packages/expo-dev-menu/android/src/release/java/expo/modules/devmenu/DevMenuManager.kt b/packages/expo-dev-menu/android/src/release/java/expo/modules/devmenu/DevMenuManager.kt index f7738580bbcf0..492be447e15f9 100644 --- a/packages/expo-dev-menu/android/src/release/java/expo/modules/devmenu/DevMenuManager.kt +++ b/packages/expo-dev-menu/android/src/release/java/expo/modules/devmenu/DevMenuManager.kt @@ -96,7 +96,6 @@ object DevMenuManager : DevMenuManagerInterface { throw IllegalStateException(DEV_MENU_IS_NOT_AVAILABLE) } - override fun setCanLaunchDevMenuOnStart(canLaunchDevMenuOnStart: Boolean) { throw IllegalStateException(DEV_MENU_IS_NOT_AVAILABLE) } diff --git a/packages/expo-dev-menu/ios/Modules/DevMenuPreferences.swift b/packages/expo-dev-menu/ios/Modules/DevMenuPreferences.swift index 992977e360eef..b73db23d62f7e 100644 --- a/packages/expo-dev-menu/ios/Modules/DevMenuPreferences.swift +++ b/packages/expo-dev-menu/ios/Modules/DevMenuPreferences.swift @@ -84,8 +84,10 @@ public class DevMenuPreferences: NSObject, RCTBridgeModule { /** Returns `true` only if the user finished onboarding, `false` otherwise. + This is now public because expo-dev-launcher needs access + in order to disable the onboarding popup for certain bundle URLs */ - static var isOnboardingFinished: Bool { + public static var isOnboardingFinished: Bool { get { return DevMenuTestInterceptorManager.interceptor?.isOnboardingFinishedKey ?? boolForKey(isOnboardingFinishedKey) }