expo-dev-client 0.4.7 → 0.6.1
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/.detoxrc.json +41 -0
- package/CHANGELOG.md +45 -0
- package/README.md +3 -4
- package/android/build.gradle +2 -1
- package/dependencies.js +3 -0
- package/e2e/DevLauncher.e2e.ts +104 -0
- package/e2e/android/DetoxTest.java +92 -0
- package/e2e/android/MainActivity.java +40 -0
- package/e2e/android/MainApplication.java +84 -0
- package/e2e/app/App.tsx +19 -0
- package/e2e/config.json +9 -0
- package/e2e/environments.js +23 -0
- package/e2e/ios/AppDelegate.m +99 -0
- package/expo-dev-client.podspec +2 -0
- package/package.json +13 -10
- package/plugin/build/constants.d.ts +1 -0
- package/plugin/build/constants.js +4 -0
- package/plugin/build/withDevClient.js +2 -1
- package/plugin/src/constants.ts +1 -0
- package/plugin/src/withDevClient.ts +3 -2
- package/test-runner.config.js +64 -0
- package/tests/instrumented/app/index.js +0 -31
- package/tests/instrumented/build.sh +0 -9
- package/yarn-error.log +0 -21896
package/.detoxrc.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"test-runner": "jest",
|
|
3
|
+
"runnerConfig": "e2e/config.json",
|
|
4
|
+
"skipLegacyWorkersInjection": true,
|
|
5
|
+
"devices": {
|
|
6
|
+
"emulator": {
|
|
7
|
+
"type": "android.emulator",
|
|
8
|
+
"device": {
|
|
9
|
+
"avdName": "DevClientEmulator"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"simulator": {
|
|
13
|
+
"type": "ios.simulator",
|
|
14
|
+
"device": {
|
|
15
|
+
"type": "iPhone 8"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"apps": {
|
|
20
|
+
"android.debug": {
|
|
21
|
+
"type": "android.apk",
|
|
22
|
+
"binaryPath": "android/app/build/outputs/apk/debug/app-debug.apk",
|
|
23
|
+
"build": "cd android && ./gradlew assembleDebug assembleAndroidTest -DtestBuildType=debug && cd .."
|
|
24
|
+
},
|
|
25
|
+
"ios.debug": {
|
|
26
|
+
"type": "ios.app",
|
|
27
|
+
"binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/dev-client-e2e.app",
|
|
28
|
+
"build": "xcodebuild -workspace ios/dev-client-e2e.xcworkspace -scheme dev-client-e2e -configuration Debug -sdk iphonesimulator -arch x86_64 -derivedDataPath ios/build"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"configurations": {
|
|
32
|
+
"android": {
|
|
33
|
+
"device": "emulator",
|
|
34
|
+
"app": "android.debug"
|
|
35
|
+
},
|
|
36
|
+
"ios": {
|
|
37
|
+
"device": "simulator",
|
|
38
|
+
"app": "ios.debug"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,51 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 0.6.1 — 2021-10-15
|
|
14
|
+
|
|
15
|
+
_This version does not introduce any user-facing changes._
|
|
16
|
+
|
|
17
|
+
## 0.6.0 — 2021-10-07
|
|
18
|
+
|
|
19
|
+
### 🛠 Breaking changes
|
|
20
|
+
|
|
21
|
+
- Added a native dependency on the `expo-manifests` package. ([#14461](https://github.com/expo/expo/pull/14461) by [@esamelson](https://github.com/esamelson))
|
|
22
|
+
- This is a breaking change for projects **without `react-native-unimodules` or `expo-modules-core` installed**. In order to upgrade from `expo-dev-client@0.5.1` or below to this version in such projects, the following changes must be made:
|
|
23
|
+
- In `ios/Podfile`, change the deployment target to `platform :ios, '12.0'` and add the following lines inside the main target:
|
|
24
|
+
```ruby
|
|
25
|
+
pod 'EXJSONUtils', path: '../node_modules/expo-json-utils/ios', :configurations => :debug
|
|
26
|
+
pod 'EXManifests', path: '../node_modules/expo-manifests/ios', :configurations => :debug
|
|
27
|
+
```
|
|
28
|
+
- In `android/settings.gradle`, add the following lines:
|
|
29
|
+
```groovy
|
|
30
|
+
include ':expo-json-utils'
|
|
31
|
+
project(':expo-json-utils').projectDir = new File('../node_modules/expo-json-utils/android')
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
include ':expo-manifests'
|
|
35
|
+
project(':expo-manifests').projectDir = new File('../node_modules/expo-manifests/android')
|
|
36
|
+
```
|
|
37
|
+
- No additional setup is necessary for projects already using `react-native-unimodules` or `expo-modules-core`.
|
|
38
|
+
- Replace Android DevLauncherManifest class with `expo-manifests`. ([#14462](https://github.com/expo/expo/pull/14462) by [@esamelson](https://github.com/esamelson))
|
|
39
|
+
|
|
40
|
+
### 🐛 Bug fixes
|
|
41
|
+
|
|
42
|
+
- Fix building errors from use_frameworks! in Podfile. ([#14523](https://github.com/expo/expo/pull/14523) by [@kudo](https://github.com/kudo))
|
|
43
|
+
|
|
44
|
+
### 💡 Others
|
|
45
|
+
|
|
46
|
+
- Updated `@expo/config-plugins` ([#14443](https://github.com/expo/expo/pull/14443) by [@EvanBacon](https://github.com/EvanBacon))
|
|
47
|
+
|
|
48
|
+
## 0.5.1 — 2021-09-03
|
|
49
|
+
|
|
50
|
+
_This version does not introduce any user-facing changes._
|
|
51
|
+
|
|
52
|
+
## 0.5.0 — 2021-09-02
|
|
53
|
+
|
|
54
|
+
### 💡 Others
|
|
55
|
+
|
|
56
|
+
- Fix .npmignore and remove `tests/` directory from published npm package. ([#13990](https://github.com/expo/expo/pull/13990) by [@esamelson](https://github.com/esamelson))
|
|
57
|
+
|
|
13
58
|
## 0.4.7 — 2021-08-06
|
|
14
59
|
|
|
15
60
|
_This version does not introduce any user-facing changes._
|
package/README.md
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# expo-dev-client
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`expo-dev-client` is an npm package installable in any Expo or React Native project. Once installed, any Debug builds of your application will gain an extensible debug menu and the ability to load projects from Expo CLI. Release builds of your application will not change other than the addition of a few header files. Your debug builds can be shared with anyone on your team who needs to work on or review your application. Your team can develop the JavaScript portion of your application with expo-cli and your custom client without waiting for your native code to build until the
|
|
4
|
+
next time you need to upgrade, install a new module, or otherwise change the native code in your project.
|
|
4
5
|
|
|
5
6
|
## Documentation
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
See [Installation](https://docs.expo.io/clients/installation/)
|
|
8
|
+
You can find the documentation under [https://docs.expo.io/clients/introduction](https://docs.expo.io/clients/introduction).
|
|
10
9
|
|
|
11
10
|
## Contributing
|
|
12
11
|
|
package/android/build.gradle
CHANGED
|
@@ -23,7 +23,7 @@ android {
|
|
|
23
23
|
minSdkVersion safeExtGet('minSdkVersion', 21)
|
|
24
24
|
targetSdkVersion safeExtGet('targetSdkVersion', 30)
|
|
25
25
|
versionCode 1
|
|
26
|
-
versionName "0.
|
|
26
|
+
versionName "0.6.1"
|
|
27
27
|
|
|
28
28
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
29
29
|
}
|
|
@@ -81,6 +81,7 @@ dependencies {
|
|
|
81
81
|
androidTestImplementation project(":expo-updates-interface")
|
|
82
82
|
androidTestImplementation project(":expo-dev-menu")
|
|
83
83
|
androidTestImplementation project(":expo-dev-launcher")
|
|
84
|
+
androidTestImplementation project(":expo-manifests")
|
|
84
85
|
|
|
85
86
|
//noinspection GradleDynamicVersion
|
|
86
87
|
androidTestImplementation 'com.facebook.react:react-native:+' // From node_modules
|
package/dependencies.js
CHANGED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { element, expect, waitFor, by, device } from 'detox';
|
|
2
|
+
|
|
3
|
+
const MenuTimeout = 50000;
|
|
4
|
+
const LauncherMainScreenTimeout = 30000;
|
|
5
|
+
const LocalAppTimeout = 60000;
|
|
6
|
+
|
|
7
|
+
function getInvocationManager() {
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
return global.detox[Object.getOwnPropertySymbols(global.detox)[0]]._invocationManager;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function getLocalIPAddress(): string {
|
|
13
|
+
if (device.getPlatform() === 'ios') {
|
|
14
|
+
return 'localhost';
|
|
15
|
+
}
|
|
16
|
+
return require('os')
|
|
17
|
+
.networkInterfaces()
|
|
18
|
+
.en0.find((elm: { family: string }) => elm.family === 'IPv4').address;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function openMenu(): Promise<void> {
|
|
22
|
+
if (device.getPlatform() === 'android') {
|
|
23
|
+
return getInvocationManager().execute({
|
|
24
|
+
target: {
|
|
25
|
+
type: 'Class',
|
|
26
|
+
value: 'com.testrunner.DevClientDetoxHelper',
|
|
27
|
+
},
|
|
28
|
+
method: 'openMenu',
|
|
29
|
+
args: [],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return await device.shake();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe('DevLauncher', () => {
|
|
36
|
+
beforeEach(async () => {
|
|
37
|
+
await device.launchApp({ newInstance: true });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should render main screen', async () => {
|
|
41
|
+
await expect(element(by.id('DevLauncherMainScreen'))).toBeVisible();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should be able to open dev menu', async () => {
|
|
45
|
+
await expect(element(by.id('DevLauncherMainScreen'))).toBeVisible();
|
|
46
|
+
|
|
47
|
+
await openMenu();
|
|
48
|
+
|
|
49
|
+
await waitFor(element(by.id('DevMenuMainScreen')))
|
|
50
|
+
.toBeVisible()
|
|
51
|
+
.withTimeout(MenuTimeout);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should be able to load app from URL', async () => {
|
|
55
|
+
const urlInput = element(by.id('DevLauncherURLInput'));
|
|
56
|
+
const loadButton = element(by.id('DevLauncherLoadAppButton'));
|
|
57
|
+
|
|
58
|
+
await expect(urlInput).toBeVisible();
|
|
59
|
+
await expect(loadButton).toBeVisible();
|
|
60
|
+
|
|
61
|
+
await urlInput.typeText(`http://${getLocalIPAddress()}:8081`);
|
|
62
|
+
if (device.getPlatform() === 'android') {
|
|
63
|
+
// close keyboard
|
|
64
|
+
await device.pressBack();
|
|
65
|
+
}
|
|
66
|
+
await loadButton.multiTap(2);
|
|
67
|
+
|
|
68
|
+
await waitFor(element(by.id('LocalAppMainScreen')))
|
|
69
|
+
.toBeVisible()
|
|
70
|
+
.withTimeout(LocalAppTimeout);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should be able to come back to the dev launcher screen', async () => {
|
|
74
|
+
const urlInput = element(by.id('DevLauncherURLInput'));
|
|
75
|
+
const loadButton = element(by.id('DevLauncherLoadAppButton'));
|
|
76
|
+
|
|
77
|
+
await expect(urlInput).toBeVisible();
|
|
78
|
+
await expect(loadButton).toBeVisible();
|
|
79
|
+
|
|
80
|
+
await urlInput.typeText(`http://${getLocalIPAddress()}:8081`);
|
|
81
|
+
if (device.getPlatform() === 'android') {
|
|
82
|
+
// close keyboard
|
|
83
|
+
await device.pressBack();
|
|
84
|
+
}
|
|
85
|
+
await loadButton.multiTap(2);
|
|
86
|
+
|
|
87
|
+
await waitFor(element(by.id('LocalAppMainScreen')))
|
|
88
|
+
.toBeVisible()
|
|
89
|
+
.withTimeout(LocalAppTimeout);
|
|
90
|
+
|
|
91
|
+
await openMenu();
|
|
92
|
+
|
|
93
|
+
const backToLauncher = element(by.text('Back to Launcher'));
|
|
94
|
+
|
|
95
|
+
await waitFor(backToLauncher)
|
|
96
|
+
.toBeVisible()
|
|
97
|
+
.withTimeout(MenuTimeout);
|
|
98
|
+
await backToLauncher.tap();
|
|
99
|
+
|
|
100
|
+
await waitFor(element(by.id('DevLauncherMainScreen')))
|
|
101
|
+
.toBeVisible()
|
|
102
|
+
.withTimeout(LauncherMainScreenTimeout);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,92 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
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.DevMenuSettingsInterface;
|
|
16
|
+
import expo.modules.ApplicationLifecycleDispatcher;
|
|
17
|
+
import expo.modules.ReactNativeHostWrapper;
|
|
18
|
+
import expo.modules.devlauncher.DevLauncherController;
|
|
19
|
+
import expo.modules.devmenu.DevMenuDefaultSettings;
|
|
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 "index";
|
|
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 DevMenuSettingsInterface overrideSettings() {
|
|
59
|
+
return new DevMenuDefaultSettings() {
|
|
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
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
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
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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;
|
|
@@ -0,0 +1,99 @@
|
|
|
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 EXDevMenu;
|
|
9
|
+
|
|
10
|
+
#import <EXDevLauncher/EXDevLauncherController.h>
|
|
11
|
+
|
|
12
|
+
@interface DevMenuDetoxTestInterceptor : NSObject<DevMenuTestInterceptor>
|
|
13
|
+
|
|
14
|
+
@end
|
|
15
|
+
|
|
16
|
+
@implementation DevMenuDetoxTestInterceptor
|
|
17
|
+
|
|
18
|
+
- (BOOL)isOnboardingFinishedKey
|
|
19
|
+
{
|
|
20
|
+
return YES;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
- (BOOL)shouldShowAtLaunch
|
|
24
|
+
{
|
|
25
|
+
return NO;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@end
|
|
29
|
+
|
|
30
|
+
@interface AppDelegate () <RCTBridgeDelegate>
|
|
31
|
+
|
|
32
|
+
@property (nonatomic, strong) NSDictionary *launchOptions;
|
|
33
|
+
|
|
34
|
+
@end
|
|
35
|
+
|
|
36
|
+
@implementation AppDelegate
|
|
37
|
+
|
|
38
|
+
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
|
39
|
+
{
|
|
40
|
+
[DevMenuTestInterceptorManager setTestInterceptor:[DevMenuDetoxTestInterceptor new]];
|
|
41
|
+
|
|
42
|
+
self.launchOptions = launchOptions;
|
|
43
|
+
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
|
44
|
+
|
|
45
|
+
EXDevLauncherController *controller = [EXDevLauncherController sharedInstance];
|
|
46
|
+
[controller startWithWindow:self.window delegate:(id<EXDevLauncherControllerDelegate>)self launchOptions:launchOptions];
|
|
47
|
+
|
|
48
|
+
[super application:application didFinishLaunchingWithOptions:launchOptions];
|
|
49
|
+
|
|
50
|
+
return YES;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
- (RCTBridge *)initializeReactNativeApp
|
|
54
|
+
{
|
|
55
|
+
NSDictionary *launchOptions = [EXDevLauncherController.sharedInstance getLaunchOptions];
|
|
56
|
+
|
|
57
|
+
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
|
|
58
|
+
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"main" initialProperties:nil];
|
|
59
|
+
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
|
|
60
|
+
|
|
61
|
+
UIViewController *rootViewController = [UIViewController new];
|
|
62
|
+
rootViewController.view = rootView;
|
|
63
|
+
self.window.rootViewController = rootViewController;
|
|
64
|
+
[self.window makeKeyAndVisible];
|
|
65
|
+
|
|
66
|
+
return bridge;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
|
|
70
|
+
return [[EXDevLauncherController sharedInstance] sourceUrl];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Linking API
|
|
74
|
+
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
|
|
75
|
+
if ([EXDevLauncherController.sharedInstance onDeepLink:url options:options]) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return [RCTLinkingManager application:application openURL:url options:options];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Universal Links
|
|
83
|
+
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
|
|
84
|
+
return [RCTLinkingManager application:application
|
|
85
|
+
continueUserActivity:userActivity
|
|
86
|
+
restorationHandler:restorationHandler];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@end
|
|
90
|
+
|
|
91
|
+
@implementation AppDelegate (EXDevLauncherControllerDelegate)
|
|
92
|
+
|
|
93
|
+
- (void)devLauncherController:(EXDevLauncherController *)developmentClientController
|
|
94
|
+
didStartWithSuccess:(BOOL)success
|
|
95
|
+
{
|
|
96
|
+
developmentClientController.appBridge = [self initializeReactNativeApp];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
@end
|
package/expo-dev-client.podspec
CHANGED
|
@@ -12,10 +12,12 @@ Pod::Spec.new do |s|
|
|
|
12
12
|
s.homepage = package['homepage']
|
|
13
13
|
s.platform = :ios, '11.0'
|
|
14
14
|
s.source = { git: 'https://github.com/expo/expo.git' }
|
|
15
|
+
s.static_framework = true
|
|
15
16
|
s.header_dir = 'EXDevClient'
|
|
16
17
|
|
|
17
18
|
s.dependency 'expo-dev-launcher', :configurations => :debug
|
|
18
19
|
s.dependency 'expo-dev-menu', :configurations => :debug
|
|
19
20
|
s.dependency 'expo-dev-menu-interface'
|
|
21
|
+
s.dependency 'EXManifests', :configurations => :debug
|
|
20
22
|
s.dependency 'EXUpdatesInterface'
|
|
21
23
|
end
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-dev-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Expo Development Client",
|
|
5
5
|
"main": "build/DevClient.js",
|
|
6
6
|
"types": "build/DevClient.d.ts",
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"test": "expo-module test",
|
|
12
12
|
"prepare": "expo-module prepare",
|
|
13
13
|
"prepublishOnly": "expo-module prepublishOnly",
|
|
14
|
-
"expo-module": "expo-module"
|
|
14
|
+
"expo-module": "expo-module",
|
|
15
|
+
"e2e": "expo-test-runner run-test -t e2e"
|
|
15
16
|
},
|
|
16
17
|
"keywords": [
|
|
17
18
|
"react-native",
|
|
@@ -28,19 +29,21 @@
|
|
|
28
29
|
},
|
|
29
30
|
"author": "650 Industries, Inc.",
|
|
30
31
|
"license": "MIT",
|
|
31
|
-
"homepage": "https://docs.expo.
|
|
32
|
+
"homepage": "https://docs.expo.dev/clients/introduction/",
|
|
32
33
|
"dependencies": {
|
|
33
|
-
"@expo/config-plugins": "^3.
|
|
34
|
-
"expo-dev-launcher": "0.
|
|
35
|
-
"expo-dev-menu": "0.
|
|
36
|
-
"expo-dev-menu-interface": "0.
|
|
37
|
-
"expo-
|
|
34
|
+
"@expo/config-plugins": "^3.1.0",
|
|
35
|
+
"expo-dev-launcher": "0.8.2",
|
|
36
|
+
"expo-dev-menu": "0.8.3",
|
|
37
|
+
"expo-dev-menu-interface": "0.4.1",
|
|
38
|
+
"expo-manifests": "~0.2.2",
|
|
39
|
+
"expo-updates-interface": "~0.4.0"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
|
-
"expo-module-scripts": "^2.0.0"
|
|
42
|
+
"expo-module-scripts": "^2.0.0",
|
|
43
|
+
"expo-test-runner": "0.0.6"
|
|
41
44
|
},
|
|
42
45
|
"jest": {
|
|
43
46
|
"preset": "expo-module-scripts/ios"
|
|
44
47
|
},
|
|
45
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "e30402e90972d9e1838d7b63a40a71a41398a772"
|
|
46
49
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const InstallationPage = "https://docs.expo.dev/clients/installation/";
|