expo-dev-client 6.0.19 → 6.1.0-canary-20251205-756eb7a

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/CHANGELOG.md CHANGED
@@ -6,35 +6,41 @@
6
6
 
7
7
  ### 🎉 New features
8
8
 
9
+ - Add initial macOS support ([#41330](https://github.com/expo/expo/pull/41330) by [@gabrieldonadel](https://github.com/gabrieldonadel))
10
+
9
11
  ### 🐛 Bug fixes
10
12
 
11
13
  ### 💡 Others
12
14
 
13
- ## 6.0.19 2025-12-04
15
+ ## 6.0.20 - 2025-12-05
16
+
17
+ _This version does not introduce any user-facing changes._
18
+
19
+ ## 6.0.19 - 2025-12-04
14
20
 
15
21
  _This version does not introduce any user-facing changes._
16
22
 
17
- ## 6.0.18 2025-11-17
23
+ ## 6.0.18 - 2025-11-17
18
24
 
19
25
  _This version does not introduce any user-facing changes._
20
26
 
21
- ## 6.0.17 2025-11-05
27
+ ## 6.0.17 - 2025-11-05
22
28
 
23
29
  _This version does not introduce any user-facing changes._
24
30
 
25
- ## 6.0.16 2025-10-21
31
+ ## 6.0.16 - 2025-10-21
26
32
 
27
33
  _This version does not introduce any user-facing changes._
28
34
 
29
- ## 6.0.15 2025-10-10
35
+ ## 6.0.15 - 2025-10-10
30
36
 
31
37
  _This version does not introduce any user-facing changes._
32
38
 
33
- ## 6.0.14 2025-10-09
39
+ ## 6.0.14 - 2025-10-09
34
40
 
35
41
  _This version does not introduce any user-facing changes._
36
42
 
37
- ## 6.0.13 2025-10-01
43
+ ## 6.0.13 - 2025-10-01
38
44
 
39
45
  _This version does not introduce any user-facing changes._
40
46
 
@@ -8,13 +8,13 @@ expoModule {
8
8
  }
9
9
 
10
10
  group = "host.exp.exponent"
11
- version = "6.0.19"
11
+ version = "6.1.0-canary-20251205-756eb7a"
12
12
 
13
13
  android {
14
14
  namespace "expo.modules.devclient"
15
15
  defaultConfig {
16
16
  versionCode 1
17
- versionName "6.0.19"
17
+ versionName "6.1.0-canary-20251205-756eb7a"
18
18
  testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
19
19
  }
20
20
 
@@ -46,28 +46,28 @@ dependencies {
46
46
  androidTestImplementation 'com.facebook.react:react-android'
47
47
  androidTestImplementation 'com.facebook.react:hermes-android'
48
48
 
49
- androidTestImplementation('androidx.test.espresso:espresso-core:3.6.1')
50
- androidTestImplementation('androidx.test:core:1.6.1')
51
- androidTestImplementation('androidx.test:core-ktx:1.6.1')
52
- androidTestImplementation('androidx.test.ext:junit:1.2.1')
53
- androidTestImplementation('androidx.test.ext:junit-ktx:1.2.1')
54
- androidTestImplementation('androidx.test:runner:1.6.2')
55
- androidTestImplementation('androidx.test:rules:1.6.1')
49
+ androidTestImplementation('androidx.test.espresso:espresso-core:3.7.0')
50
+ androidTestImplementation('androidx.test:core:1.7.0')
51
+ androidTestImplementation('androidx.test:core-ktx:1.7.0')
52
+ androidTestImplementation('androidx.test.ext:junit:1.3.0')
53
+ androidTestImplementation('androidx.test.ext:junit-ktx:1.3.0')
54
+ androidTestImplementation('androidx.test:runner:1.7.0')
55
+ androidTestImplementation('androidx.test:rules:1.7.0')
56
56
 
57
57
  androidTestImplementation 'org.webkit:android-jsc:+'
58
58
 
59
59
  androidTestImplementation "io.insert-koin:koin-test:3.1.2"
60
60
  androidTestImplementation "io.insert-koin:koin-test-junit4:3.1.2"
61
61
 
62
- androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3"
63
- androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1"
62
+ androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2"
63
+ androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2"
64
64
 
65
- androidTestImplementation "androidx.appcompat:appcompat:1.7.0"
65
+ androidTestImplementation "androidx.appcompat:appcompat:1.7.1"
66
66
 
67
- androidTestImplementation "com.google.truth:truth:1.1.2"
68
67
  androidTestImplementation 'io.mockk:mockk-android:1.13.11'
68
+ androidTestImplementation "com.google.truth:truth:1.4.5"
69
69
 
70
70
  // Fixes "e: java.lang.AssertionError: No such enum entry LIBRARY_GROUP_PREFIX in org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl@b254b575"
71
71
  // According to the https://stackoverflow.com/a/67736351
72
- implementation 'androidx.annotation:annotation:1.2.0'
72
+ implementation 'androidx.annotation:annotation:1.9.1'
73
73
  }
@@ -12,7 +12,8 @@ Pod::Spec.new do |s|
12
12
  s.homepage = package['homepage']
13
13
  s.platforms = {
14
14
  :ios => '15.1',
15
- :tvos => '15.1'
15
+ :tvos => '15.1',
16
+ :osx => '13.0'
16
17
  }
17
18
  s.source = { git: 'https://github.com/expo/expo.git' }
18
19
  s.static_framework = true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-dev-client",
3
- "version": "6.0.19",
3
+ "version": "6.1.0-canary-20251205-756eb7a",
4
4
  "description": "Expo Development Client",
5
5
  "main": "build/DevClient.js",
6
6
  "types": "build/DevClient.d.ts",
@@ -32,21 +32,20 @@
32
32
  "license": "MIT",
33
33
  "homepage": "https://docs.expo.dev/versions/latest/sdk/dev-client/",
34
34
  "dependencies": {
35
- "expo-dev-launcher": "6.0.19",
36
- "expo-dev-menu": "7.0.18",
37
- "expo-dev-menu-interface": "2.0.0",
38
- "expo-manifests": "~1.0.9",
39
- "expo-updates-interface": "~2.0.0"
35
+ "expo-dev-launcher": "6.1.0-canary-20251205-756eb7a",
36
+ "expo-dev-menu": "7.1.0-canary-20251205-756eb7a",
37
+ "expo-dev-menu-interface": "2.0.1-canary-20251205-756eb7a",
38
+ "expo-manifests": "1.0.11-canary-20251205-756eb7a",
39
+ "expo-updates-interface": "2.0.1-canary-20251205-756eb7a"
40
40
  },
41
41
  "devDependencies": {
42
- "expo-module-scripts": "^5.0.8",
43
- "expo-test-runner": "0.3.7"
42
+ "expo-module-scripts": "5.1.0-canary-20251205-756eb7a",
43
+ "expo-test-runner": "0.3.9-canary-20251205-756eb7a"
44
44
  },
45
45
  "peerDependencies": {
46
- "expo": "*"
46
+ "expo": "55.0.0-canary-20251205-756eb7a"
47
47
  },
48
48
  "jest": {
49
49
  "preset": "expo-module-scripts"
50
- },
51
- "gitHead": "e8b838828e5e985379c07294dc932dba66c89562"
50
+ }
52
51
  }
@@ -1,138 +0,0 @@
1
- import { element, expect, waitFor, by, device } from 'detox';
2
-
3
- const LauncherMainScreenTimeout = 100 * 1000;
4
- const MenuTimeout = 100 * 1000;
5
- const LocalAppTimeout = 160 * 1000;
6
-
7
- const sleep = (duration: number) =>
8
- new Promise<void>((resolve) => setTimeout(() => resolve(), duration));
9
-
10
- async function pressElementByString(buttonString: string) {
11
- const button = element(by.text(buttonString));
12
- await expect(button).toBeVisible();
13
- await tapButton(button);
14
- }
15
-
16
- async function pressMenuElementByString(buttonString: string, timeout: number = 0) {
17
- let button = element(by.text(buttonString));
18
-
19
- await waitFor(button).toBeVisible().withTimeout(timeout);
20
-
21
- // When we open the dev-menu, we will see an animation.
22
- // Unfortunately, if we try to click to button before the
23
- // animation finishes, it may not work. We might click different a button.
24
- // So try to wait for the animation to finish.
25
- await sleep(1000);
26
-
27
- button = element(by.text(buttonString));
28
- await waitFor(button).toBeVisible();
29
-
30
- await tapButton(button);
31
- }
32
-
33
- async function runWithoutSynchronization(block: () => Promise<void>) {
34
- await device.disableSynchronization();
35
- await block();
36
- await device.enableSynchronization();
37
- }
38
-
39
- function getInvocationManager() {
40
- // @ts-ignore
41
- return global.detox[Object.getOwnPropertySymbols(global.detox)[0]]._invocationManager;
42
- }
43
-
44
- function getLocalIPAddress(): string {
45
- return require('os')
46
- .networkInterfaces()
47
- .en0.find((elm: { family: string }) => elm.family === 'IPv4').address;
48
- }
49
-
50
- async function openMenu(): Promise<void> {
51
- if (device.getPlatform() === 'android') {
52
- return await getInvocationManager().execute({
53
- target: {
54
- type: 'Class',
55
- value: 'com.testrunner.DevClientDetoxHelper',
56
- },
57
- method: 'openMenu',
58
- args: [],
59
- });
60
- }
61
- return await device.shake();
62
- }
63
-
64
- async function waitForLauncherMainScreen() {
65
- await waitFor(element(by.id('DevLauncherMainScreen')))
66
- .toBeVisible()
67
- .withTimeout(LauncherMainScreenTimeout);
68
- }
69
-
70
- async function waitForAppMainScreen() {
71
- await waitFor(element(by.id('LocalAppMainScreen')))
72
- .toBeVisible()
73
- .withTimeout(LocalAppTimeout);
74
- }
75
-
76
- async function ensureThatLauncherMainScreenIsVisible() {
77
- if (device.getPlatform() === 'ios') {
78
- await expect(element(by.id('DevLauncherMainScreen'))).toBeVisible();
79
- return;
80
- }
81
-
82
- await waitForLauncherMainScreen();
83
- }
84
-
85
- async function tapButton(button: Detox.IndexableNativeElement) {
86
- // We have to make 2 tap - it is a bug in React Native.
87
- await button.multiTap(2);
88
- }
89
-
90
- describe('DevLauncher', () => {
91
- beforeEach(async () => {
92
- await device.launchApp({ newInstance: true });
93
- });
94
-
95
- it('should render main screen', async () => {
96
- await ensureThatLauncherMainScreenIsVisible();
97
- });
98
-
99
- it('should be able to go to the settings screen and come back to the main screen', async () => {
100
- await ensureThatLauncherMainScreenIsVisible();
101
-
102
- await pressElementByString('Settings');
103
- await expect(element(by.id('DevLauncherSettingsScreen'))).toBeVisible();
104
-
105
- await pressElementByString('Home');
106
- await expect(element(by.id('DevLauncherMainScreen'))).toBeVisible();
107
- });
108
-
109
- it('should be able to load app from URL and come back to the launcher screen', async () => {
110
- await ensureThatLauncherMainScreenIsVisible();
111
-
112
- const urlToggle = element(by.id('DevLauncherURLToggle'));
113
- const urlInput = element(by.id('DevLauncherURLInput'));
114
- const loadButton = element(by.id('DevLauncherLoadAppButton'));
115
-
116
- await expect(urlToggle).toBeVisible();
117
- await urlToggle.tap();
118
-
119
- await expect(urlInput).toBeVisible();
120
- await expect(loadButton).toBeVisible();
121
-
122
- await urlInput.typeText(`http://${getLocalIPAddress()}:8081`);
123
- if (device.getPlatform() === 'android') {
124
- // close keyboard
125
- await device.pressBack();
126
- }
127
-
128
- await runWithoutSynchronization(async () => {
129
- await tapButton(loadButton);
130
- await waitForAppMainScreen();
131
- await openMenu();
132
-
133
- await pressMenuElementByString('Go home', MenuTimeout);
134
-
135
- await waitForLauncherMainScreen();
136
- });
137
- });
138
- });
@@ -1,92 +0,0 @@
1
- package com.testrunner;
2
-
3
- import static androidx.test.espresso.Espresso.onView;
4
- import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
5
- import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
6
-
7
- import android.app.Activity;
8
- import android.content.Context;
9
- import android.content.ContextWrapper;
10
- import android.view.View;
11
- import android.view.ViewGroup;
12
-
13
- import androidx.test.ext.junit.runners.AndroidJUnit4;
14
- import androidx.test.filters.LargeTest;
15
- import androidx.test.rule.ActivityTestRule;
16
-
17
- import com.facebook.react.ReactApplication;
18
- import com.facebook.react.ReactNativeHost;
19
- import com.wix.detox.Detox;
20
- import com.wix.detox.config.DetoxConfig;
21
-
22
- import org.junit.Rule;
23
- import org.junit.Test;
24
- import org.junit.runner.RunWith;
25
-
26
- import expo.modules.devlauncher.DevLauncherController;
27
- import expo.modules.devlauncher.launcher.DevLauncherActivity;
28
- import expo.modules.devmenu.DevMenuManager;
29
-
30
- // We need this class to pass dev launcher host to detox.
31
- // Otherwise it won't detect that the app has been started.
32
- class ReactNativeHolder extends ContextWrapper implements ReactApplication {
33
- public ReactNativeHolder(Context base) {
34
- super(base);
35
- }
36
-
37
- @Override
38
- public ReactNativeHost getReactNativeHost() {
39
- return DevLauncherController.getInstance().getDevClientHost();
40
- }
41
- }
42
-
43
- class DevClientDetoxHelper {
44
- public static Activity getCurrentActivity() {
45
- final Activity[] activity = new Activity[1];
46
-
47
- onView(isRoot()).check((view, noViewFoundException) -> {
48
-
49
- View checkedView = view;
50
-
51
- while (checkedView instanceof ViewGroup && ((ViewGroup) checkedView).getChildCount() > 0) {
52
-
53
- checkedView = ((ViewGroup) checkedView).getChildAt(0);
54
-
55
- if (checkedView.getContext() instanceof Activity) {
56
- activity[0] = (Activity) checkedView.getContext();
57
- return;
58
- }
59
- }
60
- });
61
- return activity[0];
62
- }
63
-
64
- public static void openMenu() throws InterruptedException {
65
- getInstrumentation().waitForIdleSync();
66
- Activity activity = getCurrentActivity();
67
- int counter = 10;
68
- while (counter-- > 0 && activity == null) {
69
- Thread.sleep(100);
70
- activity = getCurrentActivity();
71
- }
72
-
73
- DevMenuManager.INSTANCE.openMenu(activity, null);
74
- }
75
- }
76
-
77
- @RunWith(AndroidJUnit4.class)
78
- @LargeTest
79
- public class DetoxTest {
80
- @Rule
81
- public ActivityTestRule<DevLauncherActivity> mActivityRule = new ActivityTestRule<>(DevLauncherActivity.class, false, false);
82
-
83
- @Test
84
- public void runDetoxTests() {
85
- DetoxConfig detoxConfig = new DetoxConfig();
86
- detoxConfig.idlePolicyConfig.masterTimeoutSec = 90;
87
- detoxConfig.rnContextLoadTimeoutSec = 180;
88
-
89
- ReactNativeHolder reactNativeHolder = new ReactNativeHolder(getInstrumentation().getTargetContext().getApplicationContext());
90
- Detox.runTests(mActivityRule, reactNativeHolder, detoxConfig);
91
- }
92
- }
@@ -1,40 +0,0 @@
1
- // custom
2
- package com.testrunner;
3
-
4
- import android.content.Intent;
5
-
6
- import expo.modules.devmenu.react.DevMenuAwareReactActivity;
7
- import com.facebook.react.ReactActivityDelegate;
8
-
9
- import expo.modules.ReactActivityDelegateWrapper;
10
- import expo.modules.devlauncher.DevLauncherController;
11
-
12
- public class MainActivity extends DevMenuAwareReactActivity {
13
- /**
14
- * Returns the name of the main component registered from JavaScript.
15
- * This is used to schedule rendering of the component.
16
- */
17
- @Override
18
- protected String getMainComponentName() {
19
- return "main";
20
- }
21
-
22
- @Override
23
- public void onNewIntent(Intent intent) {
24
- if (DevLauncherController.tryToHandleIntent(this, intent)) {
25
- return;
26
- }
27
- super.onNewIntent(intent);
28
- }
29
-
30
- @Override
31
- protected ReactActivityDelegate createReactActivityDelegate() {
32
- return DevLauncherController.wrapReactActivityDelegate(this, () -> new ReactActivityDelegateWrapper(
33
- this,
34
- new ReactActivityDelegate(
35
- this,
36
- getMainComponentName()
37
- )
38
- ));
39
- }
40
- }
@@ -1,84 +0,0 @@
1
- package com.testrunner;
2
-
3
- import android.app.Application;
4
- import android.content.res.Configuration;
5
-
6
- import androidx.annotation.NonNull;
7
- import androidx.annotation.Nullable;
8
-
9
- import com.facebook.react.PackageList;
10
- import com.facebook.react.ReactApplication;
11
- import com.facebook.react.ReactNativeHost;
12
- import com.facebook.react.ReactPackage;
13
- import com.facebook.soloader.SoLoader;
14
-
15
- import expo.interfaces.devmenu.DevMenuPreferencesInterface;
16
- import expo.modules.ApplicationLifecycleDispatcher;
17
- import expo.modules.ReactNativeHostWrapper;
18
- import expo.modules.devlauncher.DevLauncherController;
19
- import expo.modules.devmenu.DevMenuDefaultPreferences;
20
- import expo.modules.devmenu.DevMenuManager;
21
- import expo.modules.devmenu.tests.DevMenuTestInterceptor;
22
-
23
- import java.util.List;
24
-
25
- public class MainApplication extends Application implements ReactApplication {
26
- private final ReactNativeHost mReactNativeHost = new ReactNativeHostWrapper(
27
- this,
28
- new ReactNativeHost(this) {
29
- @Override
30
- public boolean getUseDeveloperSupport() {
31
- return BuildConfig.DEBUG;
32
- }
33
-
34
- @Override
35
- protected List<ReactPackage> getPackages() {
36
- return new PackageList(this).getPackages();
37
- }
38
-
39
- @Override
40
- protected String getJSMainModuleName() {
41
- return ".expo/.virtual-metro-entry";
42
- }
43
- });
44
-
45
- @Override
46
- public ReactNativeHost getReactNativeHost() {
47
- return mReactNativeHost;
48
- }
49
-
50
- @Override
51
- public void onCreate() {
52
- super.onCreate();
53
- SoLoader.init(this, /* native exopackage */ false);
54
-
55
- DevMenuManager.INSTANCE.setTestInterceptor(new DevMenuTestInterceptor() {
56
- @Nullable
57
- @Override
58
- public DevMenuPreferencesInterface overrideSettings() {
59
- return new DevMenuDefaultPreferences() {
60
- @Override
61
- public boolean getShowsAtLaunch() {
62
- return false;
63
- }
64
-
65
- @Override
66
- public boolean isOnboardingFinished() {
67
- return true;
68
- }
69
- };
70
- }
71
- });
72
-
73
- DevLauncherController.initialize(this, mReactNativeHost);
74
-
75
-
76
- ApplicationLifecycleDispatcher.onApplicationCreate(this);
77
- }
78
-
79
- @Override
80
- public void onConfigurationChanged(@NonNull Configuration newConfig) {
81
- super.onConfigurationChanged(newConfig);
82
- ApplicationLifecycleDispatcher.onConfigurationChanged(this, newConfig);
83
- }
84
- }
package/e2e/app/App.tsx DELETED
@@ -1,19 +0,0 @@
1
- import React from 'react';
2
- import { StyleSheet, Text, View } from 'react-native';
3
-
4
- export default function App() {
5
- return (
6
- <View style={styles.container} testID="LocalAppMainScreen">
7
- <Text>Open up App.js to start working on your app!</Text>
8
- </View>
9
- );
10
- }
11
-
12
- const styles = StyleSheet.create({
13
- container: {
14
- flex: 1,
15
- backgroundColor: '#fff',
16
- alignItems: 'center',
17
- justifyContent: 'center',
18
- },
19
- });
package/e2e/config.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "maxWorkers": 1,
3
- "testEnvironment": "./environments",
4
- "testRunner": "jest-circus/runner",
5
- "testTimeout": 180000,
6
- "testRegex": "\\.e2e\\.ts$",
7
- "reporters": ["detox/runners/jest/streamlineReporter"],
8
- "verbose": true
9
- }
@@ -1,23 +0,0 @@
1
- const {
2
- DetoxCircusEnvironment,
3
- SpecReporter,
4
- WorkerAssignReporter,
5
- } = require('detox/runners/jest-circus');
6
-
7
- class CustomDetoxEnvironment extends DetoxCircusEnvironment {
8
- constructor(config, context) {
9
- super(config, context);
10
-
11
- // Can be safely removed, if you are content with the default value (=300000ms)
12
- this.initTimeout = 300000;
13
-
14
- // This takes care of generating status logs on a per-spec basis. By default, Jest only reports at file-level.
15
- // This is strictly optional.
16
- this.registerListeners({
17
- SpecReporter,
18
- WorkerAssignReporter,
19
- });
20
- }
21
- }
22
-
23
- module.exports = CustomDetoxEnvironment;
@@ -1,100 +0,0 @@
1
- #import "AppDelegate.h"
2
-
3
- #import <React/RCTBridge.h>
4
- #import <React/RCTBundleURLProvider.h>
5
- #import <React/RCTRootView.h>
6
- #import <React/RCTLinkingManager.h>
7
-
8
- @import ExpoModulesCore;
9
- @import EXDevMenu;
10
-
11
- #import <EXDevLauncher/EXDevLauncherController.h>
12
-
13
- @interface DevMenuDetoxTestInterceptor : NSObject<DevMenuTestInterceptor>
14
-
15
- @end
16
-
17
- @implementation DevMenuDetoxTestInterceptor
18
-
19
- - (BOOL)isOnboardingFinishedKey
20
- {
21
- return YES;
22
- }
23
-
24
- - (BOOL)shouldShowAtLaunch
25
- {
26
- return NO;
27
- }
28
-
29
- @end
30
-
31
- @interface AppDelegate () <RCTBridgeDelegate>
32
-
33
- @property (nonatomic, strong) NSDictionary *launchOptions;
34
-
35
- @end
36
-
37
- @implementation AppDelegate
38
-
39
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
40
- {
41
- [DevMenuTestInterceptorManager setTestInterceptor:[DevMenuDetoxTestInterceptor new]];
42
-
43
- self.launchOptions = launchOptions;
44
- self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
45
-
46
- EXDevLauncherController *controller = [EXDevLauncherController sharedInstance];
47
- [controller startWithWindow:self.window delegate:(id<EXDevLauncherControllerDelegate>)self launchOptions:launchOptions];
48
-
49
- [super application:application didFinishLaunchingWithOptions:launchOptions];
50
-
51
- return YES;
52
- }
53
-
54
- - (RCTBridge *)initializeReactNativeApp
55
- {
56
- NSDictionary *launchOptions = [EXDevLauncherController.sharedInstance getLaunchOptions];
57
-
58
- RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
59
- RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"main" initialProperties:nil];
60
- rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
61
-
62
- UIViewController *rootViewController = [UIViewController new];
63
- rootViewController.view = rootView;
64
- self.window.rootViewController = rootViewController;
65
- [self.window makeKeyAndVisible];
66
-
67
- return bridge;
68
- }
69
-
70
- - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
71
- return [[EXDevLauncherController sharedInstance] sourceUrl];
72
- }
73
-
74
- // Linking API
75
- - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
76
- if ([EXDevLauncherController.sharedInstance onDeepLink:url options:options]) {
77
- return true;
78
- }
79
-
80
- return [RCTLinkingManager application:application openURL:url options:options];
81
- }
82
-
83
- // Universal Links
84
- - (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
85
- return [RCTLinkingManager application:application
86
- continueUserActivity:userActivity
87
- restorationHandler:restorationHandler];
88
- }
89
-
90
- @end
91
-
92
- @implementation AppDelegate (EXDevLauncherControllerDelegate)
93
-
94
- - (void)devLauncherController:(EXDevLauncherController *)developmentClientController
95
- didStartWithSuccess:(BOOL)success
96
- {
97
- developmentClientController.appBridge = [self initializeReactNativeApp];
98
- }
99
-
100
- @end