@capacitor/cli 8.4.3-nightly-20260730T154011.0 → 8.5.0
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/assets/android-template.tar.gz +0 -0
- package/assets/capacitor-cordova-android-plugins.tar.gz +0 -0
- package/assets/capacitor-cordova-ios-plugins.tar.gz +0 -0
- package/assets/ios-pods-template.tar.gz +0 -0
- package/assets/ios-spm-template.tar.gz +0 -0
- package/dist/tasks/migrate-uiscene.js +273 -0
- package/dist/tasks/migrate.js +6 -0
- package/dist/util/spm.js +36 -1
- package/dist/util/xcode.js +48 -0
- package/package.json +3 -1
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.__testables = exports.migrateToUIScene = void 0;
|
|
4
|
+
const fs_extra_1 = require("fs-extra");
|
|
5
|
+
const path_1 = require("path");
|
|
6
|
+
const common_1 = require("../common");
|
|
7
|
+
const log_1 = require("../log");
|
|
8
|
+
const fs_1 = require("../util/fs");
|
|
9
|
+
const spm_1 = require("../util/spm");
|
|
10
|
+
const template_1 = require("../util/template");
|
|
11
|
+
const xcode_1 = require("../util/xcode");
|
|
12
|
+
async function migrateToUIScene(config) {
|
|
13
|
+
const signals = readDetectionSignals(config);
|
|
14
|
+
const state = classify(signals);
|
|
15
|
+
switch (state) {
|
|
16
|
+
case 'already-migrated':
|
|
17
|
+
log_1.logger.info('UIScene migration: project already migrated, skipping.');
|
|
18
|
+
return;
|
|
19
|
+
case 'partial':
|
|
20
|
+
log_1.logger.warn(`UIScene migration: project is in a partial state (${describeSignals(signals)}). ` +
|
|
21
|
+
`Skipping automated migration — finish the migration by hand or reset to a clean 8.4 state first.`);
|
|
22
|
+
return;
|
|
23
|
+
case 'eligible':
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
const assets = await loadTemplateAssets(config);
|
|
27
|
+
if (!assets) {
|
|
28
|
+
log_1.logger.error('UIScene migration: could not read shipped iOS template assets; skipping.');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
await (0, common_1.runTask)('Adding UIApplicationSceneManifest to Info.plist.', () => (0, spm_1.addSceneManifestIfNeeded)(config));
|
|
32
|
+
await (0, common_1.runTask)('Writing SceneDelegate.swift.', async () => {
|
|
33
|
+
const { written } = writeSceneDelegate(config, assets.sceneDelegate);
|
|
34
|
+
if (!written) {
|
|
35
|
+
log_1.logger.warn('SceneDelegate.swift already exists, skipping.');
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
await (0, common_1.runTask)('Patching AppDelegate.swift with configurationForConnecting.', async () => {
|
|
39
|
+
const { patched, reason } = patchAppDelegate(config, assets.configurationForConnectingSnippet);
|
|
40
|
+
if (!patched && reason) {
|
|
41
|
+
log_1.logger.warn(`AppDelegate.swift not patched: ${reason}`);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
await (0, common_1.runTask)('Registering SceneDelegate.swift with the Xcode App target.', async () => {
|
|
45
|
+
var _a;
|
|
46
|
+
const pbxprojPath = (0, path_1.join)(config.ios.nativeXcodeProjDirAbs, 'project.pbxproj');
|
|
47
|
+
try {
|
|
48
|
+
const { added } = (0, xcode_1.addSwiftFileToAppTarget)(pbxprojPath, 'App', 'SceneDelegate.swift');
|
|
49
|
+
if (!added) {
|
|
50
|
+
log_1.logger.warn('SceneDelegate.swift is already registered in the App target, skipping.');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
log_1.logger.warn(`Could not register SceneDelegate.swift automatically: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : err}. ` +
|
|
55
|
+
'Add SceneDelegate.swift to the App target in Xcode manually.');
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
await scanAndWarn(config);
|
|
59
|
+
printNextSteps();
|
|
60
|
+
}
|
|
61
|
+
exports.migrateToUIScene = migrateToUIScene;
|
|
62
|
+
async function scanAndWarn(config) {
|
|
63
|
+
const findings = [];
|
|
64
|
+
const swiftFiles = await (0, fs_1.readdirp)(config.ios.platformDirAbs, {
|
|
65
|
+
filter: (item) => {
|
|
66
|
+
if (!item.stats.isFile())
|
|
67
|
+
return false;
|
|
68
|
+
if (!item.path.endsWith('.swift'))
|
|
69
|
+
return false;
|
|
70
|
+
const p = item.path;
|
|
71
|
+
return (!p.includes(`${path_1.sep}Pods${path_1.sep}`) &&
|
|
72
|
+
!p.includes(`${path_1.sep}build${path_1.sep}`) &&
|
|
73
|
+
!p.includes(`${path_1.sep}DerivedData${path_1.sep}`) &&
|
|
74
|
+
!p.includes(`${path_1.sep}.build${path_1.sep}`));
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
const tokenPatterns = [
|
|
78
|
+
{ token: /UIApplication\.shared\.applicationState/, label: 'UIApplication.shared.applicationState' },
|
|
79
|
+
{ token: /\btmpWindow\b/, label: 'tmpWindow' },
|
|
80
|
+
{ token: /\bTmpViewController\b/, label: 'TmpViewController' },
|
|
81
|
+
];
|
|
82
|
+
for (const filePath of swiftFiles) {
|
|
83
|
+
const source = (0, fs_extra_1.readFileSync)(filePath, 'utf-8');
|
|
84
|
+
source.split('\n').forEach((line, idx) => {
|
|
85
|
+
for (const { token, label } of tokenPatterns) {
|
|
86
|
+
if (token.test(line)) {
|
|
87
|
+
findings.push(`${filePath}:${idx + 1}: uses ${label}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const appDelegatePath = (0, path_1.join)(config.ios.nativeTargetDirAbs, 'AppDelegate.swift');
|
|
93
|
+
if ((0, fs_extra_1.existsSync)(appDelegatePath)) {
|
|
94
|
+
const source = (0, fs_extra_1.readFileSync)(appDelegatePath, 'utf-8');
|
|
95
|
+
if (hasCustomDelegateBody(source, /func application\([^)]*\bopen url:/)) {
|
|
96
|
+
findings.push(`${appDelegatePath}: custom application(_:open:) body — review for UIScene compatibility`);
|
|
97
|
+
}
|
|
98
|
+
if (hasCustomDelegateBody(source, /func application\([^)]*\bcontinue userActivity:/)) {
|
|
99
|
+
findings.push(`${appDelegatePath}: custom application(_:continue:) body — review for UIScene compatibility`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (findings.length === 0)
|
|
103
|
+
return;
|
|
104
|
+
log_1.logger.warn('UIScene scan found patterns that may need manual review:');
|
|
105
|
+
for (const finding of findings) {
|
|
106
|
+
log_1.logger.warn(` ${finding}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function hasCustomDelegateBody(source, sigRegex) {
|
|
110
|
+
const match = source.match(sigRegex);
|
|
111
|
+
if (!match || match.index === undefined)
|
|
112
|
+
return false;
|
|
113
|
+
const openIdx = source.indexOf('{', match.index);
|
|
114
|
+
if (openIdx === -1)
|
|
115
|
+
return false;
|
|
116
|
+
let depth = 1;
|
|
117
|
+
let i = openIdx + 1;
|
|
118
|
+
while (i < source.length && depth > 0) {
|
|
119
|
+
const ch = source[i];
|
|
120
|
+
if (ch === '{')
|
|
121
|
+
depth++;
|
|
122
|
+
else if (ch === '}')
|
|
123
|
+
depth--;
|
|
124
|
+
i++;
|
|
125
|
+
}
|
|
126
|
+
if (depth !== 0)
|
|
127
|
+
return false;
|
|
128
|
+
const body = source.slice(openIdx + 1, i - 1);
|
|
129
|
+
const codeLines = body
|
|
130
|
+
.split('\n')
|
|
131
|
+
.map((l) => l.trim())
|
|
132
|
+
.filter((l) => l.length > 0 && !l.startsWith('//'));
|
|
133
|
+
if (codeLines.length === 0)
|
|
134
|
+
return false;
|
|
135
|
+
return codeLines.some((l) => !l.includes('ApplicationDelegateProxy.shared'));
|
|
136
|
+
}
|
|
137
|
+
function printNextSteps() {
|
|
138
|
+
log_1.logger.info('');
|
|
139
|
+
log_1.logger.info('UIScene migration next steps:');
|
|
140
|
+
log_1.logger.info(' • Review any warnings above for legacy API usage or custom AppDelegate URL/activity handlers.');
|
|
141
|
+
log_1.logger.info(' • Full guide: https://capacitorjs.com/docs/updating/8-5');
|
|
142
|
+
}
|
|
143
|
+
async function loadTemplateAssets(config) {
|
|
144
|
+
const packageManager = await config.ios.packageManager;
|
|
145
|
+
const archiveName = packageManager === 'SPM' ? 'ios-spm-template.tar.gz' : 'ios-pods-template.tar.gz';
|
|
146
|
+
const archivePath = (0, path_1.join)(config.cli.assetsDirAbs, archiveName);
|
|
147
|
+
const tempDir = (0, path_1.join)(config.cli.assetsDirAbs, 'tempUISceneTemplate');
|
|
148
|
+
try {
|
|
149
|
+
await (0, template_1.extractTemplate)(archivePath, tempDir);
|
|
150
|
+
const sceneDelegatePath = (0, path_1.join)(tempDir, 'App', 'App', 'SceneDelegate.swift');
|
|
151
|
+
const appDelegatePath = (0, path_1.join)(tempDir, 'App', 'App', 'AppDelegate.swift');
|
|
152
|
+
if (!(0, fs_extra_1.existsSync)(sceneDelegatePath) || !(0, fs_extra_1.existsSync)(appDelegatePath)) {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
const sceneDelegate = (0, fs_extra_1.readFileSync)(sceneDelegatePath, 'utf-8');
|
|
156
|
+
const appDelegateSource = (0, fs_extra_1.readFileSync)(appDelegatePath, 'utf-8');
|
|
157
|
+
const configurationForConnectingSnippet = extractConfigurationForConnecting(appDelegateSource);
|
|
158
|
+
if (!configurationForConnectingSnippet) {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
return { sceneDelegate, configurationForConnectingSnippet };
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
(0, fs_1.deleteFolderRecursive)(tempDir);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function writeSceneDelegate(config, contents) {
|
|
168
|
+
const path = (0, path_1.join)(config.ios.nativeTargetDirAbs, 'SceneDelegate.swift');
|
|
169
|
+
if ((0, fs_extra_1.existsSync)(path)) {
|
|
170
|
+
return { written: false };
|
|
171
|
+
}
|
|
172
|
+
(0, fs_extra_1.writeFileSync)(path, contents);
|
|
173
|
+
return { written: true };
|
|
174
|
+
}
|
|
175
|
+
function patchAppDelegate(config, snippet) {
|
|
176
|
+
const path = (0, path_1.join)(config.ios.nativeTargetDirAbs, 'AppDelegate.swift');
|
|
177
|
+
if (!(0, fs_extra_1.existsSync)(path)) {
|
|
178
|
+
return { patched: false, reason: 'AppDelegate.swift not found.' };
|
|
179
|
+
}
|
|
180
|
+
const source = (0, fs_extra_1.readFileSync)(path, 'utf-8');
|
|
181
|
+
if (source.includes('UISceneConfiguration(name:')) {
|
|
182
|
+
return { patched: false, reason: 'configurationForConnecting already present.' };
|
|
183
|
+
}
|
|
184
|
+
const patched = insertBeforeAppDelegateClassEnd(source, snippet);
|
|
185
|
+
if (!patched) {
|
|
186
|
+
return { patched: false, reason: 'could not locate AppDelegate class body.' };
|
|
187
|
+
}
|
|
188
|
+
(0, fs_extra_1.writeFileSync)(path, patched);
|
|
189
|
+
return { patched: true };
|
|
190
|
+
}
|
|
191
|
+
function extractConfigurationForConnecting(appDelegateSource) {
|
|
192
|
+
const sigRegex = /^ {4}func application\(_ application: UIApplication,\n {21}configurationForConnecting\b/m;
|
|
193
|
+
const sigMatch = appDelegateSource.match(sigRegex);
|
|
194
|
+
if (!sigMatch || sigMatch.index === undefined) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const openIdx = appDelegateSource.indexOf('{', sigMatch.index);
|
|
198
|
+
if (openIdx === -1) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
let depth = 1;
|
|
202
|
+
let i = openIdx + 1;
|
|
203
|
+
while (i < appDelegateSource.length && depth > 0) {
|
|
204
|
+
const ch = appDelegateSource[i];
|
|
205
|
+
if (ch === '{')
|
|
206
|
+
depth++;
|
|
207
|
+
else if (ch === '}')
|
|
208
|
+
depth--;
|
|
209
|
+
i++;
|
|
210
|
+
}
|
|
211
|
+
if (depth !== 0) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
return '\n' + appDelegateSource.slice(sigMatch.index, i) + '\n';
|
|
215
|
+
}
|
|
216
|
+
function insertBeforeAppDelegateClassEnd(source, snippet) {
|
|
217
|
+
const classDeclRegex = /\bclass\s+AppDelegate\b[^{]*\{/;
|
|
218
|
+
const match = source.match(classDeclRegex);
|
|
219
|
+
if (!match || match.index === undefined) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
const openIdx = source.indexOf('{', match.index);
|
|
223
|
+
let depth = 1;
|
|
224
|
+
let i = openIdx + 1;
|
|
225
|
+
while (i < source.length && depth > 0) {
|
|
226
|
+
const ch = source[i];
|
|
227
|
+
if (ch === '{')
|
|
228
|
+
depth++;
|
|
229
|
+
else if (ch === '}')
|
|
230
|
+
depth--;
|
|
231
|
+
i++;
|
|
232
|
+
}
|
|
233
|
+
if (depth !== 0) {
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
const closeIdx = i - 1;
|
|
237
|
+
return source.slice(0, closeIdx) + snippet + source.slice(closeIdx);
|
|
238
|
+
}
|
|
239
|
+
function readDetectionSignals(config) {
|
|
240
|
+
const sceneDelegatePath = (0, path_1.join)(config.ios.nativeTargetDirAbs, 'SceneDelegate.swift');
|
|
241
|
+
const appDelegatePath = (0, path_1.join)(config.ios.nativeTargetDirAbs, 'AppDelegate.swift');
|
|
242
|
+
return {
|
|
243
|
+
hasManifest: (0, spm_1.hasSceneManifest)(config),
|
|
244
|
+
hasSceneDelegate: (0, fs_extra_1.existsSync)(sceneDelegatePath),
|
|
245
|
+
hasConfigurationForConnecting: (0, fs_extra_1.existsSync)(appDelegatePath) && (0, fs_extra_1.readFileSync)(appDelegatePath, 'utf-8').includes('UISceneConfiguration(name:'),
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
function classify(signals) {
|
|
249
|
+
const { hasManifest, hasSceneDelegate, hasConfigurationForConnecting } = signals;
|
|
250
|
+
const trueCount = [hasManifest, hasSceneDelegate, hasConfigurationForConnecting].filter(Boolean).length;
|
|
251
|
+
if (trueCount === 0)
|
|
252
|
+
return 'eligible';
|
|
253
|
+
if (trueCount === 3)
|
|
254
|
+
return 'already-migrated';
|
|
255
|
+
return 'partial';
|
|
256
|
+
}
|
|
257
|
+
function describeSignals({ hasManifest, hasSceneDelegate, hasConfigurationForConnecting, }) {
|
|
258
|
+
const present = [];
|
|
259
|
+
const missing = [];
|
|
260
|
+
(hasManifest ? present : missing).push('UIApplicationSceneManifest');
|
|
261
|
+
(hasSceneDelegate ? present : missing).push('SceneDelegate.swift');
|
|
262
|
+
(hasConfigurationForConnecting ? present : missing).push('AppDelegate.configurationForConnecting');
|
|
263
|
+
return `present: [${present.join(', ')}]; missing: [${missing.join(', ')}]`;
|
|
264
|
+
}
|
|
265
|
+
// Exported for tests.
|
|
266
|
+
exports.__testables = {
|
|
267
|
+
classify,
|
|
268
|
+
describeSignals,
|
|
269
|
+
insertBeforeAppDelegateClassEnd,
|
|
270
|
+
extractConfigurationForConnecting,
|
|
271
|
+
hasCustomDelegateBody,
|
|
272
|
+
scanAndWarn,
|
|
273
|
+
};
|
package/dist/tasks/migrate.js
CHANGED
|
@@ -14,6 +14,7 @@ const log_1 = require("../log");
|
|
|
14
14
|
const fs_1 = require("../util/fs");
|
|
15
15
|
const subprocess_1 = require("../util/subprocess");
|
|
16
16
|
const template_1 = require("../util/template");
|
|
17
|
+
const migrate_uiscene_1 = require("./migrate-uiscene");
|
|
17
18
|
// eslint-disable-next-line prefer-const
|
|
18
19
|
let allDependencies = {};
|
|
19
20
|
const libs = ['@capacitor/core', '@capacitor/cli', '@capacitor/ios', '@capacitor/android'];
|
|
@@ -136,6 +137,7 @@ async function migrateCommand(config, noprompt, packagemanager) {
|
|
|
136
137
|
else {
|
|
137
138
|
log_1.logger.warn('Skipped updating deployment target');
|
|
138
139
|
}
|
|
140
|
+
await (0, migrate_uiscene_1.migrateToUIScene)(config);
|
|
139
141
|
}
|
|
140
142
|
if (!installFailed) {
|
|
141
143
|
await (0, common_1.runTask)(`Running cap sync.`, () => {
|
|
@@ -324,6 +326,10 @@ async function writeBreakingChanges() {
|
|
|
324
326
|
if (broken.length > 0) {
|
|
325
327
|
log_1.logger.info(`IMPORTANT: Review https://capacitorjs.com/docs/next/updating/8-0#plugins for breaking changes in these plugins that you use: ${broken.join(', ')}.`);
|
|
326
328
|
}
|
|
329
|
+
if (allDependencies['@capacitor/ios']) {
|
|
330
|
+
log_1.logger.info('IMPORTANT: Capacitor 8.5 adopts UIScene on iOS. ' +
|
|
331
|
+
'See https://capacitorjs.com/docs/updating/8-5 for the full 8.4 → 8.5 migration guide.');
|
|
332
|
+
}
|
|
327
333
|
}
|
|
328
334
|
async function getAndroidVariablesAndClasspaths(config) {
|
|
329
335
|
const tempAndroidTemplateFolder = (0, path_1.join)(config.cli.assetsDirAbs, 'tempAndroidTemplate');
|
package/dist/util/spm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.checkPackageTraitsRequirements = exports.checkSwiftToolsVersion = exports.addInfoPlistDebugIfNeeded = exports.runCocoapodsDeintegrate = exports.generatePackageText = exports.removeCocoapodsFiles = exports.extractSPMPackageDirectory = exports.checkPluginsForPackageSwift = exports.generatePackageFile = exports.findPackageSwiftFile = exports.checkPackageManager = void 0;
|
|
3
|
+
exports.checkPackageTraitsRequirements = exports.checkSwiftToolsVersion = exports.addSceneManifestIfNeeded = exports.hasSceneManifest = exports.addInfoPlistDebugIfNeeded = exports.runCocoapodsDeintegrate = exports.generatePackageText = exports.removeCocoapodsFiles = exports.extractSPMPackageDirectory = exports.checkPluginsForPackageSwift = exports.generatePackageFile = exports.findPackageSwiftFile = exports.checkPackageManager = void 0;
|
|
4
4
|
const fs_extra_1 = require("fs-extra");
|
|
5
5
|
const os_1 = require("os");
|
|
6
6
|
const path_1 = require("path");
|
|
@@ -221,6 +221,41 @@ async function addInfoPlistDebugIfNeeded(config) {
|
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
exports.addInfoPlistDebugIfNeeded = addInfoPlistDebugIfNeeded;
|
|
224
|
+
function hasSceneManifest(config) {
|
|
225
|
+
const infoPlist = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist');
|
|
226
|
+
if (!(0, fs_extra_1.existsSync)(infoPlist)) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
const entries = (0, plist_1.parse)((0, fs_extra_1.readFileSync)(infoPlist, 'utf-8'));
|
|
230
|
+
return entries['UIApplicationSceneManifest'] !== undefined;
|
|
231
|
+
}
|
|
232
|
+
exports.hasSceneManifest = hasSceneManifest;
|
|
233
|
+
async function addSceneManifestIfNeeded(config) {
|
|
234
|
+
const infoPlist = (0, path_1.resolve)(config.ios.nativeTargetDirAbs, 'Info.plist');
|
|
235
|
+
if (!(0, fs_extra_1.existsSync)(infoPlist)) {
|
|
236
|
+
log_1.logger.warn(infoPlist + ' not found.');
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const entries = (0, plist_1.parse)((0, fs_extra_1.readFileSync)(infoPlist, 'utf-8'));
|
|
240
|
+
if (entries['UIApplicationSceneManifest'] !== undefined) {
|
|
241
|
+
log_1.logger.warn('Found UIApplicationSceneManifest in ' + infoPlist + ', skipping.');
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
entries['UIApplicationSceneManifest'] = {
|
|
245
|
+
UIApplicationSupportsMultipleScenes: false,
|
|
246
|
+
UISceneConfigurations: {
|
|
247
|
+
UIWindowSceneSessionRoleApplication: [
|
|
248
|
+
{
|
|
249
|
+
UISceneConfigurationName: 'Default Configuration',
|
|
250
|
+
UISceneDelegateClassName: '$(PRODUCT_MODULE_NAME).SceneDelegate',
|
|
251
|
+
UISceneStoryboardFile: 'Main',
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
(0, fs_extra_1.writeFileSync)(infoPlist, (0, plist_1.build)(entries));
|
|
257
|
+
}
|
|
258
|
+
exports.addSceneManifestIfNeeded = addSceneManifestIfNeeded;
|
|
224
259
|
async function checkSwiftToolsVersion(config, version) {
|
|
225
260
|
if (!version) {
|
|
226
261
|
return null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findGroupUuidByComment = exports.addSwiftFileToAppTarget = void 0;
|
|
4
|
+
const fs_extra_1 = require("fs-extra");
|
|
5
|
+
const xcode_1 = require("xcode");
|
|
6
|
+
/**
|
|
7
|
+
* Register a Swift source file with the first native target of an Xcode project.
|
|
8
|
+
*
|
|
9
|
+
* Writes entries in PBXFileReference, PBXBuildFile, the named PBXGroup's children,
|
|
10
|
+
* and the target's Sources build phase. Idempotent: a second call is a no-op.
|
|
11
|
+
*
|
|
12
|
+
* @param pbxprojPath Absolute path to project.pbxproj
|
|
13
|
+
* @param groupName Comment/name of the PBXGroup the file belongs under (e.g. 'App')
|
|
14
|
+
* @param fileRelPath Path of the file relative to the group (e.g. 'SceneDelegate.swift')
|
|
15
|
+
*/
|
|
16
|
+
function addSwiftFileToAppTarget(pbxprojPath, groupName, fileRelPath) {
|
|
17
|
+
const project = (0, xcode_1.project)(pbxprojPath);
|
|
18
|
+
project.parseSync();
|
|
19
|
+
if (project.hasFile(fileRelPath)) {
|
|
20
|
+
return { added: false };
|
|
21
|
+
}
|
|
22
|
+
const groupUuid = findGroupUuidByComment(project, groupName);
|
|
23
|
+
if (!groupUuid) {
|
|
24
|
+
throw new Error(`Could not find PBXGroup with comment "${groupName}" in ${pbxprojPath}`);
|
|
25
|
+
}
|
|
26
|
+
const targetUuid = project.getFirstTarget().uuid;
|
|
27
|
+
const result = project.addSourceFile(fileRelPath, { target: targetUuid }, groupUuid);
|
|
28
|
+
if (!result) {
|
|
29
|
+
throw new Error(`Failed to register ${fileRelPath} in ${pbxprojPath}`);
|
|
30
|
+
}
|
|
31
|
+
(0, fs_extra_1.writeFileSync)(pbxprojPath, project.writeSync(), 'utf-8');
|
|
32
|
+
return { added: true };
|
|
33
|
+
}
|
|
34
|
+
exports.addSwiftFileToAppTarget = addSwiftFileToAppTarget;
|
|
35
|
+
// Exported for tests.
|
|
36
|
+
function findGroupUuidByComment(project, comment) {
|
|
37
|
+
const groups = project.hash.project.objects.PBXGroup;
|
|
38
|
+
const COMMENT_SUFFIX = '_comment';
|
|
39
|
+
for (const key of Object.keys(groups)) {
|
|
40
|
+
if (!key.endsWith(COMMENT_SUFFIX))
|
|
41
|
+
continue;
|
|
42
|
+
if (groups[key] === comment) {
|
|
43
|
+
return key.substring(0, key.length - COMMENT_SUFFIX.length);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
exports.findGroupUuidByComment = findGroupUuidByComment;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor/cli",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.5.0",
|
|
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)",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"semver": "^7.6.3",
|
|
61
61
|
"tar": "^7.5.3",
|
|
62
62
|
"tslib": "^2.8.1",
|
|
63
|
+
"xcode": "^3.0.1",
|
|
63
64
|
"xml2js": "^0.6.2"
|
|
64
65
|
},
|
|
65
66
|
"devDependencies": {
|
|
@@ -70,6 +71,7 @@
|
|
|
70
71
|
"@types/prompts": "^2.4.9",
|
|
71
72
|
"@types/semver": "^7.5.8",
|
|
72
73
|
"@types/tmp": "^0.2.6",
|
|
74
|
+
"@types/xcode": "^3.0.0",
|
|
73
75
|
"@types/xml2js": "0.4.5",
|
|
74
76
|
"jest": "^29.7.0",
|
|
75
77
|
"jest-environment-jsdom": "^29.7.0",
|