mirror of
https://github.com/apache/cordova-android.git
synced 2026-01-30 00:05:28 +08:00
feat!: android 12 splash screen (#1441)
* chore!: remove old splashscreen logic * feat(splashscreen): add backwards compatibility * chore: remove unused method * chore: prefix splashscreen_background with cdv_ * feat: support android 12 splashscreen api configs * feat: improve & refactor the logic for android splashscreen api 12 * feat: splashscreen copy image resources * feat: splashscreen branding image & xml cleanup * fix: splashscreen cleanup & branding conditions * fix: splashscreen @color usage * feat: update default Apache Cordova splash screen * chore: add missing asf header * fix: splashscreen image size * chore: use Theme.SplashScreen.IconBackground as default parent to support windowSplashScreenIconBackgroundColor * fix: center default test image by correct pivot * fix: fs-extra copySync * feat: re-add AutoHideSplashScreen and SplashScreenDelay preference support * chore: move splashscreen into CordovaActivity * feat: support splashscreen.hide & centralize to SplashScreenPlugin * chore: cleanup SplashScreenPlugin * feat: support fade, default auto hide on onPageFinished, support delays, refactor * refactor: cleanup splash screen * refactor: cleanup remove unused import * chore: add show method as unsupported * test: create a spy on updateProjectSplashScreen * style: add ending new line * chore: improve logging to warn when image path is missing * chore: split windowSplashScreenAnimatedIcon and windowSplashScreenBrandingImage case and added branding warning * chore: improve when to display warning * fix: add splashscreen dependency to app as well * chore: move the core-splashscreen dep lower Co-authored-by: Niklas Merz <niklasmerz@linux.com>
This commit is contained in:
@@ -73,6 +73,8 @@ class Api {
|
||||
configXml: path.join(appRes, 'xml', 'config.xml'),
|
||||
defaultConfigXml: path.join(this.root, 'cordova', 'defaults.xml'),
|
||||
strings: path.join(appRes, 'values', 'strings.xml'),
|
||||
themes: path.join(appRes, 'values', 'themes.xml'),
|
||||
colors: path.join(appRes, 'values', 'colors.xml'),
|
||||
manifest: path.join(appMain, 'AndroidManifest.xml'),
|
||||
build: path.join(this.root, 'build'),
|
||||
javaSrc: path.join(appMain, 'java')
|
||||
|
||||
364
lib/prepare.js
364
lib/prepare.js
@@ -62,16 +62,14 @@ module.exports.prepare = function (cordovaProject, options) {
|
||||
updateUserProjectGradlePropertiesConfig(this, args);
|
||||
|
||||
// Update own www dir with project's www assets and plugins' assets and js-files
|
||||
return Promise.resolve(updateWww(cordovaProject, this.locations)).then(function () {
|
||||
// update project according to config.xml changes.
|
||||
return updateProjectAccordingTo(self._config, self.locations);
|
||||
}).then(function () {
|
||||
updateIcons(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
|
||||
updateSplashes(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
|
||||
updateFileResources(cordovaProject, path.relative(cordovaProject.root, self.locations.root));
|
||||
}).then(function () {
|
||||
events.emit('verbose', 'Prepared android project successfully');
|
||||
});
|
||||
return Promise.resolve(updateWww(cordovaProject, this.locations))
|
||||
.then(() => updateProjectAccordingTo(self._config, self.locations))
|
||||
.then(function () {
|
||||
updateIcons(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
|
||||
updateFileResources(cordovaProject, path.relative(cordovaProject.root, self.locations.root));
|
||||
}).then(function () {
|
||||
events.emit('verbose', 'Prepared android project successfully');
|
||||
});
|
||||
};
|
||||
|
||||
/** @param {PlatformApi} project */
|
||||
@@ -171,7 +169,6 @@ module.exports.clean = function (options) {
|
||||
return Promise.resolve().then(function () {
|
||||
cleanWww(projectRoot, self.locations);
|
||||
cleanIcons(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res));
|
||||
cleanSplashes(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res));
|
||||
cleanFileResources(projectRoot, projectConfig, path.relative(projectRoot, self.locations.root));
|
||||
});
|
||||
};
|
||||
@@ -267,19 +264,10 @@ function cleanWww (projectRoot, locations) {
|
||||
* @param {Object} locations A map of locations for this platform
|
||||
*/
|
||||
function updateProjectAccordingTo (platformConfig, locations) {
|
||||
// Update app name by editing res/values/strings.xml
|
||||
const strings = xmlHelpers.parseElementtreeSync(locations.strings);
|
||||
updateProjectStrings(platformConfig, locations);
|
||||
updateProjectSplashScreen(platformConfig, locations);
|
||||
|
||||
const name = platformConfig.name();
|
||||
strings.find('string[@name="app_name"]').text = name.replace(/'/g, '\\\'');
|
||||
|
||||
const shortName = platformConfig.shortName && platformConfig.shortName();
|
||||
if (shortName && shortName !== name) {
|
||||
strings.find('string[@name="launcher_name"]').text = shortName.replace(/'/g, '\\\'');
|
||||
}
|
||||
|
||||
fs.writeFileSync(locations.strings, strings.write({ indent: 4 }), 'utf-8');
|
||||
events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
|
||||
|
||||
// Update app name for gradle project
|
||||
fs.writeFileSync(path.join(locations.root, 'cdv-gradle-name.gradle'),
|
||||
@@ -342,6 +330,262 @@ function updateProjectAccordingTo (platformConfig, locations) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates project structure and AndroidManifest according to project's configuration.
|
||||
*
|
||||
* @param {ConfigParser} platformConfig A project's configuration that will
|
||||
* be used to update project
|
||||
* @param {Object} locations A map of locations for this platform
|
||||
*/
|
||||
function updateProjectStrings (platformConfig, locations) {
|
||||
// Update app name by editing res/values/strings.xml
|
||||
const strings = xmlHelpers.parseElementtreeSync(locations.strings);
|
||||
|
||||
const name = platformConfig.name();
|
||||
strings.find('string[@name="app_name"]').text = name.replace(/'/g, '\\\'');
|
||||
|
||||
const shortName = platformConfig.shortName && platformConfig.shortName();
|
||||
if (shortName && shortName !== name) {
|
||||
strings.find('string[@name="launcher_name"]').text = shortName.replace(/'/g, '\\\'');
|
||||
}
|
||||
|
||||
fs.writeFileSync(locations.strings, strings.write({ indent: 4 }), 'utf-8');
|
||||
events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ConfigParser} platformConfig A project's configuration that will
|
||||
* be used to update project
|
||||
* @param {Object} locations A map of locations for this platform
|
||||
*/
|
||||
function updateProjectSplashScreen (platformConfig, locations) {
|
||||
// res/values/themes.xml
|
||||
const themes = xmlHelpers.parseElementtreeSync(locations.themes);
|
||||
const splashScreenTheme = themes.find('style[@name="Theme.App.SplashScreen"]');
|
||||
|
||||
[
|
||||
'windowSplashScreenAnimatedIcon',
|
||||
'windowSplashScreenAnimationDuration',
|
||||
'windowSplashScreenBackground',
|
||||
'windowSplashScreenBrandingImage',
|
||||
'windowSplashScreenIconBackgroundColor',
|
||||
'postSplashScreenTheme'
|
||||
].forEach(themeKey => {
|
||||
const cdvConfigPrefKey = 'Android' + themeKey.charAt(0).toUpperCase() + themeKey.slice(1);
|
||||
const cdvConfigPrefValue = platformConfig.getPreference(cdvConfigPrefKey, this.platform);
|
||||
let themeTargetNode = splashScreenTheme.find(`item[@name="${themeKey}"]`);
|
||||
|
||||
switch (themeKey) {
|
||||
case 'windowSplashScreenBackground':
|
||||
// use the user defined value for "colors.xml"
|
||||
updateProjectSplashScreenBackgroundColor(cdvConfigPrefValue, locations);
|
||||
|
||||
// force the themes value to `@color/cdv_splashscreen_background`
|
||||
themeTargetNode.text = '@color/cdv_splashscreen_background';
|
||||
break;
|
||||
|
||||
case 'windowSplashScreenAnimatedIcon':
|
||||
// handle here the cases of "png" vs "xml" (drawable)
|
||||
// If "png":
|
||||
// - Clear out default or previous set "drawable/ic_cdv_splashscreen.xml" if exisiting.
|
||||
// - Copy png in correct mipmap dir with name "ic_cdv_splashscreen.png"
|
||||
// If "xml":
|
||||
// - Clear out "{mipmap}/ic_cdv_splashscreen.png" if exisiting.
|
||||
// - Copy xml into drawable dir with name "ic_cdv_splashscreen.xml"
|
||||
|
||||
// updateProjectSplashScreenIcon()
|
||||
// value should change depending on case:
|
||||
// If "png": "@mipmap/ic_cdv_splashscreen"
|
||||
// If "xml": "@drawable/ic_cdv_splashscreen"
|
||||
updateProjectSplashScreenImage(locations, themeKey, cdvConfigPrefKey, cdvConfigPrefValue);
|
||||
break;
|
||||
|
||||
case 'windowSplashScreenBrandingImage':
|
||||
// display warning only when set.
|
||||
if (cdvConfigPrefValue) {
|
||||
events.emit('warn', `"${themeKey}" is currently not supported by the splash screen compatibility library. https://issuetracker.google.com/issues/194301890`);
|
||||
}
|
||||
|
||||
updateProjectSplashScreenImage(locations, themeKey, cdvConfigPrefKey, cdvConfigPrefValue);
|
||||
|
||||
// force the themes value to `@color/cdv_splashscreen_icon_background`
|
||||
if (!cdvConfigPrefValue && themeTargetNode) {
|
||||
splashScreenTheme.remove(themeTargetNode);
|
||||
} else if (cdvConfigPrefValue) {
|
||||
// if there is no current node, create a new node.
|
||||
if (!themeTargetNode) {
|
||||
themeTargetNode = themes.getroot().makeelement('item', { name: themeKey });
|
||||
splashScreenTheme.append(themeTargetNode);
|
||||
}
|
||||
|
||||
// set the user defined color.
|
||||
themeTargetNode.text = '@drawable/ic_cdv_splashscreen_branding';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'windowSplashScreenIconBackgroundColor':
|
||||
// use the user defined value for "colors.xml"
|
||||
updateProjectSplashScreenIconBackgroundColor(cdvConfigPrefValue, locations);
|
||||
|
||||
// force the themes value to `@color/cdv_splashscreen_icon_background`
|
||||
if (!cdvConfigPrefValue && themeTargetNode) {
|
||||
// currentItem.remove();
|
||||
splashScreenTheme.remove(themeTargetNode);
|
||||
} else if (cdvConfigPrefValue) {
|
||||
// if there is no current color, create a new node.
|
||||
if (!themeTargetNode) {
|
||||
themeTargetNode = themes.getroot().makeelement('item', { name: themeKey });
|
||||
splashScreenTheme.append(themeTargetNode);
|
||||
}
|
||||
|
||||
// set the user defined color.
|
||||
themeTargetNode.text = '@color/cdv_splashscreen_icon_background';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'windowSplashScreenAnimationDuration':
|
||||
themeTargetNode.text = cdvConfigPrefValue || '200';
|
||||
break;
|
||||
|
||||
case 'postSplashScreenTheme':
|
||||
themeTargetNode.text = cdvConfigPrefValue || '@style/Theme.AppCompat.NoActionBar';
|
||||
break;
|
||||
|
||||
default:
|
||||
events.emit('warn', `The theme property "${themeKey}" does not exist`);
|
||||
}
|
||||
});
|
||||
|
||||
fs.writeFileSync(locations.themes, themes.write({ indent: 4 }), 'utf-8');
|
||||
events.emit('verbose', 'Wrote out Android application themes to ' + locations.themes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} splashBackgroundColor SplashScreen Background Color Hex Code
|
||||
* be used to update project
|
||||
* @param {Object} locations A map of locations for this platform
|
||||
*/
|
||||
function updateProjectSplashScreenBackgroundColor (splashBackgroundColor, locations) {
|
||||
if (!splashBackgroundColor) { splashBackgroundColor = '#FFFFFF'; }
|
||||
|
||||
// res/values/colors.xml
|
||||
const colors = xmlHelpers.parseElementtreeSync(locations.colors);
|
||||
colors.find('color[@name="cdv_splashscreen_background"]').text = splashBackgroundColor.replace(/'/g, '\\\'');
|
||||
|
||||
fs.writeFileSync(locations.colors, colors.write({ indent: 4 }), 'utf-8');
|
||||
events.emit('verbose', 'Wrote out Android application SplashScreen Color to ' + locations.colors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} splashIconBackgroundColor SplashScreen Icon Background Color Hex Code
|
||||
* be used to update project
|
||||
* @param {Object} locations A map of locations for this platform
|
||||
*/
|
||||
function updateProjectSplashScreenIconBackgroundColor (splashIconBackgroundColor, locations) {
|
||||
// res/values/colors.xml
|
||||
const colors = xmlHelpers.parseElementtreeSync(locations.colors);
|
||||
// node name
|
||||
const name = 'cdv_splashscreen_icon_background';
|
||||
|
||||
// get the current defined color
|
||||
let currentColor = colors.find(`color[@name="${name}"]`);
|
||||
|
||||
if (!splashIconBackgroundColor && currentColor) {
|
||||
colors.getroot().remove(currentColor);
|
||||
} else if (splashIconBackgroundColor) {
|
||||
// if there is no current color, create a new node.
|
||||
if (!currentColor) {
|
||||
currentColor = colors.getroot().makeelement('color', { name });
|
||||
colors.getroot().append(currentColor);
|
||||
}
|
||||
|
||||
// set the user defined color.
|
||||
currentColor.text = splashIconBackgroundColor.replace(/'/g, '\\\'');
|
||||
}
|
||||
|
||||
// write out the changes.
|
||||
fs.writeFileSync(locations.colors, colors.write({ indent: 4 }), 'utf-8');
|
||||
events.emit('verbose', 'Wrote out Android application SplashScreen Icon Color to ' + locations.colors);
|
||||
}
|
||||
|
||||
function cleanupAndSetProjectSplashScreenImage (srcFile, destFilePath, possiblePreviousDestFilePath, cleanupOnly = false) {
|
||||
if (fs.existsSync(possiblePreviousDestFilePath)) {
|
||||
fs.removeSync(possiblePreviousDestFilePath);
|
||||
}
|
||||
|
||||
if (cleanupOnly && fs.existsSync(destFilePath)) {
|
||||
// Also remove dest file path for cleanup even if previous was not use.
|
||||
fs.removeSync(destFilePath);
|
||||
}
|
||||
|
||||
if (!cleanupOnly && srcFile && fs.existsSync(srcFile)) {
|
||||
fs.copySync(srcFile, destFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
function updateProjectSplashScreenImage (locations, themeKey, cdvConfigPrefKey, cdvConfigPrefValue = '') {
|
||||
const SPLASH_SCREEN_IMAGE_BY_THEME_KEY = {
|
||||
windowSplashScreenAnimatedIcon: 'ic_cdv_splashscreen',
|
||||
windowSplashScreenBrandingImage: 'ic_cdv_splashscreen_branding'
|
||||
};
|
||||
|
||||
const destFileName = SPLASH_SCREEN_IMAGE_BY_THEME_KEY[themeKey] || null;
|
||||
if (!destFileName) throw new CordovaError(`${themeKey} is not valid for image detection.`);
|
||||
|
||||
// Default paths of where images are saved
|
||||
const destPngDir = path.join(locations.res, 'drawable-nodpi');
|
||||
const destXmlDir = path.join(locations.res, 'drawable');
|
||||
|
||||
// Dest File Name and Path
|
||||
const destFileNameExt = destFileName + '.xml';
|
||||
let destFilePath = path.join(destXmlDir, destFileNameExt);
|
||||
let possiblePreviousDestFilePath = path.join(destPngDir, destFileName + '.png');
|
||||
|
||||
// Default Drawable Source File
|
||||
const defaultSrcFilePath = themeKey !== 'windowSplashScreenBrandingImage'
|
||||
? require.resolve('cordova-android/templates/project/res/drawable/' + destFileNameExt)
|
||||
: null;
|
||||
|
||||
if (!cdvConfigPrefValue || !fs.existsSync(cdvConfigPrefValue)) {
|
||||
let emitType = 'verbose';
|
||||
let emmitMessage = `The "${cdvConfigPrefKey}" is undefined. Cordova's default will be used.`;
|
||||
|
||||
if (cdvConfigPrefValue && !fs.existsSync(cdvConfigPrefValue)) {
|
||||
emitType = 'warn';
|
||||
emmitMessage = `The "${cdvConfigPrefKey}" value does not exist. Cordova's default will be used.`;
|
||||
}
|
||||
|
||||
events.emit(emitType, emmitMessage);
|
||||
const cleanupOnly = themeKey === 'windowSplashScreenBrandingImage';
|
||||
cleanupAndSetProjectSplashScreenImage(defaultSrcFilePath, destFilePath, possiblePreviousDestFilePath, cleanupOnly);
|
||||
return;
|
||||
}
|
||||
|
||||
const iconExtension = path.extname(cdvConfigPrefValue).toLowerCase();
|
||||
|
||||
if (iconExtension === '.png') {
|
||||
// Put the image at this location.
|
||||
destFilePath = path.join(destPngDir, destFileName + '.png');
|
||||
|
||||
// Check for this file and remove.
|
||||
possiblePreviousDestFilePath = path.join(destXmlDir, destFileName + '.xml');
|
||||
|
||||
// copy the png to correct mipmap folder with name of ic_cdv_splashscreen.png
|
||||
// delete ic_cdv_splashscreen.xml from drawable folder
|
||||
// update themes.xml windowSplashScreenAnimatedIcon value to @mipmap/ic_cdv_splashscreen
|
||||
cleanupAndSetProjectSplashScreenImage(cdvConfigPrefValue, destFilePath, possiblePreviousDestFilePath);
|
||||
} else if (iconExtension === '.xml') {
|
||||
// copy the xml to drawable folder with name of ic_cdv_splashscreen.xml
|
||||
// delete ic_cdv_splashscreen.png from mipmap folder
|
||||
// update themes.xml windowSplashScreenAnimatedIcon value to @drawable/ic_cdv_splashscreen
|
||||
cleanupAndSetProjectSplashScreenImage(cdvConfigPrefValue, destFilePath, possiblePreviousDestFilePath);
|
||||
} else {
|
||||
// use the default destFilePath & possiblePreviousDestFilePath, no update require.
|
||||
events.emit('warn', `The "${cdvConfigPrefKey}" had an unsupported extension. Cordova's default will be used.`);
|
||||
cleanupAndSetProjectSplashScreenImage(defaultSrcFilePath, destFilePath, possiblePreviousDestFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
// Consturct the default value for versionCode as
|
||||
// PATCH + MINOR * 100 + MAJOR * 10000
|
||||
// see http://developer.android.com/tools/publishing/versioning.html
|
||||
@@ -380,68 +624,6 @@ function getAdaptiveImageResourcePath (resourcesDir, type, density, name, source
|
||||
return resourcePath;
|
||||
}
|
||||
|
||||
function makeSplashCleanupMap (projectRoot, resourcesDir) {
|
||||
// Build an initial resource map that deletes all existing splash screens
|
||||
const existingSplashPaths = glob.sync(
|
||||
`${resourcesDir.replace(/\\/g, '/')}/drawable-*/screen.{png,9.png,webp,jpg,jpeg}`,
|
||||
{ cwd: projectRoot }
|
||||
);
|
||||
return makeCleanResourceMap(existingSplashPaths);
|
||||
}
|
||||
|
||||
function updateSplashes (cordovaProject, platformResourcesDir) {
|
||||
const resources = cordovaProject.projectConfig.getSplashScreens('android');
|
||||
|
||||
// if there are no "splash" elements in config.xml
|
||||
if (resources.length === 0) {
|
||||
events.emit('verbose', 'This app does not have splash screens defined');
|
||||
// We must not return here!
|
||||
// If the user defines no splash screens, the cleanup map will cause any
|
||||
// existing splash screen images (e.g. the defaults that we copy into a
|
||||
// new app) to be removed from the app folder, which is what we want.
|
||||
}
|
||||
|
||||
// Build an initial resource map that deletes all existing splash screens
|
||||
const resourceMap = makeSplashCleanupMap(cordovaProject.root, platformResourcesDir);
|
||||
|
||||
let hadMdpi = false;
|
||||
resources.forEach(function (resource) {
|
||||
if (!resource.density) {
|
||||
return;
|
||||
}
|
||||
if (resource.density === 'mdpi') {
|
||||
hadMdpi = true;
|
||||
}
|
||||
const targetPath = getImageResourcePath(
|
||||
platformResourcesDir, 'drawable', resource.density, 'screen', path.basename(resource.src));
|
||||
resourceMap[targetPath] = resource.src;
|
||||
});
|
||||
|
||||
// There's no "default" drawable, so assume default == mdpi.
|
||||
if (!hadMdpi && resources.defaultResource) {
|
||||
const targetPath = getImageResourcePath(
|
||||
platformResourcesDir, 'drawable', 'mdpi', 'screen', path.basename(resources.defaultResource.src));
|
||||
resourceMap[targetPath] = resources.defaultResource.src;
|
||||
}
|
||||
|
||||
events.emit('verbose', 'Updating splash screens at ' + platformResourcesDir);
|
||||
FileUpdater.updatePaths(
|
||||
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
|
||||
}
|
||||
|
||||
function cleanSplashes (projectRoot, projectConfig, platformResourcesDir) {
|
||||
const resources = projectConfig.getSplashScreens('android');
|
||||
if (resources.length > 0) {
|
||||
const resourceMap = makeSplashCleanupMap(projectRoot, platformResourcesDir);
|
||||
|
||||
events.emit('verbose', 'Cleaning splash screens at ' + platformResourcesDir);
|
||||
|
||||
// No source paths are specified in the map, so updatePaths() will delete the target files.
|
||||
FileUpdater.updatePaths(
|
||||
resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
|
||||
}
|
||||
}
|
||||
|
||||
function updateIcons (cordovaProject, platformResourcesDir) {
|
||||
const icons = cordovaProject.projectConfig.getIcons('android');
|
||||
|
||||
@@ -521,7 +703,7 @@ function updateIconResourceForAdaptive (preparedIcons, resourceMap, platformReso
|
||||
const android_icons = preparedIcons.android_icons;
|
||||
const default_icon = preparedIcons.default_icon;
|
||||
|
||||
// The source paths for icons and splashes are relative to
|
||||
// The source paths for icons are relative to
|
||||
// project's config.xml location, so we use it as base path.
|
||||
let background;
|
||||
let foreground;
|
||||
@@ -620,7 +802,7 @@ function updateIconResourceForLegacy (preparedIcons, resourceMap, platformResour
|
||||
const android_icons = preparedIcons.android_icons;
|
||||
const default_icon = preparedIcons.default_icon;
|
||||
|
||||
// The source paths for icons and splashes are relative to
|
||||
// The source paths for icons are relative to
|
||||
// project's config.xml location, so we use it as base path.
|
||||
for (const density in android_icons) {
|
||||
const targetPath = getImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher', path.basename(android_icons[density].src));
|
||||
@@ -750,16 +932,6 @@ function mapImageResources (rootDir, subDir, type, resourceName) {
|
||||
return pathMap;
|
||||
}
|
||||
|
||||
/** Returns resource map that deletes all given paths */
|
||||
function makeCleanResourceMap (resourcePaths) {
|
||||
const pathMap = {};
|
||||
resourcePaths.map(path.normalize)
|
||||
.forEach(resourcePath => {
|
||||
pathMap[resourcePath] = null;
|
||||
});
|
||||
return pathMap;
|
||||
}
|
||||
|
||||
function updateFileResources (cordovaProject, platformDir) {
|
||||
const files = cordovaProject.projectConfig.getFileResources('android');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user