diff --git a/native/.gitignore b/native/.gitignore index dee60a8f8..c09192e0a 100644 --- a/native/.gitignore +++ b/native/.gitignore @@ -1,65 +1,64 @@ # OSX # .DS_Store # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate ios/.xcode.env.local # Android/IntelliJ # build/ .idea .gradle local.properties *.iml *.hprof # node.js # node_modules/ npm-debug.log yarn-error.log # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://docs.fastlane.tools/best-practices/source-control/ */fastlane/report.xml */fastlane/Preview.html */fastlane/screenshots # Bundle artifact *.jsbundle # Ruby / CocoaPods /ios/Pods/ /vendor/bundle/ android/app/.cxx/ codegen/dist -facts/network.json facts/alchemy.json # Expo .expo diff --git a/native/app.config.js b/native/app.config.js index 23a8c1e1c..40c0fd731 100644 --- a/native/app.config.js +++ b/native/app.config.js @@ -1,26 +1,40 @@ /* eslint-disable flowtype/require-valid-file-annotation */ import ip from 'internal-ip'; // Finds this machine's hostname in the local network. This is useful for // debugging on a real device. The `COMM_DEV` environment variable must be set // or this function will return `null`. The `COMM_NAT_DEV_HOSTNAME` environment // variable can be used to override the autodetected hostname. function getDevHostname() { const { COMM_DEV: isDev, COMM_NAT_DEV_HOSTNAME } = process.env; if (!isDev) { return null; } if (COMM_NAT_DEV_HOSTNAME) { return COMM_NAT_DEV_HOSTNAME; } - return ip.v4.sync(); + const autodetectedHostname = ip.v4.sync(); + + // we only want to show this warning once, but this expo config file is + // evaluated multiple times, so we use a flag to make sure it's only shown + // once + if (!autodetectedHostname && !process.env._HOSTNAME_WARNING_SHOWN) { + console.warn( + 'Failed to autodetect `natDevHostname`. Please provide it manually ' + + 'by setting the `COMM_NAT_DEV_HOSTNAME` environment variable: ' + + '`COMM_NAT_DEV_HOSTNAME=${hostname} yarn dev`', + ); + process.env._HOSTNAME_WARNING_SHOWN = true; + } + + return autodetectedHostname; } export default { extra: { // developer machine's hostname in the local network natDevHostname: getDevHostname(), }, }; diff --git a/native/utils/dev-hostname.js b/native/utils/dev-hostname.js index 1b90de03f..bb0305b6a 100644 --- a/native/utils/dev-hostname.js +++ b/native/utils/dev-hostname.js @@ -1,47 +1,31 @@ // @flow import Constants from 'expo-constants'; let warnNatDevHostnameUndefined = true; const defaultNatDevHostname = '192.168.1.1'; function readHostnameFromExpoConfig(): ?string { const { natDevHostname: detectedHostname } = Constants.expoConfig.extra || {}; if (!detectedHostname || typeof detectedHostname !== 'string') { return null; } warnNatDevHostnameUndefined = false; return detectedHostname; } -function readHostnameFromNetworkJson(): string { - try { - // this is your machine's hostname in the local network - // usually it looks like this: 192.168.1.x - // to find it you may want to use `ifconfig | grep '192.168'` - // command in the terminal - // example of native/facts/network.json: - // { "natDevHostname": "192.168.1.x" } - // $FlowExpectedError: It's a conditional require so the file may not exist - const hostname: string = require('../facts/network.json').natDevHostname; - warnNatDevHostnameUndefined = false; - return hostname; - } catch (e) { - return defaultNatDevHostname; - } -} - -const natDevHostname: string = - readHostnameFromExpoConfig() ?? readHostnameFromNetworkJson(); - function checkForMissingNatDevHostname() { if (!warnNatDevHostnameUndefined) { return; } console.warn( - 'Failed to autodetect natDevHostname. ' + - 'Please specify it manually in native/facts/network.json', + 'Failed to read `natDevHostname` from Expo config. ' + + 'Please provide it manually by setting the `COMM_NAT_DEV_HOSTNAME` ' + + 'environment variable: `COMM_NAT_DEV_HOSTNAME=${hostname} yarn dev`', ); warnNatDevHostnameUndefined = false; } +const natDevHostname: string = + readHostnameFromExpoConfig() || defaultNatDevHostname; + export { natDevHostname, checkForMissingNatDevHostname }; diff --git a/patches/@expo+cli+0.4.10.patch b/patches/@expo+cli+0.4.10.patch index 8e799000d..b551c0baf 100644 --- a/patches/@expo+cli+0.4.10.patch +++ b/patches/@expo+cli+0.4.10.patch @@ -1,80 +1,73 @@ diff --git a/node_modules/@expo/cli/build/src/start/interface/interactiveActions.js b/node_modules/@expo/cli/build/src/start/interface/interactiveActions.js -index 9ab8961..ab012c0 100644 +index 9ab8961..27b9cc2 100644 --- a/node_modules/@expo/cli/build/src/start/interface/interactiveActions.js +++ b/node_modules/@expo/cli/build/src/start/interface/interactiveActions.js @@ -45,12 +45,17 @@ class DevServerManagerActions { if (this.devServerManager.getNativeDevServerPort()) { const devServer = this.devServerManager.getDefaultDevServer(); try { + const devServerUrl = devServer.getDevServerUrl(); const nativeRuntimeUrl = devServer.getNativeRuntimeUrl(); const interstitialPageUrl = devServer.getRedirectUrl(); (0, _commandsTable).printQRCode(interstitialPageUrl != null ? interstitialPageUrl : nativeRuntimeUrl); if (interstitialPageUrl) { Log.log((0, _commandsTable).printItem(_chalk.default`Choose an app to open your project at {underline ${interstitialPageUrl}}`)); } + if (nativeRuntimeUrl !== devServerUrl) { + // When using a custom scheme, the IP in the deep link URL is difficult to read, so we print the LAN address too. + Log.log((0, _commandsTable).printItem(_chalk.default`Dev server LAN address: {underline ${devServerUrl}}`)); + } Log.log((0, _commandsTable).printItem(_chalk.default`Metro waiting on {underline ${nativeRuntimeUrl}}`)); // TODO: if development build, change this message! Log.log((0, _commandsTable).printItem("Scan the QR code above with Expo Go (Android) or the Camera app (iOS)")); diff --git a/node_modules/@expo/cli/build/src/start/server/BundlerDevServer.js b/node_modules/@expo/cli/build/src/start/server/BundlerDevServer.js -index 0a601bd..2c0a210 100644 +index 0a601bd..c4dbd20 100644 --- a/node_modules/@expo/cli/build/src/start/server/BundlerDevServer.js +++ b/node_modules/@expo/cli/build/src/start/server/BundlerDevServer.js -@@ -255,6 +255,23 @@ class BundlerDevServer { +@@ -255,6 +255,16 @@ class BundlerDevServer { return `${location.protocol}://localhost:${location.port}`; } var _url; + if (location.host === 'localhost') { + // try autodetect IP + try { + const ip = require("../../utils/ip").getIpAddress(); + if (ip !== "127.0.0.1") { + return `${location.protocol}://${ip}:${location.port}`; + } + } catch(e) {} -+ // fall back to facts/network.json -+ try { -+ const { natDevHostname } = require('../../../../../../../native/facts/network.json'); -+ if (natDevHostname != null) { -+ return `${location.protocol}://${natDevHostname}:${location.port}`; -+ } -+ } catch(e) {} -+ // if everithing else fails, fall back to localhost ++ // if the above fails, fall back to localhost + } return (_url = location.url) != null ? _url : null; } /** Get the base URL for JS inspector */ getJsInspectorBaseUrl() { diff --git a/node_modules/@expo/cli/build/src/utils/scheme.js b/node_modules/@expo/cli/build/src/utils/scheme.js index 0d1b9dd..3b0402b 100644 --- a/node_modules/@expo/cli/build/src/utils/scheme.js +++ b/node_modules/@expo/cli/build/src/utils/scheme.js @@ -50,7 +50,9 @@ function sortLongest(obj) { } async function getSchemesForIosAsync(projectRoot) { try { - const infoPlistBuildProperty = (0, _getInfoPlistPath).getInfoPlistPathFromPbxproj(projectRoot); + // see https://github.com/expo/expo/discussions/20875 for details on this patch + // if this patch ever breaks, it can be worked around by adding a --scheme flag to the expo start command + const infoPlistBuildProperty = (0, _getInfoPlistPath).getInfoPlistPathFromPbxproj(projectRoot, { buildConfiguration: 'Debug' }); debug(`ios application Info.plist path:`, infoPlistBuildProperty); if (infoPlistBuildProperty) { const configPath = _path.default.join(projectRoot, "ios", infoPlistBuildProperty); @@ -71,6 +73,14 @@ async function getSchemesForAndroidAsync(projectRoot) { const configPath = await _configPlugins.AndroidConfig.Paths.getAndroidManifestAsync(projectRoot); const manifest = await _configPlugins.AndroidConfig.Manifest.readAndroidManifestAsync(configPath); const schemes = await _configPlugins.AndroidConfig.Scheme.getSchemesFromManifest(manifest); + // see https://github.com/expo/expo/discussions/20875 for details on this patch + // if this patch ever breaks, it can be worked around by adding a --scheme flag to the expo start command + if (schemes.length < 1) { + const debugManifestPath = _path.default.join(projectRoot, 'android/app/src/debug/AndroidManifest.xml'); + const debugManifest = await _configPlugins.AndroidConfig.Manifest.readAndroidManifestAsync(debugManifestPath); + const debugSchemes = await _configPlugins.AndroidConfig.Scheme.getSchemesFromManifest(debugManifest); + schemes.push(...debugSchemes); + } debug(`android application schemes:`, schemes); return sortLongest(schemes); } catch (error) {