@capacitor/cli 4.0.0-nightly-c3aa3d6c.0 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,39 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [4.0.1](https://github.com/ionic-team/capacitor/compare/4.0.0...4.0.1) (2022-07-28)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **cli:** Correct Splash theme update ([#5805](https://github.com/ionic-team/capacitor/issues/5805)) ([25b82a8](https://github.com/ionic-team/capacitor/commit/25b82a84425bf09b2be45b213788b0e13982b9b3))
12
+ * **cli:** Revert some splash migration errors ([#5806](https://github.com/ionic-team/capacitor/issues/5806)) ([471feed](https://github.com/ionic-team/capacitor/commit/471feedc07bef357ac798fcba664bd373e9f8ebf))
13
+
14
+
15
+
16
+
17
+
18
+ # [4.0.0](https://github.com/ionic-team/capacitor/compare/4.0.0-beta.2...4.0.0) (2022-07-27)
19
+
20
+
21
+ ### Features
22
+
23
+ * **android:** Add android.minWebviewVersion configuration option ([#5768](https://github.com/ionic-team/capacitor/issues/5768)) ([ad83827](https://github.com/ionic-team/capacitor/commit/ad838279e9cd190ce6f1a020a0ac9e3916786324))
24
+ * **cli:** add migrator for cap3 to cap4 ([#5762](https://github.com/ionic-team/capacitor/issues/5762)) ([7cb660a](https://github.com/ionic-team/capacitor/commit/7cb660a34d9a87274761d4492d0d77c9ef44ace8))
25
+ * Add option for custom error page ([#5723](https://github.com/ionic-team/capacitor/issues/5723)) ([e8bdef3](https://github.com/ionic-team/capacitor/commit/e8bdef3b4634e4ad45fa8fc34c7c0ab8dfa383f3))
26
+
27
+
28
+
29
+
30
+
31
+ # [4.0.0-beta.2](https://github.com/ionic-team/capacitor/compare/4.0.0-beta.1...4.0.0-beta.2) (2022-07-08)
32
+
33
+ **Note:** Version bump only for package @capacitor/cli
34
+
35
+
36
+
37
+
38
+
6
39
  # [4.0.0-beta.1](https://github.com/ionic-team/capacitor/compare/4.0.0-beta.0...4.0.0-beta.1) (2022-06-27)
7
40
 
8
41
  **Note:** Version bump only for package @capacitor/cli
Binary file
Binary file
@@ -169,8 +169,7 @@ async function handleCordovaPluginsGradle(config, cordovaPlugins) {
169
169
  var _a, _b, _c;
170
170
  const pluginsGradlePath = path_1.join(config.android.cordovaPluginsDirAbs, 'build.gradle');
171
171
  const kotlinNeeded = await kotlinNeededCheck(config, cordovaPlugins);
172
- const isKotlinVersionInVariablesGradle = (await getVariablesGradleFile(config)).includes('kotlin_version');
173
- const kotlinVersionString = (_c = (_b = (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.preferences) === null || _b === void 0 ? void 0 : _b.GradlePluginKotlinVersion) !== null && _c !== void 0 ? _c : '1.4.32';
172
+ const kotlinVersionString = (_c = (_b = (_a = config.app.extConfig.cordova) === null || _a === void 0 ? void 0 : _a.preferences) === null || _b === void 0 ? void 0 : _b.GradlePluginKotlinVersion) !== null && _c !== void 0 ? _c : '1.7.0';
174
173
  const frameworksArray = [];
175
174
  let prefsArray = [];
176
175
  const applyArray = [];
@@ -206,12 +205,9 @@ async function handleCordovaPluginsGradle(config, cordovaPlugins) {
206
205
  buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + frameworkString.concat('\n') + ' $2');
207
206
  buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + applyString.concat('\n') + '$2');
208
207
  if (kotlinNeeded) {
209
- buildGradle = buildGradle.replace(/(buildscript\s{\n(\t|\s{4})repositories\s{\n((\t{2}|\s{8}).+\n)+(\t|\s{4})}\n(\t|\s{4})dependencies\s{\n(\t{2}|\s{8}).+)\n((\t|\s{4})}\n}\n)/, `$1\n classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:` +
210
- (isKotlinVersionInVariablesGradle
211
- ? '$kotlin_version'
212
- : kotlinVersionString) +
213
- `"\n$8`);
214
- buildGradle = buildGradle.replace(/(ext\s{)/, `$1\n kotlin_version = project.hasProperty('kotlin_version') ? rootProject.ext.kotlin_version : '${kotlinVersionString}'\n androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.6.0'`);
208
+ buildGradle = buildGradle.replace(/(buildscript\s{\n(\t|\s{4})repositories\s{\n((\t{2}|\s{8}).+\n)+(\t|\s{4})}\n(\t|\s{4})dependencies\s{\n(\t{2}|\s{8}).+)\n((\t|\s{4})}\n}\n)/, `$1\n classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"\n$8`);
209
+ buildGradle = buildGradle.replace(/(ext\s{)/, `$1\n androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.8.0'`);
210
+ buildGradle = buildGradle.replace(/(buildscript\s{)/, `$1\n ext.kotlin_version = project.hasProperty('kotlin_version') ? rootProject.ext.kotlin_version : '${kotlinVersionString}'`);
215
211
  buildGradle = buildGradle.replace(/(apply\splugin:\s'com\.android\.library')/, `$1\napply plugin: 'kotlin-android'`);
216
212
  buildGradle = buildGradle.replace(/(compileOptions\s{\n((\t{2}|\s{8}).+\n)+(\t|\s{4})})\n(})/, `$1\n sourceSets {\n main.java.srcDirs += 'src/main/kotlin'\n }\n$5`);
217
213
  }
@@ -191,6 +191,15 @@ export interface CapacitorConfig {
191
191
  * @default true
192
192
  */
193
193
  initialFocus?: boolean;
194
+ /**
195
+ * The minimum supported webview version on Android supported by your app.
196
+ *
197
+ * The minimum supported cannot be lower than version `55`, which is required for Capacitor.
198
+ *
199
+ * @since 4.0.0
200
+ * @default 60
201
+ */
202
+ minWebViewVersion?: number;
194
203
  };
195
204
  ios?: {
196
205
  /**
@@ -403,6 +412,13 @@ export interface CapacitorConfig {
403
412
  * @default []
404
413
  */
405
414
  allowNavigation?: string[];
415
+ /**
416
+ * Specify path to a local html page to display in case of errors.
417
+ *
418
+ * @since 4.0.0
419
+ * @default null
420
+ */
421
+ errorPath?: string;
406
422
  };
407
423
  cordova?: {
408
424
  /**
package/dist/index.js CHANGED
@@ -147,6 +147,13 @@ function runProgram(config) {
147
147
  const { newPluginCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/new-plugin')));
148
148
  await newPluginCommand();
149
149
  }));
150
+ commander_1.program
151
+ .command('migrate')
152
+ .description('Migrate your current Capacitor app to the latest major version of Capacitor.')
153
+ .action(cli_1.wrapAction(async () => {
154
+ const { migrateCommand } = await Promise.resolve().then(() => tslib_1.__importStar(require('./tasks/migrate')));
155
+ await migrateCommand(config);
156
+ }));
150
157
  commander_1.program.arguments('[command]').action(cli_1.wrapAction(async (cmd) => {
151
158
  if (typeof cmd === 'undefined') {
152
159
  log_1.output.write(`\n ${emoji_1.emoji('⚡️', '--')} ${colors_1.default.strong('Capacitor - Cross-Platform apps with JavaScript and the Web')} ${emoji_1.emoji('⚡️', '--')}\n\n`);
@@ -0,0 +1,638 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.migrateCommand = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const utils_fs_1 = require("@ionic/utils-fs");
6
+ const path_1 = require("path");
7
+ const rimraf_1 = tslib_1.__importDefault(require("rimraf"));
8
+ const common_1 = require("../common");
9
+ const errors_1 = require("../errors");
10
+ const log_1 = require("../log");
11
+ const fs_1 = require("../util/fs");
12
+ const subprocess_1 = require("../util/subprocess");
13
+ const template_1 = require("../util/template");
14
+ const xml_1 = require("../util/xml");
15
+ // eslint-disable-next-line prefer-const
16
+ let allDependencies = {};
17
+ const libs = [
18
+ '@capacitor/core',
19
+ '@capacitor/cli',
20
+ '@capacitor/ios',
21
+ '@capacitor/android',
22
+ ];
23
+ const plugins = [
24
+ '@capacitor/action-sheet',
25
+ '@capacitor/app',
26
+ '@capacitor/app-launcher',
27
+ '@capacitor/browser',
28
+ '@capacitor/camera',
29
+ '@capacitor/clipboard',
30
+ '@capacitor/device',
31
+ '@capacitor/dialog',
32
+ '@capacitor/filesystem',
33
+ '@capacitor/geolocation',
34
+ '@capacitor/google-maps',
35
+ '@capacitor/haptics',
36
+ '@capacitor/keyboard',
37
+ '@capacitor/local-notifications',
38
+ '@capacitor/motion',
39
+ '@capacitor/network',
40
+ '@capacitor/push-notifications',
41
+ '@capacitor/screen-reader',
42
+ '@capacitor/share',
43
+ '@capacitor/splash-screen',
44
+ '@capacitor/status-bar',
45
+ '@capacitor/text-zoom',
46
+ '@capacitor/toast',
47
+ ];
48
+ const coreVersion = '^4.0.0';
49
+ const pluginVersion = '^4.0.0';
50
+ async function migrateCommand(config) {
51
+ if (config === null) {
52
+ errors_1.fatal('Config data missing');
53
+ }
54
+ const variablesAndClasspaths = await getAndroidVarriablesAndClasspaths(config);
55
+ if (!variablesAndClasspaths) {
56
+ errors_1.fatal('Variable and Classpath info could not be read.');
57
+ }
58
+ //*
59
+ allDependencies = {
60
+ ...config.app.package.dependencies,
61
+ ...config.app.package.devDependencies,
62
+ };
63
+ const monorepoWarning = 'Please note this tool is not intended for use in a mono-repo enviroment, please check out the Ionic vscode extension for this functionality.';
64
+ log_1.logger.info(monorepoWarning);
65
+ const { migrateconfirm } = await log_1.logPrompt(`Capacitor 4 sets a deployment target of iOS 13 and Android 12 (SDK 32). \n`, {
66
+ type: 'text',
67
+ name: 'migrateconfirm',
68
+ message: `Are you sure you want to migrate? (Y/n)`,
69
+ initial: 'y',
70
+ });
71
+ if (typeof migrateconfirm === 'string' &&
72
+ migrateconfirm.toLowerCase() === 'y') {
73
+ try {
74
+ const { npmInstallConfirm } = await log_1.logPrompt(`Would you like the migrator to run npm install to install the latest versions of capacitor packages? (Those using other package managers should answer N)`, {
75
+ type: 'text',
76
+ name: 'npmInstallConfirm',
77
+ message: `Run Npm Install? (Y/n)`,
78
+ initial: 'y',
79
+ });
80
+ const runNpmInstall = typeof npmInstallConfirm === 'string' &&
81
+ npmInstallConfirm.toLowerCase() === 'y';
82
+ await common_1.runTask(`Installing Latest NPM Modules.`, () => {
83
+ return installLatestNPMLibs(runNpmInstall, config);
84
+ });
85
+ await common_1.runTask(`Migrating @capacitor/storage to @capacitor/preferences.`, () => {
86
+ return migrateStoragePluginToPreferences(runNpmInstall);
87
+ });
88
+ if (allDependencies['@capacitor/ios'] &&
89
+ utils_fs_1.existsSync(config.ios.platformDirAbs)) {
90
+ // Set deployment target to 13.0
91
+ await common_1.runTask(`Migrating deployment target to 13.0.`, () => {
92
+ return updateFile(config, path_1.join(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj'), 'IPHONEOS_DEPLOYMENT_TARGET = ', ';', '13.0');
93
+ });
94
+ // Update Podfile to 13.0
95
+ await common_1.runTask(`Migrating Podfile to 13.0.`, () => {
96
+ return updateFile(config, path_1.join(config.ios.nativeProjectDirAbs, 'Podfile'), `platform :ios, '`, `'`, '13.0');
97
+ });
98
+ await common_1.runTask(`Migrating Podfile to use post_install script.`, () => {
99
+ return podfileAssertDeploymentTarget(path_1.join(config.ios.nativeProjectDirAbs, 'Podfile'));
100
+ });
101
+ // Remove touchesBegan
102
+ await common_1.runTask(`Migrating AppDelegate.swift by removing touchesBegan.`, () => {
103
+ return updateFile(config, path_1.join(config.ios.nativeTargetDirAbs, 'AppDelegate.swift'), `override func touchesBegan`, `}`, undefined, true);
104
+ });
105
+ // Remove NSAppTransportSecurity
106
+ await common_1.runTask(`Migrating Info.plist by removing NSAppTransportSecurity key.`, () => {
107
+ return removeKey(path_1.join(config.ios.nativeTargetDirAbs, 'Info.plist'), 'NSAppTransportSecurity');
108
+ });
109
+ // Remove USE_PUSH
110
+ await common_1.runTask(`Migrating by removing USE_PUSH.`, () => {
111
+ return replacePush(path_1.join(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj'));
112
+ });
113
+ // Remove from App Delegate
114
+ await common_1.runTask(`Migrating App Delegate.`, () => {
115
+ return replaceIfUsePush(config);
116
+ });
117
+ }
118
+ if (allDependencies['@capacitor/android'] &&
119
+ utils_fs_1.existsSync(config.android.platformDirAbs)) {
120
+ // AndroidManifest.xml add attribute: <activity android:exported="true"
121
+ await common_1.runTask(`Migrating AndroidManifest.xml by adding android:exported attribute to Activity.`, () => {
122
+ return updateAndroidManifest(path_1.join(config.android.srcMainDirAbs, 'AndroidManifest.xml'));
123
+ });
124
+ // Update build.gradle
125
+ const { leaveJCenterPrompt } = await log_1.logPrompt(`Some projects still require JCenter to function. If your project does, please answer yes below.`, {
126
+ type: 'text',
127
+ name: 'leaveJCenterPrompt',
128
+ message: `Keep JCenter if present? (y/N)`,
129
+ initial: 'n',
130
+ });
131
+ await common_1.runTask(`Migrating build.gradle file.`, () => {
132
+ return updateBuildGradle(path_1.join(config.android.platformDirAbs, 'build.gradle'), typeof leaveJCenterPrompt === 'string' &&
133
+ leaveJCenterPrompt.toLowerCase() === 'y', variablesAndClasspaths);
134
+ });
135
+ // Update app.gradle
136
+ await common_1.runTask(`Migrating app/build.gradle file.`, () => {
137
+ return updateAppBuildGradle(path_1.join(config.android.appDirAbs, 'build.gradle'));
138
+ });
139
+ // Update gradle-wrapper.properties
140
+ await common_1.runTask(`Migrating gradle-wrapper.properties by updating gradle version from 7.0 to 7.4.2.`, () => {
141
+ return updateGradleWrapper(path_1.join(config.android.platformDirAbs, 'gradle', 'wrapper', 'gradle-wrapper.properties'));
142
+ });
143
+ // Variables gradle
144
+ await common_1.runTask(`Migrating variables.gradle file.`, () => {
145
+ return (async () => {
146
+ for (const variable of Object.keys(variablesAndClasspaths.variables)) {
147
+ if (!(await updateFile(config, path_1.join(config.android.platformDirAbs, 'variables.gradle'), `${variable} = '`, `'`, variablesAndClasspaths.variables[variable].toString(), true))) {
148
+ const didWork = await updateFile(config, path_1.join(config.android.platformDirAbs, 'variables.gradle'), `${variable} = `, `\n`, variablesAndClasspaths.variables[variable].toString(), true);
149
+ if (!didWork) {
150
+ let file = readFile(path_1.join(config.android.platformDirAbs, 'variables.gradle'));
151
+ if (file) {
152
+ file = file.replace('}', ` ${variable} = '${variablesAndClasspaths.variables[variable].toString()}'\n}`);
153
+ utils_fs_1.writeFileSync(path_1.join(config.android.platformDirAbs, 'variables.gradle'), file);
154
+ }
155
+ }
156
+ }
157
+ }
158
+ })();
159
+ });
160
+ // remove init
161
+ await common_1.runTask('Migrating MainActivity by removing init().', () => {
162
+ return removeOldInitAndroid(config);
163
+ });
164
+ rimraf_1.default.sync(path_1.join(config.android.appDirAbs, 'build'));
165
+ // add new splashscreen
166
+ await common_1.runTask('Migrate to Android 12 Splashscreen and apply DayNight theme.', () => {
167
+ return addNewSplashScreen(config);
168
+ });
169
+ }
170
+ // Run Cap Sync
171
+ await common_1.runTask(`Running cap sync.`, () => {
172
+ return subprocess_1.getCommandOutput('npx', ['cap', 'sync']);
173
+ });
174
+ // Write all breaking changes
175
+ await common_1.runTask(`Writing breaking changes.`, () => {
176
+ return writeBreakingChanges();
177
+ });
178
+ log_1.logSuccess(`Migration to Capacitor ${coreVersion} is complete. Run and test your app!`);
179
+ }
180
+ catch (err) {
181
+ errors_1.fatal(`Failed to migrate: ${err}`);
182
+ }
183
+ }
184
+ else {
185
+ errors_1.fatal(`User canceled migration.`);
186
+ }
187
+ //*/
188
+ }
189
+ exports.migrateCommand = migrateCommand;
190
+ async function installLatestNPMLibs(runInstall, config) {
191
+ const pkgJsonPath = path_1.join(config.app.rootDir, 'package.json');
192
+ const pkgJsonFile = readFile(pkgJsonPath);
193
+ if (!pkgJsonFile) {
194
+ return;
195
+ }
196
+ const pkgJson = JSON.parse(pkgJsonFile);
197
+ for (const devDepKey of Object.keys(pkgJson['devDependencies'])) {
198
+ if (libs.includes(devDepKey)) {
199
+ pkgJson['devDependencies'][devDepKey] = coreVersion;
200
+ }
201
+ else if (plugins.includes(devDepKey)) {
202
+ pkgJson['devDependencies'][devDepKey] = pluginVersion;
203
+ }
204
+ }
205
+ for (const depKey of Object.keys(pkgJson['dependencies'])) {
206
+ if (libs.includes(depKey)) {
207
+ pkgJson['dependencies'][depKey] = coreVersion;
208
+ }
209
+ else if (plugins.includes(depKey)) {
210
+ pkgJson['dependencies'][depKey] = pluginVersion;
211
+ }
212
+ }
213
+ utils_fs_1.writeFileSync(pkgJsonPath, JSON.stringify(pkgJson, null, 2), {
214
+ encoding: 'utf-8',
215
+ });
216
+ if (runInstall) {
217
+ rimraf_1.default.sync(path_1.join(config.app.rootDir, 'package-lock.json'));
218
+ rimraf_1.default.sync(path_1.join(config.app.rootDir, 'node_modules/@capacitor/!(cli)'));
219
+ await subprocess_1.getCommandOutput('npm', ['i']);
220
+ }
221
+ else {
222
+ log_1.logger.info(`Please run an install command with your package manager of choice. (ex: yarn install)`);
223
+ }
224
+ }
225
+ async function migrateStoragePluginToPreferences(runInstall) {
226
+ if (allDependencies['@capacitor/storage']) {
227
+ log_1.logger.info('NOTE: @capacitor/storage was renamed to @capacitor/preferences, please be sure to replace occurances in your code.');
228
+ if (runInstall) {
229
+ await subprocess_1.getCommandOutput('npm', ['uninstall', '@capacitor/storage']);
230
+ await subprocess_1.getCommandOutput('npm', [
231
+ 'i',
232
+ `@capacitor/preferences@${pluginVersion}`,
233
+ ]);
234
+ }
235
+ else {
236
+ log_1.logger.info(`Please manually uninstall @capacitor/storage and replace it with @capacitor/preferences@${pluginVersion}`);
237
+ }
238
+ }
239
+ }
240
+ async function writeBreakingChanges() {
241
+ const breaking = [
242
+ '@capacitor/storage',
243
+ '@capacitor/camera',
244
+ '@capacitor/push-notifications',
245
+ '@capacitor/local-notifications',
246
+ ];
247
+ const broken = [];
248
+ for (const lib of breaking) {
249
+ if (allDependencies[lib]) {
250
+ broken.push(lib);
251
+ }
252
+ }
253
+ if (broken.length > 0) {
254
+ log_1.logger.info(`IMPORTANT: Review https://capacitorjs.com/docs/updating/4-0#plugins for breaking changes in these plugins that you use: ${broken.join(', ')}.`);
255
+ }
256
+ if (allDependencies['@capacitor/android']) {
257
+ log_1.logger.info('Warning: The Android Gradle plugin was updated and it requires Java 11 to run. You may need to select this in Android Studio.');
258
+ }
259
+ }
260
+ async function updateAndroidManifest(filename) {
261
+ const txt = readFile(filename);
262
+ if (!txt) {
263
+ return;
264
+ }
265
+ const hasAndroidExportedAlreadySet = new RegExp(/<activity([^>]*(android:exported=")[^>]*)>/g).test(txt);
266
+ let isAndroidExportedSetToFalse = false;
267
+ if (hasAndroidExportedAlreadySet) {
268
+ isAndroidExportedSetToFalse = new RegExp(/<activity([^>]*(android:exported="false")[^>]*)>/g).test(txt);
269
+ }
270
+ // AndroidManifest.xml add attribute: <activity android:exported="true"
271
+ if (hasAndroidExportedAlreadySet && !isAndroidExportedSetToFalse) {
272
+ return; // Probably already updated manually
273
+ }
274
+ let replaced = txt;
275
+ if (!hasAndroidExportedAlreadySet) {
276
+ replaced = setAllStringIn(txt, '<activity', ' ', `\n android:exported="true"\n`);
277
+ }
278
+ else {
279
+ log_1.logger.info(`Found 'android:exported="false"' in your AndroidManifest.xml, if this is not intentional please update it manually to "true".`);
280
+ }
281
+ if (txt == replaced) {
282
+ log_1.logger.error(`Unable to update Android Manifest. Missing <activity> tag`);
283
+ return;
284
+ }
285
+ utils_fs_1.writeFileSync(filename, replaced, 'utf-8');
286
+ }
287
+ async function updateBuildGradle(filename, leaveJCenter, variablesAndClasspaths) {
288
+ // In build.gradle add dependencies:
289
+ // classpath 'com.android.tools.build:gradle:7.2.1'
290
+ // classpath 'com.google.gms:google-services:4.3.10'
291
+ const txt = readFile(filename);
292
+ if (!txt) {
293
+ return;
294
+ }
295
+ const neededDeps = {
296
+ 'com.android.tools.build:gradle': variablesAndClasspaths['com.android.tools.build:gradle'],
297
+ 'com.google.gms:google-services': variablesAndClasspaths['com.google.gms:google-services'],
298
+ };
299
+ let replaced = txt;
300
+ for (const dep of Object.keys(neededDeps)) {
301
+ if (!replaced.includes(`classpath '${dep}`)) {
302
+ replaced = txt.replace('dependencies {', `dependencies {\n classpath '${dep}:${neededDeps[dep]}'`);
303
+ }
304
+ else {
305
+ // Update
306
+ replaced = setAllStringIn(replaced, `classpath '${dep}:`, `'`, neededDeps[dep]);
307
+ log_1.logger.info(`Set ${dep} = ${neededDeps[dep]}.`);
308
+ }
309
+ }
310
+ // Replace jcenter()
311
+ const lines = replaced.split('\n');
312
+ let inRepositories = false;
313
+ let hasMavenCentral = false;
314
+ let final = '';
315
+ for (const line of lines) {
316
+ if (line.includes('repositories {')) {
317
+ inRepositories = true;
318
+ hasMavenCentral = false;
319
+ }
320
+ else if (line.trim() == '}') {
321
+ // Make sure we have mavenCentral()
322
+ if (inRepositories && !hasMavenCentral) {
323
+ final += ' mavenCentral()\n';
324
+ log_1.logger.info(`Added mavenCentral().`);
325
+ }
326
+ inRepositories = false;
327
+ }
328
+ if (inRepositories && line.trim() === 'mavenCentral()') {
329
+ hasMavenCentral = true;
330
+ }
331
+ if (inRepositories && line.trim() === 'jcenter()' && !leaveJCenter) {
332
+ // skip jCentral()
333
+ log_1.logger.info(`Removed jcenter().`);
334
+ }
335
+ else {
336
+ final += line + '\n';
337
+ }
338
+ }
339
+ if (txt !== final) {
340
+ utils_fs_1.writeFileSync(filename, final, 'utf-8');
341
+ return;
342
+ }
343
+ }
344
+ async function getAndroidVarriablesAndClasspaths(config) {
345
+ const tempAndroidTemplateFolder = path_1.join(config.cli.assetsDirAbs, 'tempAndroidTemplate');
346
+ await template_1.extractTemplate(config.cli.assets.android.platformTemplateArchiveAbs, tempAndroidTemplateFolder);
347
+ const variablesGradleFile = readFile(path_1.join(tempAndroidTemplateFolder, 'variables.gradle'));
348
+ const buildGradleFile = readFile(path_1.join(tempAndroidTemplateFolder, 'build.gradle'));
349
+ if (!variablesGradleFile || !buildGradleFile) {
350
+ return;
351
+ }
352
+ fs_1.deleteFolderRecursive(tempAndroidTemplateFolder);
353
+ const firstIndxOfCATBGV = buildGradleFile.indexOf(`classpath 'com.android.tools.build:gradle:`) + 42;
354
+ const firstIndxOfCGGGS = buildGradleFile.indexOf(`com.google.gms:google-services:`) + 31;
355
+ const comAndroidToolsBuildGradleVersion = '' +
356
+ buildGradleFile.substring(firstIndxOfCATBGV, buildGradleFile.indexOf("'", firstIndxOfCATBGV));
357
+ const comGoogleGmsGoogleServices = '' +
358
+ buildGradleFile.substring(firstIndxOfCGGGS, buildGradleFile.indexOf("'", firstIndxOfCGGGS));
359
+ const variablesGradleAsJSON = JSON.parse(variablesGradleFile
360
+ .replace('ext ', '')
361
+ .replace(/=/g, ':')
362
+ .replace(/\n/g, ',')
363
+ .replace(/,([^:]+):/g, function (_k, p1) {
364
+ return `,"${p1}":`;
365
+ })
366
+ .replace('{,', '{')
367
+ .replace(',}', '}')
368
+ .replace(/\s/g, '')
369
+ .replace(/'/g, '"'));
370
+ return {
371
+ 'variables': variablesGradleAsJSON,
372
+ 'com.android.tools.build:gradle': comAndroidToolsBuildGradleVersion,
373
+ 'com.google.gms:google-services': comGoogleGmsGoogleServices,
374
+ };
375
+ }
376
+ function readFile(filename) {
377
+ try {
378
+ if (!utils_fs_1.existsSync(filename)) {
379
+ log_1.logger.error(`Unable to find ${filename}. Try updating it manually`);
380
+ return;
381
+ }
382
+ return utils_fs_1.readFileSync(filename, 'utf-8');
383
+ }
384
+ catch (err) {
385
+ log_1.logger.error(`Unable to read ${filename}. Verify it is not already open. ${err}`);
386
+ }
387
+ }
388
+ async function updateAppBuildGradle(filename) {
389
+ const txt = readFile(filename);
390
+ if (!txt) {
391
+ return;
392
+ }
393
+ let replaced = txt;
394
+ if (!txt.includes('androidx.coordinatorlayout:coordinatorlayout:')) {
395
+ replaced = replaced.replace('dependencies {', 'dependencies {\n implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"');
396
+ }
397
+ if (!txt.includes('androidx.core:core-splashscreen:')) {
398
+ replaced = replaced.replace('dependencies {', 'dependencies {\n implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"');
399
+ }
400
+ // const lines = txt.split('\n');
401
+ if (replaced !== txt) {
402
+ utils_fs_1.writeFileSync(filename, replaced, 'utf-8');
403
+ }
404
+ }
405
+ async function updateGradleWrapper(filename) {
406
+ const txt = readFile(filename);
407
+ if (!txt) {
408
+ return;
409
+ }
410
+ const replaced = setAllStringIn(txt, 'distributionUrl=', '\n',
411
+ // eslint-disable-next-line no-useless-escape
412
+ `https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip`);
413
+ utils_fs_1.writeFileSync(filename, replaced, 'utf-8');
414
+ }
415
+ async function updateFile(config, filename, textStart, textEnd, replacement, skipIfNotFound) {
416
+ if (config === null) {
417
+ return false;
418
+ }
419
+ const path = filename;
420
+ let txt = readFile(path);
421
+ if (!txt) {
422
+ return false;
423
+ }
424
+ if (txt.includes(textStart)) {
425
+ if (replacement) {
426
+ txt = setAllStringIn(txt, textStart, textEnd, replacement);
427
+ utils_fs_1.writeFileSync(path, txt, { encoding: 'utf-8' });
428
+ }
429
+ else {
430
+ // Replacing in code so we need to count the number of brackets to find the end of the function in swift
431
+ const lines = txt.split('\n');
432
+ let replaced = '';
433
+ let keep = true;
434
+ let brackets = 0;
435
+ for (const line of lines) {
436
+ if (line.includes(textStart)) {
437
+ keep = false;
438
+ }
439
+ if (!keep) {
440
+ brackets += (line.match(/{/g) || []).length;
441
+ brackets -= (line.match(/}/g) || []).length;
442
+ if (brackets == 0) {
443
+ keep = true;
444
+ }
445
+ }
446
+ else {
447
+ replaced += line + '\n';
448
+ }
449
+ }
450
+ utils_fs_1.writeFileSync(path, replaced, { encoding: 'utf-8' });
451
+ }
452
+ return true;
453
+ }
454
+ else if (!skipIfNotFound) {
455
+ log_1.logger.error(`Unable to find "${textStart}" in ${filename}. Try updating it manually`);
456
+ }
457
+ return false;
458
+ }
459
+ function setAllStringIn(data, start, end, replacement) {
460
+ let position = 0;
461
+ let result = data;
462
+ let replaced = true;
463
+ while (replaced) {
464
+ const foundIdx = result.indexOf(start, position);
465
+ if (foundIdx == -1) {
466
+ replaced = false;
467
+ }
468
+ else {
469
+ const idx = foundIdx + start.length;
470
+ position = idx + replacement.length;
471
+ result =
472
+ result.substring(0, idx) +
473
+ replacement +
474
+ result.substring(result.indexOf(end, idx));
475
+ }
476
+ }
477
+ return result;
478
+ }
479
+ async function replaceIfUsePush(config) {
480
+ const startLine = '#if USE_PUSH';
481
+ const endLine = '#endif';
482
+ const filename = path_1.join(config.ios.nativeTargetDirAbs, 'AppDelegate.swift');
483
+ const txt = readFile(filename);
484
+ if (!txt) {
485
+ return;
486
+ }
487
+ const lines = txt.split('\n');
488
+ let startLineIndex = null;
489
+ let endLineIndex = null;
490
+ for (const [key, item] of lines.entries()) {
491
+ if (item.includes(startLine)) {
492
+ startLineIndex = key;
493
+ break;
494
+ }
495
+ }
496
+ if (startLineIndex !== null) {
497
+ for (const [key, item] of lines.entries()) {
498
+ if (item.includes(endLine) && key > startLineIndex) {
499
+ endLineIndex = key;
500
+ break;
501
+ }
502
+ }
503
+ if (endLineIndex !== null) {
504
+ lines[endLineIndex] = '';
505
+ lines[startLineIndex] = '';
506
+ utils_fs_1.writeFileSync(filename, lines.join('\n'), 'utf-8');
507
+ }
508
+ }
509
+ }
510
+ async function replacePush(filename) {
511
+ const txt = readFile(filename);
512
+ if (!txt) {
513
+ return;
514
+ }
515
+ let replaced = txt;
516
+ replaced = replaced.replace('DEBUG USE_PUSH', 'DEBUG');
517
+ replaced = replaced.replace('USE_PUSH', '""');
518
+ if (replaced != txt) {
519
+ utils_fs_1.writeFileSync(filename, replaced, 'utf-8');
520
+ }
521
+ }
522
+ async function removeKey(filename, key) {
523
+ const txt = readFile(filename);
524
+ if (!txt) {
525
+ return;
526
+ }
527
+ let lines = txt.split('\n');
528
+ let removed = false;
529
+ let removing = false;
530
+ lines = lines.filter(line => {
531
+ if (removing && line.includes('</dict>')) {
532
+ removing = false;
533
+ return false;
534
+ }
535
+ if (line.includes(`<key>${key}</key`)) {
536
+ removing = true;
537
+ removed = true;
538
+ }
539
+ return !removing;
540
+ });
541
+ if (removed) {
542
+ utils_fs_1.writeFileSync(filename, lines.join('\n'), 'utf-8');
543
+ }
544
+ }
545
+ async function podfileAssertDeploymentTarget(filename) {
546
+ const txt = readFile(filename);
547
+ if (!txt) {
548
+ return;
549
+ }
550
+ let replaced = txt;
551
+ if (!replaced.includes(`require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers`)) {
552
+ replaced =
553
+ `require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'\n\n` +
554
+ txt;
555
+ }
556
+ if (replaced.includes('post_install do |installer|')) {
557
+ if (!replaced.includes(`assertDeploymentTarget(installer)`)) {
558
+ replaced = replaced.replace('post_install do |installer|', `post_install do |installer|\n assertDeploymentTarget(installer)\n`);
559
+ }
560
+ }
561
+ else {
562
+ replaced =
563
+ replaced +
564
+ `\n\npost_install do |installer|\n assertDeploymentTarget(installer)\nend\n`;
565
+ }
566
+ utils_fs_1.writeFileSync(filename, replaced, 'utf-8');
567
+ }
568
+ async function removeOldInitAndroid(config) {
569
+ const xmlData = await xml_1.readXML(path_1.join(config.android.srcMainDirAbs, 'AndroidManifest.xml'));
570
+ const manifestNode = xmlData.manifest;
571
+ const applicationChildNodes = manifestNode.application;
572
+ let mainActivityClassPath = '';
573
+ applicationChildNodes.find(applicationChildNode => {
574
+ const activityChildNodes = applicationChildNode.activity;
575
+ if (!Array.isArray(activityChildNodes)) {
576
+ return false;
577
+ }
578
+ const mainActivityNode = activityChildNodes.find(activityChildNode => {
579
+ const intentFilterChildNodes = activityChildNode['intent-filter'];
580
+ if (!Array.isArray(intentFilterChildNodes)) {
581
+ return false;
582
+ }
583
+ return intentFilterChildNodes.find(intentFilterChildNode => {
584
+ const actionChildNodes = intentFilterChildNode.action;
585
+ if (!Array.isArray(actionChildNodes)) {
586
+ return false;
587
+ }
588
+ const mainActionChildNode = actionChildNodes.find(actionChildNode => {
589
+ const androidName = actionChildNode.$['android:name'];
590
+ return androidName === 'android.intent.action.MAIN';
591
+ });
592
+ if (!mainActionChildNode) {
593
+ return false;
594
+ }
595
+ const categoryChildNodes = intentFilterChildNode.category;
596
+ if (!Array.isArray(categoryChildNodes)) {
597
+ return false;
598
+ }
599
+ return categoryChildNodes.find(categoryChildNode => {
600
+ const androidName = categoryChildNode.$['android:name'];
601
+ return androidName === 'android.intent.category.LAUNCHER';
602
+ });
603
+ });
604
+ });
605
+ if (mainActivityNode) {
606
+ mainActivityClassPath = mainActivityNode.$['android:name'];
607
+ }
608
+ return mainActivityNode;
609
+ });
610
+ const mainActivityClassName = mainActivityClassPath.split('.').pop();
611
+ const mainActivityPathArray = mainActivityClassPath.split('.');
612
+ mainActivityPathArray.pop();
613
+ const mainActivityClassFileName = `${mainActivityClassName}.java`;
614
+ const mainActivityClassFilePath = path_1.join(path_1.join(config.android.srcMainDirAbs, 'java'), ...mainActivityPathArray, mainActivityClassFileName);
615
+ let data = readFile(mainActivityClassFilePath);
616
+ if (data) {
617
+ const bindex = data.indexOf('this.init(savedInstanceState');
618
+ if (bindex == -1)
619
+ return;
620
+ const eindex = data.indexOf('}});', bindex) + 4;
621
+ data = data.replace(data.substring(bindex, eindex), '');
622
+ data = data.replace('// Initializes the Bridge', '');
623
+ utils_fs_1.writeFileSync(mainActivityClassFilePath, data);
624
+ }
625
+ }
626
+ async function addNewSplashScreen(config) {
627
+ const stylePath = path_1.join(config.android.srcMainDirAbs, 'res', 'values', 'styles.xml');
628
+ let stylesXml = readFile(stylePath);
629
+ if (!stylesXml)
630
+ return;
631
+ stylesXml = stylesXml.replace(`parent="AppTheme.NoActionBar"`, `parent="Theme.SplashScreen"`);
632
+ // revert wrong replaces
633
+ stylesXml = stylesXml.replace(`name="Theme.SplashScreen"`, `name="AppTheme.NoActionBar"`);
634
+ stylesXml = stylesXml.replace(`name="Theme.SplashScreenLaunch"`, `name="AppTheme.NoActionBarLaunch"`);
635
+ // Apply DayNight theme
636
+ stylesXml = stylesXml.replace(`parent="Theme.AppCompat.NoActionBar"`, `parent="Theme.AppCompat.DayNight.NoActionBar"`);
637
+ utils_fs_1.writeFileSync(stylePath, stylesXml);
638
+ }
package/dist/util/fs.js CHANGED
@@ -1,7 +1,24 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertToUnixPath = void 0;
3
+ exports.deleteFolderRecursive = exports.convertToUnixPath = void 0;
4
+ const utils_fs_1 = require("@ionic/utils-fs");
5
+ const path_1 = require("path");
4
6
  const convertToUnixPath = (path) => {
5
7
  return path.replace(/\\/g, '/');
6
8
  };
7
9
  exports.convertToUnixPath = convertToUnixPath;
10
+ const deleteFolderRecursive = (directoryPath) => {
11
+ if (utils_fs_1.existsSync(directoryPath)) {
12
+ utils_fs_1.readdirSync(directoryPath).forEach(file => {
13
+ const curPath = path_1.join(directoryPath, file);
14
+ if (utils_fs_1.lstatSync(curPath).isDirectory()) {
15
+ exports.deleteFolderRecursive(curPath);
16
+ }
17
+ else {
18
+ utils_fs_1.unlinkSync(curPath);
19
+ }
20
+ });
21
+ utils_fs_1.rmdirSync(directoryPath);
22
+ }
23
+ };
24
+ exports.deleteFolderRecursive = deleteFolderRecursive;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor/cli",
3
- "version": "4.0.0-nightly-c3aa3d6c.0",
3
+ "version": "4.0.1",
4
4
  "description": "Capacitor: Cross-platform apps with JavaScript and the web",
5
5
  "homepage": "https://capacitorjs.com",
6
6
  "author": "Ionic Team <hi@ionic.io> (https://ionic.io)",
@@ -56,6 +56,7 @@
56
56
  "open": "^8.4.0",
57
57
  "plist": "^3.0.5",
58
58
  "prompts": "^2.4.2",
59
+ "rimraf": "^3.0.2",
59
60
  "semver": "^7.3.7",
60
61
  "tar": "^6.1.11",
61
62
  "tslib": "^2.4.0",
@@ -66,12 +67,12 @@
66
67
  "@types/jest": "^26.0.4",
67
68
  "@types/plist": "^3.0.2",
68
69
  "@types/prompts": "^2.0.14",
70
+ "@types/rimraf": "^3.0.2",
69
71
  "@types/semver": "^7.3.10",
70
72
  "@types/tar": "^6.1.1",
71
73
  "@types/tmp": "^0.2.3",
72
74
  "@types/xml2js": "0.4.5",
73
75
  "jest": "^26.1.0",
74
- "rimraf": "^3.0.2",
75
76
  "tmp": "^0.2.1",
76
77
  "ts-jest": "^26.1.3",
77
78
  "typescript": "~4.1.2"
@@ -82,5 +83,5 @@
82
83
  "publishConfig": {
83
84
  "access": "public"
84
85
  },
85
- "gitHead": "c3aa3d6cbc6dc17d4c580038047ed3a4d8e168a2"
86
+ "gitHead": "a14824b660ccd39b7ed150a26debb15e9a161303"
86
87
  }