@maoyugames/phaser-framework 1.0.16 → 1.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{BasePlatform-CwVOo3_q.d.ts → BasePlatform-DqIfl-Oi.d.ts} +1 -1
- package/dist/{chunk-PDESBWLX.js → chunk-NFEHUFN7.js} +1 -1
- package/dist/cli/index.js +260 -129
- package/dist/index.d.ts +34 -3
- package/dist/platform/capacitor.d.ts +2 -2
- package/dist/platform/capacitor.js +1 -1
- package/dist/platform/facebook.d.ts +4 -3
- package/dist/platform/facebook.js +64 -6
- package/dist/platform/tiktok.d.ts +2 -2
- package/dist/platform/tiktok.js +145 -53
- package/dist/platform/web.d.ts +2 -2
- package/dist/platform/web.js +1 -1
- package/dist/platform/wechat.d.ts +1 -1
- package/dist/platform/youtube.d.ts +71 -0
- package/dist/platform/youtube.js +310 -0
- package/dist/{types-WJYVtDfo.d.ts → types-CxYJ9uz0.d.ts} +6 -1
- package/package.json +5 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { b as HttpRequestOptions, U as Unsubscribe, H as Handler, p as LogLevel, A as AdResult, t as PurchaseResult, q as LoginResult, d as IPlatform, i as IPlatformLifecycle, S as SafeArea } from './types-
|
|
2
|
-
export { a as HttpMethod, c as HttpResponse, I as IDisposable, e as IPlatformAds, f as IPlatformAnalytics, g as IPlatformAuth, h as IPlatformDevice, j as IPlatformMission, k as IPlatformNet, l as IPlatformPayment, m as IPlatformShortcut, n as IPlatformSocket, o as IPlatformStorage, L as LaunchOptions, P as PlatformInfo, r as PlatformName, s as PlatformUnsupportedError, R as Result, u as SocketOptions, v as SystemInfo, V as Vec2, w as err, x as ok } from './types-
|
|
1
|
+
import { b as HttpRequestOptions, U as Unsubscribe, H as Handler, p as LogLevel, A as AdResult, t as PurchaseResult, q as LoginResult, d as IPlatform, i as IPlatformLifecycle, S as SafeArea } from './types-CxYJ9uz0.js';
|
|
2
|
+
export { a as HttpMethod, c as HttpResponse, I as IDisposable, e as IPlatformAds, f as IPlatformAnalytics, g as IPlatformAuth, h as IPlatformDevice, j as IPlatformMission, k as IPlatformNet, l as IPlatformPayment, m as IPlatformShortcut, n as IPlatformSocket, o as IPlatformStorage, L as LaunchOptions, P as PlatformInfo, r as PlatformName, s as PlatformUnsupportedError, R as Result, u as SocketOptions, v as SystemInfo, V as Vec2, w as err, x as ok } from './types-CxYJ9uz0.js';
|
|
3
3
|
import Phaser from 'phaser';
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -1805,6 +1805,35 @@ interface FacebookPlatformConfig {
|
|
|
1805
1805
|
/** 广告位配置(覆盖 common.ads) */
|
|
1806
1806
|
ads?: AdsConfig;
|
|
1807
1807
|
}
|
|
1808
|
+
/**
|
|
1809
|
+
* YouTube Playables 平台配置。
|
|
1810
|
+
*
|
|
1811
|
+
* YouTube Playables SDK 由构建侧通过 `<script src="https://www.youtube.com/game_api/v1">`
|
|
1812
|
+
* 注入 <head>(必须在游戏 bundle 前),运行时挂载全局 `ytgame`。
|
|
1813
|
+
* 文档:https://developers.google.com/youtube/gaming/playables/reference/getting_started
|
|
1814
|
+
*
|
|
1815
|
+
* 注意:YouTube Playables **禁止任何内购**(off-platform 也不允许),故无 IAP 相关字段;
|
|
1816
|
+
* 广告(激励/插屏)走 ytgame.ads.*,广告位由 YouTube 后台 monetization 配置,游戏侧
|
|
1817
|
+
* rewardId 经 common.ads / ads 传入。
|
|
1818
|
+
*/
|
|
1819
|
+
interface YouTubePlatformConfig {
|
|
1820
|
+
/** 页面标题(注入 index.html <title>) */
|
|
1821
|
+
title?: string;
|
|
1822
|
+
/**
|
|
1823
|
+
* YouTube Playables SDK 脚本地址(注入 index.html <head> 第一个 script)。
|
|
1824
|
+
* 不填用官方默认 https://www.youtube.com/game_api/v1。
|
|
1825
|
+
*/
|
|
1826
|
+
sdkUrl?: string;
|
|
1827
|
+
/** 屏幕方向(用于 viewport / meta 提示) */
|
|
1828
|
+
orientation?: Orientation;
|
|
1829
|
+
/** 业务后端基址(覆盖 common.apiBaseURL) */
|
|
1830
|
+
apiBaseURL?: string;
|
|
1831
|
+
/**
|
|
1832
|
+
* 广告位配置(覆盖 common.ads)。YouTube 激励广告用 reward id(UUID 形态),
|
|
1833
|
+
* 由 YouTube 后台 monetization 生成,填到 ads.rewardedUnitId。
|
|
1834
|
+
*/
|
|
1835
|
+
ads?: AdsConfig;
|
|
1836
|
+
}
|
|
1808
1837
|
/** Capacitor(iOS + Android 原生 App)平台配置 */
|
|
1809
1838
|
interface CapacitorPlatformConfig {
|
|
1810
1839
|
/** 应用包名/反向域名(写入 capacitor.config appId,如 com.example.app) */
|
|
@@ -1842,6 +1871,8 @@ interface PlatformConfig {
|
|
|
1842
1871
|
facebook?: FacebookPlatformConfig;
|
|
1843
1872
|
/** Capacitor 原生 App */
|
|
1844
1873
|
capacitor?: CapacitorPlatformConfig;
|
|
1874
|
+
/** YouTube Playables */
|
|
1875
|
+
youtube?: YouTubePlatformConfig;
|
|
1845
1876
|
}
|
|
1846
1877
|
|
|
1847
|
-
export { AdResult, type AdsConfig, App, type AppConfig, BaseModule, BasePanel, BaseScene, Button, type ButtonConfig, type ButtonStyle, type CapacitorPlatformConfig, ConfigTable, ConfigTableManager, ErrorCode, type FacebookPlatformConfig, FrameworkError, Handler, HttpClient, type HttpClientConfig, HttpError, type HttpInterceptors, HttpRequestOptions, I18n, type I18nOptions, type IAccountService, type IAdsManager, type IAnalyticsManager, type IApp, type IAssetLoader, type IAudioManager, type IConfigService, type IEventBus, type IHttpClient, type IKcpTransport, type ILogger, type INetManager, type IPanelManager, type IPaymentManager, IPlatform, IPlatformLifecycle, type ISceneManager, type ISocketClient, type IStorageManager, IconButton, type IconButtonConfig, JsonCodec, KcpClient, type KcpClientConfig, type KcpTransportFactory, type LayerName, Layers, LogLevel, LoginResult, MessageChannel, type MessageChannelOptions, type MessageCodec, type MessageEnvelope, MessageError, ModuleRegistry, NetManager, type NetManagerOptions, type NetProtocol, ObjectPool, type Orientation, type PanelCtor, PanelManager, type PlatformConfig, PlatformContext, PurchaseResult, SafeArea, SaveManager, type SaveSlot, type SaveSlotOptions, type ScheduleHandle, Scheduler, type SocketClientConfig, type SocketState, type StartGameOptions, type Store, type TikTokPlatformConfig, TypedEventBus, Unsubscribe, type WeChatPlatformConfig, type WebPlatformConfig, WebSocketClient, createStore, createTypedEventBus, isFrameworkError, normalizeLocale, startGame };
|
|
1878
|
+
export { AdResult, type AdsConfig, App, type AppConfig, BaseModule, BasePanel, BaseScene, Button, type ButtonConfig, type ButtonStyle, type CapacitorPlatformConfig, ConfigTable, ConfigTableManager, ErrorCode, type FacebookPlatformConfig, FrameworkError, Handler, HttpClient, type HttpClientConfig, HttpError, type HttpInterceptors, HttpRequestOptions, I18n, type I18nOptions, type IAccountService, type IAdsManager, type IAnalyticsManager, type IApp, type IAssetLoader, type IAudioManager, type IConfigService, type IEventBus, type IHttpClient, type IKcpTransport, type ILogger, type INetManager, type IPanelManager, type IPaymentManager, IPlatform, IPlatformLifecycle, type ISceneManager, type ISocketClient, type IStorageManager, IconButton, type IconButtonConfig, JsonCodec, KcpClient, type KcpClientConfig, type KcpTransportFactory, type LayerName, Layers, LogLevel, LoginResult, MessageChannel, type MessageChannelOptions, type MessageCodec, type MessageEnvelope, MessageError, ModuleRegistry, NetManager, type NetManagerOptions, type NetProtocol, ObjectPool, type Orientation, type PanelCtor, PanelManager, type PlatformConfig, PlatformContext, PurchaseResult, SafeArea, SaveManager, type SaveSlot, type SaveSlotOptions, type ScheduleHandle, Scheduler, type SocketClientConfig, type SocketState, type StartGameOptions, type Store, type TikTokPlatformConfig, TypedEventBus, Unsubscribe, type WeChatPlatformConfig, type WebPlatformConfig, WebSocketClient, type YouTubePlatformConfig, createStore, createTypedEventBus, isFrameworkError, normalizeLocale, startGame };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as PlatformName, h as IPlatformDevice, i as IPlatformLifecycle } from '../types-
|
|
2
|
-
import { B as BasePlatform } from '../BasePlatform-
|
|
1
|
+
import { r as PlatformName, h as IPlatformDevice, i as IPlatformLifecycle } from '../types-CxYJ9uz0.js';
|
|
2
|
+
import { B as BasePlatform } from '../BasePlatform-DqIfl-Oi.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Capacitor(原生 WebView 容器)平台适配器。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BasePlatform, DomLifecycle } from '../chunk-PDESBWLX.js';
|
|
2
1
|
import { PlatformUnsupportedError } from '../chunk-II3JM4R3.js';
|
|
2
|
+
import { BasePlatform, DomLifecycle } from '../chunk-NFEHUFN7.js';
|
|
3
3
|
import { __publicField } from '../chunk-PKBMQBKP.js';
|
|
4
4
|
|
|
5
5
|
// src/platform/impl/capacitor/CapacitorPlatform.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as PlatformName, o as IPlatformStorage, g as IPlatformAuth, e as IPlatformAds, l as IPlatformPayment, h as IPlatformDevice, i as IPlatformLifecycle } from '../types-
|
|
2
|
-
import { B as BasePlatform } from '../BasePlatform-
|
|
1
|
+
import { r as PlatformName, o as IPlatformStorage, g as IPlatformAuth, e as IPlatformAds, l as IPlatformPayment, h as IPlatformDevice, m as IPlatformShortcut, i as IPlatformLifecycle } from '../types-CxYJ9uz0.js';
|
|
2
|
+
import { B as BasePlatform } from '../BasePlatform-DqIfl-Oi.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Facebook Instant Games 平台适配器。
|
|
@@ -24,8 +24,9 @@ declare class FacebookPlatform extends BasePlatform {
|
|
|
24
24
|
readonly storage: IPlatformStorage;
|
|
25
25
|
readonly auth: IPlatformAuth;
|
|
26
26
|
readonly ads: IPlatformAds;
|
|
27
|
-
|
|
27
|
+
payment?: IPlatformPayment;
|
|
28
28
|
readonly device: IPlatformDevice;
|
|
29
|
+
readonly shortcut: IPlatformShortcut;
|
|
29
30
|
readonly lifecycle: IPlatformLifecycle;
|
|
30
31
|
init(): Promise<void>;
|
|
31
32
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BasePlatform, DomLifecycle } from '../chunk-PDESBWLX.js';
|
|
2
1
|
import { PlatformUnsupportedError } from '../chunk-II3JM4R3.js';
|
|
2
|
+
import { BasePlatform, DomLifecycle } from '../chunk-NFEHUFN7.js';
|
|
3
3
|
import { __publicField } from '../chunk-PKBMQBKP.js';
|
|
4
4
|
|
|
5
5
|
// src/platform/impl/facebook/FacebookPlatform.ts
|
|
@@ -86,12 +86,29 @@ var FacebookAuth = class {
|
|
|
86
86
|
raw: info
|
|
87
87
|
};
|
|
88
88
|
}
|
|
89
|
+
// Zero Permissions 模型(SDK v8.0+,2026-06 核对 developers.facebook.com 官方文档):
|
|
90
|
+
// 游戏**无法直接 JS 读取** name/profile picture —— Meta 改在独立 iFrame「Overlay Views」内渲染
|
|
91
|
+
// 用户信息(游戏在 bundle 放 XML 布局,用 {{FBInstant.player.name}}/{{...photo}} 占位,
|
|
92
|
+
// FBInstant.views.createOverlayView 创建,游戏拿不到原始值)。
|
|
93
|
+
// 因此 getName/getPhoto 在 Zero Permissions 下返 undefined 或抛 → 这里 try-catch 返 null,
|
|
94
|
+
// 业务排行榜用 player ID / 游客显示。如需在游戏内显示真实 FB 昵称/头像,需另接 Overlay Views
|
|
95
|
+
// (XML 布局 + createOverlayView,本游戏未接;player 身份本身用 getSignedPlayerInfoAsync 已足够)。
|
|
89
96
|
async getProfile() {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
if (!hasFB()) return null;
|
|
98
|
+
try {
|
|
99
|
+
const name = FBInstant.player.getName?.();
|
|
100
|
+
const photo = FBInstant.player.getPhoto?.();
|
|
101
|
+
if (!name && !photo) return null;
|
|
102
|
+
return { nickname: name ?? "", avatarUrl: photo ?? "" };
|
|
103
|
+
} catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// 身份(login)用 getSignedPlayerInfoAsync(player ID + signature),Zero Permissions 与普通模式
|
|
108
|
+
// 都可用、且是 Zero Permissions 的**默认身份**。FB 无 TikTok 那种"显式授权拿 user.info"的弹窗,
|
|
109
|
+
// authorize 直接复用 login(业务「首次进排行榜引导授权」逻辑跨平台通用,FB 下等价于静默拿 player ID)。
|
|
110
|
+
authorize(_scope) {
|
|
111
|
+
return this.login();
|
|
95
112
|
}
|
|
96
113
|
};
|
|
97
114
|
var FacebookAds = class {
|
|
@@ -144,6 +161,37 @@ var FacebookAds = class {
|
|
|
144
161
|
}
|
|
145
162
|
}
|
|
146
163
|
};
|
|
164
|
+
var FacebookShortcut = class {
|
|
165
|
+
check() {
|
|
166
|
+
if (!hasFB() || typeof FBInstant.canCreateShortcutAsync !== "function") {
|
|
167
|
+
return Promise.resolve(false);
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
return FBInstant.canCreateShortcutAsync().then(
|
|
171
|
+
(ok) => !!ok,
|
|
172
|
+
() => false
|
|
173
|
+
);
|
|
174
|
+
} catch {
|
|
175
|
+
return Promise.resolve(false);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
add() {
|
|
179
|
+
if (!hasFB() || typeof FBInstant.createShortcutAsync !== "function") {
|
|
180
|
+
return Promise.resolve(false);
|
|
181
|
+
}
|
|
182
|
+
try {
|
|
183
|
+
return FBInstant.createShortcutAsync().then(
|
|
184
|
+
() => true,
|
|
185
|
+
() => false
|
|
186
|
+
);
|
|
187
|
+
} catch {
|
|
188
|
+
return Promise.resolve(false);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
getMissionReward() {
|
|
192
|
+
return Promise.resolve({ canReceive: false });
|
|
193
|
+
}
|
|
194
|
+
};
|
|
147
195
|
var FacebookPayment = class {
|
|
148
196
|
async purchase(productId, extra) {
|
|
149
197
|
requireFB("payment.purchase");
|
|
@@ -222,8 +270,12 @@ var FacebookPlatform = class extends BasePlatform {
|
|
|
222
270
|
__publicField(this, "storage", this.fbStorage);
|
|
223
271
|
__publicField(this, "auth", new FacebookAuth());
|
|
224
272
|
__publicField(this, "ads", new FacebookAds());
|
|
273
|
+
// payment 在 iOS 宿主下由 init() 撤下(Apple 审核指南 4.7 禁止 iOS 展示任何支付/内购功能),故非 readonly。
|
|
225
274
|
__publicField(this, "payment", new FacebookPayment());
|
|
226
275
|
__publicField(this, "device", new FacebookDevice());
|
|
276
|
+
__publicField(this, "shortcut", new FacebookShortcut());
|
|
277
|
+
// mission 不实现(FB 无"侧边栏入口任务"概念,TikTok 特有);保持 undefined,
|
|
278
|
+
// 业务层 App.platform.mission?.startEntrance() 会安全跳过。
|
|
227
279
|
__publicField(this, "lifecycle", new FacebookLifecycle(
|
|
228
280
|
() => this.getLaunchOptions()
|
|
229
281
|
));
|
|
@@ -235,6 +287,12 @@ var FacebookPlatform = class extends BasePlatform {
|
|
|
235
287
|
await FBInstant.initializeAsync();
|
|
236
288
|
FBInstant.setLoadingProgress(100);
|
|
237
289
|
await FBInstant.startGameAsync();
|
|
290
|
+
try {
|
|
291
|
+
if (FBInstant.getPlatform?.() === "IOS") {
|
|
292
|
+
this.payment = void 0;
|
|
293
|
+
}
|
|
294
|
+
} catch {
|
|
295
|
+
}
|
|
238
296
|
try {
|
|
239
297
|
this._system = { ...this._system, language: FBInstant.getLocale() };
|
|
240
298
|
} catch {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as PlatformName, g as IPlatformAuth, e as IPlatformAds, l as IPlatformPayment, h as IPlatformDevice, f as IPlatformAnalytics, m as IPlatformShortcut, j as IPlatformMission, i as IPlatformLifecycle } from '../types-
|
|
2
|
-
import { B as BasePlatform } from '../BasePlatform-
|
|
1
|
+
import { r as PlatformName, g as IPlatformAuth, e as IPlatformAds, l as IPlatformPayment, h as IPlatformDevice, f as IPlatformAnalytics, m as IPlatformShortcut, j as IPlatformMission, i as IPlatformLifecycle } from '../types-CxYJ9uz0.js';
|
|
2
|
+
import { B as BasePlatform } from '../BasePlatform-DqIfl-Oi.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* TikTok Mini Games(Minis)平台适配器。
|
package/dist/platform/tiktok.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BasePlatform } from '../chunk-PDESBWLX.js';
|
|
2
1
|
import { PlatformUnsupportedError } from '../chunk-II3JM4R3.js';
|
|
2
|
+
import { BasePlatform } from '../chunk-NFEHUFN7.js';
|
|
3
3
|
import { __publicField } from '../chunk-PKBMQBKP.js';
|
|
4
4
|
|
|
5
5
|
// src/platform/impl/tiktok/TikTokPlatform.ts
|
|
@@ -57,29 +57,66 @@ var TikTokAuth = class {
|
|
|
57
57
|
async getProfile() {
|
|
58
58
|
return null;
|
|
59
59
|
}
|
|
60
|
+
// 显式授权(game.authorize):弹 TikTok 授权页拿带 scope 的 code,后端换 token 后调 /v2/user/info/
|
|
61
|
+
// 取 nickname/avatar。callback 式,包成 Promise + 10s 超时(同 login,防永久 pending)。
|
|
62
|
+
authorize(scope = "user.info.basic") {
|
|
63
|
+
requireTT("auth.authorize");
|
|
64
|
+
return new Promise((resolve, reject) => {
|
|
65
|
+
let settled = false;
|
|
66
|
+
const timer = setTimeout(() => {
|
|
67
|
+
if (settled) return;
|
|
68
|
+
settled = true;
|
|
69
|
+
reject(new Error("TikTok authorize timeout"));
|
|
70
|
+
}, 1e4);
|
|
71
|
+
const finish = (fn) => {
|
|
72
|
+
if (settled) return;
|
|
73
|
+
settled = true;
|
|
74
|
+
clearTimeout(timer);
|
|
75
|
+
fn();
|
|
76
|
+
};
|
|
77
|
+
try {
|
|
78
|
+
TTMinis.game.authorize({
|
|
79
|
+
scope,
|
|
80
|
+
success: (res) => {
|
|
81
|
+
const code = res?.code ?? res?.authResponse?.code ?? "";
|
|
82
|
+
finish(() => code ? resolve({ code, raw: res }) : reject(new Error("authorize: no code")));
|
|
83
|
+
},
|
|
84
|
+
fail: (err) => finish(() => reject(new Error(`TikTok authorize fail: ${err?.errMsg ?? JSON.stringify(err)}`)))
|
|
85
|
+
});
|
|
86
|
+
} catch (e) {
|
|
87
|
+
finish(() => reject(e));
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
60
91
|
};
|
|
61
92
|
var TikTokAds = class {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
93
|
+
constructor() {
|
|
94
|
+
// TikTok H5 SDK 激励视频:createRewardedVideoAd 返回**单例**广告对象,适配器缓存复用。
|
|
95
|
+
// 反编译 connect.tiktok-minis.com/game/sdk.js(2026-06-02,广告类 `Rn`)确认:ad 对象**确有**
|
|
96
|
+
// show/onClose/onError/offClose;**当前版本无** load/onLoad/destroy —— create 后广告自动拉取,
|
|
97
|
+
// show() 内部先 await SDK 自身加载 Promise 再展示。故本适配器对 load/onLoad 用**可选调用**
|
|
98
|
+
// (`ad.load?.()` / `ad.onLoad?.()`),缺失时 ensureLoaded 乐观置就绪并直接 show(由 show 内部等加载);
|
|
99
|
+
// 真机若为更高版本带 load/onLoad,则走预加载快路径。两种情况都正确,绝不调用不存在的方法。
|
|
100
|
+
//
|
|
101
|
+
// ⚠ 历史 bug(导致"广告请求多、曝光低"):旧实现每次 showRewarded 都 createRewardedVideoAd
|
|
102
|
+
// 新建实例并**立刻 show**(广告尚未加载完)。每次 create 触发一次广告请求,但 show 在未就绪时
|
|
103
|
+
// 失败 → 请求计数 +1、曝光计数 +0,且重复建实例放大请求量。
|
|
104
|
+
// 修复:单例缓存 + 一次性绑定回调 + 先 load 再 show(show 失败重试一次 load→show)。
|
|
105
|
+
/** 单例广告实例(按首个 adUnitId 创建,后续复用);创建失败时为 undefined 并允许下次重建 */
|
|
106
|
+
__publicField(this, "adPromise");
|
|
107
|
+
/** 当前 show 调用的结果回调;激励视频为模态,同一时刻只有一个 */
|
|
108
|
+
__publicField(this, "pendingShow");
|
|
109
|
+
/** 广告是否已加载就绪;show(消耗)或出错后置 false,需重新 load */
|
|
110
|
+
__publicField(this, "loaded", false);
|
|
70
111
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const onError = (msg) => {
|
|
76
|
-
console.warn("[ads.showRewarded] error:", msg);
|
|
77
|
-
resolve("failed");
|
|
78
|
-
};
|
|
112
|
+
/** 取/建单例广告实例,并**一次性**绑定 onLoad/onClose/onError(复用不重复绑定) */
|
|
113
|
+
getAd(adUnitId) {
|
|
114
|
+
if (this.adPromise) return this.adPromise;
|
|
115
|
+
this.adPromise = new Promise((resolve) => {
|
|
79
116
|
try {
|
|
80
117
|
const adSync = TTMinis.game.createRewardedVideoAd({ adUnitId });
|
|
81
118
|
if (adSync && typeof adSync.show === "function") {
|
|
82
|
-
this.
|
|
119
|
+
resolve(this.wireOnce(adSync));
|
|
83
120
|
return;
|
|
84
121
|
}
|
|
85
122
|
} catch (e) {
|
|
@@ -87,43 +124,94 @@ var TikTokAds = class {
|
|
|
87
124
|
}
|
|
88
125
|
try {
|
|
89
126
|
TTMinis.game.createRewardedVideoAd((res) => {
|
|
90
|
-
if (res?.is_success && res.rewardedVideoAd)
|
|
91
|
-
|
|
92
|
-
} else {
|
|
93
|
-
onError(JSON.stringify(res?.error ?? "create failed"));
|
|
94
|
-
}
|
|
127
|
+
if (res?.is_success && res.rewardedVideoAd) resolve(this.wireOnce(res.rewardedVideoAd));
|
|
128
|
+
else resolve(void 0);
|
|
95
129
|
}, { adUnitId });
|
|
96
130
|
} catch (e) {
|
|
97
|
-
|
|
131
|
+
console.warn("[ads] async createRewardedVideoAd failed:", e?.message);
|
|
132
|
+
resolve(void 0);
|
|
98
133
|
}
|
|
99
134
|
});
|
|
135
|
+
return this.adPromise;
|
|
100
136
|
}
|
|
101
|
-
|
|
102
|
-
|
|
137
|
+
/** 一次性绑定生命周期回调:onLoad 标记就绪;onClose/onError 结算当前 pendingShow */
|
|
138
|
+
wireOnce(ad) {
|
|
139
|
+
try {
|
|
140
|
+
ad.onLoad?.(() => {
|
|
141
|
+
this.loaded = true;
|
|
142
|
+
});
|
|
143
|
+
} catch {
|
|
144
|
+
}
|
|
103
145
|
try {
|
|
104
146
|
ad.onClose((res) => {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
onResult(!!res?.isEnded);
|
|
147
|
+
this.loaded = false;
|
|
148
|
+
this.settle(res?.isEnded ? "completed" : "skipped");
|
|
108
149
|
});
|
|
109
150
|
} catch (e) {
|
|
110
|
-
|
|
151
|
+
console.warn("[ads] onClose unsupported:", e?.message);
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
ad.onError?.((res) => {
|
|
155
|
+
this.loaded = false;
|
|
156
|
+
console.warn("[ads.showRewarded] error:", res?.error?.error_msg);
|
|
157
|
+
this.settle("failed");
|
|
158
|
+
});
|
|
159
|
+
} catch {
|
|
160
|
+
}
|
|
161
|
+
return ad;
|
|
162
|
+
}
|
|
163
|
+
/** 结算当前 show 的结果(只结算挂起的那一次) */
|
|
164
|
+
settle(r) {
|
|
165
|
+
const resolve = this.pendingShow;
|
|
166
|
+
this.pendingShow = void 0;
|
|
167
|
+
resolve?.(r);
|
|
168
|
+
}
|
|
169
|
+
/** 确保广告已加载:已就绪直接返回,否则 load() 等待(老 SDK 无 load 则乐观置就绪) */
|
|
170
|
+
async ensureLoaded(ad) {
|
|
171
|
+
if (this.loaded) return;
|
|
172
|
+
if (typeof ad.load === "function") await ad.load();
|
|
173
|
+
this.loaded = true;
|
|
174
|
+
}
|
|
175
|
+
/** 预加载:创建单例 + 拉一条广告,使后续 show 即时展示(降低请求/曝光错配) */
|
|
176
|
+
async preloadRewarded(adUnitId) {
|
|
177
|
+
if (!hasTT()) return;
|
|
178
|
+
const ad = await this.getAd(adUnitId);
|
|
179
|
+
if (!ad) {
|
|
180
|
+
this.adPromise = void 0;
|
|
111
181
|
return;
|
|
112
182
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
settled = true;
|
|
118
|
-
onError(res?.error?.error_msg ?? "ad error");
|
|
119
|
-
});
|
|
120
|
-
} catch {
|
|
121
|
-
}
|
|
183
|
+
try {
|
|
184
|
+
await this.ensureLoaded(ad);
|
|
185
|
+
} catch (e) {
|
|
186
|
+
console.warn("[ads.preloadRewarded] load failed:", e?.message);
|
|
122
187
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
188
|
+
}
|
|
189
|
+
showRewarded(adUnitId) {
|
|
190
|
+
requireTT("ads.showRewarded");
|
|
191
|
+
return new Promise((resolve) => {
|
|
192
|
+
this.pendingShow = resolve;
|
|
193
|
+
void (async () => {
|
|
194
|
+
const ad = await this.getAd(adUnitId);
|
|
195
|
+
if (!ad) {
|
|
196
|
+
this.adPromise = void 0;
|
|
197
|
+
this.settle("failed");
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
await this.ensureLoaded(ad);
|
|
202
|
+
await ad.show();
|
|
203
|
+
} catch (e) {
|
|
204
|
+
console.warn("[ads.showRewarded] show failed, retry after load:", e?.message);
|
|
205
|
+
this.loaded = false;
|
|
206
|
+
try {
|
|
207
|
+
await this.ensureLoaded(ad);
|
|
208
|
+
await ad.show();
|
|
209
|
+
} catch (e2) {
|
|
210
|
+
console.warn("[ads.showRewarded] show failed after reload:", e2?.message);
|
|
211
|
+
this.settle("failed");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
})();
|
|
127
215
|
});
|
|
128
216
|
}
|
|
129
217
|
// 插页广告:官方文档 createInterstitialAd 自 SDK 0.3.0;当前反编译版 sdk.js 未见此 API,
|
|
@@ -276,7 +364,12 @@ var TikTokPayment = class {
|
|
|
276
364
|
fail: (err) => {
|
|
277
365
|
if (settled) return;
|
|
278
366
|
settled = true;
|
|
279
|
-
|
|
367
|
+
const e = err;
|
|
368
|
+
const code = e?.error?.error_code;
|
|
369
|
+
const msg = e?.error?.error_msg ?? e?.errMsg ?? "unknown";
|
|
370
|
+
const wrapped = new Error(`TikTok pay failed${code !== void 0 ? ` (code=${code})` : ""}: ${msg}`);
|
|
371
|
+
wrapped.cause = err;
|
|
372
|
+
reject(wrapped);
|
|
280
373
|
}
|
|
281
374
|
});
|
|
282
375
|
} catch (e) {
|
|
@@ -311,15 +404,14 @@ var TikTokDevice = class {
|
|
|
311
404
|
} catch {
|
|
312
405
|
}
|
|
313
406
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
407
|
+
// 剪贴板:TikTok Minis 下**无任何可用实现**,故 setClipboard/getClipboard 不提供(IPlatformDevice
|
|
408
|
+
// 两者均为可选,业务侧 device.setClipboard?.() 会安全跳过)。依据(反编译 connect.tiktok-minis.com/game/sdk.js
|
|
409
|
+
// 2026-06-02):
|
|
410
|
+
// 1. TTMinis.game 上**不存在** setClipboardData/getClipboardData(这是臆造的方法名;SDK 的
|
|
411
|
+
// copyToClipboard/fetchClipBoard 属直播宿主 JSB,不在 minigame game API 暴露,也无 game 方法);
|
|
412
|
+
// 2. navigator.clipboard.read/readText/write/writeText 被 SDK 主动禁用(替换为 console.error 桩),
|
|
413
|
+
// 故浏览器退路也走不通。
|
|
414
|
+
// 结论:TikTok 真无剪贴板能力 → 如实不实现,而非调用不存在的方法在运行时抛 TypeError。
|
|
323
415
|
// shareAppMessage 是 callback 式(2026-05-30 反编译核对),不是 Promise;这里包成 Promise。
|
|
324
416
|
share(payload) {
|
|
325
417
|
requireTT("device.share");
|
package/dist/platform/web.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as PlatformName, h as IPlatformDevice } from '../types-
|
|
2
|
-
import { B as BasePlatform } from '../BasePlatform-
|
|
1
|
+
import { r as PlatformName, h as IPlatformDevice } from '../types-CxYJ9uz0.js';
|
|
2
|
+
import { B as BasePlatform } from '../BasePlatform-DqIfl-Oi.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Web(普通浏览器 / H5)平台适配器。
|
package/dist/platform/web.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { d as IPlatform, k as IPlatformNet, o as IPlatformStorage, i as IPlatformLifecycle, g as IPlatformAuth, e as IPlatformAds, l as IPlatformPayment, h as IPlatformDevice, P as PlatformInfo, L as LaunchOptions } from '../types-
|
|
1
|
+
import { d as IPlatform, k as IPlatformNet, o as IPlatformStorage, i as IPlatformLifecycle, g as IPlatformAuth, e as IPlatformAds, l as IPlatformPayment, h as IPlatformDevice, P as PlatformInfo, L as LaunchOptions } from '../types-CxYJ9uz0.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* 微信小游戏平台适配器。
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { r as PlatformName, o as IPlatformStorage, g as IPlatformAuth, e as IPlatformAds, h as IPlatformDevice, i as IPlatformLifecycle } from '../types-CxYJ9uz0.js';
|
|
2
|
+
import { B as BasePlatform } from '../BasePlatform-DqIfl-Oi.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* YouTube Playables 平台适配器。
|
|
6
|
+
*
|
|
7
|
+
* 运行环境:YouTube Playables(YouTube 内嵌的 HTML5 小游戏沙箱),全局对象 `ytgame.*`。
|
|
8
|
+
* SDK 由外壳 index.html 的 <script src="https://www.youtube.com/game_api/v1"> 注入(页面第一个脚本)。
|
|
9
|
+
*
|
|
10
|
+
* API 来源(2026-06-01 拉取核对,代码内各处标注):
|
|
11
|
+
* - 官方 SDK reference:https://developers.google.com/youtube/gaming/playables/reference/sdk
|
|
12
|
+
* - 官方 getting_started:https://developers.google.com/youtube/gaming/playables/reference/getting_started
|
|
13
|
+
* - Phaser 官方模板:https://github.com/phaserjs/template-youtube-playables(src/YouTubePlayables.js)
|
|
14
|
+
*
|
|
15
|
+
* 能力实现:
|
|
16
|
+
* - hasDOM=true(Playables 跑在 webview),isMiniGame=true
|
|
17
|
+
* - net:fetch + 标准 WebSocket(继承 BasePlatform)
|
|
18
|
+
* - storage:ytgame.game.saveData/loadData 是「整份序列化 string」存档(非 per-key KV),
|
|
19
|
+
* IPlatformStorage 是同步 KV → 采用「内存缓存 + 异步整份回写」:init 时 loadData 预拉
|
|
20
|
+
* 解析成 Map,getItem 读缓存,setItem 写缓存并去抖异步 saveData 整份。
|
|
21
|
+
* - auth:YouTube **不暴露用户身份/openId**,也无可换 token 的 OAuth code。存档由 YouTube 内部
|
|
22
|
+
* 按已登录用户隔离。login 返回一个**本地持久化的匿名 id**(存进 storage),并把它当 code/openId,
|
|
23
|
+
* 供业务排行榜「本机身份」使用;getProfile 返 null(拿不到昵称/头像);authorize 不实现(undefined)。
|
|
24
|
+
* - ads:ytgame.ads.requestRewardedAd(rewardId) → 'completed'/'skipped';requestInterstitialAd() → 'closed'/'failed'。
|
|
25
|
+
* - payment:**不实现**(undefined)。YouTube Playables 禁止任何内购(含 off-platform),
|
|
26
|
+
* 业务层 App.payment 为 undefined 自动降级。
|
|
27
|
+
* - device.share:YouTube Playables SDK 无分享 API → share 不实现(undefined);震动/剪贴板退回浏览器。
|
|
28
|
+
* - lifecycle:ytgame.system.onPause/onResume;非 Playables 环境退回 DOM visibilitychange。
|
|
29
|
+
* - shortcut / mission:YouTube 无对应能力 → 不实现(undefined)。
|
|
30
|
+
* - 排行榜:ytgame.engagement.sendScore({value}) 作为平台特有能力暴露 sendScore(score)(见类末尾)。
|
|
31
|
+
*
|
|
32
|
+
* init 时序(官方:SDK ready → firstFrameReady → ... → gameReady):
|
|
33
|
+
* 读 DOM 系统信息 → firstFrameReady() → getLanguage 覆盖语言 → 预拉存档 → 同步音频状态 → gameReady()。
|
|
34
|
+
* setLoadingProgress(p):YouTube **无** setLoadingProgress API,映射为「首次 >0 触发 firstFrameReady,
|
|
35
|
+
* 到 1 触发 gameReady」,保持与其它平台一致的对外接口。
|
|
36
|
+
*
|
|
37
|
+
* 所有 ytgame 访问均 typeof 检测 + try-catch:非 YouTube 环境(typeof ytgame === 'undefined')安全降级,不崩。
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
declare class YouTubePlatform extends BasePlatform {
|
|
41
|
+
readonly platformName: PlatformName;
|
|
42
|
+
readonly isMiniGame = true;
|
|
43
|
+
private readonly ytStorage;
|
|
44
|
+
/** firstFrameReady / gameReady 仅可调用一次的幂等守卫 */
|
|
45
|
+
private _firstFrameReady;
|
|
46
|
+
private _gameReady;
|
|
47
|
+
readonly storage: IPlatformStorage;
|
|
48
|
+
readonly auth: IPlatformAuth;
|
|
49
|
+
readonly ads: IPlatformAds;
|
|
50
|
+
readonly device: IPlatformDevice;
|
|
51
|
+
readonly lifecycle: IPlatformLifecycle;
|
|
52
|
+
init(): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* 加载进度上报。YouTube **无** setLoadingProgress API:
|
|
55
|
+
* 这里把对外接口映射为「首次 progress>0 触发 firstFrameReady,progress≥1 触发 gameReady」,
|
|
56
|
+
* 让业务加载场景的进度回调在 YouTube 上也能正确驱动 firstFrameReady/gameReady 时序。
|
|
57
|
+
* @param progress 0..1 的小数
|
|
58
|
+
*/
|
|
59
|
+
setLoadingProgress(progress: number): void;
|
|
60
|
+
/**
|
|
61
|
+
* 上报排行榜分数(YouTube 平台特有能力,framework 无通用 score 接口)。
|
|
62
|
+
* 业务可经 (App.platform as YouTubePlatform).sendScore(n) 调用。
|
|
63
|
+
* ytgame.engagement.sendScore({value}):value 须为整数且 ≤ Number.MAX_SAFE_INTEGER,否则被拒。
|
|
64
|
+
* 文档:https://developers.google.com/youtube/gaming/playables/reference/sdk#sendscore
|
|
65
|
+
*/
|
|
66
|
+
sendScore(value: number): Promise<boolean>;
|
|
67
|
+
private callFirstFrameReady;
|
|
68
|
+
private callGameReady;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export { YouTubePlatform };
|