Fix `react-native link` issue when using multiple manifests

Summary:
`react-native link` often fails due to the wrong manifest being used when you use a debug manifest. `findManifest` returns `debug/AndroidManifest.xml` instead of `main/AndroidManifest.xml`. And the debug manifest usually does not have the package name defined so `projectConfigAndroid` throws a cryptic "Cannot read property 'replace' of undefined" error.

This fixes the issue by throwing a more user friendly error and providing a `manifestPath` userConfig.

This is mostly based on comments to #10050.
Closes https://github.com/facebook/react-native/pull/13373

Differential Revision: D4945690

Pulled By: shergin

fbshipit-source-id: b177f916fd4799c873d2515c18cbb87bef3203f0
This commit is contained in:
Daniel Friesen 2017-06-06 14:11:54 -07:00 committed by Facebook Github Bot
parent 2dfcde4c7b
commit 1ad08aa659
4 changed files with 46 additions and 2 deletions

View File

@ -20,6 +20,25 @@ exports.valid = {
}, },
}; };
exports.userConfigManifest = {
src: {
main: {
'AndroidManifest.xml': manifest,
com: {
some: {
example: {
'Main.java': mainJavaClass,
'ReactPackage.java': fs.readFileSync(path.join(__dirname, './files/ReactPackage.java')),
},
},
},
},
debug: {
'AndroidManifest.xml': fs.readFileSync(path.join(__dirname, './files/AndroidManifest-debug.xml')),
},
},
};
exports.corrupted = { exports.corrupted = {
src: { src: {
'AndroidManifest.xml': manifest, 'AndroidManifest.xml': manifest,

View File

@ -0,0 +1,3 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>

View File

@ -15,6 +15,9 @@ describe('android::getProjectConfig', () => {
flat: { flat: {
android: mocks.valid, android: mocks.valid,
}, },
multiple: {
android: mocks.userConfigManifest,
},
noManifest: { noManifest: {
android: {}, android: {},
}, },
@ -43,6 +46,16 @@ describe('android::getProjectConfig', () => {
expect(getProjectConfig(folder, userConfig)).not.toBe(null); expect(getProjectConfig(folder, userConfig)).not.toBe(null);
expect(typeof getProjectConfig(folder, userConfig)).toBe('object'); expect(typeof getProjectConfig(folder, userConfig)).toBe('object');
}); });
it('multiple', () => {
const userConfig = {
manifestPath: 'src/main/AndroidManifest.xml'
};
const folder = 'multiple';
expect(getProjectConfig(folder, userConfig)).not.toBe(null);
expect(typeof getProjectConfig(folder, userConfig)).toBe('object');
});
}); });
it('should return `null` if android project was not found', () => { it('should return `null` if android project was not found', () => {

View File

@ -29,7 +29,9 @@ exports.projectConfig = function projectConfigAndroid(folder, userConfig) {
const sourceDir = path.join(folder, src); const sourceDir = path.join(folder, src);
const isFlat = sourceDir.indexOf('app') === -1; const isFlat = sourceDir.indexOf('app') === -1;
const manifestPath = findManifest(sourceDir); const manifestPath = userConfig.manifestPath
? path.join(sourceDir, userConfig.manifestPath)
: findManifest(sourceDir);
if (!manifestPath) { if (!manifestPath) {
return null; return null;
@ -38,6 +40,11 @@ exports.projectConfig = function projectConfigAndroid(folder, userConfig) {
const manifest = readManifest(manifestPath); const manifest = readManifest(manifestPath);
const packageName = userConfig.packageName || getPackageName(manifest); const packageName = userConfig.packageName || getPackageName(manifest);
if (!packageName) {
throw new Error(`Package name not found in ${manifestPath}`);
}
const packageFolder = userConfig.packageFolder || const packageFolder = userConfig.packageFolder ||
packageName.replace(/\./g, path.sep); packageName.replace(/\./g, path.sep);
@ -92,7 +99,9 @@ exports.dependencyConfig = function dependencyConfigAndroid(folder, userConfig)
} }
const sourceDir = path.join(folder, src); const sourceDir = path.join(folder, src);
const manifestPath = findManifest(sourceDir); const manifestPath = userConfig.manifestPath
? path.join(sourceDir, userConfig.manifestPath)
: findManifest(sourceDir);
if (!manifestPath) { if (!manifestPath) {
return null; return null;