What is expo-dev-launcher?
The expo-dev-launcher package is a development tool for Expo applications that allows developers to launch and test their apps in a development environment. It provides functionalities to reload the app, open the developer menu, and handle deep links, among other features.
What are expo-dev-launcher's main functionalities?
Reload the App
This feature allows developers to programmatically reload the application, which is useful for testing changes without manually restarting the app.
import { reloadAsync } from 'expo-dev-launcher';
async function reloadApp() {
await reloadAsync();
}
Open Developer Menu
This feature enables developers to open the developer menu programmatically, providing quick access to development tools and options.
import { openMenu } from 'expo-dev-launcher';
function openDevMenu() {
openMenu();
}
Handle Deep Links
This feature allows the app to handle deep links, making it easier to test and debug deep linking functionality during development.
import { addDeepLinkListener } from 'expo-dev-launcher';
addDeepLinkListener((url) => {
console.log('Deep link received:', url);
});
Other packages similar to expo-dev-launcher
react-native-restart
The react-native-restart package provides a simple way to programmatically restart a React Native application. While it focuses solely on restarting the app, it lacks the broader set of development tools provided by expo-dev-launcher.
react-native-deep-link
The react-native-deep-link package is designed to handle deep linking in React Native applications. It offers similar deep link handling capabilities as expo-dev-launcher but does not include other development tools like reloading the app or opening the developer menu.
react-native-dev-menu
The react-native-dev-menu package allows developers to customize and open the developer menu in React Native applications. It provides similar functionality to the developer menu feature in expo-dev-launcher but does not include other features like reloading the app or handling deep links.
expo-dev-launcher
This is a pre-release version of the Expo dev launcher package for testing.
⚙️ Installation
Firstly, you need to add the expo-dev-launcher
package to your project.
yarn
yarn add expo-dev-launcher expo-dev-menu-interface
npm
npm install expo-dev-launcher expo-dev-menu-interface
Then you can start to configure the native projects using steps below.
🤖 Android
-
Initialize the DevLauncherController
.
Open your MainApplication.{java|kt}
and add the following lines:
Java
...
import expo.modules.devlauncher.DevLauncherController;
...
public class MainApplication extends Application implements ReactApplication {
...
@Override
public void onCreate() {
super.onCreate();
...
DevLauncherController.initialize(this, mReactNativeHost);
}
}
Kotlin
...
import expo.modules.devlauncher.DevLauncherController;
...
public class MainApplication : Application(), ReactApplication {
...
override public fun onCreate() {
super.onCreate();
...
DevLauncherController.initialize(this, mReactNativeHost);
}
}
-
Wrap the default ReactActivityDelegate
with the one from DevLauncher
.
Open your MainActivity.{java|kt}
and add the following lines:
Java
...
import expo.modules.devlauncher.DevLauncherController;
...
public class MainActivity extends DevMenuAwareReactActivity {
...
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return DevLauncherController.wrapReactActivityDelegate(
this,
() -> new ReactActivityDelegate(this, getMainComponentName())
);
}
}
Kotlin
...
import expo.modules.devlauncher.DevLauncherController;
...
public class MainActivity : DevMenuAwareReactActivity() {
...
protected override fun ReactActivityDelegate createReactActivityDelegate(): ReactActivityDelegate {
return DevLauncherController.wrapReactActivityDelegate(this) {
ReactActivityDelegate(this, getMainComponentName())
});
}
}
-
Pass new intents to the DevLauncherController
.
Note: This step is not required but without it, deep-link handling won't work.
Open your MainActivity.{java|kt}
and add the following method:
Java
...
public class MainActivity extends DevMenuAwareReactActivity {
...
@Override
public void onNewIntent(Intent intent) {
if (DevLauncherController.tryToHandleIntent(this, intent)) {
return;
}
super.onNewIntent(intent);
}
}
Kotlin
...
public class MainActivity : DevMenuAwareReactActivity() {
...
public override fun onNewIntent(intent: Intent) {
if (DevLauncherController.tryToHandleIntent(this, intent)) {
return;
}
super.onNewIntent(intent);
}
}
🍏 iOS
-
Run npx pod-install
after installing the npm package.
-
Set up the EXDevLauncherControllerDelegate
.
Objective-C
Open your AppDelegate.h
and implement EXDevLauncherControllerDelegate
.
...
#import <EXDevLauncherController.h>
...
@interface AppDelegate : UMAppDelegateWrapper <RCTBridgeDelegate, EXDevLauncherControllerDelegate> // Here you're implementing the `EXDevLauncherControllerDelegate`
@end
Open your AppDelegate.m
and add the following method:
...
@implementation AppDelegate
...
- (void)developmentClientController:(EXDevLauncherController * )devLauncherController
didStartWithSuccess:(BOOL)success
{
devLauncherController.appBridge = [self initializeReactNativeApp];
}
...
@end
Swift
Open your AppDelegate.swift
and implement EXDevLauncherControllerDelegate
.
...
@UIApplicationMain
class AppDelegate: UMAppDelegateWrapper, EXDevLauncherControllerDelegate {
...
func developmentClientController(_ devLauncherController: EXDevLauncherController!, didStartWithSuccess success: Bool) {
devLauncherController.appBridge = initializeReactNativeBridge()
}
...
}
-
Start the EXDevLauncherController
.
Open your AppDelegate.{m|swift}
and add the following lines:
Objective-C
@implementation AppDelegate
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
EXDevLauncherController *controller = [EXDevLauncherController sharedInstance];
[controller startWithWindow:self.window delegate:self launchOptions:launchOptions];
}
...
@end
Swift
...
@UIApplicationMain
class AppDelegate: UMAppDelegateWrapper {
...
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let controller = EXDevLauncherController.sharedInstance()
controller?.start(with: window, delegate: self, launchOptions: launchOptions);
}
...
}
-
Change the source URL.
Open your AppDelegate.{m|swift}
and add the following lines:
Objective-C
...
@implementation AppDelegate
...
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
{
return [[EXDevLauncherController sharedInstance] sourceUrl];
}
...
@end
Swift
...
@UIApplicationMain
class AppDelegate: UMAppDelegateWrapper {
...
func sourceURL(for bridge: RCTBridge!) -> URL! {
return EXDevLauncherController.sharedInstance()?.sourceUrl()
}
...
}
-
Handle deep links.
Open your AppDelegate.{m|swift}
and add the following lines:
Objective-C
...
#import <React/RCTLinkingManager.h>
...
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
if ([EXDevLauncherController.sharedInstance onDeepLink:url options:options]) {
return true;
}
return [RCTLinkingManager application:application openURL:url options:options];
}
...
@end
Swift
...
class AppDelegate: UMAppDelegateWrapper {
...
func initializeReactNativeBridge() -> RCTBridge? {
if let bridge = RCTBridge(delegate: self, launchOptions: EXDevelopmentClientController.sharedInstance()!.getLaunchOptions()) {
...
}
}
...
override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
if (useDevClient && EXDevLauncherController.sharedInstance()!.onDeepLink(url, options: options)) {
return true;
}
return RCTLinkingManager.application(app, open: url, options: options)
}
...
}