@playcraft/build 0.0.11 → 0.0.14

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 (102) hide show
  1. package/dist/analyzers/__tests__/optimization-analyzer.test.d.ts +1 -0
  2. package/dist/analyzers/__tests__/optimization-analyzer.test.js +169 -0
  3. package/dist/analyzers/playable-analyzer.js +3 -2
  4. package/dist/analyzers/scene-asset-collector.js +99 -9
  5. package/dist/base-builder.d.ts +15 -78
  6. package/dist/base-builder.js +34 -735
  7. package/dist/engines/engine-detector.d.ts +38 -0
  8. package/dist/engines/engine-detector.js +201 -0
  9. package/dist/engines/generic-adapter.d.ts +71 -0
  10. package/dist/engines/generic-adapter.js +378 -0
  11. package/dist/engines/index.d.ts +7 -0
  12. package/dist/engines/index.js +7 -0
  13. package/dist/engines/playcanvas-adapter.d.ts +85 -0
  14. package/dist/engines/playcanvas-adapter.js +813 -0
  15. package/dist/generators/config-generator.js +59 -1
  16. package/dist/index.d.ts +4 -0
  17. package/dist/index.js +4 -0
  18. package/dist/loaders/playcraft-loader.js +240 -5
  19. package/dist/platforms/adikteev.d.ts +1 -1
  20. package/dist/platforms/adikteev.js +30 -34
  21. package/dist/platforms/applovin.d.ts +1 -1
  22. package/dist/platforms/applovin.js +34 -33
  23. package/dist/platforms/base.d.ts +27 -5
  24. package/dist/platforms/base.js +79 -181
  25. package/dist/platforms/bigo.d.ts +1 -1
  26. package/dist/platforms/bigo.js +28 -28
  27. package/dist/platforms/facebook.d.ts +1 -1
  28. package/dist/platforms/facebook.js +21 -10
  29. package/dist/platforms/google.d.ts +1 -1
  30. package/dist/platforms/google.js +28 -21
  31. package/dist/platforms/index.d.ts +1 -0
  32. package/dist/platforms/index.js +4 -0
  33. package/dist/platforms/inmobi.d.ts +1 -1
  34. package/dist/platforms/inmobi.js +27 -32
  35. package/dist/platforms/ironsource.d.ts +1 -1
  36. package/dist/platforms/ironsource.js +37 -37
  37. package/dist/platforms/liftoff.d.ts +1 -1
  38. package/dist/platforms/liftoff.js +24 -27
  39. package/dist/platforms/mintegral.d.ts +10 -0
  40. package/dist/platforms/mintegral.js +65 -0
  41. package/dist/platforms/moloco.d.ts +1 -1
  42. package/dist/platforms/moloco.js +18 -20
  43. package/dist/platforms/playcraft.d.ts +1 -1
  44. package/dist/platforms/playcraft.js +2 -2
  45. package/dist/platforms/remerge.d.ts +1 -1
  46. package/dist/platforms/remerge.js +19 -20
  47. package/dist/platforms/snapchat.d.ts +1 -1
  48. package/dist/platforms/snapchat.js +35 -23
  49. package/dist/platforms/tiktok.d.ts +1 -1
  50. package/dist/platforms/tiktok.js +28 -24
  51. package/dist/platforms/unity.d.ts +1 -1
  52. package/dist/platforms/unity.js +32 -32
  53. package/dist/playable-builder.d.ts +1 -0
  54. package/dist/playable-builder.js +19 -3
  55. package/dist/templates/__loading__.js +100 -0
  56. package/dist/templates/__modules__.js +47 -0
  57. package/dist/templates/__settings__.template.js +20 -0
  58. package/dist/templates/__start__.js +332 -0
  59. package/dist/templates/index.html +18 -0
  60. package/dist/templates/logo.png +0 -0
  61. package/dist/templates/manifest.json +1 -0
  62. package/dist/templates/patches/cannon.min.js +28 -0
  63. package/dist/templates/patches/lz4.js +10 -0
  64. package/dist/templates/patches/one-page-http-get.js +20 -0
  65. package/dist/templates/patches/one-page-inline-game-scripts.js +52 -0
  66. package/dist/templates/patches/one-page-mraid-resize-canvas.js +46 -0
  67. package/dist/templates/patches/p2.min.js +27 -0
  68. package/dist/templates/patches/playcraft-no-xhr.js +76 -0
  69. package/dist/templates/playcanvas-stable.min.js +16363 -0
  70. package/dist/templates/styles.css +43 -0
  71. package/dist/types.d.ts +114 -1
  72. package/dist/types.js +77 -1
  73. package/dist/utils/ammo-detector.d.ts +9 -0
  74. package/dist/utils/ammo-detector.js +76 -0
  75. package/dist/utils/build-mode-detector.js +2 -0
  76. package/dist/utils/minify.d.ts +32 -0
  77. package/dist/utils/minify.js +82 -0
  78. package/dist/vite/config-builder-generic.d.ts +70 -0
  79. package/dist/vite/config-builder-generic.js +251 -0
  80. package/dist/vite/config-builder.d.ts +8 -0
  81. package/dist/vite/config-builder.js +56 -16
  82. package/dist/vite/platform-configs.d.ts +1 -0
  83. package/dist/vite/platform-configs.js +30 -1
  84. package/dist/vite/plugin-build-state.d.ts +2 -0
  85. package/dist/vite/plugin-build-state.js +5 -3
  86. package/dist/vite/plugin-compress-js.d.ts +21 -0
  87. package/dist/vite/plugin-compress-js.js +213 -0
  88. package/dist/vite/plugin-esm-html-generator.js +15 -2
  89. package/dist/vite/plugin-platform.d.ts +5 -0
  90. package/dist/vite/plugin-platform.js +502 -36
  91. package/dist/vite/plugin-playcanvas.d.ts +1 -0
  92. package/dist/vite/plugin-playcanvas.js +181 -88
  93. package/dist/vite/plugin-source-builder.js +102 -21
  94. package/dist/vite-builder.d.ts +25 -7
  95. package/dist/vite-builder.js +141 -52
  96. package/package.json +4 -2
  97. package/physics/cannon-rigidbody-adapter.js +243 -22
  98. package/templates/__loading__.js +0 -12
  99. package/templates/index.esm.mjs +0 -11
  100. package/templates/patches/one-page-mraid-resize-canvas.js +18 -4
  101. package/templates/patches/playcraft-cta-adapter.js +129 -31
  102. package/templates/patches/scene-physics-defaults.js +49 -0
@@ -1,6 +1,11 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import { minifyPatchCode } from '../utils/minify.js';
5
+ // 缓存压缩后的 CTA 适配器代码
6
+ let cachedMinifiedCTAAdapter = null;
7
+ // 缓存压缩后的平台脚本
8
+ const platformScriptCache = new Map();
4
9
  export class PlatformAdapter {
5
10
  constructor(options) {
6
11
  this.options = options;
@@ -20,200 +25,93 @@ export class PlatformAdapter {
20
25
  return await fs.readFile(templatePath, 'utf-8');
21
26
  }
22
27
  /**
23
- * 获取 CTA 适配器脚本(同步版本,用于模板字符串)
28
+ * 压缩平台脚本代码
29
+ * @param scriptCode - 原始 JavaScript 代码
30
+ * @param cacheKey - 缓存键(通常是平台名称)
31
+ * @returns 压缩后的 <script> 标签
32
+ */
33
+ async minifyPlatformScript(scriptCode, cacheKey) {
34
+ const key = cacheKey || this.getName();
35
+ if (platformScriptCache.has(key)) {
36
+ return `<script>${platformScriptCache.get(key)}</script>`;
37
+ }
38
+ const minified = await minifyPatchCode(scriptCode, key);
39
+ platformScriptCache.set(key, minified);
40
+ return `<script>${minified}</script>`;
41
+ }
42
+ /**
43
+ * 获取 CTA 适配器脚本(异步版本,带压缩)
44
+ */
45
+ async getCTAAdapterScriptAsync() {
46
+ if (cachedMinifiedCTAAdapter) {
47
+ return `<script>${cachedMinifiedCTAAdapter}</script>`;
48
+ }
49
+ const ctaCode = await this.readTemplateFile('playcraft-cta-adapter.js');
50
+ const minified = await minifyPatchCode(ctaCode, 'playcraft-cta-adapter.js');
51
+ cachedMinifiedCTAAdapter = minified;
52
+ return `<script>${minified}</script>`;
53
+ }
54
+ /**
55
+ * 生成 Store URLs 注入脚本
56
+ * 将 storeUrls 以全局变量写入 HTML,供 CTA 适配器读取
57
+ */
58
+ getStoreUrlsScript() {
59
+ const urls = this.options.storeUrls || {};
60
+ // 只有存在有效 URL 时才注入
61
+ if (!urls.ios && !urls.android) {
62
+ return '';
63
+ }
64
+ const safeUrls = {
65
+ ...(urls.ios ? { ios: urls.ios } : {}),
66
+ ...(urls.android ? { android: urls.android } : {}),
67
+ };
68
+ return `<script>window.__PLAYCRAFT_STORE_URLS__=${JSON.stringify(safeUrls)};</script>`;
69
+ }
70
+ /**
71
+ * 获取 CTA 适配器脚本(同步版本,使用预压缩代码)
72
+ * @deprecated 推荐使用 getCTAAdapterScriptAsync
24
73
  */
25
74
  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
- `;
75
+ // 预压缩的 CTA 适配器代码(由 terser 压缩生成)
76
+ // 注意:此版本已移除硬编码地址,改为读取 window.__PLAYCRAFT_STORE_URLS__
77
+ const minifiedCode = `!function(){"use strict";var _s=(typeof window!=="undefined"&&window.__PLAYCRAFT_STORE_URLS__)||{};var IOS_STORE_URL=_s.ios||"";var ANDROID_STORE_URL=_s.android||"";function i(){var ua=navigator.userAgent||"";return(/iPad|iPhone|iPod/.test(ua)||"MacIntel"===navigator.platform&&navigator.maxTouchPoints>1?"ios":/Android/i.test(ua)?"android":"unknown")==="ios"?IOS_STORE_URL:ANDROID_STORE_URL}function e(){this.platform=null,this.isReady=!1,this.readyCallbacks=[],this.detectPlatform(),this.initialize()}e.prototype.detectPlatform=function(){"undefined"!=typeof FbPlayableAd?this.platform="facebook":"undefined"!=typeof mraid?this.platform="mraid":"undefined"!=typeof dapi?this.platform="dapi":"undefined"!=typeof ExitApi?this.platform="google":void 0!==window.BGY_MRAID?this.platform="bigo":"function"==typeof snapchatCta?this.platform="snapchat":"function"==typeof window.openAppStore?this.platform="tiktok":"function"==typeof window.install?this.platform="mintegral":void 0!==window.TJ_API&&"function"==typeof window.TJ_API.click?this.platform="tapjoy":void 0!==window.NUC&&window.NUC.trigger&&"function"==typeof window.NUC.trigger.convert?this.platform="nucleo":void 0!==window.smxTracking&&"function"==typeof window.smxTracking.redirect?this.platform="smadex":(this.platform="unknown",console.warn("[PlayCraft CTA] Unknown platform")),console.log("[PlayCraft CTA] Platform:",this.platform)},e.prototype.initialize=function(){var i=this;switch(this.platform){case"facebook":case"google":case"bigo":case"snapchat":case"tiktok":case"mintegral":case"tapjoy":case"nucleo":case"smadex":default:this.isReady=!0,this.notifyReady();break;case"mraid":mraid.isReady&&mraid.isReady()?(this.isReady=!0,this.notifyReady()):mraid.addEventListener&&mraid.addEventListener("ready",function(){i.isReady=!0,i.notifyReady()});break;case"dapi":dapi.isReady&&dapi.isReady()?(this.isReady=!0,this.notifyReady()):dapi.addEventListener&&dapi.addEventListener("ready",function(){i.isReady=!0,i.notifyReady()})}},e.prototype.notifyReady=function(){for(var i=0;i<this.readyCallbacks.length;i++)try{this.readyCallbacks[i]()}catch(i){console.error("[PlayCraft CTA] Ready callback error:",i)}this.readyCallbacks=[]},e.prototype.onReady=function(i){this.isReady?setTimeout(i,0):this.readyCallbacks.push(i)},e.prototype.jump=function(e){e=e||{},this.isReady||console.warn("[PlayCraft CTA] Not ready"),console.log("[PlayCraft CTA] Jump - platform:",this.platform);try{switch(this.platform){case"facebook":"undefined"!=typeof FbPlayableAd&&FbPlayableAd.onCTAClick&&FbPlayableAd.onCTAClick();break;case"mraid":"undefined"!=typeof mraid&&mraid.open&&mraid.open(e.url||i());break;case"dapi":"undefined"!=typeof dapi&&dapi.openStoreUrl&&dapi.openStoreUrl();break;case"google":"undefined"!=typeof ExitApi&&ExitApi.exit&&ExitApi.exit();break;case"bigo":void 0!==window.BGY_MRAID&&window.BGY_MRAID.open&&window.BGY_MRAID.open();break;case"snapchat":"function"==typeof snapchatCta&&snapchatCta();break;case"tiktok":"function"==typeof window.openAppStore&&window.openAppStore();break;case"mintegral":"function"==typeof window.install&&window.install();break;case"tapjoy":void 0!==window.TJ_API&&window.TJ_API.click&&window.TJ_API.click();break;case"nucleo":void 0!==window.NUC&&window.NUC.trigger&&window.NUC.trigger.convert&&window.NUC.trigger.convert(e.url||i());break;case"smadex":void 0!==window.smxTracking&&window.smxTracking.redirect&&window.smxTracking.redirect();break;default:this.fallbackJump(e.url)}}catch(i){console.error("[PlayCraft CTA] Jump failed:",i),this.fallbackJump(e.url)}},e.prototype.fallbackJump=function(e){var o=e||i();if("undefined"!=typeof FbPlayableAd&&FbPlayableAd.onCTAClick)FbPlayableAd.onCTAClick();else if("undefined"!=typeof mraid&&mraid.open)mraid.open(o);else if("undefined"!=typeof dapi&&dapi.openStoreUrl)dapi.openStoreUrl();else if("undefined"!=typeof ExitApi&&ExitApi.exit)ExitApi.exit();else if(void 0!==window.BGY_MRAID&&window.BGY_MRAID.open)window.BGY_MRAID.open();else if("function"==typeof snapchatCta)snapchatCta();else if("function"==typeof window.openAppStore)window.openAppStore();else if("function"==typeof window.install)window.install();else if(void 0!==window.TJ_API&&window.TJ_API.click)window.TJ_API.click();else if(void 0!==window.NUC&&window.NUC.trigger&&window.NUC.trigger.convert)window.NUC.trigger.convert(o);else if(void 0!==window.smxTracking&&window.smxTracking.redirect)window.smxTracking.redirect();else{try{parent.postMessage("download","*")}catch(i){}o&&window.open(o,"_blank")}},e.prototype.getPlatform=function(){return this.platform},e.prototype.checkReady=function(){return this.isReady};var o=new e;window.PlayCraftCTA={jump:function(i){o.jump(i)},jump2AppStore:function(i){o.jump(i)},onReady:function(i){o.onReady(i)},getPlatform:function(){return o.getPlatform()},isReady:function(){return o.checkReady()}},window.jump2AppStore=window.PlayCraftCTA.jump2AppStore}();`;
78
+ return `<script>${minifiedCode}</script>`;
79
+ }
80
+ /**
81
+ * 在 HTML 中注入 CTA 适配器(异步版本)
82
+ */
83
+ async injectCTAAdapterAsync(html) {
84
+ const storeUrlsScript = this.getStoreUrlsScript();
85
+ const ctaScript = await this.getCTAAdapterScriptAsync();
86
+ const combined = storeUrlsScript + ctaScript;
87
+ // 在 </head> 之前或 </body> 之前注入
88
+ if (html.includes('</head>')) {
89
+ return html.replace('</head>', `${combined}\n</head>`);
90
+ }
91
+ else if (html.includes('</body>')) {
92
+ return html.replace('</body>', `${combined}\n</body>`);
93
+ }
94
+ else {
95
+ return combined + '\n' + html;
96
+ }
202
97
  }
203
98
  /**
204
- * 在 HTML 中注入 CTA 适配器
99
+ * 在 HTML 中注入 CTA 适配器(同步版本)
100
+ * @deprecated 推荐使用 injectCTAAdapterAsync
205
101
  */
206
102
  injectCTAAdapter(html) {
103
+ const storeUrlsScript = this.getStoreUrlsScript();
207
104
  const ctaScript = this.getCTAAdapterScript();
105
+ const combined = storeUrlsScript + ctaScript;
208
106
  // 在 </head> 之前或 </body> 之前注入
209
107
  if (html.includes('</head>')) {
210
- return html.replace('</head>', `${ctaScript}\n</head>`);
108
+ return html.replace('</head>', `${combined}\n</head>`);
211
109
  }
212
110
  else if (html.includes('</body>')) {
213
- return html.replace('</body>', `${ctaScript}\n</body>`);
111
+ return html.replace('</body>', `${combined}\n</body>`);
214
112
  }
215
113
  else {
216
- return ctaScript + '\n' + html;
114
+ return combined + '\n' + html;
217
115
  }
218
116
  }
219
117
  }
@@ -4,7 +4,7 @@ export declare class BigoAdapter 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(BIGO 要求)
@@ -10,38 +10,38 @@ export class BigoAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'zip';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
14
  // BIGO Ads 需要 BIGO JS-SDK
15
- const bigoScript = `
16
- <script src="https://static-web.likeevideo.com/oss/material-ad/playable-ad-demo/bgy-mraid-sdk.js"></script>
17
- <script>
18
- // BIGO JS-SDK 桥接(如果 SDK 加载失败)
19
- window.BGY_MRAID = window.BGY_MRAID || {
20
- open: function(url) {
21
- console.log('BIGO CTA: opening store');
22
- window.open(url);
23
- },
24
- gameReady: function() {
25
- console.log('BIGO: game ready');
26
- },
27
- gameEnd: function() {
28
- console.log('BIGO: game end');
15
+ const bigoScriptCode = `
16
+ window.BGY_MRAID = window.BGY_MRAID || {
17
+ open: function(url) {
18
+ console.log('BIGO CTA: opening store');
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';
29
24
  }
30
- };
31
- </script>
32
- <!--
33
- 注意:
34
- - BIGO Ads 要求 ZIP 格式,含 config.json
35
- - config.json 需包含 orientation 字段:0=横或竖/1=仅竖/2=仅横
36
- - 接入 BIGO JS-SDK
37
- - CTA 使用 window.BGY_MRAID.open()
38
- - 游戏结束调用 window.BGY_MRAID.gameEnd()
39
- - 可选调用 gameReady()
40
- - 素材不得为 mraid.js 格式
41
- -->
25
+ var _s = (typeof window !== 'undefined' && window.__PLAYCRAFT_STORE_URLS__) || {};
26
+ var storeUrl = url || (getOS() === 'ios' ? (_s.ios || '') : (_s.android || ''));
27
+ window.open(storeUrl, '_blank');
28
+ },
29
+ gameReady: function() {
30
+ console.log('BIGO: game ready');
31
+ },
32
+ gameEnd: function() {
33
+ console.log('BIGO: game end');
34
+ }
35
+ };
42
36
  `;
37
+ const sdkScript = `<script src="https://static-web.likeevideo.com/oss/material-ad/playable-ad-demo/bgy-mraid-sdk.js"></script>`;
38
+ const fallbackScript = await this.minifyPlatformScript(bigoScriptCode, 'bigo-sdk');
39
+ const comment = `<!-- BIGO: ZIP格式, config.json含orientation, 使用BGY_MRAID.open() -->`;
43
40
  // 在 </head> 之前插入
44
- return html.replace('</head>', `${bigoScript}</head>`);
41
+ html = html.replace('</head>', `${sdkScript}${fallbackScript}${comment}</head>`);
42
+ // 注入统一的 CTA 适配器
43
+ html = await this.injectCTAAdapterAsync(html);
44
+ return html;
45
45
  }
46
46
  getPlatformScript() {
47
47
  return `
@@ -4,6 +4,6 @@ export declare class FacebookAdapter 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,22 +10,33 @@ export class FacebookAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'html';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
14
  // Facebook 需要 FbPlayableAd API
15
- const fbScript = `
16
- <script>
17
- window.FbPlayableAd = window.FbPlayableAd || {
18
- onCTAClick: function() {
19
- console.log('Facebook CTA clicked');
20
- // 这里会被 Facebook 替换为实际的跟踪代码
15
+ const fbScriptCode = `
16
+ window.FbPlayableAd = window.FbPlayableAd || {
17
+ onCTAClick: function() {
18
+ console.log('Facebook CTA clicked');
19
+ function getOS(){
20
+ var ua = navigator.userAgent || '';
21
+ if (/iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) {
22
+ return 'ios';
23
+ } else if (/Android/i.test(ua)) {
24
+ return 'android';
25
+ }
26
+ return 'unknown';
21
27
  }
22
- };
23
- </script>
28
+ var _s = window.__PLAYCRAFT_STORE_URLS__ || {};
29
+ var url = getOS() === 'ios' ? (_s.ios || '') : (_s.android || '');
30
+ window.open(url, '_blank');
31
+ }
32
+ };
24
33
  `;
34
+ // 压缩平台脚本
35
+ const fbScript = await this.minifyPlatformScript(fbScriptCode, 'facebook-api');
25
36
  // 在 </head> 之前插入平台特定的 API
26
37
  html = html.replace('</head>', `${fbScript}</head>`);
27
38
  // 注入统一的 CTA 适配器
28
- html = this.injectCTAAdapter(html);
39
+ html = await this.injectCTAAdapterAsync(html);
29
40
  return html;
30
41
  }
31
42
  getPlatformScript() {
@@ -4,7 +4,7 @@ export declare class GoogleAdapter 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,30 +10,37 @@ export class GoogleAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'zip';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
14
  // Google Ads 需要 exitapi.js
15
- const googleScript = `
16
- <script>
17
- // Google Ads Exit API
18
- window.ExitApi = window.ExitApi || {
19
- exit: function() {
20
- console.log('Google Ads CTA: opening store');
21
- // Google 会替换为实际的跟踪代码
22
- window.open('https://play.google.com/store', '_blank');
15
+ const googleScriptCode = `
16
+ window.ExitApi = window.ExitApi || {
17
+ exit: function() {
18
+ console.log('Google Ads CTA: opening store');
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';
23
24
  }
24
- };
25
- </script>
26
- <!--
27
- 注意:
28
- - Google Ads 要求 ZIP 格式,最大 5MB,最多 512 文件
29
- - 必须包含 <!DOCTYPE html> 和完整的 html/head/body 结构
30
- - 使用 <meta name="ad.orientation" content="portrait|landscape"> 声明方向
31
- - 支持 Google 托管库:Fonts/jQuery/Greensock/CreateJS
32
- -->
33
- <meta name="ad.size" content="320x480,480x320,768x1024,1024x768">
25
+ var _s = window.__PLAYCRAFT_STORE_URLS__ || {};
26
+ var url = getOS() === 'ios' ? (_s.ios || '') : (_s.android || '');
27
+ window.open(url, '_blank');
28
+ }
29
+ };
34
30
  `;
35
- // </head> 之前插入
36
- return html.replace('</head>', `${googleScript}</head>`);
31
+ const googleScript = await this.minifyPlatformScript(googleScriptCode, 'google-exitapi');
32
+ const meta = `<meta name="ad.size" content="320x480,480x320,768x1024,1024x768">`;
33
+ const mobileMeta = `<meta name="mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-capable" content="yes">`;
34
+ const orientationMeta = `<meta name="screen-orientation" content="landscape"><meta name="orientation" content="landscape">`;
35
+ const comment = `<!-- Google Ads: ZIP 最大 5MB, 512 文件, 使用 ExitApi.exit() -->`;
36
+ // 替换模板中已有的 viewport meta,增加 Google 所需的属性
37
+ const googleViewport = `<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, viewport-fit=cover">`;
38
+ html = html.replace(/<meta\s+name=['"]viewport['"][^>]*>/i, googleViewport);
39
+ // 在 </head> 之前插入 Google 特有标签(横屏锁定、mobile-web-app、ad.size 等)
40
+ html = html.replace('</head>', `${googleScript}${comment}${mobileMeta}${orientationMeta}${meta}</head>`);
41
+ // 注入统一的 CTA 适配器
42
+ html = await this.injectCTAAdapterAsync(html);
43
+ return html;
37
44
  }
38
45
  getPlatformScript() {
39
46
  return `
@@ -16,3 +16,4 @@ export { BigoAdapter } from './bigo.js';
16
16
  export { InMobiAdapter } from './inmobi.js';
17
17
  export { AdikteevAdapter } from './adikteev.js';
18
18
  export { RemergeAdapter } from './remerge.js';
19
+ export { MintegralAdapter } from './mintegral.js';
@@ -12,6 +12,7 @@ import { BigoAdapter } from './bigo.js';
12
12
  import { InMobiAdapter } from './inmobi.js';
13
13
  import { AdikteevAdapter } from './adikteev.js';
14
14
  import { RemergeAdapter } from './remerge.js';
15
+ import { MintegralAdapter } from './mintegral.js';
15
16
  export function createPlatformAdapter(options) {
16
17
  switch (options.platform) {
17
18
  case 'playcraft':
@@ -42,6 +43,8 @@ export function createPlatformAdapter(options) {
42
43
  return new AdikteevAdapter(options);
43
44
  case 'remerge':
44
45
  return new RemergeAdapter(options);
46
+ case 'mintegral':
47
+ return new MintegralAdapter(options);
45
48
  default:
46
49
  throw new Error(`Unsupported platform: ${options.platform}`);
47
50
  }
@@ -61,3 +64,4 @@ export { BigoAdapter } from './bigo.js';
61
64
  export { InMobiAdapter } from './inmobi.js';
62
65
  export { AdikteevAdapter } from './adikteev.js';
63
66
  export { RemergeAdapter } from './remerge.js';
67
+ export { MintegralAdapter } from './mintegral.js';
@@ -4,7 +4,7 @@ export declare class InMobiAdapter 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,42 +10,37 @@ export class InMobiAdapter extends PlatformAdapter {
10
10
  getDefaultFormat() {
11
11
  return 'zip';
12
12
  }
13
- modifyHTML(html, assets) {
13
+ async modifyHTML(html, assets) {
14
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">
15
+ const inmobiScriptCode = `
16
+ window.mraid = window.mraid || {
17
+ getVersion: function() { return '2.0'; },
18
+ isReady: function() { return true; },
19
+ open: function(url) {
20
+ console.log('InMobi 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') setTimeout(listener, 0);
29
+ },
30
+ removeEventListener: function(event, listener) {},
31
+ getState: function() { return 'default'; },
32
+ getPlacementType: function() { return 'interstitial'; },
33
+ getMaxSize: function() { return { width: window.innerWidth, height: window.innerHeight }; },
34
+ getCurrentPosition: function() { return { x: 0, y: 0, width: window.innerWidth, height: window.innerHeight }; },
35
+ getScreenSize: function() { return { width: screen.width, height: screen.height }; }
36
+ };
44
37
  `;
38
+ const inmobiScript = await this.minifyPlatformScript(inmobiScriptCode, 'inmobi-mraid');
39
+ const comment = `<!-- InMobi: ZIP格式, 使用mraid.open() -->`;
45
40
  // 在 </head> 之前插入平台特定的 API
46
- html = html.replace('</head>', `${inmobiScript}</head>`);
41
+ html = html.replace('</head>', `${inmobiScript}${comment}</head>`);
47
42
  // 注入统一的 CTA 适配器
48
- html = this.injectCTAAdapter(html);
43
+ html = await this.injectCTAAdapterAsync(html);
49
44
  return html;
50
45
  }
51
46
  getPlatformScript() {
@@ -4,7 +4,7 @@ export declare class IronSourceAdapter 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
  }