Skip to content

Commit df04f5e

Browse files
committed
feat: Implement new architecture for CodePush module and dialog
- Added CodePushDialogImpl to handle dialog display logic. - Introduced CodePushNativeModuleImpl for native module functionality. - Created new CodePushDialog and CodePushNativeModule classes for the new architecture. - Migrated existing dialog and native module implementations to the new structure. - Updated package.json to include codegen configuration for new modules. - Added TypeScript specifications for CodePush and CodePushDialog. - Ensured backward compatibility with old architecture by retaining old classes.
1 parent ed0952a commit df04f5e

File tree

13 files changed

+701
-249
lines changed

13 files changed

+701
-249
lines changed

AlertAdapter.js

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,22 @@ import React, { Platform } from "react-native";
22
let { Alert } = React;
33

44
if (Platform.OS === "android") {
5-
const { NativeModules: { CodePushDialog } } = React;
5+
function resolveNativeModule(name) {
6+
const ReactNative = require("react-native");
7+
try {
8+
const turboModule =
9+
ReactNative.TurboModuleRegistry && ReactNative.TurboModuleRegistry.get
10+
? ReactNative.TurboModuleRegistry.get(name)
11+
: null;
12+
if (turboModule) return turboModule;
13+
} catch (_e) {
14+
// Ignore and fall back to legacy NativeModules.
15+
}
16+
17+
return ReactNative.NativeModules ? ReactNative.NativeModules[name] : null;
18+
}
19+
20+
const CodePushDialog = resolveNativeModule("CodePushDialog");
621

722
Alert = {
823
alert(title, message, buttons) {
@@ -13,6 +28,10 @@ if (Platform.OS === "android") {
1328
const button1Text = buttons[0] ? buttons[0].text : null,
1429
button2Text = buttons[1] ? buttons[1].text : null;
1530

31+
if (!CodePushDialog) {
32+
throw "CodePushDialog native module is not installed.";
33+
}
34+
1635
CodePushDialog.showDialog(
1736
title, message, button1Text, button2Text,
1837
(buttonId) => { buttons[buttonId].onPress && buttons[buttonId].onPress(); },
@@ -21,4 +40,4 @@ if (Platform.OS === "android") {
2140
};
2241
}
2342

24-
module.exports = { Alert };
43+
module.exports = { Alert };

CodePush.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,22 @@ import { AppState, Platform } from "react-native";
55
import log from "./logging";
66
import hoistStatics from 'hoist-non-react-statics';
77

8-
let NativeCodePush = require("react-native").NativeModules.CodePush;
8+
function resolveNativeModule(name) {
9+
const ReactNative = require("react-native");
10+
try {
11+
const turboModule =
12+
ReactNative.TurboModuleRegistry && ReactNative.TurboModuleRegistry.get
13+
? ReactNative.TurboModuleRegistry.get(name)
14+
: null;
15+
if (turboModule) return turboModule;
16+
} catch (_e) {
17+
// Ignore and fall back to legacy NativeModules.
18+
}
19+
20+
return ReactNative.NativeModules ? ReactNative.NativeModules[name] : null;
21+
}
22+
23+
let NativeCodePush = resolveNativeModule("CodePush");
924
const PackageMixins = require("./package-mixins")(NativeCodePush);
1025

1126
async function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatchCallback = null) {

android/app/build.gradle

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
apply plugin: "com.android.library"
22

3+
def safeExtGet(prop, fallback) {
4+
return rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
5+
}
6+
37
def isNewArchitectureEnabled() {
48
// To opt-in for the New Architecture, you can either:
59
// - Set `newArchEnabled` to true inside the `gradle.properties` file
@@ -22,27 +26,38 @@ def DEFAULT_MIN_SDK_VERSION = 16
2226
android {
2327
namespace "com.microsoft.codepush.react"
2428

25-
compileSdkVersion rootProject.hasProperty('compileSdkVersion') ? rootProject.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION
26-
buildToolsVersion rootProject.hasProperty('buildToolsVersion') ? rootProject.buildToolsVersion : DEFAULT_BUILD_TOOLS_VERSION
29+
compileSdkVersion safeExtGet("compileSdkVersion", DEFAULT_COMPILE_SDK_VERSION)
30+
buildToolsVersion safeExtGet("buildToolsVersion", DEFAULT_BUILD_TOOLS_VERSION)
31+
32+
buildFeatures {
33+
buildConfig true
34+
}
2735

2836
defaultConfig {
29-
minSdkVersion rootProject.hasProperty('minSdkVersion') ? rootProject.minSdkVersion : DEFAULT_MIN_SDK_VERSION
30-
targetSdkVersion rootProject.hasProperty('targetSdkVersion') ? rootProject.targetSdkVersion : DEFAULT_TARGET_SDK_VERSION
37+
minSdkVersion safeExtGet("minSdkVersion", DEFAULT_MIN_SDK_VERSION)
38+
targetSdkVersion safeExtGet("targetSdkVersion", DEFAULT_TARGET_SDK_VERSION)
3139
versionCode 1
3240
versionName "1.0"
3341
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", IS_NEW_ARCHITECTURE_ENABLED.toString()
42+
consumerProguardFiles 'proguard-rules.pro'
3443
}
3544

36-
lintOptions {
37-
abortOnError false
45+
sourceSets {
46+
main {
47+
if (IS_NEW_ARCHITECTURE_ENABLED) {
48+
java.srcDirs += ["src/newarch/java"]
49+
} else {
50+
java.srcDirs += ["src/oldarch/java"]
51+
}
52+
}
3853
}
3954

40-
defaultConfig {
41-
consumerProguardFiles 'proguard-rules.pro'
55+
lintOptions {
56+
abortOnError false
4257
}
4358
}
4459

4560
dependencies {
46-
implementation "com.facebook.react:react-native:+"
61+
implementation("com.facebook.react:react-android")
4762
implementation 'com.nimbusds:nimbus-jose-jwt:9.37.3'
4863
}

android/app/src/main/java/com/microsoft/codepush/react/CodePush.java

Lines changed: 52 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,24 @@
77

88
import com.facebook.react.ReactHost;
99
import com.facebook.react.ReactInstanceManager;
10-
import com.facebook.react.ReactPackage;
10+
import com.facebook.react.BaseReactPackage;
1111
import com.facebook.react.bridge.JavaScriptModule;
1212
import com.facebook.react.bridge.NativeModule;
1313
import com.facebook.react.bridge.ReactApplicationContext;
14+
import com.facebook.react.module.model.ReactModuleInfo;
15+
import com.facebook.react.module.model.ReactModuleInfoProvider;
1416
import com.facebook.react.uimanager.ViewManager;
1517

1618
import org.json.JSONException;
1719
import org.json.JSONObject;
1820

1921
import java.io.File;
2022
import java.util.ArrayList;
23+
import java.util.HashMap;
2124
import java.util.List;
25+
import java.util.Map;
2226

23-
public class CodePush implements ReactPackage {
27+
public class CodePush extends BaseReactPackage {
2428
private static final Object LOCK = new Object();
2529
private static volatile CodePush mCurrentInstance;
2630
public static CodePush getInstance(String deploymentKey, Context context, boolean isDebugMode) {
@@ -422,14 +426,14 @@ static ReactHost getReactHost() {
422426
}
423427

424428
@Override
425-
public List<NativeModule> createNativeModules(ReactApplicationContext reactApplicationContext) {
426-
CodePushNativeModule codePushModule = new CodePushNativeModule(reactApplicationContext, this, mUpdateManager, mTelemetryManager, mSettingsManager);
427-
CodePushDialog dialogModule = new CodePushDialog(reactApplicationContext);
428-
429-
List<NativeModule> nativeModules = new ArrayList<>();
430-
nativeModules.add(codePushModule);
431-
nativeModules.add(dialogModule);
432-
return nativeModules;
429+
public NativeModule getModule(String name, ReactApplicationContext reactApplicationContext) {
430+
if (CodePushNativeModule.NAME.equals(name)) {
431+
return new CodePushNativeModule(reactApplicationContext, this, mUpdateManager, mTelemetryManager, mSettingsManager);
432+
}
433+
if (CodePushDialog.NAME.equals(name)) {
434+
return new CodePushDialog(reactApplicationContext);
435+
}
436+
return null;
433437
}
434438

435439
// Deprecated in RN v0.47.
@@ -441,4 +445,42 @@ public List<Class<? extends JavaScriptModule>> createJSModules() {
441445
public List<ViewManager> createViewManagers(ReactApplicationContext reactApplicationContext) {
442446
return new ArrayList<>();
443447
}
448+
449+
@Override
450+
public ReactModuleInfoProvider getReactModuleInfoProvider() {
451+
return new ReactModuleInfoProvider() {
452+
@Override
453+
public Map<String, ReactModuleInfo> getReactModuleInfos() {
454+
boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
455+
456+
Map<String, ReactModuleInfo> map = new HashMap<>();
457+
map.put(
458+
CodePushNativeModule.NAME,
459+
new ReactModuleInfo(
460+
CodePushNativeModule.NAME,
461+
CodePushNativeModule.NAME,
462+
false,
463+
false,
464+
true,
465+
false,
466+
isTurboModule
467+
)
468+
);
469+
map.put(
470+
CodePushDialog.NAME,
471+
new ReactModuleInfo(
472+
CodePushDialog.NAME,
473+
CodePushDialog.NAME,
474+
false,
475+
false,
476+
false,
477+
false,
478+
isTurboModule
479+
)
480+
);
481+
482+
return map;
483+
}
484+
};
485+
}
444486
}

android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java renamed to android/app/src/main/java/com/microsoft/codepush/react/CodePushDialogImpl.java

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,54 +4,59 @@
44
import android.app.AlertDialog;
55
import android.content.DialogInterface;
66

7-
import com.facebook.react.bridge.BaseJavaModule;
87
import com.facebook.react.bridge.Callback;
98
import com.facebook.react.bridge.LifecycleEventListener;
109
import com.facebook.react.bridge.ReactApplicationContext;
11-
import com.facebook.react.bridge.ReactMethod;
1210

13-
public class CodePushDialog extends BaseJavaModule {
11+
final class CodePushDialogImpl {
12+
private final ReactApplicationContext reactContext;
1413

15-
public CodePushDialog(ReactApplicationContext reactContext) {
16-
super(reactContext);
14+
CodePushDialogImpl(ReactApplicationContext reactContext) {
15+
this.reactContext = reactContext;
1716
}
1817

19-
@ReactMethod
20-
public void showDialog(final String title, final String message, final String button1Text,
21-
final String button2Text, final Callback successCallback, Callback errorCallback) {
22-
Activity currentActivity = getReactApplicationContext().getCurrentActivity();
18+
void showDialog(
19+
final String title,
20+
final String message,
21+
final String button1Text,
22+
final String button2Text,
23+
final Callback successCallback,
24+
final Callback errorCallback
25+
) {
26+
Activity currentActivity = reactContext.getCurrentActivity();
2327
if (currentActivity == null || currentActivity.isFinishing()) {
24-
// If getCurrentActivity is null, it could be because the app is backgrounded,
25-
// so we show the dialog when the app resumes)
26-
getReactApplicationContext().addLifecycleEventListener(new LifecycleEventListener() {
28+
reactContext.addLifecycleEventListener(new LifecycleEventListener() {
2729
@Override
2830
public void onHostResume() {
29-
Activity currentActivity = getReactApplicationContext().getCurrentActivity();
30-
if (currentActivity != null) {
31-
getReactApplicationContext().removeLifecycleEventListener(this);
32-
showDialogInternal(title, message, button1Text, button2Text, successCallback, currentActivity);
31+
Activity resumedActivity = reactContext.getCurrentActivity();
32+
if (resumedActivity != null && !resumedActivity.isFinishing()) {
33+
reactContext.removeLifecycleEventListener(this);
34+
showDialogInternal(title, message, button1Text, button2Text, successCallback, resumedActivity);
3335
}
3436
}
3537

3638
@Override
3739
public void onHostPause() {
38-
3940
}
4041

4142
@Override
4243
public void onHostDestroy() {
43-
4444
}
4545
});
4646
} else {
4747
showDialogInternal(title, message, button1Text, button2Text, successCallback, currentActivity);
4848
}
4949
}
5050

51-
private void showDialogInternal(String title, String message, String button1Text,
52-
String button2Text, final Callback successCallback, Activity currentActivity) {
51+
private void showDialogInternal(
52+
String title,
53+
String message,
54+
String button1Text,
55+
String button2Text,
56+
final Callback successCallback,
57+
Activity currentActivity
58+
) {
5359
AlertDialog.Builder builder = new AlertDialog.Builder(currentActivity);
54-
5560
builder.setCancelable(false);
5661

5762
DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
@@ -61,10 +66,10 @@ public void onClick(DialogInterface dialog, int which) {
6166
dialog.cancel();
6267
switch (which) {
6368
case DialogInterface.BUTTON_POSITIVE:
64-
successCallback.invoke(0);
69+
if (successCallback != null) successCallback.invoke(0);
6570
break;
6671
case DialogInterface.BUTTON_NEGATIVE:
67-
successCallback.invoke(1);
72+
if (successCallback != null) successCallback.invoke(1);
6873
break;
6974
default:
7075
throw new CodePushUnknownException("Unknown button ID pressed.");
@@ -94,9 +99,4 @@ public void onClick(DialogInterface dialog, int which) {
9499
AlertDialog dialog = builder.create();
95100
dialog.show();
96101
}
97-
98-
@Override
99-
public String getName() {
100-
return "CodePushDialog";
101-
}
102102
}

0 commit comments

Comments
 (0)