zcw-shared 1.45.0 → 1.46.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/dist/functions/android/integrateUniAppNativePlugin.d.ts +9 -9
- package/dist/functions/android/integrateUniAppNativePlugin.js +148 -104
- package/dist/functions/android/integrateUniAppNativePlugin.js.map +1 -1
- package/dist/functions/ios/integrateNativePlugin.d.ts +20 -16
- package/dist/functions/ios/integrateNativePlugin.js +537 -183
- package/dist/functions/ios/integrateNativePlugin.js.map +1 -1
- package/dist/functions/ios/integrateThirdPartyModule.js +61 -9
- package/dist/functions/ios/integrateThirdPartyModule.js.map +1 -1
- package/dist/functions/ios/safelyModifyProjectPbxproj.js +69 -20
- package/dist/functions/ios/safelyModifyProjectPbxproj.js.map +1 -1
- package/dist/functions/uniapp/app-plus/buildIOSApp.d.ts +3 -1
- package/dist/functions/uniapp/app-plus/buildIOSApp.js +158 -147
- package/dist/functions/uniapp/app-plus/buildIOSApp.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,84 +1,113 @@
|
|
|
1
|
-
import { addFileToXcodeProject,
|
|
1
|
+
import { addFileToXcodeProject, } from "./integrateThirdPartyModule";
|
|
2
2
|
async function extractPlugin(pluginPath, extractDir, deps) {
|
|
3
3
|
try {
|
|
4
4
|
if (deps.existsSync(pluginPath)) {
|
|
5
5
|
const stat = deps.statSync(pluginPath);
|
|
6
6
|
if (stat.isDirectory()) {
|
|
7
|
+
deps.log?.("插件是目录,直接使用");
|
|
7
8
|
return {
|
|
8
9
|
success: true,
|
|
9
|
-
extractedPath: pluginPath
|
|
10
|
+
extractedPath: pluginPath,
|
|
10
11
|
};
|
|
11
12
|
}
|
|
12
13
|
}
|
|
13
|
-
if (pluginPath.endsWith(
|
|
14
|
-
const pluginName = deps.basename(pluginPath,
|
|
14
|
+
if (pluginPath.endsWith(".zip")) {
|
|
15
|
+
const pluginName = deps.basename(pluginPath, ".zip");
|
|
15
16
|
const targetDir = deps.join(extractDir, pluginName);
|
|
16
17
|
if (deps.existsSync(targetDir)) {
|
|
18
|
+
deps.log?.(`插件已解压过,使用现有目录: ${targetDir}`);
|
|
17
19
|
return {
|
|
18
20
|
success: true,
|
|
19
|
-
extractedPath: targetDir
|
|
21
|
+
extractedPath: targetDir,
|
|
20
22
|
};
|
|
21
23
|
}
|
|
22
24
|
if (!deps.existsSync(extractDir)) {
|
|
23
25
|
deps.mkdirSync(extractDir, { recursive: true });
|
|
24
26
|
}
|
|
27
|
+
deps.log?.(`开始解压插件: ${pluginPath}`);
|
|
28
|
+
deps.log?.(`解压到目录: ${extractDir}`);
|
|
25
29
|
return new Promise((resolve) => {
|
|
26
|
-
|
|
30
|
+
let resolved = false;
|
|
31
|
+
let timeoutId;
|
|
32
|
+
const child = deps.exec(`unzip -q "${pluginPath}" -d "${extractDir}"`, (error, stdout, stderr) => {
|
|
33
|
+
if (resolved)
|
|
34
|
+
return;
|
|
35
|
+
resolved = true;
|
|
36
|
+
if (timeoutId !== undefined) {
|
|
37
|
+
deps.clearTimeout(timeoutId);
|
|
38
|
+
}
|
|
27
39
|
if (error) {
|
|
40
|
+
deps.log?.(`解压失败: ${error.message}`);
|
|
41
|
+
if (stderr)
|
|
42
|
+
deps.log?.(`错误输出: ${stderr}`);
|
|
28
43
|
resolve({
|
|
29
44
|
success: false,
|
|
30
|
-
error: `解压插件失败: ${error.message}
|
|
45
|
+
error: `解压插件失败: ${error.message}`,
|
|
31
46
|
});
|
|
32
47
|
return;
|
|
33
48
|
}
|
|
49
|
+
deps.log?.("解压完成,查找解压后的目录...");
|
|
34
50
|
const files = deps.readdirSync(extractDir);
|
|
35
51
|
if (files.length === 0) {
|
|
52
|
+
deps.log?.("解压后未找到任何文件");
|
|
36
53
|
resolve({
|
|
37
54
|
success: false,
|
|
38
|
-
error:
|
|
55
|
+
error: "解压后未找到插件文件",
|
|
39
56
|
});
|
|
40
57
|
return;
|
|
41
58
|
}
|
|
42
59
|
const extractedPath = deps.join(extractDir, files[0]);
|
|
60
|
+
deps.log?.(`找到解压后的目录: ${extractedPath}`);
|
|
43
61
|
resolve({
|
|
44
62
|
success: true,
|
|
45
|
-
extractedPath
|
|
63
|
+
extractedPath,
|
|
46
64
|
});
|
|
47
65
|
});
|
|
66
|
+
timeoutId = deps.setTimeout(() => {
|
|
67
|
+
if (resolved)
|
|
68
|
+
return;
|
|
69
|
+
resolved = true;
|
|
70
|
+
child.kill();
|
|
71
|
+
deps.log?.("解压超时(30秒)");
|
|
72
|
+
resolve({
|
|
73
|
+
success: false,
|
|
74
|
+
error: "解压插件超时",
|
|
75
|
+
});
|
|
76
|
+
}, 30000);
|
|
48
77
|
});
|
|
49
78
|
}
|
|
50
79
|
return {
|
|
51
80
|
success: false,
|
|
52
|
-
error: `不支持的插件格式: ${pluginPath}
|
|
81
|
+
error: `不支持的插件格式: ${pluginPath}`,
|
|
53
82
|
};
|
|
54
83
|
}
|
|
55
84
|
catch (error) {
|
|
56
85
|
return {
|
|
57
86
|
success: false,
|
|
58
|
-
error: `解压插件异常: ${error instanceof Error ? error.message : String(error)}
|
|
87
|
+
error: `解压插件异常: ${error instanceof Error ? error.message : String(error)}`,
|
|
59
88
|
};
|
|
60
89
|
}
|
|
61
90
|
}
|
|
62
91
|
function readPluginPackageJson(pluginDir, deps) {
|
|
63
92
|
try {
|
|
64
|
-
const packageJsonPath = deps.join(pluginDir,
|
|
93
|
+
const packageJsonPath = deps.join(pluginDir, "package.json");
|
|
65
94
|
if (!deps.existsSync(packageJsonPath)) {
|
|
66
95
|
return {
|
|
67
96
|
success: false,
|
|
68
|
-
error: `插件 package.json 不存在: ${packageJsonPath}
|
|
97
|
+
error: `插件 package.json 不存在: ${packageJsonPath}`,
|
|
69
98
|
};
|
|
70
99
|
}
|
|
71
|
-
const content = deps.readFileSync(packageJsonPath,
|
|
100
|
+
const content = deps.readFileSync(packageJsonPath, "utf8");
|
|
72
101
|
const packageJson = deps.parse(content);
|
|
73
102
|
return {
|
|
74
103
|
success: true,
|
|
75
|
-
packageJson
|
|
104
|
+
packageJson,
|
|
76
105
|
};
|
|
77
106
|
}
|
|
78
107
|
catch (error) {
|
|
79
108
|
return {
|
|
80
109
|
success: false,
|
|
81
|
-
error: `读取插件 package.json 失败: ${error instanceof Error ? error.message : String(error)}
|
|
110
|
+
error: `读取插件 package.json 失败: ${error instanceof Error ? error.message : String(error)}`,
|
|
82
111
|
};
|
|
83
112
|
}
|
|
84
113
|
}
|
|
@@ -88,14 +117,14 @@ function extractIOSPluginConfig(packageJson) {
|
|
|
88
117
|
if (!iosConfig) {
|
|
89
118
|
return {
|
|
90
119
|
success: false,
|
|
91
|
-
error:
|
|
120
|
+
error: "package.json 中未找到 _dp_nativeplugin.ios 配置",
|
|
92
121
|
};
|
|
93
122
|
}
|
|
94
123
|
const plugins = iosConfig.plugins;
|
|
95
124
|
if (!plugins || !Array.isArray(plugins) || plugins.length === 0) {
|
|
96
125
|
return {
|
|
97
126
|
success: false,
|
|
98
|
-
error:
|
|
127
|
+
error: "package.json 中未找到有效的 plugins 配置",
|
|
99
128
|
};
|
|
100
129
|
}
|
|
101
130
|
const pluginItems = [];
|
|
@@ -104,29 +133,31 @@ function extractIOSPluginConfig(packageJson) {
|
|
|
104
133
|
pluginItems.push({
|
|
105
134
|
type: plugin.type,
|
|
106
135
|
name: plugin.name,
|
|
107
|
-
class: plugin.class
|
|
136
|
+
class: plugin.class,
|
|
108
137
|
});
|
|
109
138
|
}
|
|
110
139
|
}
|
|
111
140
|
if (pluginItems.length === 0) {
|
|
112
141
|
return {
|
|
113
142
|
success: false,
|
|
114
|
-
error:
|
|
143
|
+
error: "package.json 中未找到有效的插件配置",
|
|
115
144
|
};
|
|
116
145
|
}
|
|
117
|
-
const hooksClass = iosConfig.hooksClass ||
|
|
146
|
+
const hooksClass = iosConfig.hooksClass || "";
|
|
118
147
|
const frameworks = iosConfig.frameworks || [];
|
|
119
148
|
const embedFrameworks = iosConfig.embedFrameworks || [];
|
|
120
149
|
const resources = iosConfig.resources || [];
|
|
121
150
|
const privacies = iosConfig.privacies || [];
|
|
122
151
|
let parameters = undefined;
|
|
123
|
-
if (iosConfig.parameters && typeof iosConfig.parameters ===
|
|
152
|
+
if (iosConfig.parameters && typeof iosConfig.parameters === "object") {
|
|
124
153
|
parameters = {};
|
|
125
154
|
for (const [paramName, paramConfig] of Object.entries(iosConfig.parameters)) {
|
|
126
|
-
if (paramConfig &&
|
|
155
|
+
if (paramConfig &&
|
|
156
|
+
typeof paramConfig === "object" &&
|
|
157
|
+
"key" in paramConfig) {
|
|
127
158
|
parameters[paramName] = {
|
|
128
159
|
key: paramConfig.key,
|
|
129
|
-
des: paramConfig.des ||
|
|
160
|
+
des: paramConfig.des || "",
|
|
130
161
|
};
|
|
131
162
|
}
|
|
132
163
|
}
|
|
@@ -139,18 +170,18 @@ function extractIOSPluginConfig(packageJson) {
|
|
|
139
170
|
embedFrameworks,
|
|
140
171
|
resources,
|
|
141
172
|
privacies,
|
|
142
|
-
parameters
|
|
173
|
+
parameters,
|
|
143
174
|
};
|
|
144
175
|
}
|
|
145
176
|
catch (error) {
|
|
146
177
|
return {
|
|
147
178
|
success: false,
|
|
148
|
-
error: `提取插件配置失败: ${error instanceof Error ? error.message : String(error)}
|
|
179
|
+
error: `提取插件配置失败: ${error instanceof Error ? error.message : String(error)}`,
|
|
149
180
|
};
|
|
150
181
|
}
|
|
151
182
|
}
|
|
152
183
|
function addPluginToInfoPlist(xmlDoc, pluginItems, hooksClass) {
|
|
153
|
-
const dictElement = xmlDoc.getElementsByTagName(
|
|
184
|
+
const dictElement = xmlDoc.getElementsByTagName("dict")[0];
|
|
154
185
|
if (!dictElement)
|
|
155
186
|
return false;
|
|
156
187
|
let unipluginsKey = null;
|
|
@@ -158,9 +189,9 @@ function addPluginToInfoPlist(xmlDoc, pluginItems, hooksClass) {
|
|
|
158
189
|
const childNodes = Array.from(dictElement.childNodes || []).filter((node) => node.nodeType === 1);
|
|
159
190
|
for (let i = 0; i < childNodes.length; i++) {
|
|
160
191
|
const node = childNodes[i];
|
|
161
|
-
if (node.nodeName ===
|
|
192
|
+
if (node.nodeName === "key" && node.textContent === "dcloud_uniplugins") {
|
|
162
193
|
unipluginsKey = node;
|
|
163
|
-
if (i + 1 < childNodes.length && childNodes[i + 1].nodeName ===
|
|
194
|
+
if (i + 1 < childNodes.length && childNodes[i + 1].nodeName === "array") {
|
|
164
195
|
unipluginsArray = childNodes[i + 1];
|
|
165
196
|
break;
|
|
166
197
|
}
|
|
@@ -168,40 +199,40 @@ function addPluginToInfoPlist(xmlDoc, pluginItems, hooksClass) {
|
|
|
168
199
|
}
|
|
169
200
|
if (!unipluginsArray) {
|
|
170
201
|
if (!unipluginsKey) {
|
|
171
|
-
unipluginsKey = xmlDoc.createElement(
|
|
172
|
-
unipluginsKey.textContent =
|
|
202
|
+
unipluginsKey = xmlDoc.createElement("key");
|
|
203
|
+
unipluginsKey.textContent = "dcloud_uniplugins";
|
|
173
204
|
dictElement.appendChild(unipluginsKey);
|
|
174
205
|
}
|
|
175
|
-
unipluginsArray = xmlDoc.createElement(
|
|
206
|
+
unipluginsArray = xmlDoc.createElement("array");
|
|
176
207
|
dictElement.appendChild(unipluginsArray);
|
|
177
208
|
}
|
|
178
|
-
const pluginDict = xmlDoc.createElement(
|
|
179
|
-
const hooksClassKey = xmlDoc.createElement(
|
|
180
|
-
hooksClassKey.textContent =
|
|
181
|
-
const hooksClassValue = xmlDoc.createElement(
|
|
209
|
+
const pluginDict = xmlDoc.createElement("dict");
|
|
210
|
+
const hooksClassKey = xmlDoc.createElement("key");
|
|
211
|
+
hooksClassKey.textContent = "hooksClass";
|
|
212
|
+
const hooksClassValue = xmlDoc.createElement("string");
|
|
182
213
|
hooksClassValue.textContent = hooksClass;
|
|
183
214
|
pluginDict.appendChild(hooksClassKey);
|
|
184
215
|
pluginDict.appendChild(hooksClassValue);
|
|
185
|
-
const pluginsKey = xmlDoc.createElement(
|
|
186
|
-
pluginsKey.textContent =
|
|
187
|
-
const pluginsArray = xmlDoc.createElement(
|
|
216
|
+
const pluginsKey = xmlDoc.createElement("key");
|
|
217
|
+
pluginsKey.textContent = "plugins";
|
|
218
|
+
const pluginsArray = xmlDoc.createElement("array");
|
|
188
219
|
for (const plugin of pluginItems) {
|
|
189
|
-
const itemDict = xmlDoc.createElement(
|
|
190
|
-
const typeKey = xmlDoc.createElement(
|
|
191
|
-
typeKey.textContent =
|
|
192
|
-
const typeValue = xmlDoc.createElement(
|
|
220
|
+
const itemDict = xmlDoc.createElement("dict");
|
|
221
|
+
const typeKey = xmlDoc.createElement("key");
|
|
222
|
+
typeKey.textContent = "type";
|
|
223
|
+
const typeValue = xmlDoc.createElement("string");
|
|
193
224
|
typeValue.textContent = plugin.type;
|
|
194
225
|
itemDict.appendChild(typeKey);
|
|
195
226
|
itemDict.appendChild(typeValue);
|
|
196
|
-
const nameKey = xmlDoc.createElement(
|
|
197
|
-
nameKey.textContent =
|
|
198
|
-
const nameValue = xmlDoc.createElement(
|
|
227
|
+
const nameKey = xmlDoc.createElement("key");
|
|
228
|
+
nameKey.textContent = "name";
|
|
229
|
+
const nameValue = xmlDoc.createElement("string");
|
|
199
230
|
nameValue.textContent = plugin.name;
|
|
200
231
|
itemDict.appendChild(nameKey);
|
|
201
232
|
itemDict.appendChild(nameValue);
|
|
202
|
-
const classKey = xmlDoc.createElement(
|
|
203
|
-
classKey.textContent =
|
|
204
|
-
const classValue = xmlDoc.createElement(
|
|
233
|
+
const classKey = xmlDoc.createElement("key");
|
|
234
|
+
classKey.textContent = "class";
|
|
235
|
+
const classValue = xmlDoc.createElement("string");
|
|
205
236
|
classValue.textContent = plugin.class;
|
|
206
237
|
itemDict.appendChild(classKey);
|
|
207
238
|
itemDict.appendChild(classValue);
|
|
@@ -213,7 +244,7 @@ function addPluginToInfoPlist(xmlDoc, pluginItems, hooksClass) {
|
|
|
213
244
|
return true;
|
|
214
245
|
}
|
|
215
246
|
function addPluginParametersToInfoPlist(xmlDoc, parameters, parameterValues) {
|
|
216
|
-
const dictElement = xmlDoc.getElementsByTagName(
|
|
247
|
+
const dictElement = xmlDoc.getElementsByTagName("dict")[0];
|
|
217
248
|
if (!dictElement)
|
|
218
249
|
return false;
|
|
219
250
|
for (const [paramName, paramConfig] of Object.entries(parameters)) {
|
|
@@ -221,11 +252,11 @@ function addPluginParametersToInfoPlist(xmlDoc, parameters, parameterValues) {
|
|
|
221
252
|
if (!value)
|
|
222
253
|
continue;
|
|
223
254
|
const key = paramConfig.key;
|
|
224
|
-
const keys = key.split(
|
|
255
|
+
const keys = key.split(":");
|
|
225
256
|
if (keys.length === 1) {
|
|
226
|
-
const keyElement = xmlDoc.createElement(
|
|
257
|
+
const keyElement = xmlDoc.createElement("key");
|
|
227
258
|
keyElement.textContent = keys[0];
|
|
228
|
-
const valueElement = xmlDoc.createElement(
|
|
259
|
+
const valueElement = xmlDoc.createElement("string");
|
|
229
260
|
valueElement.textContent = value;
|
|
230
261
|
dictElement.appendChild(keyElement);
|
|
231
262
|
dictElement.appendChild(valueElement);
|
|
@@ -237,23 +268,24 @@ function addPluginParametersToInfoPlist(xmlDoc, parameters, parameterValues) {
|
|
|
237
268
|
const childNodes = Array.from(dictElement.childNodes || []).filter((node) => node.nodeType === 1);
|
|
238
269
|
for (let i = 0; i < childNodes.length; i++) {
|
|
239
270
|
const node = childNodes[i];
|
|
240
|
-
if (node.nodeName ===
|
|
241
|
-
if (i + 1 < childNodes.length &&
|
|
271
|
+
if (node.nodeName === "key" && node.textContent === parentKey) {
|
|
272
|
+
if (i + 1 < childNodes.length &&
|
|
273
|
+
childNodes[i + 1].nodeName === "dict") {
|
|
242
274
|
parentDict = childNodes[i + 1];
|
|
243
275
|
break;
|
|
244
276
|
}
|
|
245
277
|
}
|
|
246
278
|
}
|
|
247
279
|
if (!parentDict) {
|
|
248
|
-
const parentKeyElement = xmlDoc.createElement(
|
|
280
|
+
const parentKeyElement = xmlDoc.createElement("key");
|
|
249
281
|
parentKeyElement.textContent = parentKey;
|
|
250
|
-
parentDict = xmlDoc.createElement(
|
|
282
|
+
parentDict = xmlDoc.createElement("dict");
|
|
251
283
|
dictElement.appendChild(parentKeyElement);
|
|
252
284
|
dictElement.appendChild(parentDict);
|
|
253
285
|
}
|
|
254
|
-
const childKeyElement = xmlDoc.createElement(
|
|
286
|
+
const childKeyElement = xmlDoc.createElement("key");
|
|
255
287
|
childKeyElement.textContent = childKey;
|
|
256
|
-
const childValueElement = xmlDoc.createElement(
|
|
288
|
+
const childValueElement = xmlDoc.createElement("string");
|
|
257
289
|
childValueElement.textContent = value;
|
|
258
290
|
parentDict.appendChild(childKeyElement);
|
|
259
291
|
parentDict.appendChild(childValueElement);
|
|
@@ -262,11 +294,11 @@ function addPluginParametersToInfoPlist(xmlDoc, parameters, parameterValues) {
|
|
|
262
294
|
return true;
|
|
263
295
|
}
|
|
264
296
|
function addPrivaciesToInfoPlist(xmlDoc, privacies) {
|
|
265
|
-
const dictElement = xmlDoc.getElementsByTagName(
|
|
297
|
+
const dictElement = xmlDoc.getElementsByTagName("dict")[0];
|
|
266
298
|
if (!dictElement)
|
|
267
299
|
return false;
|
|
268
300
|
for (const privacy of privacies) {
|
|
269
|
-
const keyElements = xmlDoc.getElementsByTagName(
|
|
301
|
+
const keyElements = xmlDoc.getElementsByTagName("key");
|
|
270
302
|
let found = false;
|
|
271
303
|
for (let i = 0; i < keyElements.length; i++) {
|
|
272
304
|
const keyElement = keyElements[i];
|
|
@@ -276,47 +308,195 @@ function addPrivaciesToInfoPlist(xmlDoc, privacies) {
|
|
|
276
308
|
}
|
|
277
309
|
}
|
|
278
310
|
if (!found) {
|
|
279
|
-
const keyElement = xmlDoc.createElement(
|
|
311
|
+
const keyElement = xmlDoc.createElement("key");
|
|
280
312
|
keyElement.textContent = privacy;
|
|
281
|
-
const valueElement = xmlDoc.createElement(
|
|
282
|
-
valueElement.textContent =
|
|
313
|
+
const valueElement = xmlDoc.createElement("string");
|
|
314
|
+
valueElement.textContent = "应用需要使用此功能";
|
|
283
315
|
dictElement.appendChild(keyElement);
|
|
284
316
|
dictElement.appendChild(valueElement);
|
|
285
317
|
}
|
|
286
318
|
}
|
|
287
319
|
return true;
|
|
288
320
|
}
|
|
289
|
-
function findFilesRecursive(dir, extensions, deps) {
|
|
321
|
+
function findFilesRecursive(dir, extensions, deps, depth = 0) {
|
|
290
322
|
const result = [];
|
|
323
|
+
const maxDepth = 10;
|
|
291
324
|
if (!deps.existsSync(dir)) {
|
|
292
325
|
return result;
|
|
293
326
|
}
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
327
|
+
const bundleExtensions = [".framework", ".xcframework", ".app", ".bundle"];
|
|
328
|
+
if (depth > maxDepth) {
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
try {
|
|
332
|
+
const files = deps.readdirSync(dir);
|
|
333
|
+
for (const file of files) {
|
|
334
|
+
const filePath = deps.join(dir, file);
|
|
335
|
+
try {
|
|
336
|
+
const stat = deps.statSync(filePath);
|
|
337
|
+
if (stat.isDirectory()) {
|
|
338
|
+
let matchesExtension = false;
|
|
339
|
+
let isBundle = false;
|
|
340
|
+
for (const ext of extensions) {
|
|
341
|
+
if (file.endsWith(ext)) {
|
|
342
|
+
matchesExtension = true;
|
|
343
|
+
isBundle = bundleExtensions.includes(ext);
|
|
344
|
+
result.push(filePath);
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (!matchesExtension || !isBundle) {
|
|
349
|
+
if (!matchesExtension) {
|
|
350
|
+
result.push(...findFilesRecursive(filePath, extensions, deps, depth + 1));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
for (const ext of extensions) {
|
|
356
|
+
if (file.endsWith(ext)) {
|
|
357
|
+
result.push(filePath);
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
306
361
|
}
|
|
307
362
|
}
|
|
363
|
+
catch (error) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
308
366
|
}
|
|
309
367
|
}
|
|
368
|
+
catch (error) {
|
|
369
|
+
}
|
|
310
370
|
return result;
|
|
311
371
|
}
|
|
372
|
+
async function copyFrameworkUsingArchive(sourcePath, targetPath, deps, logFn) {
|
|
373
|
+
const log = (msg) => {
|
|
374
|
+
const message = `[copyFramework] ${msg}`;
|
|
375
|
+
if (logFn)
|
|
376
|
+
logFn(message);
|
|
377
|
+
};
|
|
378
|
+
try {
|
|
379
|
+
log(`开始复制 framework: ${deps.basename(sourcePath)}`);
|
|
380
|
+
log(` 源路径: ${sourcePath}`);
|
|
381
|
+
log(` 目标路径: ${targetPath}`);
|
|
382
|
+
const targetDir = deps.dirname(targetPath);
|
|
383
|
+
const tempDir = deps.join(targetDir, ".temp_framework_copy");
|
|
384
|
+
log(` 临时目录: ${tempDir}`);
|
|
385
|
+
if (deps.existsSync(tempDir)) {
|
|
386
|
+
log(` 清理已存在的临时目录...`);
|
|
387
|
+
await new Promise((resolve) => {
|
|
388
|
+
deps.exec(`rm -rf "${tempDir}"`, (error) => {
|
|
389
|
+
if (error) {
|
|
390
|
+
log(` 警告: 清理临时目录失败: ${error.message}`);
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
log(` 临时目录已清理`);
|
|
394
|
+
}
|
|
395
|
+
resolve();
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
if (!deps.existsSync(tempDir)) {
|
|
400
|
+
log(` 创建临时目录...`);
|
|
401
|
+
deps.mkdirSync(tempDir, { recursive: true });
|
|
402
|
+
}
|
|
403
|
+
const frameworkName = deps.basename(sourcePath);
|
|
404
|
+
const archiveName = `${frameworkName}.tar.gz`;
|
|
405
|
+
const archivePath = deps.join(tempDir, archiveName);
|
|
406
|
+
log(` 压缩文件路径: ${archivePath}`);
|
|
407
|
+
const sourceDir = deps.dirname(sourcePath);
|
|
408
|
+
const sourceName = deps.basename(sourcePath);
|
|
409
|
+
log(` 开始压缩: ${sourceDir}/${sourceName} -> ${archivePath}`);
|
|
410
|
+
return new Promise((resolve) => {
|
|
411
|
+
const startTime = Date.now();
|
|
412
|
+
deps.exec(`cd "${sourceDir}" && tar -czf "${archivePath}" "${sourceName}"`, (error, stdout, stderr) => {
|
|
413
|
+
const compressTime = Date.now() - startTime;
|
|
414
|
+
log(` 压缩完成 (耗时: ${compressTime}ms)`);
|
|
415
|
+
if (error) {
|
|
416
|
+
log(` 压缩失败: ${error.message}`);
|
|
417
|
+
if (stderr)
|
|
418
|
+
log(` stderr: ${stderr}`);
|
|
419
|
+
resolve({
|
|
420
|
+
success: false,
|
|
421
|
+
error: `压缩 framework 失败: ${error.message}`,
|
|
422
|
+
});
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const targetArchivePath = deps.join(targetDir, archiveName);
|
|
426
|
+
log(` 开始复制压缩文件: ${archivePath} -> ${targetArchivePath}`);
|
|
427
|
+
const copyStartTime = Date.now();
|
|
428
|
+
try {
|
|
429
|
+
deps.copyFileSync(archivePath, targetArchivePath);
|
|
430
|
+
const copyTime = Date.now() - copyStartTime;
|
|
431
|
+
log(` 复制压缩文件完成 (耗时: ${copyTime}ms)`);
|
|
432
|
+
}
|
|
433
|
+
catch (copyError) {
|
|
434
|
+
log(` 复制压缩文件失败: ${copyError.message || String(copyError)}`);
|
|
435
|
+
resolve({
|
|
436
|
+
success: false,
|
|
437
|
+
error: `复制压缩文件失败: ${copyError.message || String(copyError)}`,
|
|
438
|
+
});
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
log(` 开始解压: ${targetArchivePath} -> ${targetDir}`);
|
|
442
|
+
const extractStartTime = Date.now();
|
|
443
|
+
deps.exec(`cd "${targetDir}" && tar -xzf "${targetArchivePath}" && rm -f "${targetArchivePath}"`, (extractError, extractStdout, extractStderr) => {
|
|
444
|
+
const extractTime = Date.now() - extractStartTime;
|
|
445
|
+
log(` 解压完成 (耗时: ${extractTime}ms)`);
|
|
446
|
+
try {
|
|
447
|
+
if (deps.existsSync(archivePath)) {
|
|
448
|
+
deps.exec(`rm -f "${archivePath}"`, () => { });
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
catch { }
|
|
452
|
+
if (extractError) {
|
|
453
|
+
log(` 解压失败: ${extractError.message}`);
|
|
454
|
+
if (extractStderr)
|
|
455
|
+
log(` stderr: ${extractStderr}`);
|
|
456
|
+
resolve({
|
|
457
|
+
success: false,
|
|
458
|
+
error: `解压 framework 失败: ${extractError.message}`,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
const totalTime = Date.now() - startTime;
|
|
463
|
+
log(` framework 复制成功 (总耗时: ${totalTime}ms)`);
|
|
464
|
+
resolve({ success: true });
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
log(` 复制 framework 异常: ${error.message || String(error)}`);
|
|
472
|
+
return {
|
|
473
|
+
success: false,
|
|
474
|
+
error: `复制 framework 失败: ${error.message || String(error)}`,
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
}
|
|
312
478
|
export async function integrateNativePluginIOS(projectPath, projectName, pluginPath, deps, parameters) {
|
|
313
|
-
const logs = [];
|
|
314
479
|
try {
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
const tempDir = deps.join(projectPath,
|
|
480
|
+
deps.log?.(`开始集成 UniApp 原生插件: ${pluginPath}`);
|
|
481
|
+
deps.log?.("步骤 1: 解压插件");
|
|
482
|
+
const tempDir = deps.join(projectPath, ".temp");
|
|
483
|
+
if (deps.existsSync(tempDir)) {
|
|
484
|
+
deps.log?.("清理已存在的临时目录...");
|
|
485
|
+
await new Promise((resolve) => {
|
|
486
|
+
deps.exec(`rm -rf "${tempDir}"`, (error) => {
|
|
487
|
+
if (error) {
|
|
488
|
+
deps.log?.(`警告: 清理临时目录失败: ${error.message}`);
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
deps.log?.("临时目录已清理");
|
|
492
|
+
}
|
|
493
|
+
resolve();
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
}
|
|
318
497
|
if (!deps.existsSync(tempDir)) {
|
|
319
498
|
deps.mkdirSync(tempDir, { recursive: true });
|
|
499
|
+
deps.log?.("已创建临时目录");
|
|
320
500
|
}
|
|
321
501
|
const extractResult = await extractPlugin(pluginPath, tempDir, {
|
|
322
502
|
existsSync: deps.existsSync,
|
|
@@ -326,60 +506,69 @@ export async function integrateNativePluginIOS(projectPath, projectName, pluginP
|
|
|
326
506
|
exec: deps.exec,
|
|
327
507
|
basename: deps.basename,
|
|
328
508
|
dirname: deps.dirname,
|
|
329
|
-
mkdirSync: deps.mkdirSync
|
|
509
|
+
mkdirSync: deps.mkdirSync,
|
|
510
|
+
log: deps.log,
|
|
511
|
+
setTimeout: deps.setTimeout,
|
|
512
|
+
clearTimeout: deps.clearTimeout,
|
|
330
513
|
});
|
|
331
514
|
if (!extractResult.success) {
|
|
332
515
|
return {
|
|
333
516
|
success: false,
|
|
334
517
|
error: extractResult.error,
|
|
335
|
-
logs
|
|
518
|
+
logs: [],
|
|
336
519
|
};
|
|
337
520
|
}
|
|
338
521
|
const pluginDir = extractResult.extractedPath;
|
|
339
|
-
|
|
340
|
-
|
|
522
|
+
deps.log?.(`插件已解压到: ${pluginDir}`);
|
|
523
|
+
deps.log?.("步骤 2: 读取插件配置");
|
|
341
524
|
const packageJsonResult = readPluginPackageJson(pluginDir, {
|
|
342
525
|
existsSync: deps.existsSync,
|
|
343
526
|
readFileSync: deps.readFileSync,
|
|
344
527
|
join: deps.join,
|
|
345
|
-
parse: deps.parse
|
|
528
|
+
parse: deps.parse,
|
|
346
529
|
});
|
|
347
530
|
if (!packageJsonResult.success) {
|
|
348
531
|
return {
|
|
349
532
|
success: false,
|
|
350
533
|
error: packageJsonResult.error,
|
|
351
|
-
logs
|
|
534
|
+
logs: [],
|
|
352
535
|
};
|
|
353
536
|
}
|
|
354
537
|
const packageJson = packageJsonResult.packageJson;
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
538
|
+
deps.log?.(`插件名称: ${packageJson.name}`);
|
|
539
|
+
deps.log?.(`插件 ID: ${packageJson.id}`);
|
|
540
|
+
deps.log?.(`插件版本: ${packageJson.version}`);
|
|
541
|
+
deps.log?.("步骤 3: 提取 iOS 插件配置");
|
|
359
542
|
const configResult = extractIOSPluginConfig(packageJson);
|
|
360
543
|
if (!configResult.success) {
|
|
361
544
|
return {
|
|
362
545
|
success: false,
|
|
363
546
|
error: configResult.error,
|
|
364
|
-
logs
|
|
547
|
+
logs: [],
|
|
365
548
|
};
|
|
366
549
|
}
|
|
367
|
-
const { plugins: pluginItems, hooksClass, frameworks, embedFrameworks, resources, privacies, parameters: pluginParameters } = configResult;
|
|
368
|
-
|
|
550
|
+
const { plugins: pluginItems, hooksClass, frameworks, embedFrameworks, resources, privacies, parameters: pluginParameters, } = configResult;
|
|
551
|
+
deps.log?.(`找到 ${pluginItems.length} 个插件`);
|
|
369
552
|
if (hooksClass) {
|
|
370
|
-
|
|
553
|
+
deps.log?.(`Hooks 类: ${hooksClass}`);
|
|
371
554
|
}
|
|
372
|
-
|
|
373
|
-
const iosDir = deps.join(pluginDir,
|
|
555
|
+
deps.log?.("步骤 4: 复制插件文件");
|
|
556
|
+
const iosDir = deps.join(pluginDir, "ios");
|
|
557
|
+
deps.log?.(` iosDir: ${iosDir}`);
|
|
558
|
+
deps.log?.(` iosDir 存在: ${deps.existsSync(iosDir)}`);
|
|
374
559
|
if (!deps.existsSync(iosDir)) {
|
|
375
560
|
return {
|
|
376
561
|
success: false,
|
|
377
562
|
error: `插件 ios 目录不存在: ${iosDir}`,
|
|
378
|
-
logs
|
|
563
|
+
logs: [],
|
|
379
564
|
};
|
|
380
565
|
}
|
|
381
|
-
|
|
382
|
-
const
|
|
566
|
+
deps.log?.("步骤 4.1: 查找静态库 (.a)");
|
|
567
|
+
const findLibStartTime = Date.now();
|
|
568
|
+
const staticLibs = findFilesRecursive(iosDir, [".a"], deps);
|
|
569
|
+
const findLibTime = Date.now() - findLibStartTime;
|
|
570
|
+
deps.log?.(` 找到 ${staticLibs.length} 个静态库 (查找耗时: ${findLibTime}ms)`);
|
|
571
|
+
const libsDir = deps.join(projectPath, "libs");
|
|
383
572
|
if (!deps.existsSync(libsDir)) {
|
|
384
573
|
deps.mkdirSync(libsDir, { recursive: true });
|
|
385
574
|
}
|
|
@@ -387,44 +576,68 @@ export async function integrateNativePluginIOS(projectPath, projectName, pluginP
|
|
|
387
576
|
const libName = deps.basename(libPath);
|
|
388
577
|
const targetPath = deps.join(libsDir, libName);
|
|
389
578
|
deps.copyFileSync(libPath, targetPath);
|
|
390
|
-
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
const
|
|
579
|
+
deps.log?.(`已复制静态库: ${libName}`);
|
|
580
|
+
}
|
|
581
|
+
deps.log?.("步骤 4.2: 查找 framework");
|
|
582
|
+
deps.log?.(` 搜索目录: ${iosDir}`);
|
|
583
|
+
const findFrameworkStartTime = Date.now();
|
|
584
|
+
const allFrameworks = findFilesRecursive(iosDir, [".framework"], deps);
|
|
585
|
+
const findFrameworkTime = Date.now() - findFrameworkStartTime;
|
|
586
|
+
deps.log?.(`找到 ${allFrameworks.length} 个 framework (查找耗时: ${findFrameworkTime}ms)`);
|
|
587
|
+
const frameworksDir = deps.join(projectPath, "Frameworks");
|
|
397
588
|
if (!deps.existsSync(frameworksDir)) {
|
|
398
589
|
deps.mkdirSync(frameworksDir, { recursive: true });
|
|
399
590
|
}
|
|
400
|
-
for (const frameworkPath of
|
|
591
|
+
for (const frameworkPath of allFrameworks) {
|
|
401
592
|
const frameworkName = deps.basename(frameworkPath);
|
|
593
|
+
deps.log?.(`开始复制 framework: ${frameworkName}`);
|
|
402
594
|
const targetPath = deps.join(frameworksDir, frameworkName);
|
|
403
|
-
await
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
595
|
+
const copyResult = await copyFrameworkUsingArchive(frameworkPath, targetPath, {
|
|
596
|
+
existsSync: deps.existsSync,
|
|
597
|
+
readdirSync: deps.readdirSync,
|
|
598
|
+
join: deps.join,
|
|
599
|
+
dirname: deps.dirname,
|
|
600
|
+
exec: deps.exec,
|
|
601
|
+
basename: deps.basename,
|
|
602
|
+
mkdirSync: deps.mkdirSync,
|
|
603
|
+
copyFileSync: deps.copyFileSync,
|
|
604
|
+
}, deps.log);
|
|
605
|
+
if (copyResult.success) {
|
|
606
|
+
deps.log?.(`已复制 framework: ${frameworkName}`);
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
deps.log?.(`警告: 复制 framework 失败 (${frameworkName}): ${copyResult.error}`);
|
|
417
610
|
}
|
|
418
611
|
}
|
|
419
|
-
|
|
612
|
+
deps.log?.("步骤 4.4: 查找 xcframework");
|
|
613
|
+
const findXcframeworkStartTime = Date.now();
|
|
614
|
+
const xcframeworks = findFilesRecursive(iosDir, [".xcframework"], deps);
|
|
615
|
+
const findXcframeworkTime = Date.now() - findXcframeworkStartTime;
|
|
616
|
+
deps.log?.(` 找到 ${xcframeworks.length} 个 xcframework (查找耗时: ${findXcframeworkTime}ms)`);
|
|
420
617
|
for (const xcframeworkPath of xcframeworks) {
|
|
421
618
|
const xcframeworkName = deps.basename(xcframeworkPath);
|
|
422
619
|
const targetPath = deps.join(frameworksDir, xcframeworkName);
|
|
423
|
-
|
|
424
|
-
|
|
620
|
+
deps.log?.(`开始复制 xcframework: ${xcframeworkName}`);
|
|
621
|
+
const copyResult = await copyFrameworkUsingArchive(xcframeworkPath, targetPath, {
|
|
622
|
+
existsSync: deps.existsSync,
|
|
623
|
+
readdirSync: deps.readdirSync,
|
|
624
|
+
join: deps.join,
|
|
625
|
+
dirname: deps.dirname,
|
|
626
|
+
exec: deps.exec,
|
|
627
|
+
basename: deps.basename,
|
|
628
|
+
mkdirSync: deps.mkdirSync,
|
|
629
|
+
copyFileSync: deps.copyFileSync,
|
|
630
|
+
}, deps.log);
|
|
631
|
+
if (copyResult.success) {
|
|
632
|
+
deps.log?.(`已复制 xcframework: ${xcframeworkName}`);
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
deps.log?.(`警告: 复制 xcframework 失败 (${xcframeworkName}): ${copyResult.error}`);
|
|
636
|
+
}
|
|
425
637
|
}
|
|
638
|
+
deps.log?.("步骤 4.5: 复制资源文件");
|
|
426
639
|
if (resources && resources.length > 0) {
|
|
427
|
-
const resourcesTargetDir = deps.join(projectPath, projectName,
|
|
640
|
+
const resourcesTargetDir = deps.join(projectPath, projectName, "Resources");
|
|
428
641
|
if (!deps.existsSync(resourcesTargetDir)) {
|
|
429
642
|
deps.mkdirSync(resourcesTargetDir, { recursive: true });
|
|
430
643
|
}
|
|
@@ -435,20 +648,27 @@ export async function integrateNativePluginIOS(projectPath, projectName, pluginP
|
|
|
435
648
|
const targetPath = deps.join(resourcesTargetDir, resourceName);
|
|
436
649
|
const stat = deps.statSync(sourcePath);
|
|
437
650
|
if (stat.isDirectory()) {
|
|
438
|
-
await deps.cp(sourcePath, targetPath, {
|
|
651
|
+
await deps.cp(sourcePath, targetPath, {
|
|
652
|
+
recursive: true,
|
|
653
|
+
force: true,
|
|
654
|
+
});
|
|
439
655
|
}
|
|
440
656
|
else {
|
|
441
657
|
deps.copyFileSync(sourcePath, targetPath);
|
|
442
658
|
}
|
|
443
|
-
|
|
659
|
+
deps.log?.(`已复制资源文件: ${resourceName}`);
|
|
444
660
|
}
|
|
445
661
|
else {
|
|
446
|
-
|
|
662
|
+
deps.log?.(`警告: 资源文件不存在: ${sourcePath}`);
|
|
447
663
|
}
|
|
448
664
|
}
|
|
449
665
|
}
|
|
450
|
-
|
|
451
|
-
const
|
|
666
|
+
deps.log?.("步骤 4.6: 查找头文件 (.h)");
|
|
667
|
+
const findHeaderStartTime = Date.now();
|
|
668
|
+
const headers = findFilesRecursive(iosDir, [".h"], deps);
|
|
669
|
+
const findHeaderTime = Date.now() - findHeaderStartTime;
|
|
670
|
+
deps.log?.(` 找到 ${headers.length} 个头文件 (查找耗时: ${findHeaderTime}ms)`);
|
|
671
|
+
const headersDir = deps.join(projectPath, projectName, "NativePlugins");
|
|
452
672
|
if (headers.length > 0) {
|
|
453
673
|
if (!deps.existsSync(headersDir)) {
|
|
454
674
|
deps.mkdirSync(headersDir, { recursive: true });
|
|
@@ -457,140 +677,274 @@ export async function integrateNativePluginIOS(projectPath, projectName, pluginP
|
|
|
457
677
|
const headerName = deps.basename(headerPath);
|
|
458
678
|
const targetPath = deps.join(headersDir, headerName);
|
|
459
679
|
deps.copyFileSync(headerPath, targetPath);
|
|
460
|
-
|
|
680
|
+
deps.log?.(`已复制头文件: ${headerName}`);
|
|
461
681
|
}
|
|
462
682
|
}
|
|
463
|
-
|
|
683
|
+
deps.log?.("步骤 5: 修改 Info.plist");
|
|
464
684
|
const infoPlistPath = deps.join(projectPath, projectName, `${projectName}-Info.plist`);
|
|
465
685
|
if (deps.existsSync(infoPlistPath)) {
|
|
466
686
|
try {
|
|
467
|
-
const xmlContent = deps.readFileSync(infoPlistPath,
|
|
687
|
+
const xmlContent = deps.readFileSync(infoPlistPath, "utf8");
|
|
468
688
|
const parser = new deps.xmlParser();
|
|
469
|
-
const xmlDoc = parser.parseFromString(xmlContent,
|
|
470
|
-
addPluginToInfoPlist(xmlDoc, pluginItems, hooksClass ||
|
|
471
|
-
|
|
689
|
+
const xmlDoc = parser.parseFromString(xmlContent, "text/xml");
|
|
690
|
+
addPluginToInfoPlist(xmlDoc, pluginItems, hooksClass || "");
|
|
691
|
+
deps.log?.("已添加插件信息到 dcloud_uniplugins");
|
|
472
692
|
if (privacies && privacies.length > 0) {
|
|
473
693
|
addPrivaciesToInfoPlist(xmlDoc, privacies);
|
|
474
|
-
|
|
694
|
+
deps.log?.(`已添加 ${privacies.length} 个隐私权限描述`);
|
|
475
695
|
}
|
|
476
696
|
if (pluginParameters && parameters) {
|
|
477
697
|
addPluginParametersToInfoPlist(xmlDoc, pluginParameters, parameters);
|
|
478
|
-
|
|
698
|
+
deps.log?.("已添加插件参数配置");
|
|
479
699
|
}
|
|
480
700
|
const serializer = new deps.xmlSerializer();
|
|
481
701
|
const newXmlContent = serializer.serializeToString(xmlDoc);
|
|
482
|
-
deps.writeFileSync(infoPlistPath, newXmlContent,
|
|
483
|
-
|
|
702
|
+
deps.writeFileSync(infoPlistPath, newXmlContent, "utf8");
|
|
703
|
+
deps.log?.("Info.plist 修改完成");
|
|
484
704
|
}
|
|
485
705
|
catch (error) {
|
|
486
|
-
|
|
706
|
+
deps.log?.(`修改 Info.plist 失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
487
707
|
}
|
|
488
708
|
}
|
|
489
|
-
|
|
490
|
-
const projectFiles = deps
|
|
709
|
+
deps.log?.("步骤 6: 添加文件到 Xcode 项目");
|
|
710
|
+
const projectFiles = deps
|
|
711
|
+
.readdirSync(projectPath)
|
|
712
|
+
.filter((file) => file.endsWith(".xcodeproj"));
|
|
491
713
|
if (projectFiles.length === 0) {
|
|
492
|
-
|
|
714
|
+
deps.log?.("警告: 未找到 .xcodeproj 文件,跳过 Xcode 项目配置");
|
|
493
715
|
}
|
|
494
716
|
else {
|
|
495
717
|
const projectFile = projectFiles[0];
|
|
496
|
-
const projectPbxprojPath = deps.join(projectPath, projectFile,
|
|
718
|
+
const projectPbxprojPath = deps.join(projectPath, projectFile, "project.pbxproj");
|
|
497
719
|
for (const libPath of staticLibs) {
|
|
498
720
|
const libName = deps.basename(libPath);
|
|
499
721
|
const relativePath = `libs/${libName}`;
|
|
500
|
-
const addResult = addFileToXcodeProject(projectPbxprojPath, relativePath,
|
|
722
|
+
const addResult = addFileToXcodeProject(projectPbxprojPath, relativePath, "staticLibrary", {
|
|
501
723
|
existsSync: deps.existsSync,
|
|
502
724
|
readFileSync: deps.readFileSync,
|
|
503
|
-
writeFileSync: deps.writeFileSync
|
|
725
|
+
writeFileSync: deps.writeFileSync,
|
|
504
726
|
});
|
|
505
727
|
if (addResult.success) {
|
|
506
|
-
|
|
728
|
+
deps.log?.(`已添加到 Xcode 项目: ${libName}`);
|
|
507
729
|
}
|
|
508
730
|
else {
|
|
509
|
-
|
|
731
|
+
deps.log?.(`警告: 添加到 Xcode 项目失败: ${addResult.error}`);
|
|
510
732
|
}
|
|
511
733
|
}
|
|
512
|
-
for (const frameworkPath of
|
|
734
|
+
for (const frameworkPath of allFrameworks) {
|
|
513
735
|
const frameworkName = deps.basename(frameworkPath);
|
|
514
736
|
const relativePath = `Frameworks/${frameworkName}`;
|
|
515
|
-
const addResult = addFileToXcodeProject(projectPbxprojPath, relativePath,
|
|
737
|
+
const addResult = addFileToXcodeProject(projectPbxprojPath, relativePath, "framework", {
|
|
516
738
|
existsSync: deps.existsSync,
|
|
517
739
|
readFileSync: deps.readFileSync,
|
|
518
|
-
writeFileSync: deps.writeFileSync
|
|
740
|
+
writeFileSync: deps.writeFileSync,
|
|
519
741
|
});
|
|
520
742
|
if (addResult.success) {
|
|
521
|
-
|
|
743
|
+
deps.log?.(`已添加到 Xcode 项目: ${frameworkName}`);
|
|
522
744
|
}
|
|
523
745
|
else {
|
|
524
|
-
|
|
746
|
+
deps.log?.(`警告: 添加到 Xcode 项目失败: ${addResult.error}`);
|
|
525
747
|
}
|
|
526
748
|
}
|
|
527
749
|
for (const xcframeworkPath of xcframeworks) {
|
|
528
750
|
const xcframeworkName = deps.basename(xcframeworkPath);
|
|
529
751
|
const relativePath = `Frameworks/${xcframeworkName}`;
|
|
530
|
-
const addResult = addFileToXcodeProject(projectPbxprojPath, relativePath,
|
|
752
|
+
const addResult = addFileToXcodeProject(projectPbxprojPath, relativePath, "framework", {
|
|
531
753
|
existsSync: deps.existsSync,
|
|
532
754
|
readFileSync: deps.readFileSync,
|
|
533
|
-
writeFileSync: deps.writeFileSync
|
|
755
|
+
writeFileSync: deps.writeFileSync,
|
|
534
756
|
});
|
|
535
757
|
if (addResult.success) {
|
|
536
|
-
|
|
758
|
+
deps.log?.(`已添加到 Xcode 项目: ${xcframeworkName}`);
|
|
537
759
|
}
|
|
538
760
|
else {
|
|
539
|
-
|
|
761
|
+
deps.log?.(`警告: 添加到 Xcode 项目失败: ${addResult.error}`);
|
|
540
762
|
}
|
|
541
763
|
}
|
|
542
764
|
if (resources && resources.length > 0) {
|
|
543
765
|
for (const resourcePath of resources) {
|
|
544
766
|
const resourceName = deps.basename(resourcePath);
|
|
545
767
|
const relativePath = `${projectName}/Resources/${resourceName}`;
|
|
546
|
-
const addResult = addFileToXcodeProject(projectPbxprojPath, relativePath,
|
|
768
|
+
const addResult = addFileToXcodeProject(projectPbxprojPath, relativePath, "bundle", {
|
|
547
769
|
existsSync: deps.existsSync,
|
|
548
770
|
readFileSync: deps.readFileSync,
|
|
549
|
-
writeFileSync: deps.writeFileSync
|
|
771
|
+
writeFileSync: deps.writeFileSync,
|
|
550
772
|
});
|
|
551
773
|
if (addResult.success) {
|
|
552
|
-
|
|
774
|
+
deps.log?.(`已添加资源到 Xcode 项目: ${resourceName}`);
|
|
553
775
|
}
|
|
554
776
|
else {
|
|
555
|
-
|
|
777
|
+
deps.log?.(`警告: 添加资源到 Xcode 项目失败: ${addResult.error}`);
|
|
556
778
|
}
|
|
557
779
|
}
|
|
558
780
|
}
|
|
559
|
-
if (
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
781
|
+
if (frameworks && frameworks.length > 0) {
|
|
782
|
+
deps.log?.("注意: 系统库需要手动在 Xcode 中添加到 Link Binary With Libraries:");
|
|
783
|
+
for (const framework of frameworks) {
|
|
784
|
+
deps.log?.(` - ${framework}`);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
deps.log?.("步骤 6.8: 检查插件依赖");
|
|
788
|
+
const pluginFrameworkDir = deps.join(pluginDir, "ios");
|
|
789
|
+
if (deps.existsSync(pluginFrameworkDir)) {
|
|
790
|
+
try {
|
|
791
|
+
const frameworkFiles = findFilesRecursive(pluginFrameworkDir, [".m", ".mm", ".swift"], deps);
|
|
792
|
+
let hasSVGKitImport = false;
|
|
793
|
+
for (const file of frameworkFiles) {
|
|
794
|
+
try {
|
|
795
|
+
const content = deps.readFileSync(file, "utf8");
|
|
796
|
+
if (content.includes("SVGKit") || content.includes("SVGKImage")) {
|
|
797
|
+
hasSVGKitImport = true;
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
catch {
|
|
802
|
+
}
|
|
569
803
|
}
|
|
570
|
-
|
|
571
|
-
|
|
804
|
+
if (hasSVGKitImport) {
|
|
805
|
+
deps.log?.("⚠️ 警告: 插件使用了 SVGKit 库,但主项目中可能未包含该库");
|
|
806
|
+
deps.log?.(" 解决方案 1: 在主项目中使用 CocoaPods 安装 SVGKit");
|
|
807
|
+
deps.log?.(' 1. 在主项目根目录创建 Podfile,添加: pod "SVGKit", "~> 3.0"');
|
|
808
|
+
deps.log?.(" 2. 运行: pod install");
|
|
809
|
+
deps.log?.(" 3. 使用 .xcworkspace 打开项目");
|
|
810
|
+
deps.log?.(" 解决方案 2: 手动下载 SVGKit.framework 并添加到项目中");
|
|
811
|
+
deps.log?.(" 解决方案 3: 如果不需要 SVG 支持,可以移除插件中的 SVG 相关代码");
|
|
572
812
|
}
|
|
573
813
|
}
|
|
814
|
+
catch (error) {
|
|
815
|
+
}
|
|
574
816
|
}
|
|
575
|
-
if (
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
817
|
+
if (allFrameworks.length > 0 ||
|
|
818
|
+
xcframeworks.length > 0) {
|
|
819
|
+
deps.log?.("步骤 6.7: 更新 FRAMEWORK_SEARCH_PATHS");
|
|
820
|
+
try {
|
|
821
|
+
let content = deps.readFileSync(projectPbxprojPath, "utf8");
|
|
822
|
+
const frameworksSearchPath = '"$(PROJECT_DIR)/Frameworks"';
|
|
823
|
+
let modified = false;
|
|
824
|
+
const frameworkSearchPathsRegex = /(FRAMEWORK_SEARCH_PATHS\s*=\s*\()([\s\S]*?)(\t+\);)/g;
|
|
825
|
+
const matches = [];
|
|
826
|
+
let match;
|
|
827
|
+
while ((match = frameworkSearchPathsRegex.exec(content)) !== null) {
|
|
828
|
+
matches.push({
|
|
829
|
+
full: match[0],
|
|
830
|
+
start: match[1],
|
|
831
|
+
middle: match[2],
|
|
832
|
+
end: match[3],
|
|
833
|
+
index: match.index
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
for (let i = matches.length - 1; i >= 0; i--) {
|
|
837
|
+
const m = matches[i];
|
|
838
|
+
const currentPaths = m.middle.trim();
|
|
839
|
+
if (!currentPaths.includes("Frameworks") &&
|
|
840
|
+
!currentPaths.includes(frameworksSearchPath)) {
|
|
841
|
+
const indent = m.end.match(/^\t+/)?.[0] || '\t\t\t\t';
|
|
842
|
+
const newPathEntry = `${indent}${frameworksSearchPath},\n`;
|
|
843
|
+
const newMiddle = currentPaths
|
|
844
|
+
? `${currentPaths}\n${newPathEntry}`
|
|
845
|
+
: newPathEntry;
|
|
846
|
+
const newContent = `${m.start}${newMiddle}${m.end}`;
|
|
847
|
+
const before = content.substring(0, m.index);
|
|
848
|
+
const after = content.substring(m.index + m.full.length);
|
|
849
|
+
content = before + newContent + after;
|
|
850
|
+
modified = true;
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
if (modified) {
|
|
854
|
+
deps.writeFileSync(projectPbxprojPath, content, "utf8");
|
|
855
|
+
deps.log?.(`已添加 Frameworks 目录到所有 FRAMEWORK_SEARCH_PATHS 配置`);
|
|
856
|
+
}
|
|
857
|
+
else {
|
|
858
|
+
deps.log?.(`所有 FRAMEWORK_SEARCH_PATHS 已包含 Frameworks 目录`);
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
catch (error) {
|
|
862
|
+
deps.log?.(`警告: 更新 FRAMEWORK_SEARCH_PATHS 失败: ${error instanceof Error ? error.message : String(error)}`);
|
|
579
863
|
}
|
|
580
864
|
}
|
|
581
865
|
}
|
|
866
|
+
deps.log?.("步骤 7: 清理临时文件");
|
|
867
|
+
try {
|
|
868
|
+
deps.log?.(` 检查临时目录: ${tempDir}`);
|
|
869
|
+
if (deps.existsSync(tempDir)) {
|
|
870
|
+
deps.log?.(` 开始清理临时目录: ${tempDir}`);
|
|
871
|
+
await new Promise((resolve) => {
|
|
872
|
+
const timeout = deps.setTimeout(() => {
|
|
873
|
+
deps.log?.(`警告: 清理临时目录超时: ${tempDir}`);
|
|
874
|
+
resolve();
|
|
875
|
+
}, 5000);
|
|
876
|
+
deps.exec(`rm -rf "${tempDir}"`, (error) => {
|
|
877
|
+
deps.clearTimeout(timeout);
|
|
878
|
+
if (error) {
|
|
879
|
+
deps.log?.(`警告: 清理临时目录失败: ${tempDir} (${error.message})`);
|
|
880
|
+
}
|
|
881
|
+
else {
|
|
882
|
+
deps.log?.(`✓ 已清理临时目录: ${tempDir}`);
|
|
883
|
+
}
|
|
884
|
+
resolve();
|
|
885
|
+
});
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
else {
|
|
889
|
+
deps.log?.(` 临时目录不存在,跳过清理: ${tempDir}`);
|
|
890
|
+
}
|
|
891
|
+
const frameworksDir = deps.join(projectPath, "Frameworks");
|
|
892
|
+
const frameworkTempDir = deps.join(frameworksDir, ".temp_framework_copy");
|
|
893
|
+
deps.log?.(` 检查 framework 临时目录: ${frameworkTempDir}`);
|
|
894
|
+
if (deps.existsSync(frameworkTempDir)) {
|
|
895
|
+
deps.log?.(` 开始清理 framework 临时目录: ${frameworkTempDir}`);
|
|
896
|
+
await new Promise((resolve) => {
|
|
897
|
+
const timeout = deps.setTimeout(() => {
|
|
898
|
+
deps.log?.(`警告: 清理 framework 临时目录超时: ${frameworkTempDir}`);
|
|
899
|
+
resolve();
|
|
900
|
+
}, 5000);
|
|
901
|
+
deps.exec(`rm -rf "${frameworkTempDir}"`, (error) => {
|
|
902
|
+
deps.clearTimeout(timeout);
|
|
903
|
+
if (error) {
|
|
904
|
+
deps.log?.(`警告: 清理 framework 临时目录失败: ${frameworkTempDir} (${error.message})`);
|
|
905
|
+
}
|
|
906
|
+
else {
|
|
907
|
+
deps.log?.(`✓ 已清理 framework 临时目录: ${frameworkTempDir}`);
|
|
908
|
+
}
|
|
909
|
+
resolve();
|
|
910
|
+
});
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
else {
|
|
914
|
+
deps.log?.(` framework 临时目录不存在,跳过清理: ${frameworkTempDir}`);
|
|
915
|
+
}
|
|
916
|
+
deps.log?.("✓ 清理临时文件完成");
|
|
917
|
+
}
|
|
918
|
+
catch (cleanupError) {
|
|
919
|
+
deps.log?.(`警告: 清理临时文件时出错: ${cleanupError instanceof Error
|
|
920
|
+
? cleanupError.message
|
|
921
|
+
: String(cleanupError)}`);
|
|
922
|
+
}
|
|
923
|
+
deps.log?.("原生插件集成完成");
|
|
582
924
|
return {
|
|
583
925
|
success: true,
|
|
584
|
-
message:
|
|
585
|
-
logs
|
|
926
|
+
message: "原生插件集成成功",
|
|
927
|
+
logs: [],
|
|
586
928
|
};
|
|
587
929
|
}
|
|
588
930
|
catch (error) {
|
|
589
|
-
|
|
931
|
+
deps.log?.(`原生插件集成异常: ${error instanceof Error ? error.message : String(error)}`);
|
|
932
|
+
try {
|
|
933
|
+
const tempDir = deps.join(projectPath, ".temp");
|
|
934
|
+
if (deps.existsSync(tempDir)) {
|
|
935
|
+
deps.exec(`rm -rf "${tempDir}"`, () => { });
|
|
936
|
+
}
|
|
937
|
+
const frameworksDir = deps.join(projectPath, "Frameworks");
|
|
938
|
+
const frameworkTempDir = deps.join(frameworksDir, ".temp_framework_copy");
|
|
939
|
+
if (deps.existsSync(frameworkTempDir)) {
|
|
940
|
+
deps.exec(`rm -rf "${frameworkTempDir}"`, () => { });
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
catch { }
|
|
590
944
|
return {
|
|
591
945
|
success: false,
|
|
592
946
|
error: `原生插件集成异常: ${error instanceof Error ? error.message : String(error)}`,
|
|
593
|
-
logs
|
|
947
|
+
logs: [],
|
|
594
948
|
};
|
|
595
949
|
}
|
|
596
950
|
}
|