@leonxin/meetgames 0.1.7 → 0.1.11

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.
Files changed (293) hide show
  1. package/.agents/skills/meet-sdk-regression/SKILL.md +93 -0
  2. package/.cursor/mcp.example.json +16 -0
  3. package/.cursor/mcp.json +11 -0
  4. package/.cursor/skills/meetgames-mcp/SKILL.md +48 -0
  5. package/.vite/vitest/results.json +1 -0
  6. package/README.md +31 -8
  7. package/dist/aab-converter/aab-entry.d.ts +3 -0
  8. package/dist/aab-converter/aab-entry.d.ts.map +1 -0
  9. package/dist/aab-converter/aab-entry.js +49 -0
  10. package/dist/aab-converter/aab-entry.js.map +1 -0
  11. package/dist/aab-converter/apksExtractor.d.ts +2 -0
  12. package/dist/aab-converter/apksExtractor.d.ts.map +1 -0
  13. package/dist/aab-converter/apksExtractor.js +108 -0
  14. package/dist/aab-converter/apksExtractor.js.map +1 -0
  15. package/dist/aab-converter/bundletoolRunner.d.ts +15 -0
  16. package/dist/aab-converter/bundletoolRunner.d.ts.map +1 -0
  17. package/dist/aab-converter/bundletoolRunner.js +46 -0
  18. package/dist/aab-converter/bundletoolRunner.js.map +1 -0
  19. package/dist/aab-converter/cliArgs.d.ts +27 -0
  20. package/dist/aab-converter/cliArgs.d.ts.map +1 -0
  21. package/dist/aab-converter/cliArgs.js +170 -0
  22. package/dist/aab-converter/cliArgs.js.map +1 -0
  23. package/dist/aab-converter/convertAabToApk.d.ts +7 -0
  24. package/dist/aab-converter/convertAabToApk.d.ts.map +1 -0
  25. package/dist/aab-converter/convertAabToApk.js +69 -0
  26. package/dist/aab-converter/convertAabToApk.js.map +1 -0
  27. package/dist/aab-converter/resourcePaths.d.ts +4 -0
  28. package/dist/aab-converter/resourcePaths.d.ts.map +1 -0
  29. package/dist/aab-converter/resourcePaths.js +42 -0
  30. package/dist/aab-converter/resourcePaths.js.map +1 -0
  31. package/dist/aab-converter/signingOptions.d.ts +9 -0
  32. package/dist/aab-converter/signingOptions.d.ts.map +1 -0
  33. package/dist/aab-converter/signingOptions.js +21 -0
  34. package/dist/aab-converter/signingOptions.js.map +1 -0
  35. package/dist/aab-converter/types.d.ts +24 -0
  36. package/dist/aab-converter/types.d.ts.map +1 -0
  37. package/dist/aab-converter/types.js +2 -0
  38. package/dist/aab-converter/types.js.map +1 -0
  39. package/dist/android/adapter.d.ts.map +1 -1
  40. package/dist/android/adapter.js +2 -2
  41. package/dist/android/adapter.js.map +1 -1
  42. package/dist/android/detect.d.ts +2 -2
  43. package/dist/android/detect.d.ts.map +1 -1
  44. package/dist/android/detect.js +36 -8
  45. package/dist/android/detect.js.map +1 -1
  46. package/dist/android/meetSdkRemoteGradle.d.ts +0 -3
  47. package/dist/android/meetSdkRemoteGradle.d.ts.map +1 -1
  48. package/dist/android/meetSdkRemoteGradle.js +13 -20
  49. package/dist/android/meetSdkRemoteGradle.js.map +1 -1
  50. package/dist/cli.d.ts.map +1 -1
  51. package/dist/cli.js +157 -31
  52. package/dist/cli.js.map +1 -1
  53. package/dist/config/meetSdkDefaultConfig.d.ts +19 -2
  54. package/dist/config/meetSdkDefaultConfig.d.ts.map +1 -1
  55. package/dist/config/meetSdkDefaultConfig.js +67 -5
  56. package/dist/config/meetSdkDefaultConfig.js.map +1 -1
  57. package/dist/config/meetSdkIosConfig.d.ts +21 -0
  58. package/dist/config/meetSdkIosConfig.d.ts.map +1 -0
  59. package/dist/config/meetSdkIosConfig.js +66 -0
  60. package/dist/config/meetSdkIosConfig.js.map +1 -0
  61. package/dist/config/meetSdkRemoteConfig.d.ts +19 -11
  62. package/dist/config/meetSdkRemoteConfig.d.ts.map +1 -1
  63. package/dist/config/meetSdkRemoteConfig.js +89 -69
  64. package/dist/config/meetSdkRemoteConfig.js.map +1 -1
  65. package/dist/config/topsdkFeatureModules.d.ts +5 -0
  66. package/dist/config/topsdkFeatureModules.d.ts.map +1 -1
  67. package/dist/config/topsdkFeatureModules.js +26 -0
  68. package/dist/config/topsdkFeatureModules.js.map +1 -1
  69. package/dist/contracts/types.d.ts +19 -6
  70. package/dist/contracts/types.d.ts.map +1 -1
  71. package/dist/core/doctor.d.ts +17 -0
  72. package/dist/core/doctor.d.ts.map +1 -0
  73. package/dist/core/doctor.js +444 -0
  74. package/dist/core/doctor.js.map +1 -0
  75. package/dist/core/pipeline.d.ts.map +1 -1
  76. package/dist/core/pipeline.js +0 -15
  77. package/dist/core/pipeline.js.map +1 -1
  78. package/dist/core/platform.d.ts +12 -0
  79. package/dist/core/platform.d.ts.map +1 -0
  80. package/dist/core/platform.js +40 -0
  81. package/dist/core/platform.js.map +1 -0
  82. package/dist/core/reporter.js +1 -1
  83. package/dist/core/reporter.js.map +1 -1
  84. package/dist/core/workspace.d.ts +2 -2
  85. package/dist/core/workspace.d.ts.map +1 -1
  86. package/dist/core/workspace.js +4 -5
  87. package/dist/core/workspace.js.map +1 -1
  88. package/dist/index.d.ts +3 -1
  89. package/dist/index.d.ts.map +1 -1
  90. package/dist/index.js +3 -1
  91. package/dist/index.js.map +1 -1
  92. package/dist/ios/channelConfig.d.ts +1 -0
  93. package/dist/ios/channelConfig.d.ts.map +1 -1
  94. package/dist/ios/channelConfig.js +82 -0
  95. package/dist/ios/channelConfig.js.map +1 -1
  96. package/dist/ios/codeUtils.d.ts +1 -0
  97. package/dist/ios/codeUtils.d.ts.map +1 -1
  98. package/dist/ios/codeUtils.js +11 -2
  99. package/dist/ios/codeUtils.js.map +1 -1
  100. package/dist/ios/detect.d.ts +2 -2
  101. package/dist/ios/detect.d.ts.map +1 -1
  102. package/dist/ios/detect.js +49 -10
  103. package/dist/ios/detect.js.map +1 -1
  104. package/dist/ios/entitlements.d.ts +4 -0
  105. package/dist/ios/entitlements.d.ts.map +1 -0
  106. package/dist/ios/entitlements.js +53 -0
  107. package/dist/ios/entitlements.js.map +1 -0
  108. package/dist/ios/fileManager.d.ts.map +1 -1
  109. package/dist/ios/fileManager.js +3 -2
  110. package/dist/ios/fileManager.js.map +1 -1
  111. package/dist/ios/infoPlist.d.ts +1 -1
  112. package/dist/ios/infoPlist.d.ts.map +1 -1
  113. package/dist/ios/infoPlist.js.map +1 -1
  114. package/dist/ios/integrate.d.ts.map +1 -1
  115. package/dist/ios/integrate.js +211 -36
  116. package/dist/ios/integrate.js.map +1 -1
  117. package/dist/ios/pbxprojEditor.d.ts +2 -0
  118. package/dist/ios/pbxprojEditor.d.ts.map +1 -1
  119. package/dist/ios/pbxprojEditor.js +179 -1
  120. package/dist/ios/pbxprojEditor.js.map +1 -1
  121. package/dist/ios/pluginConfig.d.ts +1 -0
  122. package/dist/ios/pluginConfig.d.ts.map +1 -1
  123. package/dist/ios/pluginConfig.js +36 -4
  124. package/dist/ios/pluginConfig.js.map +1 -1
  125. package/dist/ios/sdkBundle.d.ts +1 -1
  126. package/dist/ios/sdkBundle.d.ts.map +1 -1
  127. package/dist/ios/sdkBundle.js +7 -5
  128. package/dist/ios/sdkBundle.js.map +1 -1
  129. package/dist/ios/template.d.ts +1 -0
  130. package/dist/ios/template.d.ts.map +1 -1
  131. package/dist/ios/template.js +14 -1
  132. package/dist/ios/template.js.map +1 -1
  133. package/dist/ios/types.d.ts +2 -2
  134. package/dist/ios/types.d.ts.map +1 -1
  135. package/dist/mcp/server.d.ts.map +1 -1
  136. package/dist/mcp/server.js +14 -13
  137. package/dist/mcp/server.js.map +1 -1
  138. package/dist/mcp/service.d.ts +8 -6
  139. package/dist/mcp/service.d.ts.map +1 -1
  140. package/dist/mcp/service.js +34 -14
  141. package/dist/mcp/service.js.map +1 -1
  142. package/dist/ops/handlers.d.ts.map +1 -1
  143. package/dist/ops/handlers.js +10 -4
  144. package/dist/ops/handlers.js.map +1 -1
  145. package/dist/remote/sdkHomeDownload.d.ts +65 -0
  146. package/dist/remote/sdkHomeDownload.d.ts.map +1 -0
  147. package/dist/remote/sdkHomeDownload.js +208 -0
  148. package/dist/remote/sdkHomeDownload.js.map +1 -0
  149. package/dist/remote/topsdkDownloadSdkConfig.d.ts.map +1 -1
  150. package/dist/remote/topsdkDownloadSdkConfig.js +11 -1
  151. package/dist/remote/topsdkDownloadSdkConfig.js.map +1 -1
  152. package/dist/shared/errors.d.ts +7 -0
  153. package/dist/shared/errors.d.ts.map +1 -0
  154. package/dist/shared/errors.js +16 -0
  155. package/dist/shared/errors.js.map +1 -0
  156. package/dist/shared/fileUtils.d.ts +5 -0
  157. package/dist/shared/fileUtils.d.ts.map +1 -0
  158. package/dist/shared/fileUtils.js +35 -0
  159. package/dist/shared/fileUtils.js.map +1 -0
  160. package/dist/shared/logger.d.ts +10 -0
  161. package/dist/shared/logger.d.ts.map +1 -0
  162. package/dist/shared/logger.js +37 -0
  163. package/dist/shared/logger.js.map +1 -0
  164. package/dist/shared/pathUtils.d.ts +4 -0
  165. package/dist/shared/pathUtils.d.ts.map +1 -0
  166. package/dist/shared/pathUtils.js +22 -0
  167. package/dist/shared/pathUtils.js.map +1 -0
  168. package/dist/shared/processRunner.d.ts +12 -0
  169. package/dist/shared/processRunner.d.ts.map +1 -0
  170. package/dist/shared/processRunner.js +31 -0
  171. package/dist/shared/processRunner.js.map +1 -0
  172. package/docs/AAB_CONVERTER_CLI_PLAN.md +392 -0
  173. package/docs/API.md +246 -32
  174. package/docs/CLI.md +292 -0
  175. package/docs/INTEGRATION.md +116 -0
  176. package/docs/MCP.md +86 -0
  177. package/docs/README.md +19 -10
  178. package/docs/{api → archive/api}/downloadSDKConfig.md +8 -6
  179. package/docs/{api → archive/api}/getChannelConfig-meetgames.md +1 -1
  180. package/docs/archive/ios-migration.md +2139 -0
  181. package/docs/{ → archive/product/}/346/212/200/346/234/257/346/226/271/346/241/210/350/260/203/347/240/224.md +7 -7
  182. package/docs/{ → archive/product/}/351/234/200/346/261/202/346/226/207/346/241/243.md +15 -14
  183. package/logs/convert-20260622-155037.log +5 -0
  184. package/logs/convert-20260622-155226.log +6 -0
  185. package/meetsdk-android.json +2 -1
  186. package/meetsdk-ios.json +15 -0
  187. package/package.json +10 -35
  188. package/scripts/package-aab-cli-win.mjs +193 -0
  189. package/src/aab-converter/aab-entry.ts +48 -0
  190. package/src/aab-converter/apksExtractor.ts +119 -0
  191. package/src/aab-converter/bundletoolRunner.ts +63 -0
  192. package/src/aab-converter/cliArgs.ts +194 -0
  193. package/src/aab-converter/convertAabToApk.ts +81 -0
  194. package/src/aab-converter/resourcePaths.ts +43 -0
  195. package/src/aab-converter/signingOptions.ts +29 -0
  196. package/src/aab-converter/types.ts +26 -0
  197. package/src/android/adapter.ts +9 -0
  198. package/src/android/assembleIntegrationJson.ts +33 -0
  199. package/src/android/detect.ts +132 -0
  200. package/src/android/downloadGoogleServicesJson.ts +56 -0
  201. package/src/android/gradle.ts +116 -0
  202. package/src/android/manifest.ts +50 -0
  203. package/src/android/meetSdkRemoteGradle.ts +837 -0
  204. package/src/cli.ts +488 -0
  205. package/src/config/fetchConfigWrite.ts +30 -0
  206. package/src/config/loadAndroidIntegration.ts +41 -0
  207. package/src/config/loadManifest.ts +40 -0
  208. package/src/config/meetSdkDefaultConfig.ts +99 -0
  209. package/src/config/meetSdkIosConfig.ts +87 -0
  210. package/src/config/meetSdkRemoteConfig.ts +1211 -0
  211. package/src/config/topsdkFeatureModules.ts +92 -0
  212. package/src/contracts/types.ts +121 -0
  213. package/src/core/doctor.ts +485 -0
  214. package/src/core/patch.ts +64 -0
  215. package/src/core/pipeline.ts +107 -0
  216. package/src/core/platform.ts +47 -0
  217. package/src/core/previewPatches.ts +23 -0
  218. package/src/core/reporter.ts +24 -0
  219. package/src/core/workspace.ts +29 -0
  220. package/src/entry.ts +7 -0
  221. package/src/index.ts +133 -0
  222. package/src/ios/channelConfig.ts +128 -0
  223. package/src/ios/codeUtils.ts +160 -0
  224. package/src/ios/detect.ts +105 -0
  225. package/src/ios/entitlements.ts +61 -0
  226. package/src/ios/fileManager.ts +48 -0
  227. package/src/ios/infoPlist.ts +55 -0
  228. package/src/ios/integrate.ts +516 -0
  229. package/src/ios/pbxprojEditor.ts +383 -0
  230. package/src/ios/pluginConfig.ts +97 -0
  231. package/src/ios/reserved.ts +8 -0
  232. package/src/ios/sdkBundle.ts +36 -0
  233. package/src/ios/template.ts +36 -0
  234. package/src/ios/types.ts +65 -0
  235. package/src/mcp/server.ts +170 -0
  236. package/src/mcp/service.ts +222 -0
  237. package/src/mcp-entry.ts +7 -0
  238. package/src/ops/fileStore.ts +56 -0
  239. package/src/ops/handlers.ts +304 -0
  240. package/src/remote/fetchJson.ts +22 -0
  241. package/src/remote/sdkHomeDownload.ts +274 -0
  242. package/src/remote/topsdkDownloadSdkConfig.ts +93 -0
  243. package/src/remote/topsdkGetSdkConfig.ts +122 -0
  244. package/src/remote/topsdkSign.ts +10 -0
  245. package/src/shared/errors.ts +16 -0
  246. package/src/shared/fileUtils.ts +41 -0
  247. package/src/shared/logger.ts +49 -0
  248. package/src/shared/pathUtils.ts +24 -0
  249. package/src/shared/processRunner.ts +43 -0
  250. package/test-projects/README.md +51 -0
  251. package/test-projects/_preview/pipeline.patch +281 -0
  252. package/tests/aab-converter.test.ts +213 -0
  253. package/tests/assemble.test.ts +12 -0
  254. package/tests/doctor.test.ts +89 -0
  255. package/tests/downloadGoogleServicesJson.test.ts +47 -0
  256. package/tests/fetch-remote.test.ts +23 -0
  257. package/tests/fetchConfigOverrides.test.ts +28 -0
  258. package/tests/fetchConfigWrite.test.ts +54 -0
  259. package/tests/gradle.test.ts +33 -0
  260. package/tests/integration-json.test.ts +29 -0
  261. package/tests/ios.codeUtils.test.ts +23 -0
  262. package/tests/ios.sdkBundle.test.ts +16 -0
  263. package/tests/loadManifest.test.ts +15 -0
  264. package/tests/manifest-xml.test.ts +30 -0
  265. package/tests/mcp.e2e.ts +217 -0
  266. package/tests/mcp.service.test.ts +53 -0
  267. package/tests/meetSdkRemoteConfig.test.ts +456 -0
  268. package/tests/meetSdkRemoteGradle.test.ts +414 -0
  269. package/tests/pipeline.android.test.ts +96 -0
  270. package/tests/pipeline.integration-json.test.ts +58 -0
  271. package/tests/pipeline.ios.test.ts +385 -0
  272. package/tests/pipeline.preview.patch.test.ts +85 -0
  273. package/tests/platformSelection.test.ts +77 -0
  274. package/tests/sdkHomeDownload.test.ts +124 -0
  275. package/tests/sdkVersionConfig.test.ts +130 -0
  276. package/tests/test-projects-hosts.test.ts +78 -0
  277. package/tests/topsdk.test.ts +53 -0
  278. package/tests/topsdkDownloadSdkConfig.test.ts +81 -0
  279. package/tests/topsdkFeatureModules.test.ts +116 -0
  280. package/tsconfig.json +19 -0
  281. package/vitest.config.ts +9 -0
  282. package/vitest.mcp.config.ts +11 -0
  283. package/bundled/android/sample.txt +0 -1
  284. package/docs/ANDROID.md +0 -133
  285. package/docs/CURSOR-MCP-SETUP.md +0 -72
  286. package/docs/MCP-SKILL.md +0 -63
  287. package/fixtures/api-samples/getChannelConfig-meetgames.sample.json +0 -123
  288. package/fixtures/meetsdk-remote-config.download-shape.json +0 -20
  289. package/fixtures/meetsdk-remote-config.mock.json +0 -69
  290. package/fixtures/recipes/android-default.fixture.yaml +0 -15
  291. package/fixtures/recipes/android-integration.fixture.json +0 -29
  292. package/fixtures/topsdk-config-reference.json +0 -39
  293. /package/docs/{api → archive/api}/getSDKConfig.md +0 -0
@@ -0,0 +1,130 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { afterEach, describe, expect, it, vi } from "vitest";
5
+ import { loadMeetSdkDefaultConfigWithLatestAndroidVersion } from "../src/config/meetSdkDefaultConfig.js";
6
+ import {
7
+ loadMeetSdkIosConfig,
8
+ resolveMeetSdkIosConfigPath,
9
+ syncMeetSdkIosVersionToConfig,
10
+ } from "../src/config/meetSdkIosConfig.js";
11
+
12
+ function makeTempPackageRoot(): string {
13
+ return fs.mkdtempSync(path.join(os.tmpdir(), "meet-sdk-config-"));
14
+ }
15
+
16
+ function writeAndroidDefaults(packageRoot: string): void {
17
+ fs.writeFileSync(
18
+ path.join(packageRoot, "meetsdk-android.json"),
19
+ JSON.stringify(
20
+ {
21
+ topsdk: {
22
+ version: "",
23
+ groupId: "com.sino.topsdk",
24
+ repositories: [],
25
+ },
26
+ sdkModules: {
27
+ login: {},
28
+ payment: {},
29
+ analytics: {},
30
+ },
31
+ },
32
+ null,
33
+ 2
34
+ ),
35
+ "utf8"
36
+ );
37
+ }
38
+
39
+ describe("SDK version package configs", () => {
40
+ afterEach(() => {
41
+ vi.unstubAllGlobals();
42
+ });
43
+
44
+ it("stores fetched Android SDK version in meetsdk-android.json", async () => {
45
+ const packageRoot = makeTempPackageRoot();
46
+ try {
47
+ writeAndroidDefaults(packageRoot);
48
+ vi.stubGlobal(
49
+ "fetch",
50
+ vi.fn(async () => ({
51
+ ok: true,
52
+ status: 200,
53
+ text: async () =>
54
+ JSON.stringify({
55
+ code: 200,
56
+ data: {
57
+ result: {
58
+ android: { ver: "9.8.7", date: "2026-06-20" },
59
+ ios: { ver: "1.2.3", date: "2026-06-21" },
60
+ },
61
+ },
62
+ }),
63
+ })) as unknown as typeof fetch
64
+ );
65
+
66
+ const defaults = await loadMeetSdkDefaultConfigWithLatestAndroidVersion({
67
+ sdkHomeApiBaseUrl: "https://android-version-sync.example.com",
68
+ packageRoot,
69
+ });
70
+
71
+ const stored = JSON.parse(fs.readFileSync(path.join(packageRoot, "meetsdk-android.json"), "utf8")) as {
72
+ topsdk: { version: string; date: string };
73
+ };
74
+ expect(defaults.topsdk.version).toBe("9.8.7");
75
+ expect(defaults.topsdk.date).toBe("2026-06-20");
76
+ expect(stored.topsdk.version).toBe("9.8.7");
77
+ expect(stored.topsdk.date).toBe("2026-06-20");
78
+ } finally {
79
+ fs.rmSync(packageRoot, { recursive: true, force: true });
80
+ }
81
+ });
82
+
83
+ it("stores resolved iOS SDK version in meetsdk-ios.json", () => {
84
+ const packageRoot = makeTempPackageRoot();
85
+ try {
86
+ const configPath = syncMeetSdkIosVersionToConfig({
87
+ packageRoot,
88
+ version: "1.6.0.5",
89
+ date: "2026-06-09",
90
+ packageType: "native",
91
+ plugins: ["guest", "facebook"],
92
+ });
93
+
94
+ expect(configPath).toBe(resolveMeetSdkIosConfigPath(packageRoot));
95
+ expect(loadMeetSdkIosConfig(packageRoot)).toEqual({
96
+ topsdk: {
97
+ version: "1.6.0.5",
98
+ date: "2026-06-09",
99
+ packageType: "native",
100
+ plugins: ["guest", "facebook"],
101
+ },
102
+ });
103
+ } finally {
104
+ fs.rmSync(packageRoot, { recursive: true, force: true });
105
+ }
106
+ });
107
+
108
+ it("clears stale iOS SDK date when only an explicit version is stored", () => {
109
+ const packageRoot = makeTempPackageRoot();
110
+ try {
111
+ syncMeetSdkIosVersionToConfig({
112
+ packageRoot,
113
+ version: "1.6.0.5",
114
+ date: "2026-06-09",
115
+ });
116
+ syncMeetSdkIosVersionToConfig({
117
+ packageRoot,
118
+ version: "1.6.0.6",
119
+ date: "",
120
+ });
121
+
122
+ expect(loadMeetSdkIosConfig(packageRoot).topsdk).toMatchObject({
123
+ version: "1.6.0.6",
124
+ });
125
+ expect(loadMeetSdkIosConfig(packageRoot).topsdk.date).toBeUndefined();
126
+ } finally {
127
+ fs.rmSync(packageRoot, { recursive: true, force: true });
128
+ }
129
+ });
130
+ });
@@ -0,0 +1,78 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { describe, expect, it } from "vitest";
6
+ import { buildWorkspaceContext } from "../src/core/workspace.js";
7
+
8
+ const here = path.dirname(fileURLToPath(import.meta.url));
9
+ const pkgRoot = path.resolve(here, "..");
10
+ const androidFixtureRoot = path.join(pkgRoot, "fixtures", "android-test-project");
11
+
12
+ function testProjectRoot(...names: string[]): string {
13
+ for (const name of names) {
14
+ const candidate = path.join(androidFixtureRoot, name);
15
+ if (fs.existsSync(candidate)) return candidate;
16
+ }
17
+ return path.join(androidFixtureRoot, names[0] ?? "");
18
+ }
19
+
20
+ function createAndroidAppModule(root: string, name: string, applicationId: string): void {
21
+ const moduleDir = path.join(root, name);
22
+ fs.mkdirSync(path.join(moduleDir, "src", "main"), { recursive: true });
23
+ fs.writeFileSync(
24
+ path.join(moduleDir, "build.gradle"),
25
+ [
26
+ "plugins {",
27
+ " id 'com.android.application'",
28
+ "}",
29
+ "android {",
30
+ " defaultConfig {",
31
+ ` applicationId '${applicationId}'`,
32
+ " }",
33
+ "}",
34
+ "",
35
+ ].join("\n"),
36
+ "utf8"
37
+ );
38
+ fs.writeFileSync(path.join(moduleDir, "src", "main", "AndroidManifest.xml"), "<manifest />\n", "utf8");
39
+ }
40
+
41
+ describe("fixture host trees", () => {
42
+ const powerRaidRoot = testProjectRoot("power-raid");
43
+
44
+ it("android-latest-project (plugins DSL) resolves application module :app", () => {
45
+ const root = path.join(androidFixtureRoot, "android-latest-project");
46
+ const ctx = buildWorkspaceContext(root, pkgRoot);
47
+ expect(ctx.android?.ok).toBe(true);
48
+ expect(ctx.android?.ok && ctx.android.moduleName).toBe(":app");
49
+ expect(ctx.android?.ok && ctx.android.moduleDir.endsWith(`${path.sep}app`)).toBe(true);
50
+ });
51
+
52
+ it.skipIf(!fs.existsSync(powerRaidRoot))("power-raid resolves launcher application module", () => {
53
+ const ctx = buildWorkspaceContext(powerRaidRoot, pkgRoot);
54
+ expect(ctx.android?.ok).toBe(true);
55
+ expect(ctx.android?.ok && ctx.android.moduleName).toBe(":launcher");
56
+ expect(ctx.android?.ok && ctx.android.moduleDir.endsWith(`${path.sep}launcher`)).toBe(true);
57
+ });
58
+
59
+ it("requires an Android app module selector when multiple application modules exist", () => {
60
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), "meet-android-multi-app-"));
61
+ fs.writeFileSync(path.join(root, "settings.gradle"), "include ':app'\ninclude ':demo'\n", "utf8");
62
+ createAndroidAppModule(root, "app", "com.example.app");
63
+ createAndroidAppModule(root, "demo", "com.example.demo");
64
+
65
+ const ambiguous = buildWorkspaceContext(root, pkgRoot);
66
+ expect(ambiguous.android?.ok).toBe(false);
67
+ expect(ambiguous.android?.ok ? "" : ambiguous.android?.error).toContain("MULTIPLE_APPLICATION_MODULES_FOUND: :app, :demo");
68
+
69
+ const selected = buildWorkspaceContext(root, pkgRoot, { appTarget: "demo" });
70
+ expect(selected.android?.ok).toBe(true);
71
+ expect(selected.android?.ok && selected.android.moduleName).toBe(":demo");
72
+ expect(selected.android?.ok && selected.android.moduleDir.endsWith(`${path.sep}demo`)).toBe(true);
73
+
74
+ const missing = buildWorkspaceContext(root, pkgRoot, { appTarget: "missing" });
75
+ expect(missing.android?.ok).toBe(false);
76
+ expect(missing.android?.ok ? "" : missing.android?.error).toContain("ANDROID_APPLICATION_MODULE_NOT_FOUND: :missing");
77
+ });
78
+ });
@@ -0,0 +1,53 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { topsdkMd5Base64Sign } from "../src/remote/topsdkSign.js";
3
+ import {
4
+ buildTopSdkGetSdkConfigUrl,
5
+ defaultTopSdkBaseUrl,
6
+ filterTopSdkAuthTypesForRequest,
7
+ resolveAuthTypesForGetSdkConfigRequest,
8
+ } from "../src/remote/topsdkGetSdkConfig.js";
9
+
10
+ describe("TOPSDK getSDKConfig client", () => {
11
+ it("matches topsdk-tool-ios md5_base64_byte signing", () => {
12
+ const sign = topsdkMd5Base64Sign("testApp", "secret", 1700000000000);
13
+ expect(sign).toBe("Fww7ophf9iCbLC+Rj9rQ5w==");
14
+ });
15
+
16
+ it("filters auth types like ChannelConfigManager", () => {
17
+ expect(filterTopSdkAuthTypesForRequest(["GUEST", "GOOGLE", "UI", "FACEBOOK", "IAPPAY"])).toEqual([
18
+ "GOOGLE",
19
+ "FACEBOOK",
20
+ ]);
21
+ });
22
+
23
+ it("resolveAuthTypesForGetSdkConfigRequest uses discovery when explicit list is empty", () => {
24
+ const r = resolveAuthTypesForGetSdkConfigRequest([]);
25
+ expect(r).toContain("FACEBOOK");
26
+ expect(r).toContain("GOOGLE");
27
+ expect(r).not.toContain("GUEST");
28
+ });
29
+
30
+ it("builds GET URL with repeated authType query keys", () => {
31
+ const { url } = buildTopSdkGetSdkConfigUrl({
32
+ baseUrl: "https://pre-api-sdk-gameplus.meetsocial.com/",
33
+ appId: "a",
34
+ appSecret: "b",
35
+ authTypes: ["GOOGLE", "FACEBOOK"],
36
+ channelType: "google",
37
+ timestampMillis: 99,
38
+ });
39
+ const u = new URL(url);
40
+ expect(u.pathname).toContain("getSDKConfig");
41
+ expect(u.searchParams.getAll("authType")).toEqual(["GOOGLE", "FACEBOOK"]);
42
+ expect(u.searchParams.get("channelType")).toBe("google");
43
+ expect(u.searchParams.get("appId")).toBe("a");
44
+ expect(u.searchParams.get("timestamp")).toBe("99");
45
+ expect(u.searchParams.get("sign")).toBeTruthy();
46
+ });
47
+
48
+ it("defaultTopSdkBaseUrl: prod / pre / test hosts", () => {
49
+ expect(defaultTopSdkBaseUrl("prod")).toBe("https://api-sdk-gameplus.meetsocial.com/");
50
+ expect(defaultTopSdkBaseUrl("pre")).toBe("https://pre-api-sdk-gameplus.meetsocial.com/");
51
+ expect(defaultTopSdkBaseUrl("test")).toBe("https://test-api-sdk-gameplus.meetsocial.com/");
52
+ });
53
+ });
@@ -0,0 +1,81 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ import { topsdkMd5Base64Sign } from "../src/remote/topsdkSign.js";
3
+ import {
4
+ buildTopSdkDownloadSdkConfigUrl,
5
+ fetchTopSdkDownloadSdkConfig,
6
+ parseTopSdkApiErrorBody,
7
+ } from "../src/remote/topsdkDownloadSdkConfig.js";
8
+
9
+ describe("TOPSDK downloadSDKConfig client", () => {
10
+ afterEach(() => {
11
+ vi.unstubAllGlobals();
12
+ });
13
+
14
+ it("builds GET URL with appId, channelType, sign, and timestamp", () => {
15
+ const { url } = buildTopSdkDownloadSdkConfigUrl({
16
+ baseUrl: "https://test-api-sdk-gameplus.meetsocial.com:1157/",
17
+ appId: "791251136341225472",
18
+ appSecret: "test-secret",
19
+ channelType: "GOOGLE",
20
+ timestampMillis: 1700000000000,
21
+ });
22
+ const u = new URL(url);
23
+ expect(u.pathname).toContain("downloadSDKConfig");
24
+ expect(u.searchParams.get("appId")).toBe("791251136341225472");
25
+ expect(u.searchParams.get("channelType")).toBe("GOOGLE");
26
+ expect(u.searchParams.get("timestamp")).toBe("1700000000000");
27
+ expect(u.searchParams.get("sign")).toBe(topsdkMd5Base64Sign("791251136341225472", "test-secret", 1700000000000));
28
+ expect(u.searchParams.has("devicePlatform")).toBe(false);
29
+ });
30
+
31
+ it("parseTopSdkApiErrorBody detects gp-sdk error envelope", () => {
32
+ expect(parseTopSdkApiErrorBody({ code: 4007, message: "secret error" })).toMatch(/secret error/);
33
+ expect(parseTopSdkApiErrorBody({ code: 200, data: {} })).toBeNull();
34
+ });
35
+
36
+ it("fetchTopSdkDownloadSdkConfig returns parsed JSON body and raw text", async () => {
37
+ const payload = {
38
+ packageName: "com.example.game",
39
+ topsdk: { channel: "GOOGLE", appId: "1", appSecret: "sec" },
40
+ sdkModules: { login: {}, payment: {}, analytics: {} },
41
+ };
42
+ const raw = JSON.stringify(payload, null, 2);
43
+ vi.stubGlobal(
44
+ "fetch",
45
+ vi.fn(async () => ({
46
+ ok: true,
47
+ status: 200,
48
+ text: async () => raw,
49
+ })) as unknown as typeof fetch
50
+ );
51
+
52
+ const { body, text } = await fetchTopSdkDownloadSdkConfig({
53
+ baseUrl: "https://example.com/",
54
+ appId: "1",
55
+ appSecret: "sec",
56
+ channelType: "GOOGLE",
57
+ });
58
+ expect(body).toEqual(payload);
59
+ expect(text).toBe(raw);
60
+ });
61
+
62
+ it("fetchTopSdkDownloadSdkConfig throws on API error body", async () => {
63
+ vi.stubGlobal(
64
+ "fetch",
65
+ vi.fn(async () => ({
66
+ ok: true,
67
+ status: 500,
68
+ text: async () => JSON.stringify({ code: 10000, message: "channel not found" }),
69
+ })) as unknown as typeof fetch
70
+ );
71
+
72
+ await expect(
73
+ fetchTopSdkDownloadSdkConfig({
74
+ baseUrl: "https://example.com/",
75
+ appId: "1",
76
+ appSecret: "sec",
77
+ channelType: "GOOGLE",
78
+ })
79
+ ).rejects.toThrow(/channel not found/);
80
+ });
81
+ });
@@ -0,0 +1,116 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ TOPSDK_FEATURE_MODULES,
4
+ buildTopSdkFeatureImplementationLines,
5
+ isTopSdkFeatureModuleEnabled,
6
+ } from "../src/config/topsdkFeatureModules.js";
7
+ import { defaultSdkModules, type MeetSdkRemoteConfig } from "../src/config/meetSdkRemoteConfig.js";
8
+
9
+ const base = (sdk: MeetSdkRemoteConfig["sdkModules"]): MeetSdkRemoteConfig => ({
10
+ packageName: "com.example",
11
+ topsdk: {
12
+ channel: "GOOGLE",
13
+ appId: "a",
14
+ appSecret: "s",
15
+ version: "1",
16
+ groupId: "com.sino.topsdk",
17
+ repositories: [],
18
+ },
19
+ sdkModules: sdk,
20
+ });
21
+
22
+ describe("topsdkFeatureModules", () => {
23
+ it("maps googleIap to google-iap artifact", () => {
24
+ const row = TOPSDK_FEATURE_MODULES.find((m) => m.subKey === "googleIap");
25
+ expect(row?.topsdkArtifact).toBe("google-iap");
26
+ expect(row?.category).toBe("payment");
27
+ });
28
+
29
+ it("buildTopSdkFeatureImplementationLines only includes enabled sdkModules", () => {
30
+ const m = defaultSdkModules();
31
+ m.login.google = { googleClientId: "cid" };
32
+ m.payment.googleIap = { dependencies: [{ implementation: "$groupId:google-iap:$topsdk_version" }] };
33
+ const cfg = base(m);
34
+ const lines = buildTopSdkFeatureImplementationLines(cfg);
35
+ expect(lines.some((l) => l.includes(":google:"))).toBe(true);
36
+ expect(lines.some((l) => l.includes(":google-iap:"))).toBe(true);
37
+ expect(lines.some((l) => l.includes(":guest:"))).toBe(false);
38
+ });
39
+
40
+ it("login.facebook credentials object enables facebook artifact", () => {
41
+ const m = defaultSdkModules();
42
+ m.login.facebook = { facebookAppId: "", fbLoginProtocolScheme: "", facebookClientToken: "" };
43
+ m.analytics.facebookdata = false;
44
+ const cfg = base(m);
45
+ const lines = buildTopSdkFeatureImplementationLines(cfg);
46
+ expect(lines.some((l) => l.includes(":facebook:"))).toBe(true);
47
+ expect(lines.some((l) => l.includes(":facebook-data:"))).toBe(false);
48
+ });
49
+
50
+ it("login.facebook does not imply analytics facebook-data", () => {
51
+ const m = defaultSdkModules();
52
+ m.login.facebook = {
53
+ facebookAppId: "1",
54
+ fbLoginProtocolScheme: "fb1",
55
+ facebookClientToken: "t",
56
+ };
57
+ m.analytics.facebookdata = false;
58
+ const cfg = base(m);
59
+ const lines = buildTopSdkFeatureImplementationLines(cfg);
60
+ expect(lines.some((l) => l.includes(":facebook:"))).toBe(true);
61
+ expect(lines.some((l) => l.includes(":facebook-data:"))).toBe(false);
62
+ });
63
+
64
+ it("analytics.facebookdata enables facebook-data only", () => {
65
+ const m = defaultSdkModules();
66
+ m.login.facebook = false;
67
+ m.analytics.facebookdata = { dependencies: [{ implementation: "$groupId:facebook-data:$topsdk_version" }] };
68
+ const cfg = base(m);
69
+ const lines = buildTopSdkFeatureImplementationLines(cfg);
70
+ expect(lines.some((l) => l.includes(":facebook:"))).toBe(false);
71
+ expect(lines.some((l) => l.includes(":facebook-data:"))).toBe(true);
72
+ });
73
+
74
+ it("analytics.firebase credentials enable firebase artifact", () => {
75
+ const m = defaultSdkModules();
76
+ m.analytics.firebase = {
77
+ firebase_file_url: "https://x/g.json",
78
+ repositories: ["google"],
79
+ classpath: "com.google.gms:google-services:4.4.4",
80
+ applyplugin: "com.google.gms.google-services",
81
+ };
82
+ const cfg = base(m);
83
+ expect(buildTopSdkFeatureImplementationLines(cfg).some((l) => l.includes(":firebase:"))).toBe(true);
84
+ });
85
+
86
+ it("analytics.adjust credentials enable adjust artifact", () => {
87
+ const m = defaultSdkModules();
88
+ m.analytics.adjust = { appId: "adj1" };
89
+ const cfg = base(m);
90
+ expect(buildTopSdkFeatureImplementationLines(cfg).some((l) => l.includes(":adjust:"))).toBe(true);
91
+ });
92
+
93
+ it("login.line credentials enable line artifact", () => {
94
+ const m = defaultSdkModules();
95
+ m.login.line = { clientId: "L" };
96
+ const cfg = base(m);
97
+ expect(buildTopSdkFeatureImplementationLines(cfg).some((l) => l.includes(":line:"))).toBe(true);
98
+ });
99
+
100
+ it("isTopSdkFeatureModuleEnabled reads sdkModules only", () => {
101
+ const row = TOPSDK_FEATURE_MODULES.find((m) => m.topsdkArtifact === "facebook-data")!;
102
+ const m = defaultSdkModules();
103
+ m.analytics.facebookdata = { dependencies: [{ implementation: "$groupId:facebook-data:$topsdk_version" }] };
104
+ expect(isTopSdkFeatureModuleEnabled(base(m), row)).toBe(true);
105
+ });
106
+
107
+ it("enables module only when subKey is present (key-based integrate)", () => {
108
+ const kakaoRow = TOPSDK_FEATURE_MODULES.find((m) => m.subKey === "kakao")!;
109
+ const m = defaultSdkModules();
110
+ m.login = { google: { googleClientId: "cid" } } as typeof m.login;
111
+ expect(isTopSdkFeatureModuleEnabled(base(m), kakaoRow)).toBe(false);
112
+
113
+ m.login.kakao = { clientId: "k", scheme: "s" };
114
+ expect(isTopSdkFeatureModuleEnabled(base(m), kakaoRow)).toBe(true);
115
+ });
116
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "dist",
7
+ "rootDir": "src",
8
+ "strict": true,
9
+ "declaration": true,
10
+ "declarationMap": true,
11
+ "sourceMap": true,
12
+ "skipLibCheck": true,
13
+ "resolveJsonModule": true,
14
+ "esModuleInterop": true,
15
+ "forceConsistentCasingInFileNames": true
16
+ },
17
+ "include": ["src/**/*.ts"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: false,
6
+ environment: "node",
7
+ include: ["tests/**/*.test.ts"],
8
+ },
9
+ });
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from "vitest/config";
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ globals: false,
6
+ environment: "node",
7
+ include: ["tests/mcp.e2e.ts"],
8
+ testTimeout: 20_000,
9
+ hookTimeout: 20_000,
10
+ },
11
+ });
@@ -1 +0,0 @@
1
- bundled-sample
package/docs/ANDROID.md DELETED
@@ -1,133 +0,0 @@
1
- # Android 集成工具说明
2
-
3
- 本仓库(`meet-sdk-tool`)内的 CLI 与库代码**全部为 TypeScript**;发布时由 `tsc` 编译到 `dist/*.js`,npm `bin` 指向编译产物。
4
-
5
- ## 范围
6
-
7
- - **Android**:远程拉取配置、组装 JSON、按步骤修改 Gradle / `AndroidManifest.xml` / 拷贝 `bundled/` 资源等(步骤可扩展)。
8
- - **iOS**:暂不实现;`src/ios/reserved.ts` 中保留占位类型与说明,便于后续接入。
9
-
10
- ## 远程接口文档
11
-
12
- meet-sdk-tool 用到的及对照用的 HTTP 接口(含 `downloadSDKConfig`、`getSDKConfig`、`getChannelConfig` 样例)见 **[`docs/API.md`](./API.md)**。
13
-
14
- ## 远程配置(TOPSDK,与平台无关)
15
-
16
- 与 **Android / iOS 共用同一套 HTTP 接口**,实现对齐 `topsdk-tool-ios`:
17
-
18
- - 路径:`GET {baseUrl}console/openSDK/getSDKConfig`
19
- - 查询参数:`appId`、`authType`(可重复多次)、`channelType`、`sign`、`timestamp`(毫秒)
20
- - 签名:`sign = base64( md5_binary( appId + appSecret + timestamp ) )`,与 `topsdk-tool-ios` 仓库中 `TOPSDKUtils/ChannelConfigManager.py` 的 `md5_base64_byte` 一致。
21
- - 默认 `baseUrl` 由 **`--env`** 决定(**不传则 `prod` 正式服**):`prod` → `https://api-sdk-gameplus.meetsocial.com/`;`pre` → `https://pre-api-sdk-gameplus.meetsocial.com/`;`test` → `https://test-api-sdk-gameplus.meetsocial.com/`(开发调试请显式 `--env test`)。**不再提供 `--base-url`**。
22
- - 请求前会从 `authType` 列表中移除 `GUEST`、`UI`、`IAPPAY`(与 `ChannelConfigManager.getSdkConfig` 行为一致)。Android 侧若使用 `google` 等渠道,通过 `--channel-type` 传入即可(与 iOS 传 `apple` 一样走同一 URL)。
23
- - **服务端与字段**:`gp-sdk` 的 `openSDK/getSDKConfig`(`SDKDownloadController`)返回体通常 **只有** `data.channelAuthConfig`(`VOSDKConfig`),与 `topsdk-tool` / `topsdk-tool-ios` 解析的 `channelAuthConfig` 一致。`sdk-home` 提供的是 **SDK 包下载**(`/home/sdk-download/...`),不负责该配置接口。控制台 VO 里 Facebook 的 **client token 多在 `secret`**;AppsFlyer 的 **devKey 在 `secret`**(`clientId` 可能为其它业务字段)。SDK 版本、仓库、构件依赖、Firebase Gradle plugin 等固定集成配置由工具内置的 `meetsdk-android.json` 提供。
24
-
25
- 对应 TypeScript 实现:`[src/remote/topsdkGetSdkConfig.ts](../src/remote/topsdkGetSdkConfig.ts)`、`[src/remote/topsdkSign.ts](../src/remote/topsdkSign.ts)`;映射为 mock 形输出:`[src/config/meetSdkRemoteConfig.ts](../src/config/meetSdkRemoteConfig.ts)`。
26
-
27
- ### `fetch-config` 与缓存文件 `meetsdk-remote-config.json`
28
-
29
- 拉取结果**始终**写入宿主工程根目录下的 **`meetsdk-remote-config.json`**(即 `<project-root>/meetsdk-remote-config.json`),作为本地缓存,**不提供自定义输出路径**。该文件只放每个游戏不同的后台参数:`packageName`、根级 `channel` / `devicePlatform`、`topsdk.appId/appSecret` 以及各插件的业务参数(例如登录 clientId、AppsFlyer devKey、Firebase `firebase_file_url`、Adjust appId)。固定 SDK 集成配置放在工具内置的 [`meetsdk-android.json`](../meetsdk-android.json) 中,包括 `topsdk.version/groupId/repositories`、插件仓库、Firebase `classpath/applyplugin` 和各插件 `dependencies`。标准集成步骤放在工具内置 [`recipes/android-default.yaml`](../recipes/android-default.yaml) 中,测试 fixture 放在 [`fixtures/recipes/`](../fixtures/recipes/) 中,游戏工程目录不需要放 recipe/fixture 文件。远程配置请用 `fetch-config` 或 `setup` 从后台拉取;`fixtures/meetsdk-remote-config.mock.json` 仅用于本仓库 Vitest,勿用于真实游戏工程。仓库内自带可跑的 Android 宿主样例见 `[test-projects/android-sample/](../test-projects/android-sample/)`(仅包含宿主工程文件与 `meetsdk-remote-config.json`);另可在同级目录下并列更多工程(如 `[test-projects/android-sample-b/](../test-projects/android-sample-b/)),用不同 `--project-root` 分别验证;说明见 `[test-projects/README.md](../test-projects/README.md)`。Vitest 管线测试默认只使用 `android-sample/`。
30
-
31
- **与 `topsdk-tool-ios` 一致**:iOS 工具在 Python 里固定调用 `getChannelConfigUrl() + 'console/openSDK/getSDKConfig'`,用 `appId` / `appSecret` / `channelType` / `authType[]` 等拼查询串并算 `sign`,**没有**「用户传入任意完整 URL」的模式。本 CLI 的 `fetch-config` 同样**只走该 TOPSDK 接口**,不提供 `--url`。
32
-
33
- **含义**:CLI 调用 `**console/openSDK/downloadSDKConfig`**(无需 sign):用 `appId`、`channelType` 拉取与 gp-sdk 一致的 `meetsdk-remote-config.json` 全文并**原样**写入工程根目录(不做 JSON 再序列化,不合并 `meetsdk-android.json`;后者仅在 `integrate` 时在内存中合并)。
34
-
35
- ```bash
36
- meetgames fetch-config \
37
- --project-root /path/to/android-project \
38
- --app-id 791251136341225472 \
39
- --channel-type GOOGLE \
40
- --env test
41
- ```
42
-
43
- `--app-id` 与 `--channel-type` 为调用接口所必需(也可来自已有 `meetsdk-remote-config.json` 或 `TOPSDK_APP_ID` / `TOPSDK_CHANNEL_TYPE`)。`packageName`、`topsdk.appSecret` 等由接口返回的 JSON 写入,无需 CLI 传入。gp-sdk 按 `(appId, channelType)` 查 channel。`--auth-type` / `TOPSDK_AUTH_TYPES` 已忽略(仅兼容旧脚本)。
44
-
45
- ### CLI 参数与子命令对应关系
46
-
47
- 解析器是**全局**的:除未知 token 会报错外,部分参数在某一子命令下**不会生效**(仅为与其它子命令共用同一套 flag 名)。
48
-
49
-
50
- | 参数 | `fetch-config` | `integrate` / `setup` | `doctor` |
51
- | -------------------------------- | -------------- | ------------------------------------------ | ----------------- |
52
- | `--project-root` | 是(缓存目录) | 是 | 是 |
53
- | `--app-id` | 是(必填*) | 否 | 否 |
54
- | `--channel-type` | 是(必填*) | 否 | 否 |
55
- | `--auth-type`(可重复) | 忽略(兼容) | 否 | 否 |
56
- | `--env`(`prod` / `pre` / `test`,默认 `prod`) | 是 | 否 | 否 |
57
- | `--verbose` | 是 | 是 | 是 |
58
- | `--dry-run` | 忽略 | 是(仅预览、不写盘) | 否 |
59
- | `--report-file` | 忽略 | 是 | 否 |
60
- | `--patch-file` | 忽略 | 是 | 否 |
61
- | `--help` / `-h` | 是 | 是 | 是 |
62
-
63
-
64
- 因此,在 `**fetch-config`** 上除本地 `meetsdk-remote-config.json` 外,**实际参与拉取**的还有:`--env`、`--verbose`,以及 `--app-id`、`--channel-type`(或环境变量 / 已有缓存文件)。`--dry-run`、`--report-file`、`--patch-file` 可被解析但不会改变 `fetch-config` 行为。
65
-
66
- ## 其它命令
67
-
68
- 1. `**integrate`** / `**setup**`:固定读取工具内置 `recipes/integrate-default.yaml`,对 `--project-root` 下的工程执行标准集成步骤(`setup` 会先 `fetch-config`)。
69
- 2. `**doctor**`:检测工程类型(Android / iOS)与路径,不写入配置。
70
-
71
- `**integrate` 默认写磁盘**;若流水线或本地只想生成 diff、不落盘,请显式传入 `**--dry-run`**(可配合 `--patch-file` 输出 patch 文件)。Vitest 在 `tests/pipeline.preview.patch.test.ts` 中把内置 recipe 与 schema fixture 的 dry-run diff **合并写入唯一文件** `**test-projects/_preview/pipeline.patch`**(`npm test` 后打开即可核对)。
72
-
73
- ## Gradle 编辑方式(Groovy only)
74
-
75
- | 项 | 说明 |
76
- |----|------|
77
- | **现阶段** | **正则 + 括号匹配**定位 `android` / `defaultConfig` / `dependencies` 等块;**行级正则**识别 `resValue`、`implementation`;**`// >>> TOPSDK … START/END`** 标记块做幂等写入(实现:`src/android/gradle.ts`、`src/android/meetSdkRemoteGradle.ts`) |
78
- | **将来** | 改用 **Groovy AST** 做块定位与语句级改写 |
79
- | **不支持** | **`build.gradle.kts`(Kotlin DSL)** — 仅支持 Groovy DSL 的 `build.gradle` |
80
-
81
- 详见 [技术方案调研.md §6](./技术方案调研.md#6-gradle-编辑技术路线正则--groovy-ast)。
82
-
83
- ## `gradle.applyMeetSdkRemoteConfig`
84
-
85
- 与 **sdk-integration-agent**(`topsdk-agent`)中 `gradleEditor.js` 一致:读取工程根下的 `**meetsdk-remote-config.json`**(或由步骤参数 `**configFile**` 指定相对路径),再与工具内置 `**meetsdk-android.json**` 合并;只对远程配置中已出现的插件补齐 SDK 固定配置,校验后:
86
-
87
- - 在**根目录 `build.gradle`** 的 `allprojects { repositories { … } }` 内写入 `**// >>> TOPSDK REPO AUTO START/END**` 托管块,从内置 `meetsdk-android.json` 汇总已启用插件与 TopSdk 仓库声明生成 `google()` / `mavenCentral()` / `maven { url '…' }`;默认顺序为 Firebase、AppsFlyer、TopSdk。
88
- - 若开启 `sdkModules.analytics.firebase`,在**根目录 `build.gradle`** 的 `buildscript { repositories { … } dependencies { … } }` 内写入 Firebase 所需仓库与 `classpath`(默认示例为 `com.google.gms:google-services:4.4.4`)。
89
- - 在 **application 模块 `build.gradle`** 的 `defaultConfig { … }` 内把 `applicationId` 更新为远程配置里的 `packageName`,并写入 `**resValue**`(`top_channel_id`、`top_app_id`、Facebook / Google / AppsFlyer 等),在文件顶部写入 Firebase 的 `apply plugin`(默认示例为 `com.google.gms.google-services`),并在 `**dependencies { … }**` 内写入 `**def topsdk_version` / `def groupId**`、`implementation "$groupId:ui:$topsdk_version"` 以及内置 `meetsdk-android.json` 中对应插件的 `dependencies` 配置。
90
-
91
- 与 `**gradle.insertRepositories**`(`MEET_INTEGRATE REPOS` 标记块)可并存于同一 `repositories` 闭包内;当前 `**test-projects/android-sample**` 已仅用本 op 从 `meetsdk-remote-config.json` 写入仓库与依赖。
92
-
93
- ### `sdkModules`、凭证与 Gradle 依赖
94
-
95
- - **不再**使用顶层 `facebook` / `google` / `appsflyer`,也不使用扁平 `features` / `featuresByCategory`;解析时若仍存在这些顶层键会拒绝(`tryParseAsMeetSdkRemoteConfig` 返回 `null`)。
96
- - **所有插件**:integrate 仅当 `sdkModules` 对应 scope 下**写了子键**时接入(如 `kakao`、`appsflyer`、`facebookdata`);有键则 value 为 `{}` 或参数对象。无配置则不写该键。远程配置对象只放业务参数,仓库、`classpath`、`applyplugin`、`dependencies` 从内置 `meetsdk-android.json` 按插件 key 补齐。
97
- - **`login.facebook` / `login.google` / `analytics.appsflyer` 等带参数插件**:对象内只包含插件业务参数;直接写 `true` 会被拒绝,避免缺参数误开启。
98
- - **`login.guest` / `login.email` / `payment.googleIap` / `analytics.facebook` 等无参数插件**:使用空对象 `{}` 表示开启;其中 **`analytics.facebook`** 只控制埋点构件 `facebook-data`,与登录 Facebook 无关。
99
-
100
- 示例(开启 Facebook / Google 登录与 AppsFlyer 时,参数写在对应子键下):
101
-
102
- ```json
103
- "sdkModules": {
104
- "login": {
105
- "guest": {},
106
- "email": {},
107
- "facebook": {
108
- "facebookAppId": "…",
109
- "fbLoginProtocolScheme": "fb…",
110
- "facebookClientToken": "…"
111
- },
112
- "google": { "googleClientId": "….apps.googleusercontent.com" }
113
- },
114
- "payment": {
115
- "googleIap": {}
116
- },
117
- "analytics": {
118
- "appsflyer": {
119
- "enableDebugLog": false,
120
- "devKey": "…"
121
- }
122
- }
123
- }
124
- ```
125
-
126
- - **`login.facebook`**(为对象时)→ Gradle 写入 Facebook 相关 `resValue`,并追加 TOPSDK 构件 **`facebook`**(见 [`topsdkFeatureModules.ts`](../src/config/topsdkFeatureModules.ts))。
127
- - **`analytics.facebook`**(为对象时)→ 构件 **`facebook-data`**(Maven 名在内置 `meetsdk-android.json` 中维护)。
128
- - **`fetch-config`**:仍按 `channelAuthConfig` 把各 auth 项映射为上述嵌套结构(直接落在 `sdkModules` 内)。
129
- - 扩展:在 `MeetSdkRemoteConfig` / `normalizeSdkModulesFromUnknown` 增加子模块形状,并在内置 `meetsdk-android.json` 中补对应插件的仓库、依赖或 Gradle plugin 配置。
130
-
131
- ## 后续扩展
132
-
133
- 在 `src/ops/handlers.ts` 中可继续新增其它 `op`,扩展 manifest 能驱动的工程修改能力。