Skip to content

Commit

Permalink
[expo-dev-launcher] take 2 at SDK 44 plugin compatibility (#15570)
Browse files Browse the repository at this point in the history
Co-authored-by: Łukasz Kosmaty <lukasz.kosmaty@swmansion.com># Why

when testing #15562 on the sdk-44 branch I found there were still a few issues -- (1) some expo-modules stuff would be inadvertently removed from AppDelegate, even though the project would build, and (2) tests were failing.

# How

(commit 1) added the correct logic for SDK 44's `initializeReactNativeApp` function (these regexes are getting so messy, we can't move to expo module initialization soon enough 😅 ), and added tests with a corresponding SDK 44 AppDelegate.m.
(commit 2) fixed wrong string constant that was causing failures for SDK 43 and below
(commit 3) fixed tests on the Android side that were logging warnings. @lukmccall is it correct to say that this config plugin cannot handle projects where `createReactActivityDelegate` isn't already overridden in MainActivity? I modified the tests as such, but if that isn't the case, [this warning](https://github.com/expo/expo/blob/4ca5ff72ef3abcc30cb7936eaf9c4b97fed9a5ad/packages/expo-dev-launcher/plugin/src/withDevLauncher.ts#L205-L209) needs to be changed.

# Test Plan

All tests pass. Manually tested in a blank SDK 44 app; cherry picked these commits onto sdk-44 and then used patch-package to patch entire the expo-dev-launcher package to match sdk-44 HEAD. Ran expo prebuild, saw no errors, eyeballed the code changes, and tested the following scenarios:

✅ project builds on iOS and Android
✅ iOS: can open app served by `expo start --dev-client`
✅ iOS: can open app served by `expo start --dev-client --force-manifest-type=expo-updates`
✅ Android: can open app served by `expo start --dev-client`
✅ Android: can open app served by `expo start --dev-client --force-manifest-type=expo-updates`
✅ expo install expo-updates@0.11.2, expo prebuild --clean, project builds
✅ iOS (with expo-updates integration): can open app served by `expo start --dev-client`
✅ iOS (with expo-updates integration): can open app served by `expo start --dev-client --force-manifest-type=expo-updates`
✅ iOS (with expo-updates integration): can open published app
✅ Android (with expo-updates integration): can open app served by `expo start --dev-client`
✅ Android (with expo-updates integration): can open app served by `expo start --dev-client --force-manifest-type=expo-updates`
✅ Android (with expo-updates integration): can open published app
  • Loading branch information
esamelson authored and lukmccall committed Dec 15, 2021
1 parent 78867f1 commit 88e27f1
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 16 deletions.
2 changes: 1 addition & 1 deletion packages/expo-dev-launcher/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- Fix plugin when `MainActivity.onNewIntent` exists. ([#15459](https://github.com/expo/expo/pull/15459) by [@janicduplessis](https://github.com/janicduplessis))
- Fix plugin when `expo-updates` is not present. ([#15541](https://github.com/expo/expo/pull/15541) by [@esamelson](https://github.com/esamelson))
- Include expo-platform header in manifest requests. ([#15563](https://github.com/expo/expo/pull/15563) by [@esamelson](https://github.com/esamelson))
- Fix plugin compatibility with SDK 44. ([#15562](https://github.com/expo/expo/pull/15562) by [@lukmccall](https://github.com/lukmccall))
- Fix plugin compatibility with SDK 44. ([#15562](https://github.com/expo/expo/pull/15562) & [#15570](https://github.com/expo/expo/pull/15570) by [@lukmccall](https://github.com/lukmccall) & [@esamelson](https://github.com/esamelson))

### 💡 Others

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
exports[`modifyJavaMainActivity modifies the MainActivity file for dev-launcher 1`] = `
"import android.content.Intent;
import expo.modules.devlauncher.DevLauncherController;
import android.os.Build;
import android.os.Bundle;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import expo.modules.ReactActivityDelegateWrapper;
public class MainActivity extends ReactActivity {
Expand All @@ -15,13 +22,49 @@ public class MainActivity extends ReactActivity {
super.onNewIntent(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// Set the theme to AppTheme BEFORE onCreate to support
// coloring the background, status bar, and navigation bar.
// This is required for expo-splash-screen.
setTheme(R.style.AppTheme);
super.onCreate(null);
}
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return \\"react-native-project\\";
return \\"main\\";
}
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return DevLauncherController.wrapReactActivityDelegate(this, () -> new ReactActivityDelegateWrapper(this,
new ReactActivityDelegate(this, getMainComponentName())
));
}
/**
* Align the back button behavior with Android S
* where moving root activities to background instead of finishing activities.
* @see <a href=\\"https://developer.android.com/reference/android/app/Activity#onBackPressed()\\">onBackPressed</a>
*/
@Override
public void invokeDefaultOnBackPressed() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
if (!moveTaskToBack(false)) {
// For non-root activities, use the default implementation to finish them.
super.invokeDefaultOnBackPressed();
}
return;
}
// Use the default back button implementation on Android S
// because it's doing more than {@link Activity#moveTaskToBack} in fact.
super.invokeDefaultOnBackPressed();
}
}
"
Expand All @@ -31,6 +74,10 @@ exports[`modifyJavaMainActivity modifies the MainActivity file for dev-launcher
"import android.content.Intent;
import expo.modules.devlauncher.DevLauncherController;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
import expo.modules.ReactActivityDelegateWrapper;
public class MainActivity extends ReactActivity {
/**
Expand All @@ -42,6 +89,13 @@ public class MainActivity extends ReactActivity {
return \\"react-native-project\\";
}
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return DevLauncherController.wrapReactActivityDelegate(this, () -> new ReactActivityDelegateWrapper(this,
new ReactActivityDelegate(this, getMainComponentName())
));
}
@Override
protected void onNewIntent(Intent intent) {
if (DevLauncherController.tryToHandleIntent(this, intent)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#import "AppDelegate.h"

#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTLinkingManager.h>
#import <React/RCTConvert.h>

#if defined(FB_SONARKIT_ENABLED) && __has_include(<FlipperKit/FlipperClient.h>)
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>

static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
}
#endif

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#if defined(FB_SONARKIT_ENABLED) && __has_include(<FlipperKit/FlipperClient.h>)
InitializeFlipper(application);
#endif

RCTBridge *bridge = [self.reactDelegate createBridgeWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [self.reactDelegate createRootViewWithBridge:bridge moduleName:@"main" initialProperties:nil];
rootView.backgroundColor = [UIColor whiteColor];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [self.reactDelegate createRootViewController];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];

[super application:application didFinishLaunchingWithOptions:launchOptions];

return YES;
}

- (NSArray<id<RCTBridgeModule>> *)extraModulesForBridge:(RCTBridge *)bridge
{
// If you'd like to export some custom RCTBridgeModules, add them here!
return @[];
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
#ifdef DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}

// Linking API
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
return [RCTLinkingManager application:application openURL:url options:options];
}

// Universal Links
- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler {
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import android.os.Build;
import android.os.Bundle;

import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;

import expo.modules.ReactActivityDelegateWrapper;

public class MainActivity extends ReactActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
// Set the theme to AppTheme BEFORE onCreate to support
// coloring the background, status bar, and navigation bar.
// This is required for expo-splash-screen.
setTheme(R.style.AppTheme);
super.onCreate(null);
}

/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "main";
}

@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegateWrapper(this,
new ReactActivityDelegate(this, getMainComponentName())
);
}

/**
* Align the back button behavior with Android S
* where moving root activities to background instead of finishing activities.
* @see <a href="https://developer.android.com/reference/android/app/Activity#onBackPressed()">onBackPressed</a>
*/
@Override
public void invokeDefaultOnBackPressed() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
if (!moveTaskToBack(false)) {
// For non-root activities, use the default implementation to finish them.
super.invokeDefaultOnBackPressed();
}
return;
}

// Use the default back button implementation on Android S
// because it's doing more than {@link Activity#moveTaskToBack} in fact.
super.invokeDefaultOnBackPressed();
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;

import expo.modules.ReactActivityDelegateWrapper;

public class MainActivity extends ReactActivity {
/**
Expand All @@ -10,6 +14,13 @@ protected String getMainComponentName() {
return "react-native-project";
}

@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new ReactActivityDelegateWrapper(this,
new ReactActivityDelegate(this, getMainComponentName())
);
}

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,25 @@ import path from 'path';
import { modifyJavaMainActivity } from '../withDevLauncher';

describe(modifyJavaMainActivity, () => {
/**
* The config plugin cannot currently handle projects created with react-native init
*
it(`modifies the MainActivity file for dev-launcher`, () => {
const fixture = fs.readFileSync(
path.join(__dirname, 'fixtures', 'MainActivity-react-native.java'),
'utf8'
);
expect(modifyJavaMainActivity(fixture)).toMatchSnapshot();
});
*/

it(`modifies the MainActivity file for dev-launcher`, () => {
const fixture = fs.readFileSync(
path.join(__dirname, 'fixtures', 'MainActivity-expo-modules.java'),
'utf8'
);
expect(modifyJavaMainActivity(fixture)).toMatchSnapshot();
});

it(`modifies the MainActivity file for dev-launcher when onNewIntent exists`, () => {
const fixture = fs.readFileSync(
Expand All @@ -22,7 +34,7 @@ describe(modifyJavaMainActivity, () => {

it(`modifying MainActivity twice doesn't change the content`, () => {
const firstModification = fs.readFileSync(
path.join(__dirname, 'fixtures', 'MainActivity-react-native.java'),
path.join(__dirname, 'fixtures', 'MainActivity-expo-modules.java'),
'utf8'
);
modifyJavaMainActivity(firstModification);
Expand Down
2 changes: 1 addition & 1 deletion packages/expo-dev-launcher/plugin/src/withDevLauncher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ export function modifyJavaMainActivity(content: string): string {
WarningAggregator.addWarningAndroid(
'expo-dev-launcher',
`Failed to wrap 'ReactActivityDelegate'
See the expo-dev-client installation instructions to modify your MainApplication.java manually: ${InstallationPage}`
See the expo-dev-client installation instructions to modify your MainActivity.java manually: ${InstallationPage}`
);
return content;
}
Expand Down
Loading

0 comments on commit 88e27f1

Please sign in to comment.