@leonxin/meetgames 0.1.11 → 0.1.13
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/README.md +9 -9
- package/dist/cache.d.ts +44 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +101 -0
- package/dist/cache.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +43 -37
- package/dist/cli.js.map +1 -1
- package/dist/config/meetSdkDefaultConfig.d.ts +1 -1
- package/dist/config/meetSdkDefaultConfig.d.ts.map +1 -1
- package/dist/config/meetSdkDefaultConfig.js +4 -3
- package/dist/config/meetSdkDefaultConfig.js.map +1 -1
- package/dist/config/meetSdkIosConfig.d.ts.map +1 -1
- package/dist/config/meetSdkIosConfig.js +3 -1
- package/dist/config/meetSdkIosConfig.js.map +1 -1
- package/dist/config/meetSdkRemoteConfig.d.ts +1 -0
- package/dist/config/meetSdkRemoteConfig.d.ts.map +1 -1
- package/dist/config/meetSdkRemoteConfig.js +4 -1
- package/dist/config/meetSdkRemoteConfig.js.map +1 -1
- package/dist/contracts/types.d.ts +11 -0
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/core/doctor.js +7 -7
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/pipeline.d.ts.map +1 -1
- package/dist/core/pipeline.js +3 -0
- package/dist/core/pipeline.js.map +1 -1
- package/dist/core/previewPatches.d.ts +1 -1
- package/dist/core/previewPatches.js +2 -2
- package/dist/core/previewPatches.js.map +1 -1
- package/dist/core/reporter.d.ts.map +1 -1
- package/dist/core/reporter.js +4 -0
- package/dist/core/reporter.js.map +1 -1
- package/dist/core/workspace.d.ts.map +1 -1
- package/dist/core/workspace.js +2 -0
- package/dist/core/workspace.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/ios/channelConfig.js +1 -1
- package/dist/ios/channelConfig.js.map +1 -1
- package/dist/ios/codeUtils.d.ts +1 -0
- package/dist/ios/codeUtils.d.ts.map +1 -1
- package/dist/ios/codeUtils.js +3 -0
- package/dist/ios/codeUtils.js.map +1 -1
- package/dist/ios/integrate.d.ts.map +1 -1
- package/dist/ios/integrate.js +97 -23
- package/dist/ios/integrate.js.map +1 -1
- package/dist/ios/pbxprojEditor.d.ts.map +1 -1
- package/dist/ios/pbxprojEditor.js +123 -6
- package/dist/ios/pbxprojEditor.js.map +1 -1
- package/dist/ios/sdkBundle.d.ts +1 -6
- package/dist/ios/sdkBundle.d.ts.map +1 -1
- package/dist/ios/sdkBundle.js +44 -16
- package/dist/ios/sdkBundle.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +12 -6
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/service.d.ts +3 -0
- package/dist/mcp/service.d.ts.map +1 -1
- package/dist/mcp/service.js +31 -8
- package/dist/mcp/service.js.map +1 -1
- package/dist/ops/handlers.d.ts.map +1 -1
- package/dist/ops/handlers.js +24 -19
- package/dist/ops/handlers.js.map +1 -1
- package/dist/remote/sdkHomeDownload.d.ts +1 -1
- package/dist/remote/sdkHomeDownload.d.ts.map +1 -1
- package/dist/remote/sdkHomeDownload.js +27 -6
- package/dist/remote/sdkHomeDownload.js.map +1 -1
- package/docs/API.md +16 -16
- package/docs/CLI.md +21 -22
- package/docs/INTEGRATION.md +30 -11
- package/docs/MCP.md +1 -1
- package/docs/README.md +0 -1
- package/docs/archive/api/downloadSDKConfig.md +2 -2
- package/docs/archive/api/getChannelConfig-meetgames.md +1 -1
- package/docs/archive/product//351/234/200/346/261/202/346/226/207/346/241/243.md +1 -1
- package/package.json +2 -5
- package/recipes/android-default.yaml +0 -5
- package/recipes/integrate-default.yaml +0 -5
- package/src/cache.ts +164 -0
- package/src/cli.ts +46 -38
- package/src/config/meetSdkDefaultConfig.ts +4 -3
- package/src/config/meetSdkIosConfig.ts +3 -1
- package/src/config/meetSdkRemoteConfig.ts +5 -1
- package/src/contracts/types.ts +11 -0
- package/src/core/doctor.ts +7 -7
- package/src/core/pipeline.ts +3 -0
- package/src/core/previewPatches.ts +2 -2
- package/src/core/reporter.ts +3 -0
- package/src/core/workspace.ts +2 -0
- package/src/index.ts +7 -0
- package/src/ios/channelConfig.ts +1 -1
- package/src/ios/codeUtils.ts +4 -0
- package/src/ios/integrate.ts +110 -27
- package/src/ios/pbxprojEditor.ts +121 -4
- package/src/ios/sdkBundle.ts +41 -18
- package/src/mcp/server.ts +12 -6
- package/src/mcp/service.ts +39 -8
- package/src/ops/handlers.ts +23 -19
- package/src/remote/sdkHomeDownload.ts +28 -7
- package/tests/doctor.test.ts +4 -2
- package/tests/{test-projects-hosts.test.ts → fixtures-hosts.test.ts} +2 -2
- package/tests/ios.sdkBundle.test.ts +10 -5
- package/tests/mcp.e2e.ts +2 -5
- package/tests/meetSdkRemoteConfig.test.ts +25 -0
- package/tests/pipeline.android.test.ts +1 -2
- package/tests/pipeline.ios.test.ts +133 -20
- package/tests/pipeline.preview.patch.test.ts +2 -2
- package/tests/sdkVersionConfig.test.ts +3 -2
- package/dist/aab-converter/aab-entry.d.ts +0 -3
- package/dist/aab-converter/aab-entry.d.ts.map +0 -1
- package/dist/aab-converter/aab-entry.js +0 -49
- package/dist/aab-converter/aab-entry.js.map +0 -1
- package/dist/aab-converter/apksExtractor.d.ts +0 -2
- package/dist/aab-converter/apksExtractor.d.ts.map +0 -1
- package/dist/aab-converter/apksExtractor.js +0 -108
- package/dist/aab-converter/apksExtractor.js.map +0 -1
- package/dist/aab-converter/bundletoolRunner.d.ts +0 -15
- package/dist/aab-converter/bundletoolRunner.d.ts.map +0 -1
- package/dist/aab-converter/bundletoolRunner.js +0 -46
- package/dist/aab-converter/bundletoolRunner.js.map +0 -1
- package/dist/aab-converter/cliArgs.d.ts +0 -27
- package/dist/aab-converter/cliArgs.d.ts.map +0 -1
- package/dist/aab-converter/cliArgs.js +0 -170
- package/dist/aab-converter/cliArgs.js.map +0 -1
- package/dist/aab-converter/convertAabToApk.d.ts +0 -7
- package/dist/aab-converter/convertAabToApk.d.ts.map +0 -1
- package/dist/aab-converter/convertAabToApk.js +0 -69
- package/dist/aab-converter/convertAabToApk.js.map +0 -1
- package/dist/aab-converter/resourcePaths.d.ts +0 -4
- package/dist/aab-converter/resourcePaths.d.ts.map +0 -1
- package/dist/aab-converter/resourcePaths.js +0 -42
- package/dist/aab-converter/resourcePaths.js.map +0 -1
- package/dist/aab-converter/signingOptions.d.ts +0 -9
- package/dist/aab-converter/signingOptions.d.ts.map +0 -1
- package/dist/aab-converter/signingOptions.js +0 -21
- package/dist/aab-converter/signingOptions.js.map +0 -1
- package/dist/aab-converter/types.d.ts +0 -24
- package/dist/aab-converter/types.d.ts.map +0 -1
- package/dist/aab-converter/types.js +0 -2
- package/dist/aab-converter/types.js.map +0 -1
- package/dist/shared/fileUtils.d.ts +0 -5
- package/dist/shared/fileUtils.d.ts.map +0 -1
- package/dist/shared/fileUtils.js +0 -35
- package/dist/shared/fileUtils.js.map +0 -1
- package/dist/shared/logger.d.ts +0 -10
- package/dist/shared/logger.d.ts.map +0 -1
- package/dist/shared/logger.js +0 -37
- package/dist/shared/logger.js.map +0 -1
- package/dist/shared/pathUtils.d.ts +0 -4
- package/dist/shared/pathUtils.d.ts.map +0 -1
- package/dist/shared/pathUtils.js +0 -22
- package/dist/shared/pathUtils.js.map +0 -1
- package/dist/shared/processRunner.d.ts +0 -12
- package/dist/shared/processRunner.d.ts.map +0 -1
- package/dist/shared/processRunner.js +0 -31
- package/dist/shared/processRunner.js.map +0 -1
- package/docs/AAB_CONVERTER_CLI_PLAN.md +0 -392
- package/logs/convert-20260622-155037.log +0 -5
- package/logs/convert-20260622-155226.log +0 -6
- package/scripts/package-aab-cli-win.mjs +0 -193
- package/src/aab-converter/aab-entry.ts +0 -48
- package/src/aab-converter/apksExtractor.ts +0 -119
- package/src/aab-converter/bundletoolRunner.ts +0 -63
- package/src/aab-converter/cliArgs.ts +0 -194
- package/src/aab-converter/convertAabToApk.ts +0 -81
- package/src/aab-converter/resourcePaths.ts +0 -43
- package/src/aab-converter/signingOptions.ts +0 -29
- package/src/aab-converter/types.ts +0 -26
- package/src/shared/fileUtils.ts +0 -41
- package/src/shared/logger.ts +0 -49
- package/src/shared/pathUtils.ts +0 -24
- package/src/shared/processRunner.ts +0 -43
- package/test-projects/README.md +0 -51
- package/test-projects/_preview/pipeline.patch +0 -281
- package/tests/aab-converter.test.ts +0 -213
- /package/{meetsdk-android.json → config/meetsdk-android.json} +0 -0
- /package/{meetsdk-ios.json → config/meetsdk-ios.json} +0 -0
package/src/core/workspace.ts
CHANGED
|
@@ -22,6 +22,8 @@ export function buildWorkspaceContext(
|
|
|
22
22
|
projectRoot: root,
|
|
23
23
|
packageRoot: pkg,
|
|
24
24
|
sdkHomeApiBaseUrl: options.sdkHomeApiBaseUrl,
|
|
25
|
+
remoteConfigPath: options.remoteConfigPath,
|
|
26
|
+
iosSdkRoot: options.iosSdkRoot,
|
|
25
27
|
android: detectAndroid(root, { appTarget: options.appTarget }),
|
|
26
28
|
ios: detectIOS(root, { appTarget: options.appTarget }),
|
|
27
29
|
iosReserved: iosToolingReserved,
|
package/src/index.ts
CHANGED
|
@@ -80,6 +80,13 @@ export {
|
|
|
80
80
|
isTopSdkFeatureModuleEnabled,
|
|
81
81
|
} from "./config/topsdkFeatureModules.js";
|
|
82
82
|
export { clearPreviewPatchFilesIfTargetInside, resolveDefaultPreviewPatchDir } from "./core/previewPatches.js";
|
|
83
|
+
export {
|
|
84
|
+
MEET_SDK_TOOL_CACHE_ROOT,
|
|
85
|
+
ensureCacheRoot,
|
|
86
|
+
resolveIosSdkCacheLayout,
|
|
87
|
+
resolveRemoteConfigCachePath,
|
|
88
|
+
writeRemoteConfigCache,
|
|
89
|
+
} from "./cache.js";
|
|
83
90
|
export { buildWorkspaceContext, resolvePackageRoot } from "./core/workspace.js";
|
|
84
91
|
export { runPipeline } from "./core/pipeline.js";
|
|
85
92
|
export { generatePatchForFile } from "./core/patch.js";
|
package/src/ios/channelConfig.ts
CHANGED
|
@@ -101,7 +101,7 @@ export const IOS_PLUGIN_FOLDER_BY_SUBKEY: Record<string, string> = {
|
|
|
101
101
|
};
|
|
102
102
|
|
|
103
103
|
export function enabledIosPluginFolders(config: MeetSdkRemoteConfig): string[] {
|
|
104
|
-
const folders: string[] = [];
|
|
104
|
+
const folders: string[] = ["UI"];
|
|
105
105
|
for (const [scope, bucket] of Object.entries(config.sdkModules)) {
|
|
106
106
|
if (!bucket || typeof bucket !== "object") continue;
|
|
107
107
|
const scopeRecord = bucket as Record<string, unknown>;
|
package/src/ios/codeUtils.ts
CHANGED
|
@@ -19,6 +19,10 @@ export class CodeUtils {
|
|
|
19
19
|
return norm(this.content).includes(norm(code));
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
hasCode(code: string): boolean {
|
|
23
|
+
return this.checkExisted(code);
|
|
24
|
+
}
|
|
25
|
+
|
|
22
26
|
addHeader(code: string): boolean {
|
|
23
27
|
if (this.checkExisted(code)) return true;
|
|
24
28
|
this.content = `${code}\n${this.content}`;
|
package/src/ios/integrate.ts
CHANGED
|
@@ -50,12 +50,12 @@ export interface IosIntegrateOptions {
|
|
|
50
50
|
|
|
51
51
|
const IOS_FIREBASE_CONFIG_FILE = "GoogleService-Info.plist";
|
|
52
52
|
|
|
53
|
-
function ok(changed: string[], warnings: string[] = []): StepResult {
|
|
54
|
-
return { ok: true, changedFiles: changed, warnings, errors: [] };
|
|
53
|
+
function ok(changed: string[], warnings: string[] = [], logs: string[] = []): StepResult {
|
|
54
|
+
return { ok: true, changedFiles: changed, logs, warnings, errors: [] };
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
function fail(errors: string[], warnings: string[] = []): StepResult {
|
|
58
|
-
return { ok: false, changedFiles: [], warnings, errors };
|
|
57
|
+
function fail(errors: string[], warnings: string[] = [], logs: string[] = []): StepResult {
|
|
58
|
+
return { ok: false, changedFiles: [], logs, warnings, errors };
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
function applyPlugin(
|
|
@@ -66,15 +66,19 @@ function applyPlugin(
|
|
|
66
66
|
perform: readonly PerformSetting[],
|
|
67
67
|
binaryCopies: BinaryCopy[],
|
|
68
68
|
dryRun: boolean,
|
|
69
|
+
logs: string[],
|
|
69
70
|
remoteSources: Map<string, string> = new Map()
|
|
70
71
|
): void {
|
|
71
72
|
const { config, sourceDir } = loaded;
|
|
72
73
|
const srcRoot = pbx.srcRoot;
|
|
73
74
|
|
|
75
|
+
logs.push(`- 插件:${config.name}, 类型:${config.type},版本:${config.pluginVersion}`);
|
|
76
|
+
|
|
74
77
|
if (perform.includes("frameworks") && config.frameworks?.length) {
|
|
75
78
|
for (const fw of config.frameworks) {
|
|
76
79
|
if (fw.system) {
|
|
77
80
|
addSystemFramework(pbx, fw.name);
|
|
81
|
+
logs.push(`SUCCESS: 导入系统依赖framework ${fw.name} 完成`);
|
|
78
82
|
continue;
|
|
79
83
|
}
|
|
80
84
|
const src = path.join(sourceDir, fw.name);
|
|
@@ -86,6 +90,7 @@ function applyPlugin(
|
|
|
86
90
|
fm.copyFramework(src);
|
|
87
91
|
}
|
|
88
92
|
addThirdPartyFramework(pbx, relTo, Boolean(fw.embed));
|
|
93
|
+
logs.push(`SUCCESS: 导入三方依赖framework ${fw.name} 完成`);
|
|
89
94
|
if (fw.copyFile) addCopyFile(pbx, relTo);
|
|
90
95
|
}
|
|
91
96
|
}
|
|
@@ -94,6 +99,7 @@ function applyPlugin(
|
|
|
94
99
|
for (const lib of config.libs) {
|
|
95
100
|
if (lib.system) {
|
|
96
101
|
addSystemLib(pbx, lib.name);
|
|
102
|
+
logs.push(`SUCCESS: 导入系统依赖lib ${lib.name} 完成`);
|
|
97
103
|
continue;
|
|
98
104
|
}
|
|
99
105
|
const src = path.join(sourceDir, lib.name);
|
|
@@ -102,6 +108,7 @@ function applyPlugin(
|
|
|
102
108
|
if (dryRun) binaryCopies.push({ fromAbs: src, relTo });
|
|
103
109
|
else fm.copyFile(src);
|
|
104
110
|
addSourceOrResourceFile(pbx, relTo);
|
|
111
|
+
logs.push(`SUCCESS: 导入三方依赖lib ${lib.name} 完成`);
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
114
|
|
|
@@ -110,6 +117,7 @@ function applyPlugin(
|
|
|
110
117
|
const remoteRel = remoteSources.get(`${config.name}:${source}`);
|
|
111
118
|
if (remoteRel) {
|
|
112
119
|
addSourceOrResourceFile(pbx, remoteRel);
|
|
120
|
+
logs.push(`SUCCESS: 引入资源 ${source} 完成`);
|
|
113
121
|
continue;
|
|
114
122
|
}
|
|
115
123
|
const src = path.join(sourceDir, source);
|
|
@@ -126,15 +134,17 @@ function applyPlugin(
|
|
|
126
134
|
for (const name of fs.readdirSync(dir)) {
|
|
127
135
|
const full = path.join(dir, name);
|
|
128
136
|
if (fs.statSync(full).isDirectory()) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
137
|
+
if (name.endsWith(".bundle")) {
|
|
138
|
+
addSourceOrResourceFile(pbx, fm.relFromSrc(full));
|
|
139
|
+
logs.push(`SUCCESS: 引入资源 ${name} 完成`);
|
|
140
|
+
} else {
|
|
141
|
+
walk(full);
|
|
142
|
+
}
|
|
134
143
|
continue;
|
|
135
144
|
}
|
|
136
145
|
if (/\.(h|m|mm|plist|a)$/.test(name)) {
|
|
137
146
|
addSourceOrResourceFile(pbx, fm.relFromSrc(full));
|
|
147
|
+
logs.push(`SUCCESS: 引入资源 ${name} 完成`);
|
|
138
148
|
}
|
|
139
149
|
}
|
|
140
150
|
};
|
|
@@ -146,6 +156,7 @@ function applyPlugin(
|
|
|
146
156
|
else if (fs.statSync(src).isDirectory()) fm.copyDir(src);
|
|
147
157
|
else fm.copyFile(src);
|
|
148
158
|
addSourceOrResourceFile(pbx, relTo);
|
|
159
|
+
logs.push(`SUCCESS: 引入资源 ${source} 完成`);
|
|
149
160
|
}
|
|
150
161
|
}
|
|
151
162
|
}
|
|
@@ -153,15 +164,18 @@ function applyPlugin(
|
|
|
153
164
|
if (perform.includes("buildSettings") && config.buildSettings) {
|
|
154
165
|
for (const [k, v] of Object.entries(config.buildSettings)) {
|
|
155
166
|
setBuildSetting(pbx, k, v);
|
|
167
|
+
logs.push(`SUCCESS: BuildSetting设置${k}为${v} 完成`);
|
|
156
168
|
}
|
|
157
169
|
}
|
|
158
170
|
|
|
159
171
|
if (perform.includes("OtherLinkerFlags") && config.OtherLinkerFlags?.length) {
|
|
160
172
|
for (const flag of config.OtherLinkerFlags) {
|
|
161
173
|
addOtherLinkerFlag(pbx, flag);
|
|
174
|
+
logs.push(`SUCCESS: 添加other link flag:${flag} 完成`);
|
|
162
175
|
}
|
|
163
176
|
}
|
|
164
177
|
|
|
178
|
+
logs.push(`SUCCESS: 插件${config.name}接入完成`);
|
|
165
179
|
}
|
|
166
180
|
|
|
167
181
|
function validateLoadedPluginResourcesForIos(loaded: LoadedPluginConfig): string[] {
|
|
@@ -224,6 +238,42 @@ function iosFirebaseConfigRelPath(plistDocs: PlistDocument[]): string {
|
|
|
224
238
|
return dir === "." ? IOS_FIREBASE_CONFIG_FILE : path.posix.join(dir, IOS_FIREBASE_CONFIG_FILE);
|
|
225
239
|
}
|
|
226
240
|
|
|
241
|
+
function hasSwiftSource(srcRoot: string): boolean {
|
|
242
|
+
const walk = (dir: string): boolean => {
|
|
243
|
+
let entries: fs.Dirent[];
|
|
244
|
+
try {
|
|
245
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
246
|
+
} catch {
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
for (const entry of entries) {
|
|
250
|
+
if (entry.name.startsWith(".")) continue;
|
|
251
|
+
const full = path.join(dir, entry.name);
|
|
252
|
+
if (entry.isDirectory()) {
|
|
253
|
+
if (!["Pods", "build", "DerivedData", "topSDK"].includes(entry.name) && walk(full)) return true;
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
if (entry.name.endsWith(".swift")) return true;
|
|
257
|
+
}
|
|
258
|
+
return false;
|
|
259
|
+
};
|
|
260
|
+
return walk(srcRoot);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function ensureTopSdkInstallSwift(
|
|
264
|
+
store: TextFileStore,
|
|
265
|
+
ctx: WorkspaceContext,
|
|
266
|
+
pbx: PbxContext
|
|
267
|
+
): string | null {
|
|
268
|
+
if (hasSwiftSource(pbx.srcRoot)) return null;
|
|
269
|
+
const relFromSrc = path.join(pbx.targetName, "TopSDKInstall.swift").split(path.sep).join("/");
|
|
270
|
+
const abs = path.join(pbx.srcRoot, relFromSrc);
|
|
271
|
+
const relFromProject = path.relative(ctx.projectRoot, abs).split(path.sep).join("/");
|
|
272
|
+
store.write(relFromProject, "import Foundation\n\n");
|
|
273
|
+
addSourceOrResourceFile(pbx, relFromSrc);
|
|
274
|
+
return relFromProject;
|
|
275
|
+
}
|
|
276
|
+
|
|
227
277
|
function appDelegateCodeShouldMoveToSceneDelegate(code: CodeConfig): boolean {
|
|
228
278
|
if (code.type === "header") return false;
|
|
229
279
|
const method = code.method ?? "";
|
|
@@ -274,7 +324,8 @@ function mergePlistParams(
|
|
|
274
324
|
docs: PlistDocument[],
|
|
275
325
|
loaded: LoadedPluginConfig,
|
|
276
326
|
channelConfig: Record<string, unknown>,
|
|
277
|
-
perform: readonly PerformSetting[]
|
|
327
|
+
perform: readonly PerformSetting[],
|
|
328
|
+
logs: string[]
|
|
278
329
|
): void {
|
|
279
330
|
if (!perform.includes("infoParams") && !perform.includes("urlScheme") && !perform.includes("queriesSchemes")) {
|
|
280
331
|
return;
|
|
@@ -282,18 +333,22 @@ function mergePlistParams(
|
|
|
282
333
|
for (const doc of docs) {
|
|
283
334
|
if (perform.includes("infoParams") && loaded.config.infoParams) {
|
|
284
335
|
for (const [key, raw] of Object.entries(loaded.config.infoParams)) {
|
|
285
|
-
|
|
336
|
+
const value = applyChannelTemplateValue(raw, channelConfig);
|
|
337
|
+
addPlistParam(doc.data, key, value);
|
|
338
|
+
logs.push(`SUCCESS: info.plist添加配置key:${key} value:${String(value)} 完成`);
|
|
286
339
|
}
|
|
287
340
|
}
|
|
288
341
|
if (perform.includes("queriesSchemes") && loaded.config.queriesSchemes?.length) {
|
|
289
342
|
for (const scheme of loaded.config.queriesSchemes) {
|
|
290
343
|
addQueriesScheme(doc.data, scheme);
|
|
344
|
+
logs.push(`SUCCESS: 添加queriesSchemes:${scheme} 完成`);
|
|
291
345
|
}
|
|
292
346
|
}
|
|
293
347
|
if (perform.includes("urlScheme") && loaded.config.urlScheme) {
|
|
294
348
|
let scheme = applyChannelTemplate(loaded.config.urlScheme, channelConfig);
|
|
295
349
|
if (scheme.endsWith("://")) scheme = scheme.replace("://", "");
|
|
296
350
|
addUrlScheme(doc.data, scheme);
|
|
351
|
+
logs.push(`SUCCESS: 设置urlScheme:${scheme}完成`);
|
|
297
352
|
}
|
|
298
353
|
}
|
|
299
354
|
}
|
|
@@ -331,20 +386,21 @@ export async function runIosIntegrateTopSdk(
|
|
|
331
386
|
): Promise<StepResult> {
|
|
332
387
|
if (!ctx.ios?.ok) return fail(["iOS project not detected"]);
|
|
333
388
|
const warnings: string[] = [];
|
|
389
|
+
const logs: string[] = [];
|
|
334
390
|
const changed = new Set<string>();
|
|
335
391
|
|
|
336
|
-
const configPath = path.join(ctx.projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME);
|
|
392
|
+
const configPath = ctx.remoteConfigPath ?? path.join(ctx.projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME);
|
|
337
393
|
if (!fs.existsSync(configPath)) {
|
|
338
|
-
return fail([`${MEETSDK_REMOTE_CONFIG_FILENAME} not found; run fetch-config or setup first`]);
|
|
394
|
+
return fail([`${MEETSDK_REMOTE_CONFIG_FILENAME} not found at ${configPath}; run fetch-config or setup first`], warnings, logs);
|
|
339
395
|
}
|
|
340
396
|
let remote: ReturnType<typeof tryParseAsMeetSdkRemoteConfig>;
|
|
341
397
|
try {
|
|
342
398
|
remote = tryParseAsMeetSdkRemoteConfig(JSON.parse(fs.readFileSync(configPath, "utf8")) as unknown);
|
|
343
399
|
} catch (e) {
|
|
344
|
-
return fail([e instanceof Error ? e.message : String(e)]);
|
|
400
|
+
return fail([e instanceof Error ? e.message : String(e)], warnings, logs);
|
|
345
401
|
}
|
|
346
402
|
if (!remote) {
|
|
347
|
-
return fail([`invalid ${MEETSDK_REMOTE_CONFIG_FILENAME}`]);
|
|
403
|
+
return fail([`invalid ${MEETSDK_REMOTE_CONFIG_FILENAME}`], warnings, logs);
|
|
348
404
|
}
|
|
349
405
|
const validation = validateMeetSdkRemoteConfig(remote);
|
|
350
406
|
if (!validation.ok) {
|
|
@@ -353,15 +409,17 @@ export async function runIosIntegrateTopSdk(
|
|
|
353
409
|
|
|
354
410
|
let sdkRoot: string;
|
|
355
411
|
try {
|
|
356
|
-
sdkRoot = resolveIosSdkRoot(ctx.packageRoot);
|
|
412
|
+
sdkRoot = ctx.iosSdkRoot ?? resolveIosSdkRoot(ctx.packageRoot);
|
|
357
413
|
} catch (e) {
|
|
358
|
-
return fail([e instanceof Error ? e.message : String(e)]);
|
|
414
|
+
return fail([e instanceof Error ? e.message : String(e)], warnings, logs);
|
|
359
415
|
}
|
|
360
416
|
|
|
361
417
|
const targetName = options.targetName ?? ctx.ios.targetName ?? path.basename(ctx.ios.xcodeprojPath!, ".xcodeproj");
|
|
362
418
|
const perform = options.performSettings ?? DEFAULT_PERFORM_SETTINGS;
|
|
363
419
|
const executeAppDelegate = options.executeAppDelegate !== false;
|
|
364
420
|
const dryRun = Boolean(options.dryRun);
|
|
421
|
+
logs.push("6、执行 SDK 接入");
|
|
422
|
+
logs.push(`*** 项目根目录:${ctx.projectRoot} ***`);
|
|
365
423
|
|
|
366
424
|
const channelConfig = buildChannelConfigMap(remote);
|
|
367
425
|
const coreConfigs = listSdkCoreConfigs(sdkRoot);
|
|
@@ -375,6 +433,7 @@ export async function runIosIntegrateTopSdk(
|
|
|
375
433
|
if (p) pluginConfigs.push(p);
|
|
376
434
|
else warnings.push(`iOS plugin folder not in SDK package: plugins/${folder}`);
|
|
377
435
|
}
|
|
436
|
+
|
|
378
437
|
const xcodeprojPath = ctx.ios.xcodeprojPath!;
|
|
379
438
|
const pbx = await loadPbxFromStore(store, ctx.projectRoot, xcodeprojPath, targetName);
|
|
380
439
|
const fm = new TopSdkFileManager(pbx.srcRoot);
|
|
@@ -383,30 +442,37 @@ export async function runIosIntegrateTopSdk(
|
|
|
383
442
|
try {
|
|
384
443
|
plistDocs = await ensureInfoPlists(store, ctx, pbx, targetName);
|
|
385
444
|
} catch (e) {
|
|
386
|
-
return fail([e instanceof Error ? e.message : String(e)], warnings);
|
|
445
|
+
return fail([e instanceof Error ? e.message : String(e)], warnings, logs);
|
|
387
446
|
}
|
|
388
447
|
|
|
389
448
|
const firebaseDownload = await downloadIosFirebaseConfig(remote, pbx, dryRun, iosFirebaseConfigRelPath(plistDocs));
|
|
390
449
|
warnings.push(...firebaseDownload.warnings);
|
|
391
|
-
if (firebaseDownload.errors.length) return fail(firebaseDownload.errors, warnings);
|
|
450
|
+
if (firebaseDownload.errors.length) return fail(firebaseDownload.errors, warnings, logs);
|
|
392
451
|
|
|
393
452
|
const resourceErrors = [...coreConfigs, ...pluginConfigs].flatMap(validateLoadedPluginResourcesForIos);
|
|
394
|
-
if (resourceErrors.length) return fail(resourceErrors, warnings);
|
|
453
|
+
if (resourceErrors.length) return fail(resourceErrors, warnings, logs);
|
|
395
454
|
|
|
396
455
|
const missingRequiredConfigs = validateRequiredChannelConfigs(pluginConfigs, channelConfig);
|
|
397
456
|
if (missingRequiredConfigs.length) {
|
|
398
|
-
return fail([`iOS remote config missing required channel params: ${missingRequiredConfigs.join(", ")}`], warnings);
|
|
457
|
+
return fail([`iOS remote config missing required channel params: ${missingRequiredConfigs.join(", ")}`], warnings, logs);
|
|
399
458
|
}
|
|
400
459
|
|
|
401
|
-
for (const loaded of coreConfigs) {
|
|
402
|
-
applyPlugin(loaded, pbx, fm, channelConfig, perform, binaryCopies, dryRun, firebaseDownload.remoteSources);
|
|
403
|
-
}
|
|
404
460
|
for (const loaded of pluginConfigs) {
|
|
405
|
-
applyPlugin(loaded, pbx, fm, channelConfig, perform, binaryCopies, dryRun, firebaseDownload.remoteSources);
|
|
461
|
+
applyPlugin(loaded, pbx, fm, channelConfig, perform, binaryCopies, dryRun, logs, firebaseDownload.remoteSources);
|
|
462
|
+
if (loaded.config.name === "FacebookSignin" && perform.includes("sources")) {
|
|
463
|
+
const swiftRel = ensureTopSdkInstallSwift(store, ctx, pbx);
|
|
464
|
+
if (swiftRel) {
|
|
465
|
+
changed.add(swiftRel);
|
|
466
|
+
logs.push("SUCCESS: 未检测到Swift代码文件,自动添加TopSDKInstall.swift完成");
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
for (const loaded of coreConfigs) {
|
|
471
|
+
applyPlugin(loaded, pbx, fm, channelConfig, perform, binaryCopies, dryRun, logs, firebaseDownload.remoteSources);
|
|
406
472
|
}
|
|
407
473
|
|
|
408
474
|
for (const loaded of [...coreConfigs, ...pluginConfigs]) {
|
|
409
|
-
mergePlistParams(plistDocs, loaded, channelConfig, perform);
|
|
475
|
+
mergePlistParams(plistDocs, loaded, channelConfig, perform, logs);
|
|
410
476
|
if (perform.includes("infoParams")) {
|
|
411
477
|
setAppTransportSecurity(plistDocs[0]?.data ?? {}, true);
|
|
412
478
|
}
|
|
@@ -429,6 +495,7 @@ export async function runIosIntegrateTopSdk(
|
|
|
429
495
|
for (const rel of ensureAppleSignInEntitlement(store, ctx.projectRoot, pbx)) {
|
|
430
496
|
changed.add(rel);
|
|
431
497
|
}
|
|
498
|
+
logs.push("SUCCESS: 启用SigninWithApple完成");
|
|
432
499
|
}
|
|
433
500
|
|
|
434
501
|
savePbxToStore(store, pbx);
|
|
@@ -453,14 +520,21 @@ export async function runIosIntegrateTopSdk(
|
|
|
453
520
|
}
|
|
454
521
|
for (const rel of delegateRelPaths.length === 1 ? delegateRelPaths : []) {
|
|
455
522
|
const cu = CodeUtils.fromFile(path.join(ctx.projectRoot, rel));
|
|
523
|
+
logs.push("检测到工程UIApplicationDelegate实现类,将自动接入对应接口");
|
|
456
524
|
let okInject = true;
|
|
457
525
|
for (const loaded of [...coreConfigs, ...pluginConfigs]) {
|
|
458
526
|
for (const code of appDelegateCodesForLifecycle(loaded, hasUniqueSceneDelegate)) {
|
|
527
|
+
const existed = cu.hasCode(code.content);
|
|
459
528
|
if (code.type === "header") {
|
|
460
529
|
if (!cu.addHeader(code.content)) okInject = false;
|
|
461
530
|
} else if ((code.type === "method" || code.type === "code") && code.method) {
|
|
462
531
|
if (!cu.addCodeToMethod(code.method, code.content, Boolean(code.addToReturn))) okInject = false;
|
|
463
532
|
}
|
|
533
|
+
if (okInject) {
|
|
534
|
+
logs.push(
|
|
535
|
+
`SUCCESS: 代码文件${path.join(ctx.projectRoot, rel)},${existed ? "已存在代码" : "添加代码"}${code.content}${existed ? "" : "完成"}`
|
|
536
|
+
);
|
|
537
|
+
}
|
|
464
538
|
}
|
|
465
539
|
}
|
|
466
540
|
if (!okInject) warnings.push(`AppDelegate injection incomplete for ${rel}`);
|
|
@@ -474,14 +548,21 @@ export async function runIosIntegrateTopSdk(
|
|
|
474
548
|
}
|
|
475
549
|
for (const rel of sceneDelegateRelPaths.length === 1 ? sceneDelegateRelPaths : []) {
|
|
476
550
|
const cu = CodeUtils.fromFile(path.join(ctx.projectRoot, rel));
|
|
551
|
+
logs.push("检测到工程存在UIWindowSceneDelegate实现类,将自动接入对应接口");
|
|
477
552
|
let okInject = true;
|
|
478
553
|
for (const loaded of [...coreConfigs, ...pluginConfigs]) {
|
|
479
554
|
for (const code of loaded.config.sceneDelegateCodes ?? []) {
|
|
555
|
+
const existed = cu.hasCode(code.content);
|
|
480
556
|
if (code.type === "header") {
|
|
481
557
|
if (!cu.addHeader(code.content)) okInject = false;
|
|
482
558
|
} else if ((code.type === "method" || code.type === "code") && code.method) {
|
|
483
559
|
if (!cu.addCodeToMethod(code.method, code.content, Boolean(code.addToReturn))) okInject = false;
|
|
484
560
|
}
|
|
561
|
+
if (okInject) {
|
|
562
|
+
logs.push(
|
|
563
|
+
`SUCCESS: 代码文件${path.join(ctx.projectRoot, rel)},${existed ? "已存在代码" : "添加代码"}${code.content}${existed ? "" : "完成"}`
|
|
564
|
+
);
|
|
565
|
+
}
|
|
485
566
|
}
|
|
486
567
|
}
|
|
487
568
|
if (!okInject) warnings.push(`SceneDelegate injection incomplete for ${rel}`);
|
|
@@ -491,7 +572,9 @@ export async function runIosIntegrateTopSdk(
|
|
|
491
572
|
}
|
|
492
573
|
}
|
|
493
574
|
|
|
494
|
-
|
|
575
|
+
logs.push("SUCCESS: info.plist配置写入完成");
|
|
576
|
+
logs.push("!! 接入流程已全部结束 !!");
|
|
577
|
+
return ok([...changed], warnings, logs);
|
|
495
578
|
}
|
|
496
579
|
|
|
497
580
|
async function ensureInfoPlists(
|
package/src/ios/pbxprojEditor.ts
CHANGED
|
@@ -69,9 +69,70 @@ export async function loadPbxFromStore(
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
export function savePbxToStore(store: TextFileStore, ctx: PbxContext): void {
|
|
72
|
+
stripUndefinedValues(ctx.proj.hash?.project?.objects);
|
|
73
|
+
sanitizePbxBuildSettings(ctx.proj);
|
|
72
74
|
store.write(ctx.rel, ctx.proj.writeSync());
|
|
73
75
|
}
|
|
74
76
|
|
|
77
|
+
function stripUndefinedValues(value: unknown): void {
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
for (const item of value) stripUndefinedValues(item);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (!value || typeof value !== "object") return;
|
|
83
|
+
|
|
84
|
+
const record = value as Record<string, unknown>;
|
|
85
|
+
for (const [key, nested] of Object.entries(record)) {
|
|
86
|
+
if (nested === undefined || nested === "undefined") {
|
|
87
|
+
delete record[key];
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
stripUndefinedValues(nested);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function sanitizePbxBuildSettings(proj: XcodeProject): void {
|
|
95
|
+
const buildConfigs = proj.pbxXCBuildConfigurationSection?.() ?? {};
|
|
96
|
+
for (const [uuid, cfg] of Object.entries(buildConfigs)) {
|
|
97
|
+
if (uuid.endsWith("_comment") || !cfg || typeof cfg !== "object") continue;
|
|
98
|
+
const settings = (cfg as { buildSettings?: Record<string, unknown> }).buildSettings;
|
|
99
|
+
if (!settings) continue;
|
|
100
|
+
for (const [key, raw] of Object.entries(settings)) {
|
|
101
|
+
if (typeof raw === "string") {
|
|
102
|
+
settings[key] = quotePbxStringIfNeeded(raw);
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (Array.isArray(raw)) {
|
|
106
|
+
settings[key] = raw.map((value) => (typeof value === "string" ? quotePbxStringIfNeeded(value) : value));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isPbxQuotedString(value: string): boolean {
|
|
113
|
+
return value.length >= 2 && value.startsWith('"') && value.endsWith('"');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function unquotePbxString(value: string): string {
|
|
117
|
+
if (!isPbxQuotedString(value)) return value;
|
|
118
|
+
return value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function quotePbxStringIfNeeded(value: string): string {
|
|
122
|
+
if (isPbxQuotedString(value)) return value;
|
|
123
|
+
if (!pbxStringNeedsQuotes(value)) return value;
|
|
124
|
+
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function pbxStringNeedsQuotes(value: string): boolean {
|
|
128
|
+
if (value.length === 0 || value.startsWith("-")) return true;
|
|
129
|
+
return /[^A-Za-z0-9_.$/{}()+-]/.test(value);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function samePbxStringValue(a: unknown, b: string): boolean {
|
|
133
|
+
return typeof a === "string" && unquotePbxString(a) === unquotePbxString(b);
|
|
134
|
+
}
|
|
135
|
+
|
|
75
136
|
function targetUuid(proj: XcodeProject, targetName: string): string | undefined {
|
|
76
137
|
const targets = proj.pbxNativeTargetSection?.() ?? {};
|
|
77
138
|
for (const [uuid, t] of Object.entries(targets)) {
|
|
@@ -229,7 +290,12 @@ export function addSourceOrResourceFile(ctx: PbxContext, relPathFromSrcRoot: str
|
|
|
229
290
|
if (file.endsWith(".h")) {
|
|
230
291
|
ctx.proj.addHeaderFile(file, { target });
|
|
231
292
|
} else if (file.endsWith(".m") || file.endsWith(".mm") || file.endsWith(".swift")) {
|
|
232
|
-
|
|
293
|
+
try {
|
|
294
|
+
ctx.proj.addSourceFile(file, { target });
|
|
295
|
+
} catch (e) {
|
|
296
|
+
if (!String(e instanceof Error ? e.message : e).includes("path")) throw e;
|
|
297
|
+
addSourceFileManually(ctx, file);
|
|
298
|
+
}
|
|
233
299
|
} else {
|
|
234
300
|
ensureResourcesBuildPhase(ctx.proj, ctx.targetName);
|
|
235
301
|
const opt: Record<string, unknown> = { target };
|
|
@@ -245,6 +311,51 @@ export function addSourceOrResourceFile(ctx: PbxContext, relPathFromSrcRoot: str
|
|
|
245
311
|
}
|
|
246
312
|
}
|
|
247
313
|
|
|
314
|
+
function ensureSourcesBuildPhase(proj: XcodeProject, targetName: string): void {
|
|
315
|
+
const target = targetKey(proj, targetName);
|
|
316
|
+
try {
|
|
317
|
+
proj.pbxSourcesBuildPhaseObj(target);
|
|
318
|
+
return;
|
|
319
|
+
} catch {
|
|
320
|
+
proj.addBuildPhase([], "PBXSourcesBuildPhase", "Sources", target);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function sourceFileType(file: string): string {
|
|
325
|
+
if (file.endsWith(".swift")) return "sourcecode.swift";
|
|
326
|
+
if (file.endsWith(".mm")) return "sourcecode.cpp.objcpp";
|
|
327
|
+
return "sourcecode.c.objc";
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function addSourceFileManually(ctx: PbxContext, file: string): void {
|
|
331
|
+
const basename = path.basename(file);
|
|
332
|
+
ensureSourcesBuildPhase(ctx.proj, ctx.targetName);
|
|
333
|
+
const sources = ctx.proj.pbxSourcesBuildPhaseObj(targetKey(ctx.proj, ctx.targetName));
|
|
334
|
+
const files = (sources.files ??= []) as Array<{ value?: string; comment?: string }>;
|
|
335
|
+
if (JSON.stringify(files).includes(basename)) return;
|
|
336
|
+
|
|
337
|
+
const fileRefUuid = ctx.proj.generateUuid();
|
|
338
|
+
const buildUuid = ctx.proj.generateUuid();
|
|
339
|
+
const fileRefSection = objectSection(ctx.proj, "PBXFileReference");
|
|
340
|
+
const buildFileSection = objectSection(ctx.proj, "PBXBuildFile");
|
|
341
|
+
|
|
342
|
+
fileRefSection[fileRefUuid] = {
|
|
343
|
+
isa: "PBXFileReference",
|
|
344
|
+
name: `"${basename}"`,
|
|
345
|
+
path: `"${file}"`,
|
|
346
|
+
sourceTree: '"<group>"',
|
|
347
|
+
lastKnownFileType: sourceFileType(file),
|
|
348
|
+
};
|
|
349
|
+
fileRefSection[`${fileRefUuid}_comment`] = basename;
|
|
350
|
+
buildFileSection[buildUuid] = {
|
|
351
|
+
isa: "PBXBuildFile",
|
|
352
|
+
fileRef: fileRefUuid,
|
|
353
|
+
fileRef_comment: basename,
|
|
354
|
+
};
|
|
355
|
+
buildFileSection[`${buildUuid}_comment`] = `${basename} in Sources`;
|
|
356
|
+
files.push({ value: buildUuid, comment: `${basename} in Sources` });
|
|
357
|
+
}
|
|
358
|
+
|
|
248
359
|
function resourceFileType(file: string, lastKnownFileType?: string): string {
|
|
249
360
|
if (lastKnownFileType) return lastKnownFileType;
|
|
250
361
|
if (file.endsWith(".bundle")) return "wrapper.plug-in";
|
|
@@ -317,12 +428,18 @@ export function addOtherLinkerFlag(ctx: PbxContext, flag: string): void {
|
|
|
317
428
|
if (!cfg || typeof cfg !== "object") continue;
|
|
318
429
|
const settings = (cfg as { buildSettings?: Record<string, unknown> }).buildSettings ?? {};
|
|
319
430
|
const cur = settings.OTHER_LDFLAGS;
|
|
431
|
+
const normalizedFlag = unquotePbxString(flag);
|
|
432
|
+
const nextFlag = quotePbxStringIfNeeded(normalizedFlag);
|
|
320
433
|
if (typeof cur === "string") {
|
|
321
|
-
if (!cur.includes(
|
|
434
|
+
if (!unquotePbxString(cur).split(/\s+/).includes(normalizedFlag)) {
|
|
435
|
+
settings.OTHER_LDFLAGS = [quotePbxStringIfNeeded(cur), nextFlag];
|
|
436
|
+
}
|
|
322
437
|
} else if (Array.isArray(cur)) {
|
|
323
|
-
|
|
438
|
+
const values = cur.map((value) => (typeof value === "string" ? quotePbxStringIfNeeded(value) : value));
|
|
439
|
+
if (!values.some((value) => samePbxStringValue(value, normalizedFlag))) values.push(nextFlag);
|
|
440
|
+
settings.OTHER_LDFLAGS = values;
|
|
324
441
|
} else {
|
|
325
|
-
settings.OTHER_LDFLAGS = [
|
|
442
|
+
settings.OTHER_LDFLAGS = [nextFlag];
|
|
326
443
|
}
|
|
327
444
|
(cfg as { buildSettings: Record<string, unknown> }).buildSettings = settings;
|
|
328
445
|
}
|
package/src/ios/sdkBundle.ts
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
|
|
4
|
-
const BUNDLED_IOS_REL = path.join("bundled", "ios-sdk");
|
|
5
|
-
|
|
6
|
-
export function defaultBundledIosSdkRoot(packageRoot: string): string {
|
|
7
|
-
return path.join(packageRoot, BUNDLED_IOS_REL);
|
|
8
|
-
}
|
|
3
|
+
import { MEET_SDK_TOOL_CACHE_ROOT } from "../cache.js";
|
|
9
4
|
|
|
10
5
|
/**
|
|
11
|
-
* TopSDK iOS package root
|
|
12
|
-
* Native iOS only
|
|
6
|
+
* TopSDK iOS package root from cache.
|
|
7
|
+
* Native iOS only.
|
|
13
8
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (!fs.existsSync(bundled)) {
|
|
17
|
-
throw new Error(`iOS SDK not found at ${BUNDLED_IOS_REL} (expected sdk/ and plugins/ inside).`);
|
|
18
|
-
}
|
|
9
|
+
function findIosSdkRoot(container: string): string | null {
|
|
10
|
+
if (!fs.existsSync(container)) return null;
|
|
19
11
|
const children = fs
|
|
20
|
-
.readdirSync(
|
|
12
|
+
.readdirSync(container, { withFileTypes: true })
|
|
21
13
|
.filter((d) => d.isDirectory() && !d.name.startsWith("."))
|
|
22
|
-
.map((d) => path.join(
|
|
14
|
+
.map((d) => path.join(container, d.name))
|
|
23
15
|
.sort()
|
|
24
16
|
.reverse();
|
|
25
17
|
for (const dir of children) {
|
|
@@ -27,10 +19,41 @@ export function resolveIosSdkRoot(packageRoot: string): string {
|
|
|
27
19
|
return dir;
|
|
28
20
|
}
|
|
29
21
|
}
|
|
30
|
-
if (fs.existsSync(path.join(
|
|
31
|
-
return
|
|
22
|
+
if (fs.existsSync(path.join(container, "sdk")) && fs.existsSync(path.join(container, "plugins"))) {
|
|
23
|
+
return container;
|
|
32
24
|
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function findLatestCachedIosSdkRoot(): string | null {
|
|
29
|
+
const iosCache = path.join(MEET_SDK_TOOL_CACHE_ROOT, "sdk", "ios");
|
|
30
|
+
if (!fs.existsSync(iosCache)) return null;
|
|
31
|
+
const candidates: string[] = [];
|
|
32
|
+
const walk = (dir: string): void => {
|
|
33
|
+
for (const ent of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
34
|
+
if (!ent.isDirectory() || ent.name.startsWith(".")) continue;
|
|
35
|
+
const abs = path.join(dir, ent.name);
|
|
36
|
+
if (ent.name === "extracted") {
|
|
37
|
+
candidates.push(abs);
|
|
38
|
+
} else {
|
|
39
|
+
walk(abs);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
walk(iosCache);
|
|
44
|
+
candidates.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs);
|
|
45
|
+
for (const candidate of candidates) {
|
|
46
|
+
const found = findIosSdkRoot(candidate);
|
|
47
|
+
if (found) return found;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function resolveIosSdkRoot(_packageRoot: string): string {
|
|
53
|
+
const cached = findLatestCachedIosSdkRoot();
|
|
54
|
+
if (cached) return cached;
|
|
55
|
+
|
|
33
56
|
throw new Error(
|
|
34
|
-
`iOS SDK
|
|
57
|
+
`iOS SDK not found in ${path.join(MEET_SDK_TOOL_CACHE_ROOT, "sdk", "ios")}; run download-ios-sdk or setup first.`
|
|
35
58
|
);
|
|
36
59
|
}
|