@playcraft/build 0.0.13 → 0.0.15

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 (82) hide show
  1. package/dist/analyzers/scene-asset-collector.js +99 -9
  2. package/dist/base-builder.d.ts +15 -78
  3. package/dist/base-builder.js +34 -741
  4. package/dist/engines/engine-detector.d.ts +38 -0
  5. package/dist/engines/engine-detector.js +201 -0
  6. package/dist/engines/generic-adapter.d.ts +71 -0
  7. package/dist/engines/generic-adapter.js +378 -0
  8. package/dist/engines/index.d.ts +7 -0
  9. package/dist/engines/index.js +7 -0
  10. package/dist/engines/playcanvas-adapter.d.ts +85 -0
  11. package/dist/engines/playcanvas-adapter.js +813 -0
  12. package/dist/generators/config-generator.js +59 -1
  13. package/dist/index.d.ts +4 -0
  14. package/dist/index.js +4 -0
  15. package/dist/loaders/playcraft-loader.js +240 -5
  16. package/dist/platforms/adikteev.d.ts +1 -1
  17. package/dist/platforms/adikteev.js +30 -36
  18. package/dist/platforms/applovin.d.ts +1 -1
  19. package/dist/platforms/applovin.js +31 -36
  20. package/dist/platforms/base.d.ts +27 -5
  21. package/dist/platforms/base.js +79 -181
  22. package/dist/platforms/bigo.d.ts +1 -1
  23. package/dist/platforms/bigo.js +28 -28
  24. package/dist/platforms/facebook.d.ts +1 -1
  25. package/dist/platforms/facebook.js +21 -10
  26. package/dist/platforms/google.d.ts +1 -1
  27. package/dist/platforms/google.js +28 -21
  28. package/dist/platforms/index.d.ts +1 -0
  29. package/dist/platforms/index.js +4 -0
  30. package/dist/platforms/inmobi.d.ts +1 -1
  31. package/dist/platforms/inmobi.js +27 -34
  32. package/dist/platforms/ironsource.d.ts +1 -1
  33. package/dist/platforms/ironsource.js +37 -40
  34. package/dist/platforms/liftoff.d.ts +1 -1
  35. package/dist/platforms/liftoff.js +22 -30
  36. package/dist/platforms/mintegral.d.ts +10 -0
  37. package/dist/platforms/mintegral.js +65 -0
  38. package/dist/platforms/moloco.d.ts +1 -1
  39. package/dist/platforms/moloco.js +18 -20
  40. package/dist/platforms/playcraft.d.ts +1 -1
  41. package/dist/platforms/playcraft.js +2 -2
  42. package/dist/platforms/remerge.d.ts +1 -1
  43. package/dist/platforms/remerge.js +19 -20
  44. package/dist/platforms/snapchat.d.ts +1 -1
  45. package/dist/platforms/snapchat.js +32 -26
  46. package/dist/platforms/tiktok.d.ts +1 -1
  47. package/dist/platforms/tiktok.js +28 -24
  48. package/dist/platforms/unity.d.ts +1 -1
  49. package/dist/platforms/unity.js +30 -36
  50. package/dist/playable-builder.d.ts +1 -0
  51. package/dist/playable-builder.js +16 -2
  52. package/dist/types.d.ts +113 -1
  53. package/dist/types.js +77 -1
  54. package/dist/utils/ammo-detector.d.ts +9 -0
  55. package/dist/utils/ammo-detector.js +76 -0
  56. package/dist/utils/build-mode-detector.js +2 -0
  57. package/dist/utils/minify.d.ts +32 -0
  58. package/dist/utils/minify.js +82 -0
  59. package/dist/utils/obfuscate.d.ts +42 -0
  60. package/dist/utils/obfuscate.js +216 -0
  61. package/dist/vite/config-builder-generic.d.ts +70 -0
  62. package/dist/vite/config-builder-generic.js +251 -0
  63. package/dist/vite/config-builder.d.ts +8 -0
  64. package/dist/vite/config-builder.js +53 -16
  65. package/dist/vite/platform-configs.js +29 -1
  66. package/dist/vite/plugin-compress-js.d.ts +21 -0
  67. package/dist/vite/plugin-compress-js.js +213 -0
  68. package/dist/vite/plugin-esm-html-generator.js +5 -1
  69. package/dist/vite/plugin-obfuscate.d.ts +22 -0
  70. package/dist/vite/plugin-obfuscate.js +52 -0
  71. package/dist/vite/plugin-platform.d.ts +5 -0
  72. package/dist/vite/plugin-platform.js +499 -35
  73. package/dist/vite/plugin-playcanvas.js +21 -68
  74. package/dist/vite/plugin-source-builder.js +102 -21
  75. package/dist/vite-builder.d.ts +25 -7
  76. package/dist/vite-builder.js +141 -52
  77. package/package.json +4 -2
  78. package/physics/cannon-rigidbody-adapter.js +243 -22
  79. package/templates/__loading__.js +0 -12
  80. package/templates/index.esm.mjs +0 -11
  81. package/templates/patches/playcraft-cta-adapter.js +129 -31
  82. package/templates/patches/scene-physics-defaults.js +49 -0
@@ -10,50 +10,47 @@ export class IronSourceAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'html';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
14
  // ironSource 需要 MRAID 和 dapi API
15
- const ironSourceScript = `
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) { window.open(url); },
22
- close: function() {
23
- console.log('ironSource: close() is handled by platform');
24
- },
25
- useCustomClose: function(useCustomClose) {
26
- console.warn('ironSource: useCustomClose() is not allowed');
27
- },
28
- addEventListener: function(event, listener) {},
29
- removeEventListener: function(event, listener) {},
30
- getState: function() { return 'default'; },
31
- getPlacementType: function() { return 'interstitial'; },
32
- getMaxSize: function() { return { width: window.innerWidth, height: window.innerHeight }; },
33
- getCurrentPosition: function() { return { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight }; },
34
- getScreenSize: function() { return { width: screen.width, height: screen.height }; }
35
- };
36
-
37
- // dapi API (ironSource specific)
38
- window.dapi = window.dapi || {
39
- isReady: function() { return true; },
40
- addEventListener: function(event, callback) {
41
- if (event === 'ready') {
42
- setTimeout(callback, 0);
43
- }
44
- },
45
- removeEventListener: function(event, callback) {}
46
- };
47
- </script>
48
- <!--
49
- 注意:ironSource 要求预留四角约30x30px区域给平台UI
50
- 请确保游戏内容不会被遮挡
51
- -->
15
+ const ironSourceScriptCode = `
16
+ window.mraid = window.mraid || {
17
+ getVersion: function() { return '2.0'; },
18
+ isReady: function() { return true; },
19
+ open: function(url) {
20
+ if (url) { window.open(url, '_blank'); return; }
21
+ var ua = navigator.userAgent || '';
22
+ var isIOS = /iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
23
+ var _s = window.__PLAYCRAFT_STORE_URLS__ || {};
24
+ window.open(isIOS ? (_s.ios || '') : (_s.android || ''), '_blank');
25
+ },
26
+ close: function() {
27
+ console.log('ironSource: close() handled by platform');
28
+ },
29
+ useCustomClose: function(useCustomClose) {
30
+ console.warn('ironSource: useCustomClose() not allowed');
31
+ },
32
+ addEventListener: function(event, listener) {},
33
+ removeEventListener: function(event, listener) {},
34
+ getState: function() { return 'default'; },
35
+ getPlacementType: function() { return 'interstitial'; },
36
+ getMaxSize: function() { return { width: window.innerWidth, height: window.innerHeight }; },
37
+ getCurrentPosition: function() { return { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight }; },
38
+ getScreenSize: function() { return { width: screen.width, height: screen.height }; }
39
+ };
40
+ window.dapi = window.dapi || {
41
+ isReady: function() { return true; },
42
+ addEventListener: function(event, callback) {
43
+ if (event === 'ready') setTimeout(callback, 0);
44
+ },
45
+ removeEventListener: function(event, callback) {}
46
+ };
52
47
  `;
48
+ const ironSourceScript = await this.minifyPlatformScript(ironSourceScriptCode, 'ironsource-mraid-dapi');
49
+ const comment = `<!-- ironSource: 预留四角30x30px给平台UI -->`;
53
50
  // 在 </head> 之前插入平台特定的 API
54
- html = html.replace('</head>', `${ironSourceScript}</head>`);
51
+ html = html.replace('</head>', `${ironSourceScript}${comment}</head>`);
55
52
  // 注入统一的 CTA 适配器
56
- html = this.injectCTAAdapter(html);
53
+ html = await this.injectCTAAdapterAsync(html);
57
54
  return html;
58
55
  }
59
56
  getPlatformScript() {
@@ -4,7 +4,7 @@ export declare class LiftoffAdapter extends PlatformAdapter {
4
4
  getName(): string;
5
5
  getSizeLimit(): number;
6
6
  getDefaultFormat(): 'html' | 'zip';
7
- modifyHTML(html: string, assets: AssetInfo[]): string;
7
+ modifyHTML(html: string, assets: AssetInfo[]): Promise<string>;
8
8
  getPlatformScript(): string;
9
9
  validateOptions(): void;
10
10
  }
@@ -10,40 +10,32 @@ export class LiftoffAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'zip';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
14
  // Liftoff 支持 MRAID 或 window.open
15
- const liftoffScript = `
16
- <script>
17
- // MRAID API(可选)
18
- window.mraid = window.mraid || {
19
- getVersion: function() { return '2.0'; },
20
- isReady: function() { return true; },
21
- open: function(url) {
22
- console.log('Liftoff CTA: opening store');
23
- window.open(url, '_blank');
24
- },
25
- addEventListener: function(event, listener) {},
26
- removeEventListener: function(event, listener) {},
27
- getMaxSize: function() { return { width: window.innerWidth, height: window.innerHeight }; },
28
- getCurrentPosition: function() { return { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight }; },
29
- getScreenSize: function() { return { width: screen.width, height: screen.height }; }
30
- };
31
- </script>
32
- <!--
33
- 注意:
34
- - Liftoff 要求 ZIP 格式
35
- - 文件名必须为 ASCII(禁止 UTF-8)
36
- - 大小写敏感
37
- - 跳转使用 mraid.open() 或 window.open(),禁止 window.location
38
- - 需用户交互后才能跳转
39
- - 支持标准尺寸:320x480, 480x320, 768x1024, 1024x768, 320x50, 728x90, 300x250
40
- - 关闭按钮由平台处理,可能遮挡角落 50x50px
41
- -->
15
+ const liftoffScriptCode = `
16
+ window.mraid = window.mraid || {
17
+ getVersion: function() { return '2.0'; },
18
+ isReady: function() { return true; },
19
+ open: function(url) {
20
+ console.log('Liftoff CTA: opening store');
21
+ if (url) { window.open(url, '_blank'); return; }
22
+ var ua = navigator.userAgent || '';
23
+ var isIOS = /iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
24
+ window.open(isIOS ? 'https://apps.apple.com/us/app/8-ball-pool/id543186831' : 'https://play.google.com/store/apps/details?id=com.miniclip.eightballpool', '_blank');
25
+ },
26
+ addEventListener: function(event, listener) {},
27
+ removeEventListener: function(event, listener) {},
28
+ getMaxSize: function() { return { width: window.innerWidth, height: window.innerHeight }; },
29
+ getCurrentPosition: function() { return { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight }; },
30
+ getScreenSize: function() { return { width: screen.width, height: screen.height }; }
31
+ };
42
32
  `;
33
+ const liftoffScript = await this.minifyPlatformScript(liftoffScriptCode, 'liftoff-mraid');
34
+ const comment = `<!-- Liftoff: ZIP格式, ASCII文件名, 使用mraid.open()或window.open() -->`;
43
35
  // 在 </head> 之前插入
44
- html = html.replace('</head>', `${liftoffScript}</head>`);
36
+ html = html.replace('</head>', `${liftoffScript}${comment}</head>`);
45
37
  // 注入统一的 CTA 适配器
46
- html = this.injectCTAAdapter(html);
38
+ html = await this.injectCTAAdapterAsync(html);
47
39
  return html;
48
40
  }
49
41
  getPlatformScript() {
@@ -0,0 +1,10 @@
1
+ import { PlatformAdapter } from './base.js';
2
+ import type { AssetInfo } from '../types.js';
3
+ export declare class MintegralAdapter extends PlatformAdapter {
4
+ getName(): string;
5
+ getSizeLimit(): number;
6
+ getDefaultFormat(): 'html' | 'zip';
7
+ modifyHTML(html: string, assets: AssetInfo[]): Promise<string>;
8
+ getPlatformScript(): string;
9
+ validateOptions(): void;
10
+ }
@@ -0,0 +1,65 @@
1
+ import { PlatformAdapter } from './base.js';
2
+ export class MintegralAdapter extends PlatformAdapter {
3
+ getName() {
4
+ return 'Mintegral';
5
+ }
6
+ getSizeLimit() {
7
+ // Mintegral: 5MB (ZIP)
8
+ return 5 * 1024 * 1024;
9
+ }
10
+ getDefaultFormat() {
11
+ return 'zip';
12
+ }
13
+ async modifyHTML(html, assets) {
14
+ // Mintegral 要求 charset 为 utf-8,确保存在
15
+ if (!html.includes('charset') && html.includes('<head>')) {
16
+ html = html.replace('<head>', '<head>\n<meta charset="utf-8">');
17
+ }
18
+ // Mintegral SDK polyfill(仅本地浏览器测试用的兜底)
19
+ // 真实 Mintegral 环境中 SDK 会注入 window.install 等函数,这些 polyfill 不会生效
20
+ const mintegralScriptCode = `
21
+ window.install = window.install || function() {
22
+ var ua = navigator.userAgent || '';
23
+ var isIOS = /iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
24
+ var _s = (typeof window !== 'undefined' && window.__PLAYCRAFT_STORE_URLS__) || {};
25
+ var url = isIOS ? (_s.ios || '') : (_s.android || '');
26
+ if (url) window.open(url, '_blank');
27
+ };
28
+ window.gameReady = window.gameReady || function() {};
29
+ window.gameEnd = window.gameEnd || function() {};
30
+ window.gameRetry = window.gameRetry || function() {};
31
+ if (typeof window.gameStart !== 'function') { window.gameStart = function() {}; }
32
+ if (typeof window.gameClose !== 'function') { window.gameClose = function() {}; }
33
+ window.HttpAPI = window.HttpAPI || { sendPoint: function() {} };
34
+ `;
35
+ const mintegralScript = await this.minifyPlatformScript(mintegralScriptCode, 'mintegral-sdk');
36
+ const comment = `<!-- Mintegral: ZIP格式, 5MB限制, 使用window.install()跳转, 支持横竖屏 -->`;
37
+ // 在 </head> 之前插入 polyfill 和注释,如果没有 </head> 则在文件开头插入
38
+ if (html.includes('</head>')) {
39
+ html = html.replace('</head>', `${mintegralScript}${comment}\n</head>`);
40
+ }
41
+ else {
42
+ html = `${mintegralScript}${comment}\n${html}`;
43
+ }
44
+ // 注入统一的 CTA 适配器
45
+ html = await this.injectCTAAdapterAsync(html);
46
+ return html;
47
+ }
48
+ getPlatformScript() {
49
+ return `
50
+ // Mintegral Playable Ad
51
+ // CTA: window.install && window.install();
52
+ // Lifecycle: gameReady -> gameStart -> gameEnd/gameRetry -> gameClose
53
+
54
+ // 资源加载完成后通知 SDK
55
+ if (typeof window.gameReady === 'function') {
56
+ window.gameReady();
57
+ }
58
+ `;
59
+ }
60
+ validateOptions() {
61
+ if (this.options.format && this.options.format !== 'zip') {
62
+ console.warn('警告: Mintegral 要求 ZIP 格式,将自动使用 ZIP');
63
+ }
64
+ }
65
+ }
@@ -4,7 +4,7 @@ export declare class MolocoAdapter extends PlatformAdapter {
4
4
  getName(): string;
5
5
  getSizeLimit(): number;
6
6
  getDefaultFormat(): 'html' | 'zip';
7
- modifyHTML(html: string, assets: AssetInfo[]): string;
7
+ modifyHTML(html: string, assets: AssetInfo[]): Promise<string>;
8
8
  getPlatformScript(): string;
9
9
  validateOptions(): void;
10
10
  }
@@ -10,31 +10,29 @@ export class MolocoAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'html';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
14
  // Moloco 使用 FbPlayableAd API(与 Facebook 相同)
15
- const molocoScript = `
16
- <script>
17
- // Moloco 使用 FbPlayableAd API
18
- window.FbPlayableAd = window.FbPlayableAd || {
19
- onCTAClick: function() {
20
- console.log('Moloco CTA clicked');
21
- // Moloco 要求:必须以"无参数"方式调用
15
+ const molocoScriptCode = `
16
+ window.FbPlayableAd = window.FbPlayableAd || {
17
+ onCTAClick: function() {
18
+ console.log('Moloco CTA clicked');
19
+ function getOS(){
20
+ var ua = navigator.userAgent || '';
21
+ if (/iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) return 'ios';
22
+ if (/Android/i.test(ua)) return 'android';
23
+ return 'unknown';
22
24
  }
23
- };
24
- </script>
25
- <!--
26
- 注意:
27
- - Moloco 使用单文件 HTML 格式,<5MB
28
- - CTA 必须以"无参数"方式调用 FbPlayableAd.onCTAClick()
29
- - 不得包含 mraid.js
30
- - 不允许任何外部引用或 HTTP 动态加载
31
- - 禁止 XMLHttpRequest 和 JS 重定向
32
- -->
25
+ var url = getOS() === 'ios' ? 'https://apps.apple.com/us/app/8-ball-pool/id543186831' : 'https://play.google.com/store/apps/details?id=com.miniclip.eightballpool';
26
+ window.open(url, '_blank');
27
+ }
28
+ };
33
29
  `;
30
+ const molocoScript = await this.minifyPlatformScript(molocoScriptCode, 'moloco-api');
31
+ const comment = `<!-- Moloco: 单文件 HTML <5MB, CTA 无参数调用 FbPlayableAd.onCTAClick() -->`;
34
32
  // 在 </head> 之前插入平台特定的 API
35
- html = html.replace('</head>', `${molocoScript}</head>`);
33
+ html = html.replace('</head>', `${molocoScript}${comment}</head>`);
36
34
  // 注入统一的 CTA 适配器
37
- html = this.injectCTAAdapter(html);
35
+ html = await this.injectCTAAdapterAsync(html);
38
36
  return html;
39
37
  }
40
38
  getPlatformScript() {
@@ -24,7 +24,7 @@ export declare class PlayCraftAdapter extends PlatformAdapter {
24
24
  * 应用平台特定的 HTML 修改
25
25
  * PlayCraft 构建注入 CTA 适配器
26
26
  */
27
- modifyHTML(html: string, _assets: AssetInfo[]): string;
27
+ modifyHTML(html: string, _assets: AssetInfo[]): Promise<string>;
28
28
  /**
29
29
  * 获取平台特定的 JavaScript 代码
30
30
  * PlayCraft 构建不需要额外的平台脚本
@@ -31,8 +31,8 @@ export class PlayCraftAdapter extends PlatformAdapter {
31
31
  * 应用平台特定的 HTML 修改
32
32
  * PlayCraft 构建注入 CTA 适配器
33
33
  */
34
- modifyHTML(html, _assets) {
35
- return this.injectCTAAdapter(html);
34
+ async modifyHTML(html, _assets) {
35
+ return await this.injectCTAAdapterAsync(html);
36
36
  }
37
37
  /**
38
38
  * 获取平台特定的 JavaScript 代码
@@ -4,7 +4,7 @@ export declare class RemergeAdapter extends PlatformAdapter {
4
4
  getName(): string;
5
5
  getSizeLimit(): number;
6
6
  getDefaultFormat(): 'html' | 'zip';
7
- modifyHTML(html: string, assets: AssetInfo[]): string;
7
+ modifyHTML(html: string, assets: AssetInfo[]): Promise<string>;
8
8
  getPlatformScript(): string;
9
9
  validateOptions(): void;
10
10
  }
@@ -10,31 +10,30 @@ export class RemergeAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'html';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
14
  // Remerge 使用 FbPlayableAd API(与 Facebook/Moloco 相同)
15
- const remergeScript = `
16
- <script>
17
- // Remerge 使用 FbPlayableAd API
18
- window.FbPlayableAd = window.FbPlayableAd || {
19
- onCTAClick: function() {
20
- console.log('Remerge CTA clicked');
21
- // Remerge 要求:必须以"无参数"方式调用
15
+ const remergeScriptCode = `
16
+ window.FbPlayableAd = window.FbPlayableAd || {
17
+ onCTAClick: function() {
18
+ console.log('Remerge CTA clicked');
19
+ function getOS(){
20
+ var ua = navigator.userAgent || '';
21
+ if (/iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) return 'ios';
22
+ if (/Android/i.test(ua)) return 'android';
23
+ return 'unknown';
22
24
  }
23
- };
24
- </script>
25
- <!--
26
- 注意:
27
- - Remerge 使用单文件 HTML 格式,<5MB
28
- - CTA 必须以"无参数"方式调用 FbPlayableAd.onCTAClick()
29
- - 不允许任何外部引用或 HTTP 动态加载
30
- - 禁止 XMLHttpRequest 和 JS 重定向
31
- -->
32
- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
25
+ var url = getOS() === 'ios' ? 'https://apps.apple.com/us/app/8-ball-pool/id543186831' : 'https://play.google.com/store/apps/details?id=com.miniclip.eightballpool';
26
+ window.open(url, '_blank');
27
+ }
28
+ };
33
29
  `;
30
+ const remergeScript = await this.minifyPlatformScript(remergeScriptCode, 'remerge-api');
31
+ const meta = `<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">`;
32
+ const comment = `<!-- Remerge: 单文件 HTML <5MB, CTA 无参数调用 -->`;
34
33
  // 在 </head> 之前插入平台特定的 API
35
- html = html.replace('</head>', `${remergeScript}</head>`);
34
+ html = html.replace('</head>', `${remergeScript}${comment}${meta}</head>`);
36
35
  // 注入统一的 CTA 适配器
37
- html = this.injectCTAAdapter(html);
36
+ html = await this.injectCTAAdapterAsync(html);
38
37
  return html;
39
38
  }
40
39
  getPlatformScript() {
@@ -4,7 +4,7 @@ export declare class SnapchatAdapter extends PlatformAdapter {
4
4
  getName(): string;
5
5
  getSizeLimit(): number;
6
6
  getDefaultFormat(): 'html' | 'zip';
7
- modifyHTML(html: string, assets: AssetInfo[]): string;
7
+ modifyHTML(html: string, assets: AssetInfo[]): Promise<string>;
8
8
  getPlatformScript(): string;
9
9
  validateOptions(): void;
10
10
  }
@@ -10,36 +10,42 @@ export class SnapchatAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'zip';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
14
  // Snapchat 需要 MRAID 2.0 和 snapchatCta 函数
15
- const mraidScript = `
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) { window.open(url); },
22
- close: function() { window.close(); },
23
- addEventListener: function(event, listener) {},
24
- removeEventListener: function(event, listener) {},
25
- getState: function() { return 'ready'; },
26
- getPlacementType: function() { return 'interstitial'; },
27
- getMaxSize: function() { return { width: window.innerWidth, height: window.innerHeight }; },
28
- getCurrentPosition: function() { return { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight }; },
29
- getScreenSize: function() { return { width: screen.width, height: screen.height }; }
30
- };
31
-
32
- // Snapchat CTA function
33
- window.snapchatCta = function() {
34
- if (window.mraid && window.mraid.open) {
35
- window.mraid.open('https://snapchat.com');
36
- }
37
- };
38
- </script>
15
+ const mraidScriptCode = `
16
+ window.mraid = window.mraid || {
17
+ getVersion: function() { return '2.0'; },
18
+ isReady: function() { return true; },
19
+ open: function(url) {
20
+ if (url) { window.open(url, '_blank'); return; }
21
+ var ua = navigator.userAgent || '';
22
+ var isIOS = /iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
23
+ var _s = window.__PLAYCRAFT_STORE_URLS__ || {};
24
+ window.open(isIOS ? (_s.ios || '') : (_s.android || ''), '_blank');
25
+ },
26
+ close: function() { window.close(); },
27
+ addEventListener: function(event, listener) {},
28
+ removeEventListener: function(event, listener) {},
29
+ getState: function() { return 'ready'; },
30
+ getPlacementType: function() { return 'interstitial'; },
31
+ getMaxSize: function() { return { width: window.innerWidth, height: window.innerHeight }; },
32
+ getCurrentPosition: function() { return { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight }; },
33
+ getScreenSize: function() { return { width: screen.width, height: screen.height }; }
34
+ };
35
+ window.snapchatCta = function() {
36
+ if (window.mraid && window.mraid.open) {
37
+ var _s = window.__PLAYCRAFT_STORE_URLS__ || {};
38
+ var ua = navigator.userAgent || '';
39
+ var isIOS = /iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
40
+ var url = isIOS ? (_s.ios || '') : (_s.android || '');
41
+ window.mraid.open(url);
42
+ }
43
+ };
39
44
  `;
45
+ const mraidScript = await this.minifyPlatformScript(mraidScriptCode, 'snapchat-mraid');
40
46
  html = html.replace('</head>', `${mraidScript}</head>`);
41
47
  // 注入统一的 CTA 适配器
42
- html = this.injectCTAAdapter(html);
48
+ html = await this.injectCTAAdapterAsync(html);
43
49
  return html;
44
50
  }
45
51
  getPlatformScript() {
@@ -4,7 +4,7 @@ export declare class TikTokAdapter extends PlatformAdapter {
4
4
  getName(): string;
5
5
  getSizeLimit(): number;
6
6
  getDefaultFormat(): 'html' | 'zip';
7
- modifyHTML(html: string, assets: AssetInfo[]): string;
7
+ modifyHTML(html: string, assets: AssetInfo[]): Promise<string>;
8
8
  getPlatformScript(): string;
9
9
  /**
10
10
  * 生成 config.json(TikTok/Pangle 要求)
@@ -10,33 +10,37 @@ export class TikTokAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'zip';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
14
  // TikTok/Pangle 需要 Pangle JS-SDK
15
- const pangleScript = `
16
- <script>
17
- // Pangle JS-SDK 桥接
18
- window.Pangle = window.Pangle || {
19
- open: function(url) {
20
- console.log('Pangle CTA: opening store');
21
- // Pangle SDK 会处理跳转
22
- },
23
- ready: function() {
24
- console.log('Pangle SDK ready');
25
- }
26
- };
27
-
28
- // 不使用 mraid.js(TikTok要求)
29
- </script>
30
- <!--
31
- 注意:
32
- - TikTok/Pangle 要求 ZIP 格式,含 config.json
33
- - config.json 需包含 playable_orientation 字段:0=横竖均可/1=仅竖/2=仅横
34
- - 不允许外部网络加载动态素材
35
- - 不应使用 mraid.js
36
- -->
15
+ const pangleScriptCode = `
16
+ window.Pangle = window.Pangle || {
17
+ open: function(url) {
18
+ console.log('Pangle CTA: opening store');
19
+ },
20
+ ready: function() {
21
+ console.log('Pangle SDK ready');
22
+ }
23
+ };
24
+ window.openAppStore = window.openAppStore || function() {
25
+ console.log('TikTok CTA: openAppStore');
26
+ function getOS(){
27
+ var ua = navigator.userAgent || '';
28
+ if (/iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) return 'ios';
29
+ if (/Android/i.test(ua)) return 'android';
30
+ return 'unknown';
31
+ }
32
+ var _s = (typeof window !== 'undefined' && window.__PLAYCRAFT_STORE_URLS__) || {};
33
+ var url = getOS() === 'ios' ? (_s.ios || '') : (_s.android || '');
34
+ if (url) window.open(url, '_blank');
35
+ };
37
36
  `;
37
+ const pangleScript = await this.minifyPlatformScript(pangleScriptCode, 'pangle-sdk');
38
+ const comment = `<!-- TikTok/Pangle: ZIP格式, config.json含playable_orientation, 禁止mraid.js -->`;
38
39
  // 在 </head> 之前插入
39
- return html.replace('</head>', `${pangleScript}</head>`);
40
+ html = html.replace('</head>', `${pangleScript}${comment}</head>`);
41
+ // 注入统一的 CTA 适配器
42
+ html = await this.injectCTAAdapterAsync(html);
43
+ return html;
40
44
  }
41
45
  getPlatformScript() {
42
46
  return `
@@ -4,7 +4,7 @@ export declare class UnityAdapter extends PlatformAdapter {
4
4
  getName(): string;
5
5
  getSizeLimit(): number;
6
6
  getDefaultFormat(): 'html' | 'zip';
7
- modifyHTML(html: string, assets: AssetInfo[]): string;
7
+ modifyHTML(html: string, assets: AssetInfo[]): Promise<string>;
8
8
  getPlatformScript(): string;
9
9
  validateOptions(): void;
10
10
  }
@@ -10,46 +10,40 @@ export class UnityAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'html';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
14
  // Unity Ads 需要 MRAID 3.0 支持
15
- const unityScript = `
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('Unity Ads CTA: opening store');
23
- window.open(url);
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
- getMaxSize: function() { return { width: window.innerWidth, height: window.innerHeight }; },
36
- getCurrentPosition: function() { return { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight }; },
37
- getScreenSize: function() { return { width: screen.width, height: screen.height }; }
38
- };
39
- </script>
40
- <!--
41
- 注意:
42
- - Unity Ads 要求 MRAID 3.0
43
- - 需等待 mraid.viewableChange 事件后再启动游戏
44
- - 使用 mraid.open() 跳转应用商店
45
- - 不允许自动重定向
46
- - 支持 Android ≥4.4, iOS ≥9.0
47
- -->
15
+ const unityScriptCode = `
16
+ window.mraid = window.mraid || {
17
+ getVersion: function() { return '3.0'; },
18
+ isReady: function() { return true; },
19
+ open: function(url) {
20
+ console.log('Unity Ads CTA: opening store');
21
+ if (url) { window.open(url, '_blank'); return; }
22
+ var ua = navigator.userAgent || '';
23
+ var isIOS = /iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1);
24
+ window.open(isIOS ? 'https://apps.apple.com/us/app/8-ball-pool/id543186831' : 'https://play.google.com/store/apps/details?id=com.miniclip.eightballpool', '_blank');
25
+ },
26
+ close: function() { window.close(); },
27
+ addEventListener: function(event, listener) {
28
+ if (event === 'ready' || event === 'viewableChange') {
29
+ setTimeout(function() { listener({ viewable: true }); }, 0);
30
+ }
31
+ },
32
+ removeEventListener: function(event, listener) {},
33
+ getState: function() { return 'default'; },
34
+ getPlacementType: function() { return 'interstitial'; },
35
+ isViewable: function() { return true; },
36
+ getMaxSize: function() { return { width: window.innerWidth, height: window.innerHeight }; },
37
+ getCurrentPosition: function() { return { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight }; },
38
+ getScreenSize: function() { return { width: screen.width, height: screen.height }; }
39
+ };
48
40
  `;
41
+ const unityScript = await this.minifyPlatformScript(unityScriptCode, 'unity-mraid');
42
+ const comment = `<!-- Unity Ads: MRAID 3.0, 等待viewableChange, 使用mraid.open() -->`;
49
43
  // 在 </head> 之前插入
50
- html = html.replace('</head>', `${unityScript}</head>`);
44
+ html = html.replace('</head>', `${unityScript}${comment}</head>`);
51
45
  // 注入统一的 CTA 适配器
52
- html = this.injectCTAAdapter(html);
46
+ html = await this.injectCTAAdapterAsync(html);
53
47
  return html;
54
48
  }
55
49
  getPlatformScript() {