diff --git a/lib/prepare.js b/lib/prepare.js index 342151e2..b0d2e6cd 100644 --- a/lib/prepare.js +++ b/lib/prepare.js @@ -23,7 +23,6 @@ const nopt = require('nopt'); const glob = require('fast-glob'); const events = require('cordova-common').events; const AndroidManifest = require('./AndroidManifest'); -const checkReqs = require('./check_reqs'); const xmlHelpers = require('cordova-common').xmlHelpers; const CordovaError = require('cordova-common').CordovaError; const ConfigParser = require('cordova-common').ConfigParser; @@ -308,24 +307,20 @@ function updateProjectAccordingTo (platformConfig, locations) { const destFile = java_files[0]; - // var destFile = path.join(locations.root, 'app', 'src', 'main', 'java', androidPkgName.replace(/\./g, '/'), path.basename(java_files[0])); - // fs.ensureDirSync(path.dirname(destFile)); - // events.emit('verbose', java_files[0]); - // events.emit('verbose', destFile); - // console.log(locations); - // fs.copySync(java_files[0], destFile); - utils.replaceFileContents(destFile, /package [\w.]*;/, 'package ' + androidPkgName + ';'); - events.emit('verbose', 'Wrote out Android package name "' + androidPkgName + '" to ' + destFile); - - const removeOrigPkg = checkReqs.isWindows() || checkReqs.isDarwin() - ? manifestId.toUpperCase() !== androidPkgName.toUpperCase() - : manifestId !== androidPkgName; - - if (removeOrigPkg) { + // if package name has changed, path to MainActivity.java has to track it + const newDestFile = path.join(locations.root, 'app', 'src', 'main', 'java', androidPkgName.replace(/\./g, '/'), path.basename(destFile)); + if (newDestFile.toLowerCase() !== destFile.toLowerCase()) { + // If package was name changed we need to create new java with main activity in path matching new package name + fs.ensureDirSync(path.dirname(newDestFile)); + events.emit('verbose', `copy ${destFile} to ${newDestFile}`); + fs.copySync(destFile, newDestFile); + utils.replaceFileContents(newDestFile, /package [\w.]*;/, 'package ' + androidPkgName + ';'); + events.emit('verbose', 'Wrote out Android package name "' + androidPkgName + '" to ' + newDestFile); // If package was name changed we need to remove old java with main activity - fs.removeSync(java_files[0]); + events.emit('verbose', `remove ${destFile}`); + fs.removeSync(destFile); // remove any empty directories - let currentDir = path.dirname(java_files[0]); + let currentDir = path.dirname(destFile); const sourcesRoot = path.resolve(locations.root, 'src'); while (currentDir !== sourcesRoot) { if (fs.existsSync(currentDir) && fs.readdirSync(currentDir).length === 0) { diff --git a/package-lock.json b/package-lock.json index f71c44e4..2293f61e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "devDependencies": { "@cordova/eslint-config": "^4.0.0", "cordova-js": "^6.1.0", + "elementtree": "^0.1.7", "jasmine": "^4.1.0", "jasmine-spec-reporter": "^7.0.0", "nyc": "^15.1.0", diff --git a/package.json b/package.json index 6d57f52b..03a543c2 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "devDependencies": { "@cordova/eslint-config": "^4.0.0", "cordova-js": "^6.1.0", + "elementtree": "^0.1.7", "jasmine": "^4.1.0", "jasmine-spec-reporter": "^7.0.0", "nyc": "^15.1.0", diff --git a/spec/unit/prepare.spec.js b/spec/unit/prepare.spec.js index 92f874f2..763a0ae9 100644 --- a/spec/unit/prepare.spec.js +++ b/spec/unit/prepare.spec.js @@ -21,6 +21,8 @@ const rewire = require('rewire'); const path = require('path'); const CordovaError = require('cordova-common').CordovaError; const GradlePropertiesParser = require('../../lib/config/GradlePropertiesParser'); +const utils = require('../../lib/utils'); +const et = require('elementtree'); const PATH_RESOURCE = path.join('platforms', 'android', 'app', 'src', 'main', 'res'); @@ -810,6 +812,155 @@ describe('prepare', () => { }); }); + describe('relocate CordovaActivity class java file', () => { + // Rewire + let Api; + let api; + let prepare; + + // Spies + let replaceFileContents; + let ensureDirSyncSpy; + let copySyncSpy; + let removeSyncSpy; + + // Mock Data + let cordovaProject; + let options; + let packageName; + + let initialJavaActivityPath; + + beforeEach(() => { + Api = rewire('../../lib/Api'); + prepare = rewire('../../lib/prepare'); + + cordovaProject = { + root: '/mock', + projectConfig: { + path: '/mock/config.xml', + cdvNamespacePrefix: 'cdv', + shortName: () => 'rn', + name: () => 'rename', + android_versionCode: jasmine.createSpy('android_versionCode'), + android_packageName: () => packageName, + packageName: () => packageName, + getPreference: jasmine.createSpy('getPreference'), + version: () => '1.0.0' + }, + locations: { + plugins: '/mock/plugins', + www: '/mock/www', + strings: '/mock/res/values/strings.xml' + } + }; + + api = new Api('android', cordovaProject.root); + initialJavaActivityPath = path.join(api.locations.javaSrc, 'com/company/product/MainActivity.java'); + + options = { + options: {} + }; + + Api.__set__('ConfigParser', + jasmine.createSpy('ConfigParser') + .and.returnValue(cordovaProject.projectConfig) + ); + + Api.__set__('prepare', prepare.prepare); + + prepare.__set__('updateWww', jasmine.createSpy('updateWww')); + prepare.__set__('updateIcons', jasmine.createSpy('updateIcons').and.returnValue(Promise.resolve())); + prepare.__set__('updateSplashes', jasmine.createSpy('updateSplashes').and.returnValue(Promise.resolve())); + prepare.__set__('updateFileResources', jasmine.createSpy('updateFileResources').and.returnValue(Promise.resolve())); + prepare.__set__('updateConfigFilesFrom', + jasmine.createSpy('updateConfigFilesFrom') + .and.returnValue(cordovaProject.projectConfig + )); + prepare.__set__('glob', { + sync: jasmine.createSpy('sync').and.returnValue({ + filter: jasmine.createSpy('filter').and.returnValue([ + initialJavaActivityPath + ]) + }) + }); + // prepare.__set__('events', { + // emit: function () { + // console.log(arguments); + // } + // }); + spyOn(GradlePropertiesParser.prototype, 'configure'); + + replaceFileContents = spyOn(utils, 'replaceFileContents'); + + prepare.__set__('AndroidManifest', jasmine.createSpy('AndroidManifest').and.returnValue({ + getPackageId: () => packageName, + getActivity: jasmine.createSpy('getActivity').and.returnValue({ + setOrientation: jasmine.createSpy('setOrientation').and.returnValue({ + setLaunchMode: jasmine.createSpy('setLaunchValue') + }) + }), + setVersionName: jasmine.createSpy('setVersionName').and.returnValue({ + setVersionCode: jasmine.createSpy('setVersionCode').and.returnValue({ + setPackageId: jasmine.createSpy('setPackageId').and.returnValue({ + write: jasmine.createSpy('write') + }) + }) + }) + })); + + prepare.__set__('xmlHelpers', { + parseElementtreeSync: jasmine.createSpy('parseElementtreeSync').and.returnValue(et.parse(` + + + __NAME__ + + @string/app_name + + @string/launcher_name + + `)) + }); + + ensureDirSyncSpy = jasmine.createSpy('ensureDirSync'); + copySyncSpy = jasmine.createSpy('copySync'); + removeSyncSpy = jasmine.createSpy('removeSync'); + + prepare.__set__('fs', { + writeFileSync: jasmine.createSpy('writeFileSync'), + writeJSONSync: jasmine.createSpy('writeJSONSync'), + ensureDirSync: ensureDirSyncSpy, + copySync: copySyncSpy, + removeSync: removeSyncSpy, + existsSync: jasmine.createSpy('existsSync') + }); + }); + + it('moves main activity class java file to path that tracks the package name when package name changed', async () => { + packageName = 'com.company.renamed'; + const renamedPath = path.join(api.locations.javaSrc, packageName.replace(/\./g, '/')); + const renamedJavaActivityPath = path.join(renamedPath, 'MainActivity.java'); + + await api.prepare(cordovaProject, options).then(() => { + expect(replaceFileContents).toHaveBeenCalledWith(renamedJavaActivityPath, /package [\w.]*;/, 'package ' + packageName + ';'); + expect(ensureDirSyncSpy).toHaveBeenCalledWith(renamedPath); + expect(copySyncSpy).toHaveBeenCalledWith(initialJavaActivityPath, renamedJavaActivityPath); + expect(removeSyncSpy).toHaveBeenCalledWith(initialJavaActivityPath); + }); + }); + + it('doesn\'t move main activity class java file when package name not changed', async () => { + packageName = 'com.company.product'; + + await api.prepare(cordovaProject, options).then(() => { + expect(replaceFileContents).toHaveBeenCalledTimes(0); + expect(ensureDirSyncSpy).toHaveBeenCalledTimes(0); + expect(copySyncSpy).toHaveBeenCalledTimes(0); + expect(removeSyncSpy).toHaveBeenCalledTimes(0); + }); + }); + }); + describe('updateSplashes method', function () { // Mock Data let cordovaProject;