Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 29 additions & 9 deletions expo.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,21 +193,41 @@ const withAndroidMainApplication = (config) => {
}
}

// --- 4. Add getJSBundleFile method ---
const getJSBundleFileMethodString = `
override fun getJSBundleFile(): String {
return CodePush.getJSBundleFile()
}`;
const hermesEnabledAnchor = /(override\s+val\s+isHermesEnabled:\s*Boolean\s*=\s*BuildConfig\.IS_HERMES_ENABLED)\s*\n/m;
// --- 4. Wire up CodePush bundle file ---
if (!content.includes("CodePush.getJSBundleFile()")) {
const getJSBundleFileMethodString = `
override fun getJSBundleFile(): String {
return CodePush.getJSBundleFile()
}`;
const hermesEnabledAnchor = /(override\s+val\s+isHermesEnabled:\s*Boolean\s*=\s*BuildConfig\.IS_HERMES_ENABLED)\s*\n/m;
const jsMainModuleAnchor = /(override fun getJSMainModuleName\(\): String = [^\n]+)\n/m;

if (!content.includes("override fun getJSBundleFile(): String")) {
if (hermesEnabledAnchor.test(content)) {
// RN < 0.82 and some bare RN templates still expose isHermesEnabled
content = content.replace(hermesEnabledAnchor, `$1\n${getJSBundleFileMethodString}\n`);
} else if (content.includes('ReactNativeHostWrapper(') && jsMainModuleAnchor.test(content)) {
// Expo CNG wraps the host and delegates getJSBundleFile() back to the host override.
content = content.replace(jsMainModuleAnchor, `$1\n${getJSBundleFileMethodString}\n`);
} else {
WarningAggregator.addWarningAndroid('codepush-plugin', 'Could not find `isHermesEnabled` property to anchor `getJSBundleFile()` insertion. Please review `MainApplication.kt`.');
// RN 0.82+: uses ReactHost via getDefaultReactHost() — pass jsBundleFilePath parameter
// Match the closing parenthesis of the getDefaultReactHost() call
const reactHostCallRegex = /(getDefaultReactHost\([\s\S]*?packageList\s*=[\s\S]*?\})([\s\S]*?\))/m;
if (reactHostCallRegex.test(content)) {
content = content.replace(reactHostCallRegex, (match, beforeClose, closing) => {
// Check if jsBundleFilePath is already set
if (match.includes('jsBundleFilePath')) return match;
// Insert the parameter before the closing parentheses
return `${beforeClose},\n jsBundleFilePath = CodePush.getJSBundleFile()${closing}`;
});
} else {
WarningAggregator.addWarningAndroid(
'codepush-plugin',
'Could not find a supported MainApplication anchor to configure CodePush bundle file.'
);
}
}
}

modConfig.modResults.contents = content;
return modConfig;
});
Expand Down
67 changes: 67 additions & 0 deletions test/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -536,11 +536,78 @@ const UpdateSync = "updateSync.js";
const UpdateSync2x = "updateSync2x.js";
const UpdateNotifyApplicationReadyConditional = "updateNARConditional.js";

const ExpoAndroidMainApplicationPathSegments = [
"android",
"app",
"src",
"main",
"java",
"com",
"testcodepush",
"MainApplication.kt",
];

function getExpoAndroidMainApplicationPath(projectDirectory: string): string {
return path.join(projectDirectory, TestConfig.TestAppName, ...ExpoAndroidMainApplicationPathSegments);
}

function assertExpoAndroidCodePushBundleWiring(projectDirectory: string): void {
const mainApplicationPath = getExpoAndroidMainApplicationPath(projectDirectory);
assert.ok(fs.existsSync(mainApplicationPath), `Expected generated MainApplication.kt at ${mainApplicationPath}`);

const content = fs.readFileSync(mainApplicationPath, "utf8");

if (content.includes("ReactNativeHostWrapper(")) {
assert.ok(
/override fun getJSBundleFile\(\): String\s*\{\s*return CodePush\.getJSBundleFile\(\)\s*\}/m.test(content),
`Expected CodePush getJSBundleFile() override in ${mainApplicationPath}`
);
} else {
assert.ok(
/getDefaultReactHost\([\s\S]*jsBundleFilePath = CodePush\.getJSBundleFile\(\)[\s\S]*\)/m.test(content),
`Expected CodePush jsBundleFilePath wiring in ${mainApplicationPath}`
);
}
}

//////////////////////////////////////////////////////////////////////////////////////////
// Initialize the tests.

PluginTestingFramework.initializeTests(new RNProjectManager(), supportedTargetPlatforms,
(projectManager: ProjectManager, targetPlatform: Platform.IPlatform) => {
TestBuilder.describe("#expo.android.mainApplication",
() => {
TestBuilder.it("wires the CodePush bundle file for the test app", false,
(done: Mocha.Done) => {
if (!TestConfig.isExpoApp || targetPlatform.getName() !== "android") {
done();
return;
}

try {
assertExpoAndroidCodePushBundleWiring(TestConfig.testRunDirectory);
done();
} catch (error) {
done(error);
}
});

TestBuilder.it("wires the CodePush bundle file for the update app", false,
(done: Mocha.Done) => {
if (!TestConfig.isExpoApp || targetPlatform.getName() !== "android") {
done();
return;
}

try {
assertExpoAndroidCodePushBundleWiring(TestConfig.updatesDirectory);
done();
} catch (error) {
done(error);
}
});
});

TestBuilder.describe("#window.codePush.checkForUpdate",
() => {
TestBuilder.it("window.codePush.checkForUpdate.noUpdate", false,
Expand Down