サードパーティサブスクリプションの管理
注釈:本資料はAI技術を用いて翻訳されています。
概要
AccelByte Gaming Services (AGS) は、Apple および Google Play と統合してプレイヤーのサブスクリプションを管理できます。この統合により、Apple または Google Play アカウントを使用してゲームにログインするプレイヤーのサブスクリプションデータを同期できます。
この記事では、以下の方法を説明します:
- Apple および Google Play を統合してプレイヤーのサブスクリプションを管理する
- AGS 管理ポータルでプレイヤーのサブスクリプションを管理する
- API 経由でプレイヤーのサブスクリプションデータを取得する
この統合は、AGS ストアでサポートされているサブスクリプションアイテムタイプとは異なります。詳細については、ストアアイテムの作成ページを参照してください。
前提条件
- アプリ内課金 (IAP) 設定: Google Play および Apple IAP がネームスペースで設定されていることを確認してください。詳細については、サードパーティストア統合を参照してください。
- Apple または Google Play ログイン方法: ゲームで Apple または Google Play ログイン方法が有効になっていることを確認してください。詳細については、Apple または Google の統合ガイドを参照してください。
- 管理者権限: 管理ポータルの Lookup Subscribers 機能にアクセスするために必要な管理者権限があることを確認してください。
- Unreal Engine SDK 実装:
- Unreal Engine: プレイヤーは AGS OSS および Apple または GooglePlay OSS にログインしている必要があります。
- Unity SDK 実装:
- Apple: UnityPurchasing パッケージをプロジェクトにインポートします。このプラグインは UnityPurchasing v4.8.0 を使用してテストされています。詳細については、Unity のインストールガイドを参照してください。
- Google Play: UnityPurchasing パッケージをプロジェクトにインポートします。Google Billing Library version 6(非推奨)を使用するには、少なくともバージョン 4.12.2 のパッケージを使用してください。詳細については、Unity のインストールガイドを参照してください。
Apple および Google Play の統合
Unreal Engine
const IOnlineSubsystem* OnlineSubsystemABPtr = IOnlineSubsystem::Get("ACCELBYTE");
if (OnlineSubsystemABPtr == nullptr)
{
Result.ExecuteIfBound("AB subsystem nullptr");
return;
}
check(OnlineSubsystemABPtr->GetIdentityInterface())
auto UniqueNetId = (OnlineSubsystemABPtr->GetIdentityInterface()->GetUniquePlayerId(LocalUserNum).Get());
auto ABIdentityInterface = StaticCastSharedPtr<FOnlineIdentityAccelByte>(OnlineSubsystemABPtr->GetIdentityInterface());
// OPTIONAL
// For Apple: Find the configuration on your developer Apple dashboard, the URL shows subscription group ID
// For Google: Find the configuration on your developer GooglePlay dashboard, use the ProductId from your Products>Subscriptions
FString SubscriptionGroupId = "21544099";
// For Apple: Find the configuration on your developer Apple dashboard
// For Google: Find the configuration on your developer GooglePlay dashboard, use the base plan name from your Products>Subscriptions
FString SubscriptionProductId = ProductID;
// If true, it excludes the expired subscription
bool bIsActiveOnly = true;
FOnlineQuerySubscriptionRequestAccelByte QueryRequest;
QueryRequest.ActiveOnly = bIsActiveOnly;
QueryRequest.ProductId = SubscriptionProductId;
QueryRequest.GroupId = SubscriptionGroupId;
QueryRequest.QueryPaging = FPagedQuery(0, 20); // The default paging start from index 0 and the amount is 20
// OnQueryEachEntitlement is an example of delegate
auto ResponseOnSuccess = FOnQueryPlatformSubscriptionCompleteDelegate::CreateLambda([&, OnQueryEachEntitlement](int32 _LocalUserNum, bool bWasSuccessful, const FUniqueNetId& UserId, const TArray<FAccelByteModelsThirdPartySubscriptionTransactionInfo>& QueryResult, const FOnlineError& Error)
{
if (QueryResult.Num() == 0)
{
OnQueryEachEntitlement.ExecuteIfBound(false, "EMPTY ARRAY");
}
else
{
FString SerializedResult = "EMPTY Data";
FJsonObjectConverter::UStructToJsonObjectString(QueryResult[0], SerializedResult);
OnQueryEachEntitlement.ExecuteIfBound(true, SerializedResult);
}
});
ABEntitlementInterfacePtr->AddOnQueryPlatformSubscriptionCompleteDelegate_Handle(LocalUserNum, ResponseOnSuccess);
ABEntitlementInterfacePtr->QueryPlatformSubscription(LocalUserNum, QueryRequest);
Unity
- Apple
- Google Play
-
Google Play Games でサインインします。このサインイン方法の詳細については、Google Play Games 用の Unity SDK ガイドを参照してください。
-
IDetailedStoreListenerを実装するMonoBehaviorクラスを作成します。Unity IAP が購入を処理し、このインターフェースを使用してコールバックをトリガーします。次に、以下の変数を準備します。IStoreController storeController;
public Button BuySeasonPassButton;
private string seasonPassProductId = "item_season_pass"; // 登録されたサブスクリプション製品 ID が item_season_pass という名前であると仮定
private ProductType seasonPassProductType = ProductType.Subscription; -
ログインして購入イベントをトリガーするためのスクリプトボタンを準備します。Unity Editor のインスペクターを使用して、これらのボタンを
public Button BuySeasonPassButton;にアタッチします。 -
Purchasingを初期化します。void Start()
{
InitializePurchasing();
}
void InitializePurchasing()
{
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// 購入可能な製品を追加し、そのタイプを指定
builder.AddProduct(seasonPassProductId, seasonPassProductType);
// ApplicationUsername を割り当て
if (!string.IsNullOrEmpty(AccelByteSDK.GetClientRegistry().GetApi().GetUser().Session.UserId))
{
var uid = System.Guid.Parse(AccelByteSDK.GetClientRegistry().GetApi().GetUser().Session.UserId);
appleExtensions.SetApplicationUsername(uid.ToString());
}
else
{
Debug.LogError($"プレイヤーがログインしていません。一部の機能が正しく動作しない可能性があります");
}
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
Debug.Log("アプリ内課金の初期化に成功しました");
storeController = controller;
appleExtensions = extensions.GetExtension<IAppleExtensions>();
} -
購入イベントをトリガーする関数を準備します。
event
private void BuySeasonPass()
{
storeController.InitiatePurchase(seasonPassProductId);
} -
ボタンを割り当てます。
void Start()
{
ButtonAssigning();
}
void ButtonAssigning()
{
BuySeasonPassButton.onClick.AddListener(BuySeasonPass);
} -
Process Purchaseを処理します。購入したアイテムは AGS バックエンドと同期されるため、PurchaseProcessingResult.Pendingを返す必要があることに注意してください。Processing Purchases に関する Unity のドキュメントを参照してください。ゲームクライアントが Apple からアイテムを正常に購入した場合、ProcessPurchaseがトリガーされ、そうでない場合はOnPurchaseFailedがトリガーされます。
public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
{
var product = purchaseEvent.purchasedProduct;
Debug.Log($"購入完了 - 製品: {product.definition.id}");
AGSSubscriptionEntitlementSync(product);
return PurchaseProcessingResult.Pending;
}
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
Debug.LogError($"購入失敗 - 製品: '{product.definition.id}', PurchaseFailureReason: {failureReason}");
} -
Purchased Productを AGS と同期します。private void AGSSubscriptionEntitlementSync(Product purchasedSubscription)
{
// 同期はプレイヤーが AGS サービスを使用してログインした後に機能することに注意
try
{ AccelByteSDK.GetClientRegistry().GetApi().GetEntitlement().SyncMobilePlatformSubscriptionApple(purchasedSubscription.appleOriginalTransactionID
, result =>
{
if (result.IsError)
{
Debug.Log($"{purchasedSubscription.definition.id} の AB との同期に失敗しました [{result.Error.Code}]:{result.Error.Message}");
return;
}
Debug.Log($"{purchasedSubscription.definition.id} は AB と同期されました");
FinalizePurchase(purchasedSubscription);
});
}
catch (Exception e)
{
Debug.LogError($"AB との同期に失敗しました {e.Message}");
}
} -
Pending Purchaseを確定します。private void FinalizePurchase(Product purchasedProduct)
{
Debug.Log($"保留中の購入を確認: {purchasedProduct.definition.id}");
storeController.ConfirmPendingPurchase(purchasedProduct);
} -
サブスクリプションをクエリします。パッケージサンプルの完全なスクリプトは「In App Purchase」という名前です。
public void QuerySubscription()
{
PlatformStoreId storeId = new PlatformStoreId(PlatformType.Apple);
var userId = AccelByteSDK.GetClientRegistry().GetApi().GetUser().Session.UserId;
AccelByteSDK.GetClientRegistry().GetApi().GetEntitlement().QueryUserSubscription(storeId, userId, result =>
{
if (result.IsError)
{
Debug.LogWarning($"サブスクリプションのクエリに失敗しました [{result.Error.Code}]:{result.Error.Message}");
return;
}
bool found = false;
foreach (var eInfo in result.Value.Data)
{
if (eInfo.SubscriptionGroupId == seasonPassProductId)
{
found = true;
break;
}
}
Debug.Log($"シーズンパスのサブスクリプション: {found.ToString().ToUpper()}");
});
}
-
Google Play Games でサインインします。このサインイン方法の詳細については、Google Play Games 用の Unity SDK ガイドを参照してください。
-
IDetailedStoreListenerを実装するMonoBehaviorクラスを作成します。Unity IAP が購入を処理し、このインターフェースを使用してコールバックをトリガーします。次に、以下の変数を準備します:IStoreController storeController;
public Button BuySeasonPassButton;
private string seasonPassProductId = "item_season_pass"; // 登録されたサブスクリプション製品 ID が item_season_pass という名前であると仮定
private ProductType seasonPassProductType = ProductType.Subscription; -
ログインして購入イベントをトリガーするためのスクリプトボタンを準備します。Unity Editor のインスペクターを使用して、これらのボタンを
public Button BuySeasonPassButton;にアタッチします。 -
Purchasingを初期化します。void Start()
{
InitializePurchasing();
}
void InitializePurchasing()
{
var builder = ConfigurationBuilder.Instance(StandardPurchasingModule.Instance());
// 購入可能な製品を追加し、そのタイプを指定
builder.AddProduct(seasonPassProductId, seasonPassProductType);
var accelByteUserId = AccelByteSDK.GetClientRegistry().GetApi().GetUser().Session.UserId;
if (!string.IsNullOrEmpty(accelByteUserId))
{
var uid = System.Guid.Parse(accelByteUserId);
builder.Configure<IGooglePlayConfiguration>().SetObfuscatedAccountId(uid.ToString());
}
else
{
Debug.LogWarning($"プレイヤーがログインしていません。一部の機能が正しく動作しない可能性があります");
}
UnityPurchasing.Initialize(this, builder);
}
public void OnInitialized(IStoreController controller, IExtensionProvider extensions)
{
Debug.Log("アプリ内課金の初期化に成功しました");
storeController = controller;
} -
購入イベントをトリガーする関数を準備します。
private void BuySeasonPass()
{
storeController.InitiatePurchase(seasonPassProductId);
} -
ボタンを割り当てます。
void Start()
{
ButtonAssigning();
}
void ButtonAssigning()
{
BuySeasonPassButton.onClick.AddListener(BuySeasonPass);
} -
Process Purchaseを処理します。購入したアイテムは AGS バックエンドと同期されるため、PurchaseProcessingResult.Pendingを返す必要があることに注意してください。Processing Purchases に関する Unity のドキュメントを参照してください。クライアントが Google Play ストアからアイテムを正常に購入した場合、ProcessPurchase がトリガーされ、そうでない場合はOnPurchaseFailedがトリガーされます。public PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs purchaseEvent)
{
var product = purchaseEvent.purchasedProduct;
Debug.Log($"購入完了 - 製品: {product.definition.id}");
if (product.definition.type == ProductType.Subscription)
{
AGSSubscriptionEntitlementSync(product);
}
return PurchaseProcessingResult.Pending;
}
public void OnPurchaseFailed(Product product, PurchaseFailureReason failureReason)
{
Debug.LogError($"購入失敗 - 製品: '{product.definition.id}', PurchaseFailureReason: {failureReason}");
} -
Purchased Productを AGS と同期します。private void AGSSubscriptionEntitlementSync(Product purchasedSubscription)
{
// 同期はプレイヤーが AGS を使用してログインした後に機能することに注意
try
{
string receiptPayload = JObject.Parse(product.receipt)["Payload"].ToString();
var receiptJson = JObject.Parse(receiptPayload)["json"].ToString();
var receiptObject = JObject.Parse(receiptJson);
var orderId = ((string)receiptObject["orderId"]);
var packageName = ((string)receiptObject["packageName"]);
var productId = ((string)receiptObject["productId"]);
var purchaseTime = ((long)receiptObject["purchaseTime"]);
var purchaseToken = ((string)receiptObject["purchaseToken"]);
var autoAck = true;
AccelByteSDK.GetClientRegistry().GetApi().GetEntitlement().
.SyncMobilePlatformSubscriptionGoogle(
orderId
, packageName
, productId
, purchaseTime
, purchaseToken
, autoAck
, syncResult =>
{
if (syncResult.IsError)
{
UnityEngine.Debug.LogWarning(syncResult.Error.Message);
return;
}
if (syncResult.Value.NeedConsume)
{
FinalizePurchase(product);
}
});
}
} -
Pending Purchaseを確定します。private void FinalizePurchase(Product purchasedProduct)
{
Debug.Log($"保留中の購入を確認: {purchasedProduct.definition.id}");
storeController.ConfirmPendingPurchase(purchasedProduct);
} -
サブスクリプションをクエリします。パッケージサンプルの完全なスクリプトは「In App Purchase」という名前です。
public void QuerySubscription()
{
PlatformStoreId storeId = new PlatformStoreId(PlatformType.GooglePlayGames);
var userId = AccelByteSDK.GetClientRegistry().GetApi().GetUser().Session.UserId;
AccelByteSDK.GetClientRegistry().GetApi().GetEntitlement().QueryUserSubscription(storeId, userId, result =>
{
if (result.IsError)
{
Debug.LogWarning($"サブスクリプションのクエリに失敗しました [{result.Error.Code}]:{result.Error.Message}");
return;
}
bool found = false;
foreach (var eInfo in result.Value.Data)
{
if (eInfo.SubscriptionGroupId == seasonPassProductId)
{
found = true;
break;
}
}
Debug.Log($"シーズンパスのサブスクリプション: {found.ToString().ToUpper()}");
});
}
管理ポータルでプレイヤーのサブスクリプションを管理する
プレイヤーのサブスクリプション詳細を表示する
-
管理ポータルのサイドバーで、Live Service Utilities > Lookup Subscribers に移動します。
-
Google または Apple タブで、プレイヤー ID を使用してプレイヤーを検索します。Google Product ID(Google の場合)または Subscription Group ID(Apple の場合)を使用してプレイヤーを検索することもできます。
サブスクリプションステータスを含むプレイヤーのリストが表示されます:
- User ID: プレイヤーの一意の識別子。
- Google Product ID(Google の場合)または Subscription Group ID(Apple の場合): サブスクリプションの識別子。
- Status: 現在のサブスクリプションステータス(Active または Inactive)。
- Subscription End Date: サブスクリプションの有効期限または更新日。
-
結果リストから、詳細を表示したいプレイヤーの View をクリックします。プレイヤーのサブスクリプション詳細ページが表示されます。
プレイヤーのサブスクリプション詳細を同期する
プレイヤーのサブスクリプションデータを手動で同期するには、プレイヤーのサブスクリプション詳細ページに移動し、Sync ボタンをクリックします。
API 経由でプレイヤーのサブスクリプションデータを取得する
ゲームクライアントは、Public Subscription エンドポイントを使用して AGS と直接対話し、サブスクリプションデータをクエリできます。このエンドポイントにより、ゲームクライアントは Apple または Google Play プラットフォームからユーザーのサブスクリプションをクエリできます。サブスクリプションデータへのリアルタイムアクセスを提供し、クライアントが最新の変更を把握できるようにします。
API 詳細
| パス | /public/namespaces/{namespace}/users/{userId}/iap/subscriptions/platforms/{platform} |
|---|---|
| メソッド | GET |
| 説明 | ユーザーのサブスクリプションステータスをクエリし、updatedAt でソートします。 |
| 権限 | NAMESPACE:{namespace}:USER:{userId}:IAP [READ] |
| パスパラメータ | GOOGLE または APPLE |
リクエストパラメータ
| パラメータ | タイプ | 条件 | 説明 |
|---|---|---|---|
groupId | string | オプション | サブスクリプショングループの識別子。サブスクリプショングループには、異なるオファリングを持つ関連するサブスクリプション製品が含まれます。例えば、com.newspaper.subscription は、デジタル新聞のさまざまなサブスクリプションオプションを含むグループになります。 |
productId | string | オプション | グループ内の特定のサブスクリプション製品の一意の識別子。例えば、com.newspaper.subscription グループ内に、com.newspaper.weekly、com.newspaper.monthly、com.newspaper.yearly があります。 |
activeOnly | boolean | オプション | true に設定すると、アクティブなサブスクリプションのみが返されます。 |
offset | integer | オプション | ページネーションオフセット。このパラメータのデフォルト値は 0 です。 |
limit | integer | オプション | 返す結果の数。このパラメータのデフォルト値は 20 です。 |
サンプルリクエスト
- Google Play
- Apple
GET /public/namespaces/{namespace}/users/{userId}/iap/subscriptions/platforms/google
GET /public/namespaces/{namespace}/users/{userId}/iap/subscriptions/platforms/apple
レスポンス情報
Public Subscription エンドポイントリクエストのレスポンスには、以下の情報が含まれます:
| パラメータ | 説明 |
|---|---|
platform | リクエストのターゲットプラットフォーム:APPLE または GOOGLE。 |
active | サブスクリプションがアクティブかどうかを示します |
status | サブスクリプションステータス(例:EXPIRED、ACTIVE)。 |
subscriptionGroupId | サブスクリプショングループ識別子。 |
subscriptionProductId | サブスクリプションの製品識別子。 |
startAt | サブスクリプションの開始日。 |
expiredAt | サブスクリプションの有効期限。 |
lastTransactionId | 最後のトランザクションの ID。 |
createdAt | サブスクリプションが作成された日付。 |
updatedAt | サブスクリプションデータが最後に更新された日付。 |