Skip to content

Commit 181d564

Browse files
authored
feat(cli): allow to modify cleartext setting from capacitor.config.json (#2397)
1 parent 64286f8 commit 181d564

File tree

5 files changed

+91
-82
lines changed

5 files changed

+91
-82
lines changed

cli/src/android/update.ts

Lines changed: 3 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Config } from '../config';
2-
import { buildXmlElement, checkPlatformVersions, logFatal, logInfo, parseXML, resolveNode, runTask } from '../common';
2+
import { buildXmlElement, checkPlatformVersions, logFatal, resolveNode, runTask } from '../common';
33
import { getAndroidPlugins } from './common';
4-
import { checkAndInstallDependencies, handleCordovaPluginsJS } from '../cordova';
4+
import { checkAndInstallDependencies, handleCordovaPluginsJS, writeCordovaAndroidManifest } from '../cordova';
55
import { convertToUnixPath, copySync, readFileAsync, removeSync, writeFileAsync} from '../util/fs';
66
import { join, relative, resolve } from 'path';
77
import { Plugin, PluginType, getAllElements, getFilePath, getPlatformElement, getPluginPlatform, getPluginType, getPlugins, printPlugins } from '../plugin';
@@ -32,7 +32,7 @@ export async function updateAndroid(config: Config) {
3232
await handleCordovaPluginsJS(cordovaPlugins, config, platform);
3333
await installGradlePlugins(config, capacitorPlugins, cordovaPlugins);
3434
await handleCordovaPluginsGradle(config, cordovaPlugins);
35-
await writeCordovaAndroidManifest(cordovaPlugins, config);
35+
await writeCordovaAndroidManifest(cordovaPlugins, config, platform);
3636

3737
const incompatibleCordovaPlugins = plugins
3838
.filter(p => getPluginType(p, platform) === PluginType.Incompatible);
@@ -201,75 +201,3 @@ async function getPluginsTask(config: Config) {
201201
return androidPlugins;
202202
});
203203
}
204-
205-
async function writeCordovaAndroidManifest(cordovaPlugins: Plugin[], config: Config) {
206-
const pluginsFolder = resolve(config.app.rootDir, 'android', config.android.assets.pluginsFolderName);
207-
const manifestPath = join(pluginsFolder, 'src', 'main', 'AndroidManifest.xml');
208-
let rootXMLEntries: Array<any> = [];
209-
let applicationXMLEntries: Array<any> = [];
210-
let applicationXMLAttributes: Array<any> = [];
211-
cordovaPlugins.map(async p => {
212-
const editConfig = getPlatformElement(p, platform, 'edit-config');
213-
const configFile = getPlatformElement(p, platform, 'config-file');
214-
editConfig.concat(configFile).map(async (configElement: any) => {
215-
if (configElement.$ && (configElement.$.target && configElement.$.target.includes('AndroidManifest.xml') || configElement.$.file && configElement.$.file.includes('AndroidManifest.xml'))) {
216-
const keys = Object.keys(configElement).filter(k => k !== '$');
217-
keys.map(k => {
218-
configElement[k].map((e: any) => {
219-
const xmlElement = buildXmlElement(e, k);
220-
const pathParts = getPathParts(configElement.$.parent || configElement.$.target);
221-
if (pathParts.length > 1) {
222-
if (pathParts.pop() === 'application') {
223-
if (configElement.$.mode && configElement.$.mode === 'merge') {
224-
Object.keys(e.$).map((ek: any) => {
225-
applicationXMLAttributes.push(`${ek}="${e.$[ek]}"`);
226-
});
227-
} else if (!applicationXMLEntries.includes(xmlElement) && !contains(applicationXMLEntries, xmlElement, k)) {
228-
applicationXMLEntries.push(xmlElement);
229-
}
230-
} else {
231-
logInfo(`plugin ${p.id} requires to add \n ${xmlElement} to your AndroidManifest.xml to work`);
232-
}
233-
} else {
234-
if (!rootXMLEntries.includes(xmlElement) && !contains(rootXMLEntries, xmlElement, k)) {
235-
rootXMLEntries.push(xmlElement);
236-
}
237-
}
238-
});
239-
});
240-
}
241-
});
242-
});
243-
let content = `<?xml version='1.0' encoding='utf-8'?>
244-
<manifest package="capacitor.android.plugins"
245-
xmlns:android="http://schemas.android.com/apk/res/android"
246-
xmlns:amazon="http://schemas.amazon.com/apk/res/android">
247-
<application ${applicationXMLAttributes.join('\n')}>
248-
${applicationXMLEntries.join('\n')}
249-
</application>
250-
${rootXMLEntries.join('\n')}
251-
</manifest>`;
252-
content = content.replace(new RegExp(('$PACKAGE_NAME').replace('$', '\\$&'), 'g'), config.app.appId);
253-
await writeFileAsync(manifestPath, content);
254-
}
255-
256-
function getPathParts(path: string) {
257-
const rootPath = 'manifest';
258-
path = path.replace('/*', rootPath);
259-
let parts = path.split('/').filter(part => part !== '');
260-
if (parts.length > 1 || parts.includes(rootPath)) {
261-
return parts;
262-
}
263-
return [rootPath, path];
264-
}
265-
266-
function contains(a: Array<any>, obj: any, k: string) {
267-
const element = parseXML(obj);
268-
for (var i = 0; i < a.length; i++) {
269-
const current = parseXML(a[i]);
270-
if (element && current && current[k] && element[k] && current[k].$ && element[k].$ && element[k].$['android:name'] === current[k].$['android:name']) {
271-
return true;
272-
}
273-
}
274-
return false;
275-
}

cli/src/config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,9 @@ export class Config implements CliConfig {
9090
templateName: 'app-template',
9191
templateDir: '',
9292
pluginsTemplateDir: ''
93+
},
94+
server: {
95+
cleartext: false
9396
}
9497
};
9598

cli/src/cordova.ts

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Config } from './config';
22
import { Plugin, PluginType, getJSModules, getPlatformElement, getPluginPlatform, getPluginType, getPlugins, printPlugins } from './plugin';
33
import { copySync, ensureDirSync, readFileAsync, removeSync, writeFileAsync } from './util/fs';
44
import { basename, extname, join, resolve } from 'path';
5-
import { buildXmlElement, installDeps, log, logError, logFatal, logInfo, logWarn, readXML, resolveNode, writeXML } from './common';
5+
import { buildXmlElement, installDeps, log, logError, logFatal, logInfo, logWarn, parseXML, readXML, resolveNode, writeXML } from './common';
66
import { copy as fsCopy, existsSync } from 'fs-extra';
77
import { getAndroidPlugins } from './android/common';
88
import { getIOSPlugins } from './ios/common';
@@ -214,17 +214,16 @@ export async function handleCordovaPluginsJS(cordovaPlugins: Plugin[], config: C
214214
await autoGenerateConfig(config, cordovaPlugins, platform);
215215
}
216216

217-
export async function copyCordovaJSFiles(config: Config, platform: string) {
217+
export async function getCordovaPlugins(config: Config, platform: string): Promise<Plugin[]> {
218218
const allPlugins = await getPlugins(config);
219219
let plugins: Plugin[] = [];
220220
if (platform === config.ios.name) {
221221
plugins = getIOSPlugins(allPlugins);
222222
} else if (platform === config.android.name) {
223223
plugins = getAndroidPlugins(allPlugins);
224224
}
225-
const cordovaPlugins = plugins
225+
return plugins
226226
.filter(p => getPluginType(p, platform) === PluginType.Cordova);
227-
await handleCordovaPluginsJS(cordovaPlugins, config, platform);
228227
}
229228

230229
export async function logCordovaManualSteps(cordovaPlugins: Plugin[], config: Config, platform: string) {
@@ -365,3 +364,76 @@ export async function getCordovaPreferences(config: Config) {
365364
}
366365
return cordova;
367366
}
367+
368+
export async function writeCordovaAndroidManifest(cordovaPlugins: Plugin[], config: Config, platform: string) {
369+
const pluginsFolder = resolve(config.app.rootDir, 'android', config.android.assets.pluginsFolderName);
370+
const manifestPath = join(pluginsFolder, 'src', 'main', 'AndroidManifest.xml');
371+
let rootXMLEntries: Array<any> = [];
372+
let applicationXMLEntries: Array<any> = [];
373+
let applicationXMLAttributes: Array<any> = [];
374+
cordovaPlugins.map(async p => {
375+
const editConfig = getPlatformElement(p, platform, 'edit-config');
376+
const configFile = getPlatformElement(p, platform, 'config-file');
377+
editConfig.concat(configFile).map(async (configElement: any) => {
378+
if (configElement.$ && (configElement.$.target && configElement.$.target.includes('AndroidManifest.xml') || configElement.$.file && configElement.$.file.includes('AndroidManifest.xml'))) {
379+
const keys = Object.keys(configElement).filter(k => k !== '$');
380+
keys.map(k => {
381+
configElement[k].map((e: any) => {
382+
const xmlElement = buildXmlElement(e, k);
383+
const pathParts = getPathParts(configElement.$.parent || configElement.$.target);
384+
if (pathParts.length > 1) {
385+
if (pathParts.pop() === 'application') {
386+
if (configElement.$.mode && configElement.$.mode === 'merge') {
387+
Object.keys(e.$).map((ek: any) => {
388+
applicationXMLAttributes.push(`${ek}="${e.$[ek]}"`);
389+
});
390+
} else if (!applicationXMLEntries.includes(xmlElement) && !contains(applicationXMLEntries, xmlElement, k)) {
391+
applicationXMLEntries.push(xmlElement);
392+
}
393+
} else {
394+
logInfo(`plugin ${p.id} requires to add \n ${xmlElement} to your AndroidManifest.xml to work`);
395+
}
396+
} else {
397+
if (!rootXMLEntries.includes(xmlElement) && !contains(rootXMLEntries, xmlElement, k)) {
398+
rootXMLEntries.push(xmlElement);
399+
}
400+
}
401+
});
402+
});
403+
}
404+
});
405+
});
406+
let cleartext = config.app.extConfig.server?.cleartext ? 'android:usesCleartextTraffic="true"' : '';
407+
let content = `<?xml version='1.0' encoding='utf-8'?>
408+
<manifest package="capacitor.android.plugins"
409+
xmlns:android="http://schemas.android.com/apk/res/android"
410+
xmlns:amazon="http://schemas.amazon.com/apk/res/android">
411+
<application ${applicationXMLAttributes.join('\n')}${cleartext}>
412+
${applicationXMLEntries.join('\n')}
413+
</application>
414+
${rootXMLEntries.join('\n')}
415+
</manifest>`;
416+
content = content.replace(new RegExp(('$PACKAGE_NAME').replace('$', '\\$&'), 'g'), config.app.appId);
417+
await writeFileAsync(manifestPath, content);
418+
}
419+
420+
function getPathParts(path: string) {
421+
const rootPath = 'manifest';
422+
path = path.replace('/*', rootPath);
423+
let parts = path.split('/').filter(part => part !== '');
424+
if (parts.length > 1 || parts.includes(rootPath)) {
425+
return parts;
426+
}
427+
return [rootPath, path];
428+
}
429+
430+
function contains(a: Array<any>, obj: any, k: string) {
431+
const element = parseXML(obj);
432+
for (var i = 0; i < a.length; i++) {
433+
const current = parseXML(a[i]);
434+
if (element && current && current[k] && element[k] && current[k].$ && element[k].$ && element[k].$['android:name'] === current[k].$['android:name']) {
435+
return true;
436+
}
437+
}
438+
return false;
439+
}

cli/src/definitions.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ export interface ExternalConfig {
2424
};
2525
npmClient?: string;
2626
cordova?: any;
27+
server?: {
28+
cleartext?: boolean;
29+
}
2730
}
2831

2932
export interface AppPluginsConfig {

cli/src/tasks/copy.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { copyWeb } from '../web/copy';
66
import { copyElectron } from '../electron/copy';
77
import { basename, join, relative, resolve } from 'path';
88
import { copy as fsCopy, remove } from 'fs-extra';
9-
import { copyCordovaJSFiles } from '../cordova';
9+
import { getCordovaPlugins, handleCordovaPluginsJS, writeCordovaAndroidManifest } from '../cordova';
1010
import chalk from 'chalk';
1111

1212
export async function copyCommand(config: Config, selectedPlatformName: string) {
@@ -34,12 +34,15 @@ export async function copy(config: Config, platformName: string) {
3434
await copyWebDir(config, config.ios.webDirAbs);
3535
await copyNativeBridge(config, config.ios.webDirAbs);
3636
await copyCapacitorConfig(config, join(config.ios.platformDir, config.ios.nativeProjectName, config.ios.nativeProjectName));
37-
await copyCordovaJSFiles(config, platformName);
37+
const cordovaPlugins = await getCordovaPlugins(config, platformName);
38+
await handleCordovaPluginsJS(cordovaPlugins, config, platformName);
3839
} else if (platformName === config.android.name) {
3940
await copyWebDir(config, config.android.webDirAbs);
4041
await copyNativeBridge(config, config.android.webDirAbs);
4142
await copyCapacitorConfig(config, join(config.android.platformDir, 'app/src/main/assets'));
42-
await copyCordovaJSFiles(config, platformName);
43+
const cordovaPlugins = await getCordovaPlugins(config, platformName);
44+
await handleCordovaPluginsJS(cordovaPlugins, config, platformName);
45+
await writeCordovaAndroidManifest(cordovaPlugins, config, platformName);
4346
} else if (platformName === config.web.name) {
4447
await copyWeb(config);
4548
} else if (platformName === config.electron.name) {

0 commit comments

Comments
 (0)