「Php/アプリストア連携/返金API/GooglePlayStore/RTDN」の版間の差分
提供: 初心者エンジニアの簡易メモ
(ページの作成:「==Google Play Consoleでの設定== #Google Play Consoleにログイン #「Monetization」 > 「Monetization setup」に移動 #「Real-time developer notifications」...」) |
(→pub/subのサブスクリプション作成) |
||
| (同じ利用者による、間の5版が非表示) | |||
| 行1: | 行1: | ||
| + | ==pub/subを使ってエンドポイント作成== | ||
| + | #https://console.cloud.google.com/ | ||
| + | #上部の検索バーで「Pub/Sub」と入力し、「Cloud Pub/Sub」を選択 | ||
| + | #左側メニューで「トピック」をクリック | ||
| + | #画面上部の「+トピックを作成」ボタンをクリック | ||
| + | #トピックIDに「play-refund-notifications」と入力 | ||
| + | #「作成」ボタンをクリック | ||
| + | #例:projects/your-project-id/topics/play-refund-notifications のようなトピックが生成されることを確認。 | ||
| + | |||
| + | ===pub/subのサブスクリプション作成=== | ||
| + | #Google Cloud ConsoleのPub/Subページに戻る | ||
| + | #左メニューで「サブスクリプション」をクリック | ||
| + | #画面上部の「+サブスクリプションを作成」ボタンをクリック | ||
| + | #サブスクリプション設定: | ||
| + | <pre> | ||
| + | サブスクリプションID: play-refund-notifications-sub | ||
| + | トピック名: play-refund-notifications (ドロップダウンから選択) | ||
| + | 配信タイプ: 「Push」を選択 | ||
| + | エンドポイントURL: https://yourdomain.com/notifications # 後で修正可能 | ||
| + | 確認期限: 60 (秒) | ||
| + | 認証 (オプションですが推奨): | ||
| + | 「Push認証を構成」を展開 | ||
| + | 「サービスアカウント」で適切なアカウントを選択 | ||
| + | </pre> | ||
| + | #「作成」ボタンをクリック | ||
| + | |||
==Google Play Consoleでの設定== | ==Google Play Consoleでの設定== | ||
#Google Play Consoleにログイン | #Google Play Consoleにログイン | ||
| − | # | + | #GooglePlayで収益化する/収益化のセットアップを開く |
| − | # | + | #リアルタイム デベロッパー通知の、セクションで通知を受け取るエンドポイントのトピック名(例:projects/your-project-id/topics/play-refund-notifications)を設定 |
| + | |||
| + | ==php実行準備== | ||
| + | Firebase JWTを使用する場合 | ||
| + | composer require firebase/php-jwt | ||
==phpサンプル== | ==phpサンプル== | ||
<pre> | <pre> | ||
| − | / | + | require_once 'vendor/autoload.php'; |
| + | use phpseclib3\Crypt\PublicKeyLoader; | ||
// Google Playの公開鍵を取得(キャッシュ推奨) | // Google Playの公開鍵を取得(キャッシュ推奨) | ||
function getGooglePublicKey($keyId) { | function getGooglePublicKey($keyId) { | ||
| − | + | $jwksUrl = 'https://www.googleapis.com/oauth2/v3/certs'; | |
| − | + | ||
| − | + | ||
| − | // | + | // キャッシュの実装(上記と同じ) |
| − | + | ||
| − | + | ||
| − | + | ||
| − | + | foreach ($jwks['keys'] as $key) { | |
| + | if ($key['kid'] === $keyId) { | ||
| + | return PublicKeyLoader::load($key)->toString('PKCS8'); | ||
| + | } | ||
| + | } | ||
| + | return null; | ||
} | } | ||
2025年6月20日 (金) 01:26時点における最新版
pub/subを使ってエンドポイント作成
- https://console.cloud.google.com/
- 上部の検索バーで「Pub/Sub」と入力し、「Cloud Pub/Sub」を選択
- 左側メニューで「トピック」をクリック
- 画面上部の「+トピックを作成」ボタンをクリック
- トピックIDに「play-refund-notifications」と入力
- 「作成」ボタンをクリック
- 例:projects/your-project-id/topics/play-refund-notifications のようなトピックが生成されることを確認。
pub/subのサブスクリプション作成
- Google Cloud ConsoleのPub/Subページに戻る
- 左メニューで「サブスクリプション」をクリック
- 画面上部の「+サブスクリプションを作成」ボタンをクリック
- サブスクリプション設定:
サブスクリプションID: play-refund-notifications-sub トピック名: play-refund-notifications (ドロップダウンから選択) 配信タイプ: 「Push」を選択 エンドポイントURL: https://yourdomain.com/notifications # 後で修正可能 確認期限: 60 (秒) 認証 (オプションですが推奨): 「Push認証を構成」を展開 「サービスアカウント」で適切なアカウントを選択
- 「作成」ボタンをクリック
Google Play Consoleでの設定
- Google Play Consoleにログイン
- GooglePlayで収益化する/収益化のセットアップを開く
- リアルタイム デベロッパー通知の、セクションで通知を受け取るエンドポイントのトピック名(例:projects/your-project-id/topics/play-refund-notifications)を設定
php実行準備
Firebase JWTを使用する場合
composer require firebase/php-jwt
phpサンプル
require_once 'vendor/autoload.php';
use phpseclib3\Crypt\PublicKeyLoader;
// Google Playの公開鍵を取得(キャッシュ推奨)
function getGooglePublicKey($keyId) {
$jwksUrl = 'https://www.googleapis.com/oauth2/v3/certs';
// キャッシュの実装(上記と同じ)
foreach ($jwks['keys'] as $key) {
if ($key['kid'] === $keyId) {
return PublicKeyLoader::load($key)->toString('PKCS8');
}
}
return null;
}
// JWTの検証
function verifyJwt($jwt) {
list($header, $payload, $signature) = explode('.', $jwt);
$header = json_decode(base64_decode($header), true);
$payload = json_decode(base64_decode($payload), true);
// 公開鍵を取得
$publicKey = getGooglePublicKey($header['kid']);
if (!$publicKey) {
return false;
}
// 署名検証
$data = "$header.$payload";
$signature = base64_decode(str_replace(['-', '_'], ['+', '/'], $signature));
$result = openssl_verify($data, $signature, $publicKey, 'SHA256');
return $result === 1 ? $payload : false;
}
// メイン処理
function handleRtdnNotification() {
// リクエストボディを取得
$input = file_get_contents('php://input');
$data = json_decode($input, true);
if (!$data || !isset($data['message']['data'])) {
http_response_code(400);
exit;
}
// JWTをデコード
$jwt = base64_decode($data['message']['data']);
$payload = verifyJwt($jwt);
if (!$payload) {
http_response_code(401);
exit;
}
// 通知タイプに応じて処理
$notificationType = $payload['eventType'];
$subscriptionId = $payload['subscriptionNotification']['subscriptionId'];
$purchaseToken = $payload['subscriptionNotification']['purchaseToken'];
switch ($notificationType) {
case 'SUBSCRIPTION_CANCELED':
// 定期購入がキャンセルされた
handleSubscriptionCanceled($subscriptionId, $purchaseToken);
break;
case 'SUBSCRIPTION_PURCHASED':
// 新しい定期購入
handleSubscriptionPurchased($subscriptionId, $purchaseToken);
break;
case 'SUBSCRIPTION_RENEWED':
// 定期購入が更新された
handleSubscriptionRenewed($subscriptionId, $purchaseToken);
break;
case 'SUBSCRIPTION_REVOKED':
// 返金または管理者によるキャンセル
handleSubscriptionRevoked($subscriptionId, $purchaseToken);
break;
case 'SUBSCRIPTION_RESTARTED':
// ユーザーがキャンセル後に再開
handleSubscriptionRestarted($subscriptionId, $purchaseToken);
break;
default:
// 未知の通知タイプ
http_response_code(400);
exit;
}
// 成功レスポンス
http_response_code(200);
}
// 返金処理(SUBSCRIPTION_REVOKED)
function handleSubscriptionRevoked($subscriptionId, $purchaseToken) {
// 1. Google Play Developer APIを使用して購入情報を取得
$purchaseInfo = getSubscriptionPurchaseInfo($subscriptionId, $purchaseToken);
// 2. 返金理由を確認
$revocationReason = $purchaseInfo['revocationReason'] ?? null;
// 3. ユーザーアカウントを更新(アクセス権限を削除など)
$userId = getUserIdFromPurchaseToken($purchaseToken);
revokeUserAccess($userId);
// 4. データベースに返金記録を保存
logRefund($userId, $subscriptionId, $purchaseToken, $revocationReason);
// 5. 必要に応じてユーザーに通知
sendRefundNotification($userId);
}
// Google Play Developer APIから購入情報を取得
function getSubscriptionPurchaseInfo($subscriptionId, $purchaseToken) {
// 実際にはここでGoogle Play Developer APIを呼び出す
// 必要な認証情報などを設定
// 簡易実装(実際にはAPI呼び出しが必要)
return [
'revocationReason' => 1, // 1: 返金, 2: 管理者によるキャンセル
// その他の購入情報...
];
}
// その他のヘルパー関数...
// メイン処理を実行
handleRtdnNotification();
