Skip to content

Commit c88d549

Browse files
authored
Merge pull request #1813 from belemaire/android-dynamic-feature-module
Add support for Android dynamic feature modules
2 parents ed7b78f + 7a74d4b commit c88d549

File tree

5 files changed

+58
-1
lines changed

5 files changed

+58
-1
lines changed

docs/platform-parts/container/container-integration.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,38 @@ You can configure `androidConfig` in the cauldron as show below.
150150
}
151151
```
152152

153+
##### Android Dynamic Feature Module Support
154+
155+
If the Android client mobile application consuming the container is keeping the container dependency in an Android [dynamic feature module](https://developer.android.com/codelabs/on-demand-dynamic-delivery), there will be issues with resources loading _(your MiniApps images won't be visible for example)_. This is because of React Native Android implementation, that is loading some resources via reflection, using the base package name of the application, instead of the package name of the dynamic module _[see Android documentation for more details](https://developer.android.com/guide/playcore/feature-delivery#resource-uri)_. For this reason we had no way but to fork React Native to update the implementation to properly handle this use case.\
156+
Our fork of React Native is kept in [electrode-io/react-native](https://github.com/electrode-io/react-native) repository.\
157+
We are only using it to publish special React Native AARs for Android, not for any iOS changes nor JS ones _(i.e we're not publishing anything to npm)_.\
158+
Starting with 0.63 line, we will publish custom releases of the AAR, in addition to the official versions, to include support for dynamic feature modules. These versions will have a patch number starting at 100 _(0.63.100, 0.64.100 ...)_.
159+
160+
If you are facing this fringe scenario with dynamic feature modules, here is what can be done:
161+
162+
1. Generate the container with a custom AAR version of React Native that includes support for Dynamic Feature Modules.\
163+
This can be done by supplying such a configuration to the container generator _(via --extra option or through Cauldron config)_
164+
165+
```json
166+
{
167+
"containerGenerator": {
168+
"androidConfig": {
169+
"reactNativeAarVersion": "0.64.100"
170+
}
171+
}
172+
}
173+
```
174+
175+
Always use the latest custom AAR version matching the React Native version line that your miniapps(s) are using _(for example if your miniapp is using 0.63.4, you should use 0.63.100 here)_.
176+
177+
2. Update the client application to pass the dynamic feature module package name to the container.\
178+
For example if the client application base package name is `com.foo` and the dynamic feature module containing the container dependency is named `bar`, the package name used for resources resolution in the dynamic feature module would be `com.foo.bar`.\
179+
In that case, the client application would need to call the following, prior to initializing the container.
180+
181+
```java
182+
ElectrodeReactContainer.setPackageName("com.foo.bar");
183+
```
184+
153185
##### JavaScript Engine (RN 0.60 and above)
154186

155187
Starting with React Native 0.60, the JavaScript engine is distributed separately from the React Native AAR.

ern-container-gen-android/src/AndroidGenerator.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import semver from 'semver';
3838

3939
const PATH_TO_TEMPLATES_DIR = path.join(__dirname, 'templates');
4040
const PATH_TO_HULL_DIR = path.join(__dirname, 'hull');
41+
const ERN_CUSTOM_REACT_NATIVE_AAR_PATCH_VERSION = 100;
4142

4243
export interface AndroidDependencies {
4344
files: string[];
@@ -333,7 +334,7 @@ You should replace "${annotationProcessorPrefix}:${dependency}" with "annotation
333334
mustacheView.customPermissions = _.uniq(mustacheView.customPermissions);
334335

335336
androidDependencies.regular.push(
336-
`com.walmartlabs.ern:react-native:${reactNativePlugin.version}`,
337+
`com.walmartlabs.ern:react-native:${versions.reactNativeAarVersion}`,
337338
);
338339
androidDependencies.regular.push(
339340
`com.android.support:appcompat-v7:${versions.supportLibraryVersion}`,
@@ -354,6 +355,13 @@ You should replace "${annotationProcessorPrefix}:${dependency}" with "annotation
354355
)}`,
355356
);
356357

358+
if (
359+
semver.patch(versions.reactNativeAarVersion) >=
360+
ERN_CUSTOM_REACT_NATIVE_AAR_PATCH_VERSION
361+
) {
362+
mustacheView.isCustomReactNativeAar = true;
363+
}
364+
357365
injectPluginsKaxTask.succeed(injectPluginsTaskMsg);
358366

359367
const partialProxy = (name: string) => {

ern-container-gen-android/src/hull/lib/src/main/java/com/walmartlabs/ern/container/ElectrodeReactContainer.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import com.facebook.react.ReactInstanceManager;
2727
import com.facebook.react.ReactNativeHost;
2828
import com.facebook.react.ReactPackage;
29+
import com.facebook.react.bridge.ReactApplicationContext;
2930
import com.facebook.react.bridge.ReactContext;
3031
import com.facebook.react.bridge.SafeActivityStarter;
3132
import com.facebook.react.devsupport.interfaces.DevOptionHandler;
@@ -67,6 +68,12 @@ public class ElectrodeReactContainer {
6768
private ElectrodeReactContainer() {
6869
}
6970

71+
{{#isCustomReactNativeAar}}
72+
public static void setPackageName(String packageName) {
73+
ReactApplicationContext.PACKAGE_NAME = packageName;
74+
}
75+
{{/isCustomReactNativeAar}}
76+
7077
public static synchronized ReactInstanceManager getReactInstanceManager() {
7178
throwIfNotInitialized();
7279
return sElectrodeReactNativeHost.getReactInstanceManager();

ern-core/src/android.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export interface AndroidResolvedVersions {
3939
gradleDistributionVersion: string;
4040
kotlinVersion: string;
4141
minSdkVersion: string;
42+
reactNativeAarVersion: string;
4243
sourceCompatibility: string;
4344
supportLibraryVersion: string;
4445
targetCompatibility: string;
@@ -54,6 +55,7 @@ export function resolveAndroidVersions({
5455
gradleDistributionVersion = DEFAULT_GRADLE_DISTRIBUTION_VERSION,
5556
kotlinVersion = DEFAULT_KOTLIN_VERSION,
5657
minSdkVersion,
58+
reactNativeAarVersion,
5759
sourceCompatibility = DEFAULT_SOURCE_COMPATIBILITY,
5860
supportLibraryVersion = DEFAULT_SUPPORT_LIBRARY_VERSION,
5961
targetCompatibility = DEFAULT_TARGET_COMPATIBILITY,
@@ -68,6 +70,7 @@ export function resolveAndroidVersions({
6870
gradleDistributionVersion?: string;
6971
kotlinVersion?: string;
7072
minSdkVersion?: string;
73+
reactNativeAarVersion?: string;
7174
sourceCompatibility?: string;
7275
supportLibraryVersion?: string;
7376
targetCompatibility?: string;
@@ -80,6 +83,8 @@ export function resolveAndroidVersions({
8083
? DEFAULT_MIN_SDK_VERSION_POST_RN64
8184
: DEFAULT_MIN_SDK_VERSION_PRE_RN64;
8285

86+
reactNativeAarVersion = reactNativeAarVersion ?? reactNativeVersion!;
87+
8388
return {
8489
androidGradlePlugin,
8590
androidxAppcompactVersion,
@@ -89,6 +94,7 @@ export function resolveAndroidVersions({
8994
gradleDistributionVersion,
9095
kotlinVersion,
9196
minSdkVersion: resolvedMinSdkVersion,
97+
reactNativeAarVersion,
9298
sourceCompatibility,
9399
supportLibraryVersion,
94100
targetCompatibility,

ern-core/test/android-test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ describe('android.js', () => {
223223
gradleDistributionVersion: android.DEFAULT_GRADLE_DISTRIBUTION_VERSION,
224224
kotlinVersion: android.DEFAULT_KOTLIN_VERSION,
225225
minSdkVersion: android.DEFAULT_MIN_SDK_VERSION_POST_RN64,
226+
reactNativeAarVersion: '0.64.0',
226227
sourceCompatibility: android.DEFAULT_SOURCE_COMPATIBILITY,
227228
supportLibraryVersion: android.DEFAULT_SUPPORT_LIBRARY_VERSION,
228229
targetCompatibility: android.DEFAULT_TARGET_COMPATIBILITY,
@@ -244,6 +245,7 @@ describe('android.js', () => {
244245
gradleDistributionVersion: android.DEFAULT_GRADLE_DISTRIBUTION_VERSION,
245246
kotlinVersion: android.DEFAULT_KOTLIN_VERSION,
246247
minSdkVersion: android.DEFAULT_MIN_SDK_VERSION_PRE_RN64,
248+
reactNativeAarVersion: '0.63.0',
247249
sourceCompatibility: android.DEFAULT_SOURCE_COMPATIBILITY,
248250
supportLibraryVersion: android.DEFAULT_SUPPORT_LIBRARY_VERSION,
249251
targetCompatibility: android.DEFAULT_TARGET_COMPATIBILITY,
@@ -269,6 +271,7 @@ describe('android.js', () => {
269271
gradleDistributionVersion: android.DEFAULT_GRADLE_DISTRIBUTION_VERSION,
270272
kotlinVersion: '1.4.0',
271273
minSdkVersion: '15',
274+
reactNativeAarVersion: undefined,
272275
sourceCompatibility: 'VERSION_1_9',
273276
supportLibraryVersion: android.DEFAULT_SUPPORT_LIBRARY_VERSION,
274277
targetCompatibility: 'VERSION_1_9',
@@ -300,6 +303,7 @@ describe('android.js', () => {
300303
gradleDistributionVersion: '4.5',
301304
kotlinVersion: '1.4.0',
302305
minSdkVersion: '15',
306+
reactNativeAarVersion: undefined,
303307
sourceCompatibility: 'VERSION_1_9',
304308
supportLibraryVersion: '27.0.0',
305309
targetCompatibility: 'VERSION_1_9',

0 commit comments

Comments
 (0)