mcpField
Y
yandex-js-sdk

yandex-js-sdk

github.com/hungify開発016 回インストール1 週間前に更新
リポジトリ

yandex-js-sdk について

Yandex Gamesで公開するゲーム開発者向けのJavaScript SDK連携スキルです。プレイヤーデータ、ストレージ、収益化、ランキング、ライフサイクルイベントなどを扱います。

主な機能

  1. 01SDKの初期化とライフサイクル処理
  2. 02プレイヤー認証とクラウドストレージ
  3. 03インタースティシャル・リワード・バナー広告
  4. 04アプリ内購入
  5. 05ランキングとリモート設定
  6. 06レビュー依頼とゲーム検索

活用シーン

  1. 01Yandexのプレイヤープロフィールとセーブデータの導入
  2. 02ゲーム中の広告管理
  3. 03ゲーム内購入の提供
  4. 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>

動的に読み込む場合は、init() を呼び出す前に window.YaGames && window.YaGames.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 は広告 UI が閉じられた後に呼び出されます。

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 };
}

コメント