Skip to content

Commit

Permalink
[expo-dev-menu][expo-dev-launcher] Disable onboarding popup with URL …
Browse files Browse the repository at this point in the history
…query param (expo#19024)

Add code to check for `disableOnboarding` in the URL and set `DevMenuPreferences.isOnboardingFinished=true` before the app launches.

Additionally, if testing in Detox, you can pass in a launch param to disable the onboarding popup in iOS (but not in Android). Made this change in the `apps/bare-expo` Detox tests.
  • Loading branch information
douglowder authored and Ddv0623 committed Sep 26, 2022
1 parent c7e9c1b commit 4af0b29
Show file tree
Hide file tree
Showing 13 changed files with 64 additions and 33 deletions.
3 changes: 3 additions & 0 deletions apps/bare-expo/e2e/TestSuite-test.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions apps/bare-expo/e2e/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ export async function launchWithPermissionsAsync(config, permissions, options) {
}
}, {}),
newInstance: true,
launchArgs: {
EXDevMenuIsOnboardingFinished: true,
},
});
} else {
await init(config, options);
Expand Down
1 change: 1 addition & 0 deletions packages/expo-dev-launcher/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions packages/expo-dev-launcher/ios/EXDevLauncherController.m
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
49 changes: 30 additions & 19 deletions packages/expo-dev-launcher/ios/EXDevLauncherURLHelper.swift
Original file line number Diff line number Diff line change
@@ -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")
Expand All @@ -24,7 +25,7 @@ public class EXDevLauncherUrl: NSObject {
} else {
self.url = EXDevLauncherURLHelper.replaceEXPScheme(self.url, to: "http")
}

super.init()
}
}
Expand All @@ -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
}
}
2 changes: 2 additions & 0 deletions packages/expo-dev-menu/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
})
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
4 changes: 3 additions & 1 deletion packages/expo-dev-menu/ios/Modules/DevMenuPreferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down

0 comments on commit 4af0b29

Please sign in to comment.