expo-dev-menu 4.2.0 → 4.3.0

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/.eslintignore ADDED
@@ -0,0 +1 @@
1
+ build
package/CHANGELOG.md CHANGED
@@ -10,6 +10,37 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 4.3.0 — 2023-10-17
14
+
15
+ ### 🛠 Breaking changes
16
+
17
+ - Dropped support for Android SDK 21 and 22. ([#24201](https://github.com/expo/expo/pull/24201) by [@behenate](https://github.com/behenate))
18
+
19
+ ### 🐛 Bug fixes
20
+
21
+ - [Android] Fixed Fast Refresh being disabled by default ([#24643](https://github.com/expo/expo/pull/24643) by [@gabrieldonadel](https://github.com/gabrieldonadel))
22
+
23
+ ### 💡 Others
24
+
25
+ - Drop support for configuring SDK 44 and below with Prebuild. ([#24504](https://github.com/expo/expo/pull/24504) by [@EvanBacon](https://github.com/EvanBacon))
26
+
27
+ ## 3.2.1 — 2023-09-25
28
+
29
+ _This version does not introduce any user-facing changes._
30
+
31
+ ## 4.2.1 — 2023-09-18
32
+
33
+ ### 💡 Others
34
+
35
+ - Fix eslint and TypeScript warnings ([#24497](https://github.com/expo/expo/pull/24497) by [@kadikraman](https://github.com/kadikraman))
36
+
37
+ ## 3.2.0 — 2023-09-15
38
+
39
+ ### 🎉 New features
40
+
41
+ - Add `control+d` as a hotkey to open the menu. ([#24434](https://github.com/expo/expo/pull/24434) by [@alanjhughes](https://github.com/alanjhughes))
42
+ - Separate `refresh` button from the rest ([#24426](https://github.com/expo/expo/pull/24426) by [@kadikraman](https://github.com/kadikraman))
43
+
13
44
  ## 4.2.0 — 2023-09-15
14
45
 
15
46
  ### 🎉 New features
@@ -3,15 +3,15 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven-publish'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '4.2.0'
6
+ version = '4.3.0'
7
7
 
8
- buildscript {
9
- def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
10
- if (expoModulesCorePlugin.exists()) {
11
- apply from: expoModulesCorePlugin
12
- applyKotlinExpoModulesCorePlugin()
13
- }
8
+ def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
9
+ if (expoModulesCorePlugin.exists()) {
10
+ apply from: expoModulesCorePlugin
11
+ applyKotlinExpoModulesCorePlugin()
12
+ }
14
13
 
14
+ buildscript {
15
15
  // Simple helper that allows the root project to override versions declared by this library.
16
16
  ext.safeExtGet = { prop, fallback ->
17
17
  rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
@@ -51,7 +51,19 @@ afterEvaluate {
51
51
  }
52
52
 
53
53
  android {
54
- compileSdkVersion safeExtGet("compileSdkVersion", 33)
54
+ // Remove this if and it's contents, when support for SDK49 is dropped
55
+ if (!safeExtGet("expoProvidesDefaultConfig", false)) {
56
+ compileSdkVersion safeExtGet("compileSdkVersion", 33)
57
+
58
+ defaultConfig {
59
+ minSdkVersion safeExtGet("minSdkVersion", 23)
60
+ targetSdkVersion safeExtGet("targetSdkVersion", 33)
61
+ }
62
+
63
+ lintOptions {
64
+ abortOnError false
65
+ }
66
+ }
55
67
 
56
68
  def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
57
69
  if (agpVersion.tokenize('.')[0].toInteger() < 8) {
@@ -67,13 +79,8 @@ android {
67
79
 
68
80
  namespace "expo.modules.devmenu"
69
81
  defaultConfig {
70
- minSdkVersion safeExtGet("minSdkVersion", 21)
71
- targetSdkVersion safeExtGet("targetSdkVersion", 33)
72
82
  versionCode 10
73
- versionName '4.2.0'
74
- }
75
- lintOptions {
76
- abortOnError false
83
+ versionName '4.3.0'
77
84
  }
78
85
 
79
86
  buildTypes {
@@ -69,5 +69,12 @@ internal class DevMenuInternalSettingsWrapper(private val devSettings: DevIntern
69
69
  set(value) {
70
70
  devSettings.isRemoteJSDebugEnabled = value
71
71
  }
72
+
73
+ var isJSDevModeEnabled: Boolean
74
+ get() = devSettings.isJSDevModeEnabled
75
+ set(value) {
76
+ devSettings.isJSDevModeEnabled = value
77
+ }
78
+
72
79
  val packagerConnectionSettings: PackagerConnectionSettings = devSettings.packagerConnectionSettings
73
80
  }
@@ -3,7 +3,6 @@ package expo.modules.devmenu.devtools
3
3
  import android.content.Context
4
4
  import android.content.Intent
5
5
  import android.net.Uri
6
- import android.os.Build
7
6
  import android.provider.Settings
8
7
  import android.util.Log
9
8
  import com.facebook.react.ReactInstanceManager
@@ -35,7 +34,7 @@ class DevMenuDevToolsDelegate(
35
34
  internal val devInternalSettings: DevMenuInternalSettingsWrapper?
36
35
  get() {
37
36
  val devSettings = this.devSettings ?: return null
38
- return if (devSettings.javaClass.canonicalName == "com.facebook.react.DevInternalSettings") DevMenuInternalSettingsWrapper(devSettings) else null
37
+ return if (devSettings.javaClass.canonicalName == "com.facebook.react.devsupport.DevLauncherInternalSettings") DevMenuInternalSettingsWrapper(devSettings) else null
39
38
  }
40
39
 
41
40
  val reactContext
@@ -105,10 +104,7 @@ class DevMenuDevToolsDelegate(
105
104
  * Such permission is required to enable performance monitor.
106
105
  */
107
106
  private fun requestOverlaysPermission(context: Context) {
108
- if (
109
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
110
- !Settings.canDrawOverlays(context)
111
- ) {
107
+ if (!Settings.canDrawOverlays(context)) {
112
108
  val uri = Uri.parse("package:" + context.applicationContext.packageName)
113
109
  val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, uri).apply {
114
110
  flags = Intent.FLAG_ACTIVITY_NEW_TASK
@@ -4,6 +4,7 @@ import android.util.Log
4
4
  import android.view.KeyEvent
5
5
  import com.facebook.react.bridge.ReactApplicationContext
6
6
  import com.facebook.react.bridge.ReactContextBaseJavaModule
7
+ import com.facebook.react.devsupport.HMRClient
7
8
  import expo.interfaces.devmenu.DevMenuExtensionInterface
8
9
  import expo.interfaces.devmenu.DevMenuExtensionSettingsInterface
9
10
  import expo.interfaces.devmenu.items.DevMenuDataSourceInterface
@@ -87,7 +88,20 @@ class DevMenuExtension(reactContext: ReactApplicationContext) :
87
88
  }
88
89
 
89
90
  val fastRefreshAction = {
90
- devInternalSettings.isHotModuleReplacementEnabled = !devInternalSettings.isHotModuleReplacementEnabled
91
+ val nextEnabled = !devInternalSettings.isHotModuleReplacementEnabled
92
+ devInternalSettings.isHotModuleReplacementEnabled = nextEnabled
93
+
94
+ if (reactApplicationContext != null) {
95
+ if (nextEnabled) {
96
+ reactApplicationContext.getJSModule(HMRClient::class.java).enable()
97
+ } else {
98
+ reactApplicationContext.getJSModule(HMRClient::class.java).disable()
99
+ }
100
+ }
101
+ if (nextEnabled && !devInternalSettings.isJSDevModeEnabled) {
102
+ devInternalSettings.isJSDevModeEnabled = true
103
+ reactDevManager.handleReloadJS()
104
+ }
91
105
  }
92
106
 
93
107
  action("fast-refresh", fastRefreshAction) {
package/app/App.tsx CHANGED
@@ -4,7 +4,6 @@ import { View } from 'react-native';
4
4
  import { AppProviders } from './components/AppProviders';
5
5
  import { LoadInitialData } from './components/LoadInitialData';
6
6
  import { Main } from './components/Main';
7
- import { Onboarding } from './components/Onboarding';
8
7
  import { Splash } from './components/Splash';
9
8
  import { AppInfo, DevSettings, MenuPreferences } from './native-modules/DevMenu';
10
9
 
@@ -1,8 +1,8 @@
1
1
  import { View } from 'expo-dev-client-components';
2
2
  import * as React from 'react';
3
3
 
4
- import { loadFontsAsync } from '../native-modules/DevMenu';
5
4
  import { Splash } from './Splash';
5
+ import { loadFontsAsync } from '../native-modules/DevMenu';
6
6
 
7
7
  type LoadInitialDataProps = {
8
8
  children: React.ReactElement<any> | React.ReactElement<any>[];
@@ -43,12 +43,13 @@ export function Main({ registeredCallbacks = [], isDevice }: MainProps) {
43
43
  const appInfoClipboard = useClipboard();
44
44
 
45
45
  function onCopyUrlPress() {
46
- const { hostUrl } = appInfo;
47
- urlClipboard.onCopyPress(hostUrl);
46
+ if (appInfo?.hostUrl) {
47
+ urlClipboard.onCopyPress(appInfo.hostUrl);
48
+ }
48
49
  }
49
50
 
50
51
  function onCopyAppInfoPress() {
51
- const { runtimeVersion, sdkVersion, appName, appVersion } = appInfo;
52
+ const { runtimeVersion, sdkVersion, appName, appVersion } = appInfo || {};
52
53
  appInfoClipboard.onCopyPress({ runtimeVersion, sdkVersion, appName, appVersion });
53
54
  }
54
55
 
@@ -76,9 +77,9 @@ export function Main({ registeredCallbacks = [], isDevice }: MainProps) {
76
77
  <Row align="center" shrink="1">
77
78
  <View>
78
79
  <View height="xl" width="xl" overflow="hidden" bg="secondary" rounded="medium">
79
- {Boolean(appInfo.appIcon) && (
80
+ {Boolean(appInfo?.appIcon) && (
80
81
  <Image
81
- source={{ uri: appInfo.appIcon }}
82
+ source={{ uri: appInfo?.appIcon }}
82
83
  style={{ flex: 1, resizeMode: 'contain' }}
83
84
  />
84
85
  )}
@@ -90,22 +91,22 @@ export function Main({ registeredCallbacks = [], isDevice }: MainProps) {
90
91
  <View shrink="1">
91
92
  <Row style={{ flexWrap: 'wrap' }}>
92
93
  <Heading weight="bold" numberOfLines={1}>
93
- {appInfo.appName}
94
+ {appInfo?.appName}
94
95
  </Heading>
95
96
  </Row>
96
97
 
97
- {Boolean(appInfo.runtimeVersion) && (
98
+ {Boolean(appInfo?.runtimeVersion) && (
98
99
  <>
99
100
  <Text size="small" color="secondary">
100
- {`Runtime version: ${appInfo.runtimeVersion}`}
101
+ {`Runtime version: ${appInfo?.runtimeVersion}`}
101
102
  </Text>
102
103
  </>
103
104
  )}
104
105
 
105
- {Boolean(appInfo.sdkVersion) && !appInfo.runtimeVersion && (
106
+ {Boolean(appInfo?.sdkVersion) && !appInfo?.runtimeVersion && (
106
107
  <>
107
108
  <Text size="small" color="secondary">
108
- {`SDK version: ${appInfo.sdkVersion}`}
109
+ {`SDK version: ${appInfo?.sdkVersion}`}
109
110
  </Text>
110
111
  </>
111
112
  )}
@@ -129,7 +130,7 @@ export function Main({ registeredCallbacks = [], isDevice }: MainProps) {
129
130
  <Divider />
130
131
  <View style={{ flex: 1 }}>
131
132
  <ScrollView nestedScrollEnabled>
132
- {Boolean(appInfo.hostUrl) && (
133
+ {Boolean(appInfo?.hostUrl) && (
133
134
  <>
134
135
  <View bg="default" padding="medium">
135
136
  <Text color="secondary">Connected to:</Text>
@@ -144,7 +145,7 @@ export function Main({ registeredCallbacks = [], isDevice }: MainProps) {
144
145
  <Spacer.Horizontal size="small" />
145
146
  <Row flex="1" justify="between">
146
147
  <Text type="mono" numberOfLines={2} size="small">
147
- {appInfo.hostUrl}
148
+ {appInfo?.hostUrl}
148
149
  </Text>
149
150
 
150
151
  <ClipboardIcon />
@@ -276,7 +277,7 @@ export function Main({ registeredCallbacks = [], isDevice }: MainProps) {
276
277
  </View>
277
278
  </View>
278
279
 
279
- {appInfo.engine === 'Hermes' && (
280
+ {appInfo?.engine === 'Hermes' && (
280
281
  <>
281
282
  <Spacer.Vertical size="large" />
282
283
 
@@ -316,18 +317,18 @@ export function Main({ registeredCallbacks = [], isDevice }: MainProps) {
316
317
  <Spacer.Vertical size="large" />
317
318
 
318
319
  <View mx="small" rounded="large" overflow="hidden">
319
- <AppInfoRow title="Version" value={appInfo.appVersion} />
320
+ <AppInfoRow title="Version" value={appInfo?.appVersion || 'Unknown'} />
320
321
  <Divider />
321
- {Boolean(appInfo.runtimeVersion) && (
322
+ {Boolean(appInfo?.runtimeVersion) && (
322
323
  <>
323
- <AppInfoRow title="Runtime version" value={appInfo.runtimeVersion} />
324
+ <AppInfoRow title="Runtime version" value={appInfo?.runtimeVersion || 'Unknown'} />
324
325
  <Divider />
325
326
  </>
326
327
  )}
327
328
 
328
- {Boolean(appInfo.sdkVersion) && !appInfo.runtimeVersion && (
329
+ {Boolean(appInfo?.sdkVersion) && !appInfo?.runtimeVersion && (
329
330
  <>
330
- <AppInfoRow title="SDK Version" value={appInfo.sdkVersion} />
331
+ <AppInfoRow title="SDK Version" value={appInfo?.sdkVersion || 'Unknown'} />
331
332
  <Divider />
332
333
  </>
333
334
  )}
@@ -370,7 +371,7 @@ export function Main({ registeredCallbacks = [], isDevice }: MainProps) {
370
371
  }
371
372
 
372
373
  type SettingsRowButtonProps = {
373
- icon: React.ReactElement<any>;
374
+ icon: React.ReactElement<any> | null;
374
375
  label: string;
375
376
  description?: string;
376
377
  onPress: () => void;
@@ -6,7 +6,7 @@ export function useClipboard(clearInMillis: number = 3000) {
6
6
  const [clipboardContent, setClipboardContent] = React.useState('');
7
7
  const [clipboardError, setClipboardError] = React.useState('');
8
8
 
9
- const timerRef = React.useRef(null);
9
+ const timerRef = React.useRef<ReturnType<typeof setTimeout>>();
10
10
 
11
11
  React.useEffect(() => {
12
12
  if (clipboardContent) {
@@ -17,7 +17,7 @@ const defaultDevSettings: DevMenu.DevSettings = {
17
17
  isJSInspectorAvailable: false,
18
18
  };
19
19
 
20
- const DevSettingsContext = React.createContext<DevMenu.DevSettings>(defaultDevSettings);
20
+ const DevSettingsContext = React.createContext<DevMenu.DevSettings | undefined>(defaultDevSettings);
21
21
 
22
22
  export type DevSettingsProviderProps = {
23
23
  children: React.ReactNode;