@playcraft/build 0.0.3 → 0.0.8

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 (64) hide show
  1. package/dist/analyzers/scene-asset-collector.js +210 -1
  2. package/dist/base-builder.d.ts +17 -0
  3. package/dist/base-builder.js +211 -16
  4. package/dist/generators/config-generator.js +29 -3
  5. package/dist/loaders/playcanvas-loader.d.ts +7 -0
  6. package/dist/loaders/playcanvas-loader.js +53 -3
  7. package/dist/platforms/adikteev.d.ts +10 -0
  8. package/dist/platforms/adikteev.js +72 -0
  9. package/dist/platforms/base.d.ts +12 -0
  10. package/dist/platforms/base.js +208 -0
  11. package/dist/platforms/facebook.js +5 -2
  12. package/dist/platforms/index.d.ts +4 -0
  13. package/dist/platforms/index.js +16 -0
  14. package/dist/platforms/inmobi.d.ts +10 -0
  15. package/dist/platforms/inmobi.js +68 -0
  16. package/dist/platforms/ironsource.js +5 -2
  17. package/dist/platforms/moloco.js +5 -2
  18. package/dist/platforms/playcraft.d.ts +33 -0
  19. package/dist/platforms/playcraft.js +44 -0
  20. package/dist/platforms/remerge.d.ts +10 -0
  21. package/dist/platforms/remerge.js +56 -0
  22. package/dist/templates/__loading__.js +100 -0
  23. package/dist/templates/__modules__.js +47 -0
  24. package/dist/templates/__settings__.template.js +20 -0
  25. package/dist/templates/__start__.js +332 -0
  26. package/dist/templates/index.html +18 -0
  27. package/dist/templates/logo.png +0 -0
  28. package/dist/templates/manifest.json +1 -0
  29. package/dist/templates/patches/cannon.min.js +28 -0
  30. package/dist/templates/patches/lz4.js +10 -0
  31. package/dist/templates/patches/one-page-http-get.js +20 -0
  32. package/dist/templates/patches/one-page-inline-game-scripts.js +52 -0
  33. package/dist/templates/patches/one-page-mraid-resize-canvas.js +46 -0
  34. package/dist/templates/patches/p2.min.js +27 -0
  35. package/dist/templates/patches/playcraft-no-xhr.js +76 -0
  36. package/dist/templates/playcanvas-stable.min.js +16363 -0
  37. package/dist/templates/styles.css +43 -0
  38. package/dist/types.d.ts +14 -1
  39. package/dist/utils/build-mode-detector.d.ts +9 -0
  40. package/dist/utils/build-mode-detector.js +42 -0
  41. package/dist/vite/config-builder.d.ts +29 -1
  42. package/dist/vite/config-builder.js +169 -39
  43. package/dist/vite/platform-configs.d.ts +4 -0
  44. package/dist/vite/platform-configs.js +98 -14
  45. package/dist/vite/plugin-esm-html-generator.d.ts +22 -0
  46. package/dist/vite/plugin-esm-html-generator.js +1061 -0
  47. package/dist/vite/plugin-platform.js +56 -17
  48. package/dist/vite/plugin-playcanvas.d.ts +2 -0
  49. package/dist/vite/plugin-playcanvas.js +579 -49
  50. package/dist/vite/plugin-source-builder.d.ts +3 -0
  51. package/dist/vite/plugin-source-builder.js +920 -23
  52. package/dist/vite-builder.d.ts +19 -2
  53. package/dist/vite-builder.js +162 -12
  54. package/package.json +2 -1
  55. package/physics/cannon-es-bundle.js +13092 -0
  56. package/physics/cannon-rigidbody-adapter.js +375 -0
  57. package/physics/connon-integration.js +411 -0
  58. package/templates/__start__.js +8 -3
  59. package/templates/index.esm.html +20 -0
  60. package/templates/index.esm.mjs +502 -0
  61. package/templates/patches/one-page-inline-game-scripts.js +33 -1
  62. package/templates/patches/playcraft-cta-adapter.js +297 -0
  63. package/templates/patches/playcraft-no-xhr.js +25 -1
  64. package/templates/playcanvas-esm-wrapper.mjs +827 -0
@@ -1,8 +1,15 @@
1
+ export interface ImportMapAsset {
2
+ id: string;
3
+ content: {
4
+ imports: Record<string, string>;
5
+ };
6
+ }
1
7
  export interface PlayCanvasProject {
2
8
  project: any;
3
9
  scenes: any;
4
10
  assets: any;
5
11
  format: 'playcanvas';
12
+ importMap?: ImportMapAsset;
6
13
  }
7
14
  /**
8
15
  * 加载 PlayCanvas 源代码项目
@@ -9,10 +9,60 @@ export async function loadPlayCanvasProject(projectDir) {
9
9
  fs.readFile(path.join(projectDir, 'scenes.json'), 'utf-8'),
10
10
  fs.readFile(path.join(projectDir, 'assets.json'), 'utf-8'),
11
11
  ]);
12
+ const project = JSON.parse(projectJson);
13
+ const scenes = JSON.parse(scenesJson);
14
+ const assets = JSON.parse(assetsJson);
15
+ // 检查是否有 Import Map 配置
16
+ let importMap;
17
+ const importMapId = project.settings?.importMap;
18
+ if (importMapId) {
19
+ try {
20
+ const importMapAsset = assets[String(importMapId)];
21
+ if (importMapAsset && importMapAsset.file) {
22
+ // 尝试获取文件URL,如果不存在则构建可能的路径
23
+ let importMapPath = null;
24
+ if (importMapAsset.file.url) {
25
+ importMapPath = path.join(projectDir, importMapAsset.file.url);
26
+ }
27
+ else if (importMapAsset.file.filename) {
28
+ // 尝试多个可能的路径
29
+ const filename = importMapAsset.file.filename;
30
+ const revision = importMapAsset.revision ?? 1;
31
+ const candidates = [
32
+ path.join(projectDir, 'files', 'assets', String(importMapId), String(revision), filename),
33
+ path.join(projectDir, 'files', 'assets', String(importMapId), '1', filename),
34
+ path.join(projectDir, 'files', 'assets', String(importMapId), filename),
35
+ ];
36
+ for (const candidate of candidates) {
37
+ try {
38
+ await fs.access(candidate);
39
+ importMapPath = candidate;
40
+ break;
41
+ }
42
+ catch {
43
+ // 继续尝试下一个
44
+ }
45
+ }
46
+ }
47
+ if (importMapPath) {
48
+ const importMapContent = await fs.readFile(importMapPath, 'utf-8');
49
+ importMap = {
50
+ id: String(importMapId),
51
+ content: JSON.parse(importMapContent),
52
+ };
53
+ console.log('[PlayCanvasLoader] Import Map 已加载:', importMap.id);
54
+ }
55
+ }
56
+ }
57
+ catch (error) {
58
+ console.warn('[PlayCanvasLoader] 无法加载 Import Map:', error);
59
+ }
60
+ }
12
61
  return {
13
- project: JSON.parse(projectJson),
14
- scenes: JSON.parse(scenesJson),
15
- assets: JSON.parse(assetsJson),
62
+ project,
63
+ scenes,
64
+ assets,
16
65
  format: 'playcanvas',
66
+ importMap,
17
67
  };
18
68
  }
@@ -0,0 +1,10 @@
1
+ import { PlatformAdapter } from './base.js';
2
+ import type { AssetInfo } from '../types.js';
3
+ export declare class AdikteevAdapter extends PlatformAdapter {
4
+ getName(): string;
5
+ getSizeLimit(): number;
6
+ getDefaultFormat(): 'html' | 'zip';
7
+ modifyHTML(html: string, assets: AssetInfo[]): string;
8
+ getPlatformScript(): string;
9
+ validateOptions(): void;
10
+ }
@@ -0,0 +1,72 @@
1
+ import { PlatformAdapter } from './base.js';
2
+ export class AdikteevAdapter extends PlatformAdapter {
3
+ getName() {
4
+ return 'Adikteev';
5
+ }
6
+ getSizeLimit() {
7
+ // Adikteev: 5MB
8
+ return 5 * 1024 * 1024;
9
+ }
10
+ getDefaultFormat() {
11
+ return 'html';
12
+ }
13
+ modifyHTML(html, assets) {
14
+ // Adikteev 需要 MRAID 3.0 支持
15
+ const adikteevScript = `
16
+ <script>
17
+ // MRAID 3.0 API
18
+ window.mraid = window.mraid || {
19
+ getVersion: function() { return '3.0'; },
20
+ isReady: function() { return true; },
21
+ open: function(url) {
22
+ console.log('Adikteev CTA: opening store');
23
+ window.open(url, '_blank');
24
+ },
25
+ close: function() { window.close(); },
26
+ addEventListener: function(event, listener) {
27
+ if (event === 'ready' || event === 'viewableChange') {
28
+ setTimeout(() => listener({ viewable: true }), 0);
29
+ }
30
+ },
31
+ removeEventListener: function(event, listener) {},
32
+ getState: function() { return 'default'; },
33
+ getPlacementType: function() { return 'interstitial'; },
34
+ isViewable: function() { return true; }
35
+ };
36
+ </script>
37
+ <!--
38
+ 注意:
39
+ - Adikteev 要求 MRAID 3.0
40
+ - 使用单文件 HTML 格式
41
+ - 使用 mraid.open() 跳转应用商店
42
+ - 需等待 viewableChange 事件后再启动游戏
43
+ - 不允许自动重定向
44
+ -->
45
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
46
+ `;
47
+ // 在 </head> 之前插入平台特定的 API
48
+ html = html.replace('</head>', `${adikteevScript}</head>`);
49
+ // 注入统一的 CTA 适配器
50
+ html = this.injectCTAAdapter(html);
51
+ return html;
52
+ }
53
+ getPlatformScript() {
54
+ return `
55
+ // Adikteev Playable Ad
56
+ // 等待 viewableChange 事件
57
+
58
+ if (typeof mraid !== 'undefined') {
59
+ mraid.addEventListener('viewableChange', function(viewable) {
60
+ if (viewable) {
61
+ console.log('Adikteev: playable is viewable, starting game');
62
+ }
63
+ });
64
+ }
65
+ `;
66
+ }
67
+ validateOptions() {
68
+ if (this.options.format && this.options.format !== 'html') {
69
+ console.warn('警告: Adikteev 使用单文件 HTML 格式');
70
+ }
71
+ }
72
+ }
@@ -26,4 +26,16 @@ export declare abstract class PlatformAdapter {
26
26
  * 验证配置
27
27
  */
28
28
  validateOptions(): void;
29
+ /**
30
+ * 读取模板文件
31
+ */
32
+ protected readTemplateFile(filename: string): Promise<string>;
33
+ /**
34
+ * 获取 CTA 适配器脚本(同步版本,用于模板字符串)
35
+ */
36
+ protected getCTAAdapterScript(): string;
37
+ /**
38
+ * 在 HTML 中注入 CTA 适配器
39
+ */
40
+ protected injectCTAAdapter(html: string): string;
29
41
  }
@@ -1,3 +1,6 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
1
4
  export class PlatformAdapter {
2
5
  constructor(options) {
3
6
  this.options = options;
@@ -8,4 +11,209 @@ export class PlatformAdapter {
8
11
  validateOptions() {
9
12
  // 默认实现,子类可以覆盖
10
13
  }
14
+ /**
15
+ * 读取模板文件
16
+ */
17
+ async readTemplateFile(filename) {
18
+ const currentDir = path.dirname(fileURLToPath(import.meta.url));
19
+ const templatePath = path.resolve(currentDir, '../../templates/patches', filename);
20
+ return await fs.readFile(templatePath, 'utf-8');
21
+ }
22
+ /**
23
+ * 获取 CTA 适配器脚本(同步版本,用于模板字符串)
24
+ */
25
+ getCTAAdapterScript() {
26
+ // 返回内联的 CTA 适配器代码
27
+ // 注意:这是一个简化版本,实际使用时会从文件读取
28
+ return `
29
+ <script>
30
+ // PlayCraft CTA Adapter - 统一的跳转应用商店适配器
31
+ (function() {
32
+ 'use strict';
33
+
34
+ function CTAAdapter() {
35
+ this.platform = null;
36
+ this.isReady = false;
37
+ this.readyCallbacks = [];
38
+ this.detectPlatform();
39
+ this.initialize();
40
+ }
41
+
42
+ CTAAdapter.prototype.detectPlatform = function() {
43
+ if (typeof FbPlayableAd !== 'undefined') {
44
+ this.platform = 'facebook';
45
+ } else if (typeof mraid !== 'undefined') {
46
+ this.platform = 'mraid';
47
+ } else if (typeof dapi !== 'undefined') {
48
+ this.platform = 'dapi';
49
+ } else if (typeof ExitApi !== 'undefined') {
50
+ this.platform = 'google';
51
+ } else if (typeof window.BGY_MRAID !== 'undefined') {
52
+ this.platform = 'bigo';
53
+ } else if (typeof snapchatCta === 'function') {
54
+ this.platform = 'snapchat';
55
+ } else {
56
+ this.platform = 'unknown';
57
+ }
58
+ };
59
+
60
+ CTAAdapter.prototype.initialize = function() {
61
+ var self = this;
62
+ switch (this.platform) {
63
+ case 'facebook':
64
+ case 'google':
65
+ case 'bigo':
66
+ case 'snapchat':
67
+ this.isReady = true;
68
+ this.notifyReady();
69
+ break;
70
+ case 'mraid':
71
+ if (mraid.isReady && mraid.isReady()) {
72
+ this.isReady = true;
73
+ this.notifyReady();
74
+ } else if (mraid.addEventListener) {
75
+ mraid.addEventListener('ready', function() {
76
+ self.isReady = true;
77
+ self.notifyReady();
78
+ });
79
+ }
80
+ break;
81
+ case 'dapi':
82
+ if (dapi.isReady && dapi.isReady()) {
83
+ this.isReady = true;
84
+ this.notifyReady();
85
+ } else if (dapi.addEventListener) {
86
+ dapi.addEventListener('ready', function() {
87
+ self.isReady = true;
88
+ self.notifyReady();
89
+ });
90
+ }
91
+ break;
92
+ default:
93
+ this.isReady = true;
94
+ this.notifyReady();
95
+ break;
96
+ }
97
+ };
98
+
99
+ CTAAdapter.prototype.notifyReady = function() {
100
+ for (var i = 0; i < this.readyCallbacks.length; i++) {
101
+ try {
102
+ this.readyCallbacks[i]();
103
+ } catch (e) {
104
+ console.error('[PlayCraft CTA] Ready callback error:', e);
105
+ }
106
+ }
107
+ this.readyCallbacks = [];
108
+ };
109
+
110
+ CTAAdapter.prototype.onReady = function(callback) {
111
+ if (this.isReady) {
112
+ setTimeout(callback, 0);
113
+ } else {
114
+ this.readyCallbacks.push(callback);
115
+ }
116
+ };
117
+
118
+ CTAAdapter.prototype.jump = function(options) {
119
+ options = options || {};
120
+ try {
121
+ switch (this.platform) {
122
+ case 'facebook':
123
+ if (typeof FbPlayableAd !== 'undefined' && FbPlayableAd.onCTAClick) {
124
+ FbPlayableAd.onCTAClick();
125
+ }
126
+ break;
127
+ case 'mraid':
128
+ if (typeof mraid !== 'undefined' && mraid.open) {
129
+ mraid.open(options.url || '');
130
+ }
131
+ break;
132
+ case 'dapi':
133
+ if (typeof dapi !== 'undefined' && dapi.openStoreUrl) {
134
+ dapi.openStoreUrl();
135
+ }
136
+ break;
137
+ case 'google':
138
+ if (typeof ExitApi !== 'undefined' && ExitApi.exit) {
139
+ ExitApi.exit();
140
+ }
141
+ break;
142
+ case 'bigo':
143
+ if (typeof window.BGY_MRAID !== 'undefined' && window.BGY_MRAID.open) {
144
+ window.BGY_MRAID.open();
145
+ }
146
+ break;
147
+ case 'snapchat':
148
+ if (typeof snapchatCta === 'function') {
149
+ snapchatCta();
150
+ }
151
+ break;
152
+ default:
153
+ this.fallbackJump(options.url);
154
+ break;
155
+ }
156
+ } catch (e) {
157
+ console.error('[PlayCraft CTA] Jump failed:', e);
158
+ this.fallbackJump(options.url);
159
+ }
160
+ };
161
+
162
+ CTAAdapter.prototype.fallbackJump = function(url) {
163
+ if (typeof FbPlayableAd !== 'undefined' && FbPlayableAd.onCTAClick) {
164
+ FbPlayableAd.onCTAClick();
165
+ } else if (typeof mraid !== 'undefined' && mraid.open) {
166
+ mraid.open(url || '');
167
+ } else if (typeof dapi !== 'undefined' && dapi.openStoreUrl) {
168
+ dapi.openStoreUrl();
169
+ } else if (typeof ExitApi !== 'undefined' && ExitApi.exit) {
170
+ ExitApi.exit();
171
+ } else if (typeof window.BGY_MRAID !== 'undefined' && window.BGY_MRAID.open) {
172
+ window.BGY_MRAID.open();
173
+ } else if (typeof snapchatCta === 'function') {
174
+ snapchatCta();
175
+ } else if (url) {
176
+ window.open(url, '_blank');
177
+ }
178
+ };
179
+
180
+ CTAAdapter.prototype.getPlatform = function() {
181
+ return this.platform;
182
+ };
183
+
184
+ CTAAdapter.prototype.checkReady = function() {
185
+ return this.isReady;
186
+ };
187
+
188
+ var ctaAdapter = new CTAAdapter();
189
+
190
+ window.PlayCraftCTA = {
191
+ jump: function(options) { ctaAdapter.jump(options); },
192
+ jump2AppStore: function(options) { ctaAdapter.jump(options); },
193
+ onReady: function(callback) { ctaAdapter.onReady(callback); },
194
+ getPlatform: function() { return ctaAdapter.getPlatform(); },
195
+ isReady: function() { return ctaAdapter.checkReady(); }
196
+ };
197
+
198
+ window.jump2AppStore = window.PlayCraftCTA.jump2AppStore;
199
+ })();
200
+ </script>
201
+ `;
202
+ }
203
+ /**
204
+ * 在 HTML 中注入 CTA 适配器
205
+ */
206
+ injectCTAAdapter(html) {
207
+ const ctaScript = this.getCTAAdapterScript();
208
+ // 在 </head> 之前或 </body> 之前注入
209
+ if (html.includes('</head>')) {
210
+ return html.replace('</head>', `${ctaScript}\n</head>`);
211
+ }
212
+ else if (html.includes('</body>')) {
213
+ return html.replace('</body>', `${ctaScript}\n</body>`);
214
+ }
215
+ else {
216
+ return ctaScript + '\n' + html;
217
+ }
218
+ }
11
219
  }
@@ -22,8 +22,11 @@ export class FacebookAdapter extends PlatformAdapter {
22
22
  };
23
23
  </script>
24
24
  `;
25
- // 在 </head> 之前插入
26
- return html.replace('</head>', `${fbScript}</head>`);
25
+ // 在 </head> 之前插入平台特定的 API
26
+ html = html.replace('</head>', `${fbScript}</head>`);
27
+ // 注入统一的 CTA 适配器
28
+ html = this.injectCTAAdapter(html);
29
+ return html;
27
30
  }
28
31
  getPlatformScript() {
29
32
  return `
@@ -2,6 +2,7 @@ import { PlatformAdapter } from './base.js';
2
2
  import type { BuildOptions } from '../types.js';
3
3
  export declare function createPlatformAdapter(options: BuildOptions): PlatformAdapter;
4
4
  export { PlatformAdapter } from './base.js';
5
+ export { PlayCraftAdapter } from './playcraft.js';
5
6
  export { FacebookAdapter } from './facebook.js';
6
7
  export { SnapchatAdapter } from './snapchat.js';
7
8
  export { IronSourceAdapter } from './ironsource.js';
@@ -12,3 +13,6 @@ export { UnityAdapter } from './unity.js';
12
13
  export { LiftoffAdapter } from './liftoff.js';
13
14
  export { MolocoAdapter } from './moloco.js';
14
15
  export { BigoAdapter } from './bigo.js';
16
+ export { InMobiAdapter } from './inmobi.js';
17
+ export { AdikteevAdapter } from './adikteev.js';
18
+ export { RemergeAdapter } from './remerge.js';
@@ -1,3 +1,4 @@
1
+ import { PlayCraftAdapter } from './playcraft.js';
1
2
  import { FacebookAdapter } from './facebook.js';
2
3
  import { SnapchatAdapter } from './snapchat.js';
3
4
  import { IronSourceAdapter } from './ironsource.js';
@@ -8,8 +9,13 @@ import { UnityAdapter } from './unity.js';
8
9
  import { LiftoffAdapter } from './liftoff.js';
9
10
  import { MolocoAdapter } from './moloco.js';
10
11
  import { BigoAdapter } from './bigo.js';
12
+ import { InMobiAdapter } from './inmobi.js';
13
+ import { AdikteevAdapter } from './adikteev.js';
14
+ import { RemergeAdapter } from './remerge.js';
11
15
  export function createPlatformAdapter(options) {
12
16
  switch (options.platform) {
17
+ case 'playcraft':
18
+ return new PlayCraftAdapter(options);
13
19
  case 'facebook':
14
20
  return new FacebookAdapter(options);
15
21
  case 'snapchat':
@@ -30,11 +36,18 @@ export function createPlatformAdapter(options) {
30
36
  return new MolocoAdapter(options);
31
37
  case 'bigo':
32
38
  return new BigoAdapter(options);
39
+ case 'inmobi':
40
+ return new InMobiAdapter(options);
41
+ case 'adikteev':
42
+ return new AdikteevAdapter(options);
43
+ case 'remerge':
44
+ return new RemergeAdapter(options);
33
45
  default:
34
46
  throw new Error(`Unsupported platform: ${options.platform}`);
35
47
  }
36
48
  }
37
49
  export { PlatformAdapter } from './base.js';
50
+ export { PlayCraftAdapter } from './playcraft.js';
38
51
  export { FacebookAdapter } from './facebook.js';
39
52
  export { SnapchatAdapter } from './snapchat.js';
40
53
  export { IronSourceAdapter } from './ironsource.js';
@@ -45,3 +58,6 @@ export { UnityAdapter } from './unity.js';
45
58
  export { LiftoffAdapter } from './liftoff.js';
46
59
  export { MolocoAdapter } from './moloco.js';
47
60
  export { BigoAdapter } from './bigo.js';
61
+ export { InMobiAdapter } from './inmobi.js';
62
+ export { AdikteevAdapter } from './adikteev.js';
63
+ export { RemergeAdapter } from './remerge.js';
@@ -0,0 +1,10 @@
1
+ import { PlatformAdapter } from './base.js';
2
+ import type { AssetInfo } from '../types.js';
3
+ export declare class InMobiAdapter extends PlatformAdapter {
4
+ getName(): string;
5
+ getSizeLimit(): number;
6
+ getDefaultFormat(): 'html' | 'zip';
7
+ modifyHTML(html: string, assets: AssetInfo[]): string;
8
+ getPlatformScript(): string;
9
+ validateOptions(): void;
10
+ }
@@ -0,0 +1,68 @@
1
+ import { PlatformAdapter } from './base.js';
2
+ export class InMobiAdapter extends PlatformAdapter {
3
+ getName() {
4
+ return 'InMobi';
5
+ }
6
+ getSizeLimit() {
7
+ // InMobi: 5MB
8
+ return 5 * 1024 * 1024;
9
+ }
10
+ getDefaultFormat() {
11
+ return 'zip';
12
+ }
13
+ modifyHTML(html, assets) {
14
+ // InMobi 需要 MRAID 支持
15
+ const inmobiScript = `
16
+ <script>
17
+ // MRAID 2.0 API
18
+ window.mraid = window.mraid || {
19
+ getVersion: function() { return '2.0'; },
20
+ isReady: function() { return true; },
21
+ open: function(url) {
22
+ console.log('InMobi CTA: opening store');
23
+ window.open(url, '_blank');
24
+ },
25
+ close: function() { window.close(); },
26
+ addEventListener: function(event, listener) {
27
+ if (event === 'ready') {
28
+ setTimeout(listener, 0);
29
+ }
30
+ },
31
+ removeEventListener: function(event, listener) {},
32
+ getState: function() { return 'default'; },
33
+ getPlacementType: function() { return 'interstitial'; }
34
+ };
35
+ </script>
36
+ <!--
37
+ 注意:
38
+ - InMobi 要求 ZIP 格式
39
+ - 使用 MRAID API 跳转应用商店
40
+ - 使用 mraid.open() 跳转
41
+ - 不允许自动重定向
42
+ -->
43
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
44
+ `;
45
+ // 在 </head> 之前插入平台特定的 API
46
+ html = html.replace('</head>', `${inmobiScript}</head>`);
47
+ // 注入统一的 CTA 适配器
48
+ html = this.injectCTAAdapter(html);
49
+ return html;
50
+ }
51
+ getPlatformScript() {
52
+ return `
53
+ // InMobi Playable Ad
54
+ // 使用 mraid.open() 跳转应用商店
55
+
56
+ if (typeof mraid !== 'undefined') {
57
+ mraid.addEventListener('ready', function() {
58
+ console.log('InMobi: mraid ready');
59
+ });
60
+ }
61
+ `;
62
+ }
63
+ validateOptions() {
64
+ if (this.options.format && this.options.format !== 'zip') {
65
+ console.warn('警告: InMobi 要求 ZIP 格式');
66
+ }
67
+ }
68
+ }
@@ -47,8 +47,11 @@ export class IronSourceAdapter extends PlatformAdapter {
47
47
  请确保游戏内容不会被遮挡
48
48
  -->
49
49
  `;
50
- // 在 </head> 之前插入
51
- return html.replace('</head>', `${ironSourceScript}</head>`);
50
+ // 在 </head> 之前插入平台特定的 API
51
+ html = html.replace('</head>', `${ironSourceScript}</head>`);
52
+ // 注入统一的 CTA 适配器
53
+ html = this.injectCTAAdapter(html);
54
+ return html;
52
55
  }
53
56
  getPlatformScript() {
54
57
  return `
@@ -31,8 +31,11 @@ export class MolocoAdapter extends PlatformAdapter {
31
31
  - 禁止 XMLHttpRequest 和 JS 重定向
32
32
  -->
33
33
  `;
34
- // 在 </head> 之前插入
35
- return html.replace('</head>', `${molocoScript}</head>`);
34
+ // 在 </head> 之前插入平台特定的 API
35
+ html = html.replace('</head>', `${molocoScript}</head>`);
36
+ // 注入统一的 CTA 适配器
37
+ html = this.injectCTAAdapter(html);
38
+ return html;
36
39
  }
37
40
  getPlatformScript() {
38
41
  return `
@@ -0,0 +1,33 @@
1
+ import { PlatformAdapter } from './base.js';
2
+ import type { BuildOptions, AssetInfo } from '../types.js';
3
+ /**
4
+ * PlayCraft 通用构建适配器
5
+ * 用于创建不针对特定广告平台的通用构建(Base Build)
6
+ * 适用于自托管、本地测试、通用分发等场景
7
+ */
8
+ export declare class PlayCraftAdapter extends PlatformAdapter {
9
+ constructor(options: BuildOptions);
10
+ /**
11
+ * 获取平台名称
12
+ */
13
+ getName(): string;
14
+ /**
15
+ * 获取大小限制(字节)
16
+ * PlayCraft 通用构建没有特定限制,设为 50MB
17
+ */
18
+ getSizeLimit(): number;
19
+ /**
20
+ * 获取默认格式
21
+ */
22
+ getDefaultFormat(): 'html' | 'zip';
23
+ /**
24
+ * 应用平台特定的 HTML 修改
25
+ * PlayCraft 构建注入 CTA 适配器
26
+ */
27
+ modifyHTML(html: string, _assets: AssetInfo[]): string;
28
+ /**
29
+ * 获取平台特定的 JavaScript 代码
30
+ * PlayCraft 构建不需要额外的平台脚本
31
+ */
32
+ getPlatformScript(): string;
33
+ }
@@ -0,0 +1,44 @@
1
+ import { PlatformAdapter } from './base.js';
2
+ /**
3
+ * PlayCraft 通用构建适配器
4
+ * 用于创建不针对特定广告平台的通用构建(Base Build)
5
+ * 适用于自托管、本地测试、通用分发等场景
6
+ */
7
+ export class PlayCraftAdapter extends PlatformAdapter {
8
+ constructor(options) {
9
+ super(options);
10
+ }
11
+ /**
12
+ * 获取平台名称
13
+ */
14
+ getName() {
15
+ return 'PlayCraft';
16
+ }
17
+ /**
18
+ * 获取大小限制(字节)
19
+ * PlayCraft 通用构建没有特定限制,设为 50MB
20
+ */
21
+ getSizeLimit() {
22
+ return 50 * 1024 * 1024;
23
+ }
24
+ /**
25
+ * 获取默认格式
26
+ */
27
+ getDefaultFormat() {
28
+ return 'html';
29
+ }
30
+ /**
31
+ * 应用平台特定的 HTML 修改
32
+ * PlayCraft 构建注入 CTA 适配器
33
+ */
34
+ modifyHTML(html, _assets) {
35
+ return this.injectCTAAdapter(html);
36
+ }
37
+ /**
38
+ * 获取平台特定的 JavaScript 代码
39
+ * PlayCraft 构建不需要额外的平台脚本
40
+ */
41
+ getPlatformScript() {
42
+ return '';
43
+ }
44
+ }
@@ -0,0 +1,10 @@
1
+ import { PlatformAdapter } from './base.js';
2
+ import type { AssetInfo } from '../types.js';
3
+ export declare class RemergeAdapter extends PlatformAdapter {
4
+ getName(): string;
5
+ getSizeLimit(): number;
6
+ getDefaultFormat(): 'html' | 'zip';
7
+ modifyHTML(html: string, assets: AssetInfo[]): string;
8
+ getPlatformScript(): string;
9
+ validateOptions(): void;
10
+ }