diff --git a/local-cli/core/__fixtures__/android.js b/local-cli/core/__fixtures__/android.js index ebecf9b8c9029f..cab6cbbe45c7f6 100644 --- a/local-cli/core/__fixtures__/android.js +++ b/local-cli/core/__fixtures__/android.js @@ -20,6 +20,25 @@ exports.valid = { }, }; +exports.validMultipleManifests = { + src: { + main: { + 'AndroidManifest.xml': manifest, + com: { + some: { + example: { + 'Main.java': mainJavaClass, + 'ReactPackage.java': fs.readFileSync(path.join(__dirname, './files/ReactPackage.java')), + }, + }, + }, + }, + debug: { + 'AndroidManifest.xml': manifest + }, + }, +}; + exports.corrupted = { src: { 'AndroidManifest.xml': manifest, diff --git a/local-cli/core/__tests__/android/findManifest.spec.js b/local-cli/core/__tests__/android/findManifest.spec.js index 45c2b996af3a29..e08a14ee51c6ff 100644 --- a/local-cli/core/__tests__/android/findManifest.spec.js +++ b/local-cli/core/__tests__/android/findManifest.spec.js @@ -11,6 +11,9 @@ describe('android::findManifest', () => { flat: { android: mocks.valid, }, + multipleManifests: { + android: mocks.validMultipleManifests, + }, })); it('should return a manifest path if file exists in the folder', () => { @@ -21,5 +24,9 @@ describe('android::findManifest', () => { expect(findManifest('empty')).toBe(null); }); + it('should return the main manifest before other manifests', () => { + expect(findManifest('multipleManifests')).toMatch(/[\/\\]src[\/\\]main/); + }); + afterAll(mockFs.restore); }); diff --git a/local-cli/core/config/android/findManifest.js b/local-cli/core/config/android/findManifest.js index 3827b4276e7ee5..6714bfe0d52548 100644 --- a/local-cli/core/config/android/findManifest.js +++ b/local-cli/core/config/android/findManifest.js @@ -2,16 +2,33 @@ const glob = require('glob'); const path = require('path'); /** - * Find an android application path in the folder + * Find an AndroidManifest.xml in the folder. * * @param {String} folder Name of the folder where to seek * @return {String} */ module.exports = function findManifest(folder) { - const manifestPath = glob.sync(path.join('**', 'AndroidManifest.xml'), { + // Android projects may contain multiple manifest files that are merged + // during build. Usually we should use the manifest file of the main source + // set at src/main/AndroidManifest.xml. If for some reason that manifest + // isn't available (e.g. with a highly customised build setup) we should + // look for the first manifest we find. + const globOptions = { cwd: folder, - ignore: ['node_modules/**', '**/build/**', 'Examples/**', 'examples/**'], - })[0]; + ignore: ['**/build/**'], + }; - return manifestPath ? path.join(folder, manifestPath) : null; + const mainPattern = path.join('**', 'main', 'AndroidManifest.xml'); + const mainManifestPath = glob.sync(mainPattern, globOptions)[0]; + + if (mainManifestPath) { + return path.join(folder, mainManifestPath); + } + + // Here it's possible that we might not find the manifest that contains what + // our caller is looking for but this should be better than returning null. + const anyPattern = path.join('**', 'AndroidManifest.xml'); + const anyManifestPath = glob.sync(anyPattern, globOptions)[0]; + + return anyManifestPath ? path.join(folder, anyManifestPath) : null; };