![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
expo-dev-menu
Advanced tools
The expo-dev-menu package provides a developer menu for React Native apps built with Expo. It allows developers to access various debugging and development tools directly within the app, making it easier to test and debug applications.
Access Developer Menu
This feature allows developers to open the developer menu programmatically. The developer menu provides various tools and options for debugging and testing the app.
import { DevMenu } from 'expo-dev-menu';
// Open the developer menu
DevMenu.show();
Custom Developer Menu Items
This feature allows developers to add custom items to the developer menu. These items can perform specific actions when selected, providing a way to extend the functionality of the developer menu.
import { registerDevMenuItem } from 'expo-dev-menu';
registerDevMenuItem({
name: 'Custom Item',
callback: () => {
console.log('Custom item selected');
}
});
Toggle Performance Monitor
This feature allows developers to toggle the performance monitor on and off. The performance monitor provides insights into the app's performance, such as frame rate and memory usage.
import { DevMenu } from 'expo-dev-menu';
// Toggle the performance monitor
DevMenu.togglePerformanceMonitor();
React Native Debugger is a standalone app for debugging React Native apps. It includes a range of tools for inspecting and debugging the app, such as a network inspector, Redux DevTools, and more. Unlike expo-dev-menu, it is a separate application that runs alongside the React Native app.
Flipper is a platform for debugging mobile apps, including React Native apps. It provides a range of plugins for inspecting and debugging various aspects of the app, such as network requests, layout, and more. Flipper is more comprehensive than expo-dev-menu, offering a wider range of debugging tools and integrations.
Expo/React Native module with the developer menu.
Firstly, you need to add the expo-dev-menu
package to your project.
yarn add expo-dev-menu
npm install expo-dev-menu
Then you can start to configure the native projects using steps below.
Set up the DevMenuManager
in the native code.
You can do it in two ways. We recommend using the basic initialization. However, if you have the custom activity in your application, then the advanced one will be more suitable for you.
Basic
Open the MainActivity.java
or MainActivity.kt
and make sure that your main activity class extends the DevMenuAwareReactActivity
.
...
// You need to import the `DevMenuAwareReactActivity` class
import expo.modules.devmenu.react.DevMenuAwareReactActivity;
...
// Make sure that the `MainActivity` extends the `DevMenuAwareReactActivity` class not the `ReactActivity`
public class MainActivity extends DevMenuAwareReactActivity {
...
}
...
// You need to import the `DevMenuAwareReactActivity` class
import expo.modules.devmenu.react.DevMenuAwareReactActivity;
...
// Make sure that the `MainActivity` extends the `DevMenuAwareReactActivity` class not the `ReactActivity`
class MainActivity : DevMenuAwareReactActivity() {
...
}
Advanced
I. Open the file with the main activity of your application (MainActivity.java
or MainActivity.kt
) and add methods that will communicate with the DevMenuManager
.
...
// Add those imports.
import android.view.KeyEvent;
import android.view.MotionEvent;
import expo.modules.devmenu.DevMenuManager;
...
public class MainActivity extends ReactActivity {
...
// A function which sends the touch events to the dev menu.
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
DevMenuManager.INSTANCE.onTouchEvent(ev);
return super.dispatchTouchEvent(ev);
}
// A function which handles the key commands.
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
return DevMenuManager.INSTANCE.onKeyEvent(keyCode, event) || super.onKeyUp(keyCode, event);
}
}
...
// Add those imports.
import android.view.KeyEvent;
import android.view.MotionEvent;
import expo.modules.devmenu.DevMenuManager;
...
class MainActivity : ReactActivity() {
...
// A function which sends the touch events to the dev menu.
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
DevMenuManager.onTouchEvent(ev)
return super.dispatchTouchEvent(ev)
}
// A function which handles the key commands.
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
return DevMenuManager.onKeyEvent(keyCode, event) || super.onKeyUp(keyCode, event)
}
}
II. Open the MainApplication
class (MainApplication.java
or MainApplication.kt
) and in onCreate
method initialize DevMenuManager
.
...
public class MainApplication extends Application implements ReactApplication {
...
@Override
public void onCreate() {
...
DevMenuManager.INSTANCE.initializeWithReactNativeHost(getReactNativeHost());
}
}
...
public class MainApplication : Application(), ReactApplication {
...
override fun onCreate() {
...
DevMenuManager.initializeWithReactNativeHost(reactNativeHost);
}
}
Add expo-dev-menu
to your Podfile.
...
target '<your app>' do
...
pod 'EXDevMenu', path: '../node_modules/expo-dev-menu', :configurations => :debug
...
end
Run pod install
in ios
directory.
Open file with your AppDelegate
(AppDelegate.m
or AppDelegate.swift
) and pass bridge to the DevMenuManager
.
...
// Firstly, you need to import EXDevMenu package.
#if defined(EX_DEV_MENU_ENABLED)
@import EXDevMenu;
#endif
...
@implementation AppDelegate
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
...
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"devMenuDemo"
initialProperties:nil];
// Add those lines only if you aren't using the dev-launcher.
#if defined(EX_DEV_MENU_ENABLED)
[DevMenuManager configureWithBridge:bridge];
#endif
}
@end
...
// Firstly, you need to import EXDevMenu package.
#if EX_DEV_MENU_ENABLED
@import EXDevMenu
#endif
...
@UIApplicationMain
class AppDelegate: UMAppDelegateWrapper {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
if let bridge = RCTBridge(delegate: self, launchOptions: launchOptions) {
...
// Add those lines.
#if EX_DEV_MENU_ENABLED
DevMenuManager.configure(withBridge: bridge)
#endif
}
...
}
}
You can access the developer menu by shaking your device, making a three-finger long-press gesture, or by selecting "Shake Gesture" inside the Hardware menu in the iOS simulator. You can also use keyboard shortcuts - ⌘D
on iOS, or ⌘M
on Android when you're using Mac OS and Ctrl+M
on Windows and Linux. Alternatively for Android, you can run the command adb shell input keyevent 82
to open the dev menu (82
being the Menu key code).
Note: if you're using the iOS simulator and keyboard shortcuts don't work, make sure you've selected
Send Keyboard Input to Device
inside theI/O
menu in the Simulator.
One of the main purposes of this package was to provide an easy way to create extensions. We know that developing a React Native app can be painful - often, developers need to create additional tools, which for example, clear the local storage, to test or debug their applications. Some of their work can be integrated with the application itself to save time and make the development more enjoyable.
The below instructions will show you how to create simple extension that removes a key from the NSUserDefaults
/SharedPreferences
.
Note: The tutorial was written using Kotlin and Swift. However, you can also use Java and Objective-C if you want.
Create a class which extends the ReactContextBaseJavaModule
and implements the DevMenuExtensionInterface
.
// CustomDevMenuExtension.kt
package com.devmenudemo.customdevmenuextension
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import expo.interfaces.devmenu.DevMenuExtensionInterface
import expo.interfaces.devmenu.items.DevMenuItem
class CustomDevMenuExtension(reactContext: ReactApplicationContext)
: ReactContextBaseJavaModule(reactContext),
DevMenuExtensionInterface {
override fun getName() = "CustomDevMenuExtension" // here you can provide name for your extension
override fun devMenuItems(): List<DevMenuItem>? {
// Firstly, create a function which will be called when the user presses the button.
val clearSharedPreferencesOnPress: () -> Unit = {
reactApplicationContext
.getSharedPreferences("your.shared.preferences", MODE_PRIVATE)
.edit()
.apply {
remove("key_to_remove")
Log.i("CustomDevMenuExt", "Remove key from SharedPreferences")
apply()
}
}
// Then, create `DevMenuAction` object.
val clearSharedPreferences = DevMenuAction(
actionId = "clear_shared_preferences", // This string identifies your custom action. Make sure that it's unique.
action = clearSharedPreferencesOnPress
).apply {
label = { "Clear shared preferences" } // This string will be displayed in the dev menu.
glyphName = { "delete" } // This is a icon name used to present your action. You can use any icon from the `MaterialCommunityIcons`.
importance = DevMenuItemImportance.HIGH.value // This value tells the dev-menu in which order the actions should be rendered.
keyCommand = KeyCommand(KeyEvent.KEYCODE_S) // You can associate key commend with your action.
}
// Return created object. Note: you can register multiple actions if you want.
return listOf(clearSharedPreferences)
}
}
Create a react native package class for the extension.
// CustomDevMenuExtensionPackage.kt
package com.devmenudemo.customdevmenuextension
import android.view.View
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager
class CustomDevMenuExtensionPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext) = listOf(
CustomDevMenuExtension(reactContext) // here you need to export your custom extension
)
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<View, ReactShadowNode<*>>> = listOf()
}
Go to MainApplication
(MainApplication.java
or MainApplication.kt
) and register created package.
// MainApplication.java
// You need to import your custom package.
import com.devmenudemo.customdevmenuextension.CustomDevMenuExtensionPackage; // the package can be different in your case
...
public class MainApplication extends Application implements ReactApplication {
...
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Add this line.
packages.add(new CustomDevMenuExtensionPackage());
return packages;
}
}
Create a Swift class which implements DevMenuExtensionProtocol
for your extension.
// CustomDevMenuExtension.swift
import EXDevMenuInterface
@objc(CustomDevMenuExtension)
open class CustomDevMenuExtension: NSObject, RCTBridgeModule, DevMenuExtensionProtocol {
public static func moduleName() -> String! {
return "CustomDevMenuExtension" // here you can provide name for your extension
}
@objc
open func devMenuItems() -> [DevMenuItem]? {
// Firstly, create a function which will be called when the user presses the button.
let clearNSUserDefaultsOnPress = {
let prefs = UserDefaults.standard
prefs.removeObject(forKey: "key_to_remove")
}
let clearNSUserDefaults = DevMenuAction(
withId: "clear_nsusersdefaults", // This string identifies your custom action. Make sure that it's unique.
action: clearNSUserDefaultsOnPress
)
clearNSUserDefaults.label = { "Clear NSUserDefaults" } // This string will be displayed in the dev menu.
clearNSUserDefaults.glyphName = { "delete" } // This is a icon name used to present your action. You can use any icon from the `MaterialCommunityIcons`.
clearNSUserDefaults.importance = DevMenuItem.ImportanceHigh // This value tells the dev-menu in which order the actions should be rendered.
clearNSUserDefaults.registerKeyCommand(input: "p", modifiers: .command) // You can associate key commend with your action.
// Return created object. Note: you can register multiple actions if you want.
return [clearNSUserDefaults]
}
}
Note: if you don't use Swift in your project earlier, you need to create bridging header. For more information, checks importing objective-c into swift.
Create a .m
file to integrate Swift class with react native and add the following lines.
// CustomDevMenuExtension.m
#import <React/RCTBridgeModule.h>
@interface RCT_EXTERN_REMAP_MODULE(CustomDevMenuExtensionObjc, CustomDevMenuExtension, NSObject)
@end
Add the following line into the bridging header.
#import <React/RCTBridgeModule.h>
After all those steps you should see something like this:
import * as DevMenu from 'expo-dev-menu';
For now, the DevMenu
module exports only one method - openMenu
.
Opens the dev menu.
Using this method you can open the dev menu from your JS code whenever you want. It does nothing when the dev menu is not available (i.e. in release mode).
Below you can find an example of opening the dev menu on button press:
import * as DevMenu from 'expo-dev-menu';
import { Button } from 'react-native';
export const DevMenuButton = () => (
<Button
onPress={() => {
DevMenu.openMenu();
}}
title="Press to open the dev menu 🚀"
color="#841584"
/>
);
Contributions are very welcome! Please refer to guidelines described in the contributing guide.
FAQs
Expo/React Native module with the developer menu.
The npm package expo-dev-menu receives a total of 0 weekly downloads. As such, expo-dev-menu popularity was classified as not popular.
We found that expo-dev-menu demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 27 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.