コメント
コメントの投稿
※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。
入力されていないコメントには返信しませんのであらかじめご了承くださいませ。
機能概要 | V3/V4 | V5 |
---|---|---|
購入可能なアイテム取得 | QuerySkuDetails(SkuDetailsParams, ISkuDetailsResponseListener) |
QueryProductDetails(QueryProductDetailsParams, IProductDetailsResponseListener) |
購入履歴取得 | QueryPurchaseHistory(文字列、IPurchaseHistoryListener) | QueryPurchaseHistory(QueryPurchaseHistoryParams, IPurchaseHistoryListener); |
using Android.App;
using System;
using System.Collections.Generic;
using System.Linq;
using Android.BillingClient.Api;
using Forms = AppName.Droid.Models.Forms;
using Xamarin.Forms.Internals;
namespace AppName.Droid.Services
{
/// <summary>
/// InBillingServiceV5
/// Google Play Billing Library v5 対応
/// https://developer.android.com/google/play/billing/integrate?hl=ja
/// </summary>
public class InBillingServiceV5
{
private BillingClient _billingClient = null;
private BillingClientStateListener _stateListener = null;
private ProductDetailsResponseListener _productDetailsListener = null;
private PurchaseHistoryResponseListener _purchaseHistoryListener = null;
private bool _connected = false;
private string _productId = String.Empty;
private string _itemType = String.Empty;
/// <summary>
/// アカウント情報(アプリ起動中に永続的に記憶させたいためstaticに設定)
/// </summary>
public static AccountIdentifiers AccountIdentifiers { get; set; }
/// <summary>
/// 購入結果をハンドリングするイベント
/// </summary>
public event OnPurchaseProductDelegate OnPurchaseProduct;
public event OnUserCanceledDelegate OnUserCanceled;
public event OnPurchaseProductErrorDelegate OnPurchaseProductError;
public event OnConnectedDelegate OnConnected;
public void SetConnected(bool isConnected)
{
_connected = isConnected;
if (this.OnConnected != null &&
isConnected)
{
this.OnConnected();
}
}
public bool IsConnected
{
get
{
if (_billingClient == null)
{
return false;
}
return _billingClient.IsReady && _connected;
}
}
/// <summary>
/// BillingClient を初期化する
/// </summary>
/// <param name="productId">Google Play ConsoleのアイテムID</param>
/// <param name="itemType">BillingClient.SkuType.Inapp or BillingClient.SkuType.Subs</param>
public void Initialize(string productId, string itemType)
{
try
{
_productId = productId;
_itemType = itemType;
Activity activity = Forms.MainActivity;
var listener = new PurchasesUpdatedListener(this, _itemType);
//listener.OnPurchaseProduct += () =>
//{
// if (this.OnPurchaseProduct != null)
// {
// this.OnPurchaseProduct();
// }
//};
listener.OnUserCanceled += () =>
{
if (this.OnUserCanceled != null)
{
this.OnUserCanceled();
}
};
listener.OnPurchaseProductError += (responseCode, sku) =>
{
if (this.OnPurchaseProductError != null)
{
this.OnPurchaseProductError(responseCode, sku);
}
};
//Google Play Billing Library
_billingClient = BillingClient.NewBuilder(activity)
.EnablePendingPurchases()
.SetListener(listener)
.Build();
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
}
/// <summary>
/// Google Play との接続を確立する
/// </summary>
public void StartConnection()
{
try
{
if (_billingClient == null)
{
if (!String.IsNullOrEmpty(_productId) &&
!String.IsNullOrEmpty(_itemType))
{
//一度でも接続した場合、再初期化する
this.Initialize(_productId, _itemType);
}
else
{
return;
}
}
_stateListener = new BillingClientStateListener(this);
_billingClient.StartConnection(_stateListener);
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
}
/// <summary>
/// 購入可能なアイテムを表示する
/// </summary>
public void QueryProductDetails()
{
try
{
if (!this.IsConnected)
{
return;
}
// var skuList = new List<string>();
// //skuList.Add("premium_upgrade");
// //skuList.Add("gas");
// skuList.Add(_productId);
// SkuDetailsParams param = SkuDetailsParams.NewBuilder()
// .SetSkusList(skuList)
// .SetType(_itemType)
// .Build();
var list = new List<QueryProductDetailsParams.Product>();
list.Add(QueryProductDetailsParams.Product.NewBuilder()
.SetProductId(_productId)
.SetProductType(_itemType)
.Build()
);
var prms = QueryProductDetailsParams.NewBuilder()
.SetProductList(list)
.Build();
_productDetailsListener = new ProductDetailsResponseListener();
//_billingClient.QueryProductDetails(param, _skuDetailsListener);
_billingClient.QueryProductDetails(prms, _productDetailsListener);
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
}
/// <summary>
/// 購入フローを起動する
/// </summary>
public bool CanPurchase()
{
try
{
if (!this.IsConnected)
{
return false;
}
//var detail = new SkuDetails(_productId);
var detail = _productDetailsListener.ProductDetailsList.FirstOrDefault();
return this.CanPurchase(detail);
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
return false;
}
/// <summary>
/// 購入フローを起動する
/// </summary>
public bool CanPurchase(ProductDetails productDetails)
{
try
{
if (!this.IsConnected)
{
return false;
}
// An activity reference from which the billing flow will be launched.
Activity activity = Forms.MainActivity;
// Retrieve a value for "productDetails" by calling queryProductDetailsAsync()
// Get the offerToken of the selected offer
var offerToken = productDetails.GetSubscriptionOfferDetails().FirstOrDefault().OfferToken;
var list = new List<ProductDetailsParams>();
var prms = ProductDetailsParams.NewBuilder()
.SetProductDetails(productDetails)
.SetOfferToken(offerToken)
.Build();
list.Add(prms);
BillingFlowParams.Builder builder = BillingFlowParams.NewBuilder()
.SetProductDetailsParamsList(list);
if (InBillingServiceV5.AccountIdentifiers != null)
{
//不正行為が行われる前に Google が検出できるようにする
builder = builder.SetObfuscatedAccountId(InBillingServiceV5.AccountIdentifiers.ObfuscatedAccountId)
.SetObfuscatedProfileId(InBillingServiceV5.AccountIdentifiers.ObfuscatedProfileId);
Console.WriteLine(" ** CanPurchase Set AccountIdentifiers.");
}
BillingFlowParams billingFlowParams = builder.Build();
BillingResult result = _billingClient.LaunchBillingFlow(activity, billingFlowParams);
BillingResponseCode responseCode = result.ResponseCode;
// Handle the result.
return responseCode == BillingResponseCode.Ok;
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
return false;
}
/// <summary>
/// SKU商品を消費する
/// </summary>
/// <param name="purchaseToken"></param>
public void Consume(string purchaseToken)
{
try
{
if (!this.IsConnected)
{
return;
}
ConsumeParams consumeParams =
ConsumeParams.NewBuilder()
.SetPurchaseToken(purchaseToken)
.Build();
ConsumeResponseListener listener = new ConsumeResponseListener();
listener.OnPurchaseProduct += () =>
{
if (this.OnPurchaseProduct != null)
{
this.OnPurchaseProduct();
}
};
_billingClient.Consume(consumeParams, listener);
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
}
/// <summary>
/// 定期購読を消費する
/// </summary>
/// <param name="purchaseToken"></param>
public void AcknowledgePurchase(string purchaseToken)
{
try
{
if (!this.IsConnected)
{
return;
}
AcknowledgePurchaseParams acknowledgeParams =
AcknowledgePurchaseParams.NewBuilder()
.SetPurchaseToken(purchaseToken)
.Build();
AcknowledgePurchaseResponseListener listener = new AcknowledgePurchaseResponseListener();
listener.OnPurchaseProduct += () =>
{
if (this.OnPurchaseProduct != null)
{
this.OnPurchaseProduct();
}
};
_billingClient.AcknowledgePurchase(acknowledgeParams, listener);
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
}
/// <summary>
/// 購入結果の確認クエリを投げる
/// </summary>
public Task<QueryPurchasesResult> GetQueryPurchases(string itemType)
{
try
{
if (!this.IsConnected)
{
return null;
}
// https://developer.android.com/google/play/billing/migrate-gpblv5
var prms = QueryPurchasesParams.NewBuilder()
.SetProductType(itemType)
.Build();
return _billingClient.QueryPurchasesAsync(prms);
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
return null;
}
/// <summary>
/// 購入履歴の確認クエリを投げる
/// </summary>
public void QueryPurchaseHistory()
{
try
{
if (!this.IsConnected)
{
return;
}
_purchaseHistoryListener = new PurchaseHistoryResponseListener();
var prms = QueryPurchaseHistoryParams.NewBuilder()
.SetProductType(_itemType)
.Build();
_billingClient.QueryPurchaseHistory(prms, _purchaseHistoryListener);
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
}
/// <summary>
/// 購入履歴を取得する
/// </summary>
/// <returns>購入履歴のリスト</returns>
public IList<Android.BillingClient.Api.PurchaseHistoryRecord> GetPurchaseHistoryRecords()
{
try
{
if (!this.IsConnected)
{
return null;
}
return _purchaseHistoryListener.PurchaseHistoryList;
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
return null;
}
// public async Task<IList<Android.BillingClient.Api.PurchaseHistoryRecord>> GetPurchaseHistoryRecordsAsync()
// {
// if (!this.IsConnected)
// {
// return null;
// }
//
// var ret = await _billingClient.QueryPurchaseHistoryAsync(_itemType);
// return ret.PurchaseHistoryRecords;
//
// }
/// <summary>
/// Google Play との接続を切断する
/// </summary>
public void Disconnect()
{
try
{
if (this.IsConnected &&
_billingClient != null)
{
_billingClient.EndConnection();
_billingClient.Dispose();
_billingClient = null;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
}
}
/// <summary>
/// Google Play との接続状態を管理する
/// </summary>
public class BillingClientStateListener : Java.Lang.Object, IBillingClientStateListener
{
private InBillingServiceV5 _inBillingService = null;
public BillingClientStateListener()
{
}
public BillingClientStateListener(InBillingServiceV5 instance)
{
_inBillingService = instance;
}
public void OnBillingSetupFinished(Android.BillingClient.Api.BillingResult result)
{
Console.WriteLine("OnBillingSetupFinished ResponseCode : " + result.ResponseCode.ToString());
if (result.ResponseCode == BillingResponseCode.Ok)
{
// The BillingClient is ready. You can query purchases here.
if (_inBillingService != null)
{
_inBillingService.SetConnected(true);
_inBillingService.QueryProductDetails(); //購入商品リストの確認
_inBillingService.QueryPurchaseHistory(); //購入履歴の確認
}
}
}
public void OnBillingServiceDisconnected()
{
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
Console.WriteLine("OnBillingServiceDisconnected");
if (_inBillingService != null)
{
_inBillingService.SetConnected(false);
}
}
}
/// <summary>
/// 購入可能なアイテムの結果を取得する
/// </summary>
public class ProductDetailsResponseListener : Java.Lang.Object, IProductDetailsResponseListener
{
public IList<ProductDetails> ProductDetailsList = null;
public void OnProductDetailsResponse(BillingResult result, IList<ProductDetails> list)
{
Console.WriteLine("OnProductDetailsResponse ResponseCode : " + result.ResponseCode.ToString());
if (result.ResponseCode == BillingResponseCode.Ok)
{
list.ForEach(r =>
{
Console.WriteLine("OnProductDetailsResponse ProductDetails : " + r);
});
this.ProductDetailsList = list;
}
}
}
/// <summary>
/// 購入結果の確認
/// </summary>
public class PurchasesUpdatedListener : Java.Lang.Object, IPurchasesUpdatedListener
{
private InBillingServiceV5 _instance= null;
private string _itemType = String.Empty;
public event OnUserCanceledDelegate OnUserCanceled;
public event OnPurchaseProductErrorDelegate OnPurchaseProductError;
public PurchasesUpdatedListener(InBillingServiceV5 instance, string itemType)
{
_instance = instance;
_itemType = itemType;
}
public void OnPurchasesUpdated(Android.BillingClient.Api.BillingResult result, IList<Android.BillingClient.Api.Purchase> list)
{
Console.WriteLine("OnPurchasesUpdated ResponseCode : " + result.ResponseCode.ToString());
if (result.ResponseCode == BillingResponseCode.Ok &&
list != null)
{
list.ForEach(r =>
{
//Console.WriteLine("OnPurchasesUpdated Purchase : " + r.OriginalJson);
InBillingServiceV5.AccountIdentifiers = r.AccountIdentifiers; //不正防止
this.HandlePurchase(r);
});
} else if (result.ResponseCode == BillingResponseCode.UserCancelled) {
// Handle an error caused by a user cancelling the purchase flow.
Console.WriteLine("OnPurchasesUpdated UserCancelled");
if (this.OnUserCanceled != null)
{
this.OnUserCanceled();
}
} else {
if (this.OnPurchaseProductError != null)
{
this.OnPurchaseProductError((int)result.ResponseCode, "");
}
// Handle any other error codes.
Console.WriteLine("OnPurchasesUpdated Fail");
}
}
/// <summary>
/// 購入を処理する
/// </summary>
/// <param name="purchase"></param>
public void HandlePurchase(Purchase purchase)
{
try
{
if (purchase == null)
{
Console.WriteLine("HandlePurchase purchase is null.");
return;
}
if (_instance == null)
{
Console.WriteLine("HandlePurchase _instance is null.");
return;
}
// Purchase retrieved from BillingClient#queryPurchases or your PurchasesUpdatedListener.
//Purchase purchase = ...;
// Verify the purchase.
// Ensure entitlement was not already granted for this purchaseToken.
// Grant entitlement to the user.
if (_itemType == BillingClient.SkuType.Subs)
{
_instance.AcknowledgePurchase(purchase.PurchaseToken);
}
else
{
_instance.Consume(purchase.PurchaseToken);
}
Console.WriteLine("HandlePurchase Consume Success.");
}
catch (Exception ex)
{
Console.WriteLine(ex.Tostring());
}
}
}
/// <summary>
/// 購入の処理結果を取得する
/// </summary>
public class ConsumeResponseListener : Java.Lang.Object, IConsumeResponseListener
{
public event OnPurchaseProductDelegate OnPurchaseProduct;
public event OnPurchaseProductErrorDelegate OnPurchaseProductError;
public void OnConsumeResponse(BillingResult result, string purchaseToken)
{
Console.WriteLine("OnConsumeResponse ResponseCode : " + result.ResponseCode.ToString());
if (result.ResponseCode == BillingResponseCode.Ok)
{
// Handle the success of the consume operation.
//Console.WriteLine("OnConsumeResponse purchaseToken : " + purchaseToken);
if (this.OnPurchaseProduct != null)
{
this.OnPurchaseProduct();
}
}
else
{
if (this.OnPurchaseProductError != null)
{
this.OnPurchaseProductError((int)result.ResponseCode, "");
}
}
}
}
/// <summary>
/// 定期購読の処理結果を取得する
/// </summary>
public class AcknowledgePurchaseResponseListener : Java.Lang.Object, IAcknowledgePurchaseResponseListener
{
public event OnPurchaseProductDelegate OnPurchaseProduct;
public event OnPurchaseProductErrorDelegate OnPurchaseProductError;
public void OnAcknowledgePurchaseResponse(BillingResult result)
{
Console.WriteLine("OnAcknowledgePurchaseResponse ResponseCode : " + result.ResponseCode.ToString());
if (result.ResponseCode == BillingResponseCode.Ok)
{
// Handle the success of the consume operation.
if (this.OnPurchaseProduct != null)
{
this.OnPurchaseProduct();
}
}
else
{
if (this.OnPurchaseProductError != null)
{
this.OnPurchaseProductError((int)result.ResponseCode, "");
}
}
}
}
/// <summary>
/// 購入履歴を取得する
/// </summary>
public class PurchaseHistoryResponseListener : Java.Lang.Object, IPurchaseHistoryResponseListener
{
public IList<PurchaseHistoryRecord> PurchaseHistoryList = null;
public void OnPurchaseHistoryResponse(BillingResult result, IList<PurchaseHistoryRecord> list)
{
Console.WriteLine("OnPurchaseHistoryResponse ResponseCode : " + result.ResponseCode.ToString());
if (result.ResponseCode == BillingResponseCode.Ok &&
list != null)
{
//list.ForEach(r =>
//{
// Console.WriteLine("OnPurchaseHistoryResponse PurchaseHistoryRecord : " + r.OriginalJson);
//});
this.PurchaseHistoryList = list;
}
}
}
}
※名前とタイトルが入力されていないコメントでは他のコメントとの区別ができません。
入力されていないコメントには返信しませんのであらかじめご了承くださいませ。