关于 yandex-js-sdk
面向在 Yandex Games 发布游戏的开发者,介绍 JavaScript SDK 的接入,涵盖玩家数据、存储、变现、排行榜、生命周期事件和平台功能。
主要功能
- 01SDK 初始化与生命周期处理
- 02玩家授权与云存储
- 03插屏、激励和横幅广告
- 04应用内购买
- 05排行榜与远程配置
- 06评价提示与游戏发现
适用场景
- 01接入 Yandex 玩家资料与存档数据
- 02在游戏过程中管理广告
- 03提供游戏内购买
- 04提交分数并读取远程标记
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ hungify/ playables-skills --skill yandex-js-sdk安装后在 Claude Code 中输入/yandex-js-sdk确认已加载。
详细介绍
Yandex Games JavaScript SDK
概述
Yandex Games 会在 yandex.<tld>/games 的框架中加载游戏。SDK 脚本加载后,宿主会注入全局变量 YaGames。主要功能领域包括:
- 生命周期与环境:初始化、
LoadingAPI.ready()、GameplayAPI.start/stop、暂停/恢复事件、设备信息、语言/TLD - 玩家与存储:授权、个人资料数据、按玩家隔离的键值云存储
- 变现:全屏插屏广告、激励视频、常驻横幅广告、应用内购买
- 互动:排行榜、远程配置标记、评价提示、添加到主屏幕的快捷方式、服务器时间、剪贴板写入、通过
GamesAPI进行交叉推广
SDK 不提供社交分享、邀请好友、加入社区、添加到收藏、成就或统计计数器功能。
安装
<script src="https://yandex.ru/games/sdk/v2"></script>
如果动态加载,请轮询,直到定义了 window.YaGames && window.YaGames.init,然后再调用 init()。
快速开始 / 集成工作流
首次接入 SDK 时,请按此顺序操作。每完成一步都先验证,再继续下一步。
async function bootstrap() {
// 1. Ensure SDK script has loaded
if (!window.YaGames?.init) {
throw new Error('YaGames SDK not available — check that the script tag loaded');
}
// 2. Initialize — all subsequent SDK calls require ysdk
const ysdk = await window.YaGames.init();
// 3. Bind host-driven pause / resume before anything else
ysdk.on('game_api_pause', () => {
/* mute audio, pause gameplay */
});
ysdk.on('game_api_resume', () => {
/* unmute, resume */
});
// 4. Signal that the loading screen is gone
ysdk.features.LoadingAPI?.ready();
// 5. Read environment (language, device type)
const env = readEnvironment(ysdk);
// 6. Fetch player — fall back to guest mode if not authorized
let player = null;
let storageCache = {};
try {
const info = await getPlayer(ysdk);
player = info.raw;
if (info.isAuthorized) {
storageCache = await loadStorage(player);
}
} catch (err) {
console.warn('Player init failed, continuing as guest:', err);
}
// 7. Start gameplay tracking
onGameplayStarted(ysdk);
return { ysdk, player, storageCache, env };
}
function readEnvironment(ysdk) {
return {
language: ysdk.environment.i18n.lang.toLowerCase(),
tld: ysdk.environment.i18n.tld.toLowerCase(),
deviceType: ysdk.deviceInfo.type // 'desktop' | 'mobile' | 'tablet' | 'tv'
};
}
玩家 / 授权
async function getPlayer(ysdk, { useSignedData = false } = {}) {
const player = await ysdk.getPlayer({ signed: useSignedData });
return {
raw: player,
id: player.getUniqueID(),
name: player.getName() || null,
photos: ['small', 'medium', 'large'].map((size) => player.getPhoto(size)).filter(Boolean),
isAuthorized: player.isAuthorized(),
payingStatus: player.getPayingStatus(),
signature: useSignedData ? player.signature : null
};
}
async function authorizePlayer(ysdk, options) {
const current = await getPlayer(ysdk, options);
if (current.isAuthorized) {
return current;
}
await ysdk.auth.openAuthDialog();
return getPlayer(ysdk, options);
}
存储
每次调用都会写入整个文档——没有按键操作的 API。请在客户端缓存最新快照,并在每次保存前合并数据。访客则使用 localStorage 作为回退方案。
async function loadStorage(player) {
return player.getData();
}
async function setStorage(player, cache, key, value) {
const data = { ...(cache || {}) };
if (Array.isArray(key)) {
for (let i = 0; i < key.length; i++) {
data[key[i]] = value[i];
}
} else {
data[key] = value;
}
await player.setData(data);
return data;
}
async function deleteStorage(player, cache, key) {
const data = { ...(cache || {}) };
if (Array.isArray(key)) {
for (let i = 0; i < key.length; i++) {
delete data[key[i]];
}
} else {
delete data[key];
}
await player.setData(data);
return data;
}
function getCached(cache, key) {
if (Array.isArray(key)) {
return key.map((k) => (typeof cache?.[k] === 'undefined' ? null : cache[k]));
}
return typeof cache?.[key] === 'undefined' ? null : cache[key];
}
广告
全屏插屏广告
onClose(wasShown) 在正常关闭和 SDK 跳过广告时都会触发。将 wasShown === false 视为失败。
function showInterstitial(ysdk, handlers = {}) {
ysdk.adv.showFullscreenAdv({
callbacks: {
onOpen: () => handlers.onOpen?.(),
onClose: (wasShown) => handlers.onClose?.(wasShown),
onError: (err) => handlers.onError?.(err)
}
});
}
激励视频
在 onRewarded 中发放奖励。广告界面关闭后会触发 onClose。
function showRewarded(ysdk, handlers = {}) {
ysdk.adv.showRewardedVideo({
callbacks: {
onOpen: () => handlers.onOpen?.(),
onRewarded: () => handlers.onRewarded?.(),
onClose: () => handlers.onClose?.(),
onError: (err) => handlers.onError?.(err)
}
});
}
常驻横幅广告
async function getBannerStatus(ysdk) {
return ysdk.adv.getBannerAdvStatus(); // { stickyAdvIsShowing: boolean, reason?: string }
}
async function showBanner(ysdk) {
const data = await ysdk.adv.showBannerAdv();
return data.stickyAdvIsShowing === true;
}
async function hideBanner(ysdk) {
const data = await ysdk.adv.hideBannerAdv();
return data.stickyAdvIsShowing === false;
}
支付 / IAP
初始化后获取一次支付对象。传入 signed: true,以便后端验证签名。
async function initPayments(ysdk, { signed = true } = {}) {
return ysdk.getPayments({ signed });
}
商品目录
async function getCatalog(payments) {
const products = await payments.getCatalog();
return products.map((p) => ({
id: p.id,
title: p.title,
description: p.description,
imageURI: p.imageURI,
price: p.price,
priceValue: p.priceValue,
priceCurrencyCode: p.priceCurrencyCode,
priceCurrencyImage: p.getPriceCurrencyImage?.('medium')
}));
}
购买
async function purchase(payments, productId, payload) {
const result = await payments.purchase({ id: productId, developerPayload: payload });
if (!result?.purchaseData?.purchaseToken) {
throw new Error(
`Purchase succeeded but returned no purchaseToken for product ${productId}`
);
}
return { id: productId, ...result.purchaseData };
}
已拥有的购买项目
async function getPurchases(payments) {
const list = await payments.getPurchases();
return list.map((purchase) => ({ id: purchase.productID, ...purchase.purchaseData }));
}
消耗
消耗前请确认已发放物品。消耗失败时,令牌会保留,以便重试。
async function consumePurchase(payments, purchaseToken) {
if (!purchaseToken) {
throw new Error('consumePurchase: purchaseToken is required');
}
await payments.consumePurchase(purchaseToken);
}
排行榜
排行榜在开发者控制台中配置,并通过字符串 ID 引用。设置分数需要玩家已授权。
async function setLeaderboardScore(ysdk, leaderboardId, score) {
const lb = await ysdk.getLeaderboards();
await lb.setLeaderboardScore(leaderboardId, score);
}
async function getLeaderboardEntries(ysdk, leaderboardId, { isPlayerAuthorized = false } = {}) {
const lb = await ysdk.getLeaderboards();
const options = { quantityTop: 20 };
if (isPlayerAuthorized) {
options.includeUser = true;
options.quantityAround = 3;
}
const result = await lb.getLeaderboardEntries(leaderboardId, options);
if (!result || result.entries.length === 0) {
return [];
}
return result.entries.map((e) => ({
id: e.player.uniqueID,
name: e.player.publicName,
score: e.score,
rank: e.rank,
photo: e.player.getAvatarSrc('large')
}));
}
远程配置
ysdk.getFlags(options) 会返回一个扁平的 { key: stringValue } 映射。
async function getRemoteConfig(ysdk, options = {}) {
const params = { clientFeatures: [], ...options };
return ysdk.getFlags(params);
}
服务器时间
function getServerTime(ysdk) {
// Returns Unix timestamp in milliseconds
return ysdk.serverTime();
}
社交
评价提示
async function requestReview(ysdk) {
const can = await ysdk.feedback.canReview();
if (!can.value) {
throw new Error(can.reason || 'review not available');
}
const { feedbackSent } = await ysdk.feedback.requestReview();
return feedbackSent;
}
添加到主屏幕(快捷方式)
async function canAddToHomeScreen(ysdk) {
const prompt = await ysdk.shortcut.canShowPrompt();
return prompt.canShow === true;
}
async function addToHomeScreen(ysdk) {
const result = await ysdk.shortcut.showPrompt();
return result.outcome === 'accepted';
}
剪贴板
async function clipboardWrite(ysdk, text) {
await ysdk.clipboard.writeText(text);
}
游戏生命周期、暂停与音频
每次活跃的游戏会话都应以 GameplayAPI.start() 开始、以 GameplayAPI.stop() 结束,以控制广告节奏并进行数据分析。
function onGameplayStarted(ysdk) {
ysdk.features.GameplayAPI?.start();
}
function onGameplayStopped(ysdk) {
ysdk.features.GameplayAPI?.stop();
}
function bindPauseHandlers(ysdk, { onPause, onResume }) {
ysdk.on('game_api_pause', () => onPause?.());
ysdk.on('game_api_resume', () => onResume?.());
}
对于 Yandex 未通知的可见性/焦点变化,也应结合这些 SDK 回调,使用 document.visibilitychange、window.blur 和 window.focus 进行处理。
其他 Yandex Games 游戏目录(可选)
features.GamesAPI 是否可用取决于具体游戏;调用前请检查该命名空间是否存在。
async function getAllGames(ysdk) {
const { games } = await ysdk.features.GamesAPI.getAllGames();
return games;
}
async function getGameById(ysdk, gameId) {
const { game, isAvailable } = await ysdk.features.GamesAPI.getGameByID(gameId);
return { ...game, isAvailable };
}