質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

Q&A

解決済

2回答

1507閲覧

AIDL から Google Play Billing Libraryへの移行でQuerySkuDetailsAsyncの応答がない

sunmo

総合スコア10

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Xamarin

Xamarin(ザマリン)は、iPhoneなどのiOSやAndroidで動作し、C# 言語を用いてアプリを開発できるクロスプラットフォーム開発環境です。Xamarin Studioと C# 言語を用いて、 iOS と Android の両方の開発を行うことができます。

0グッド

0クリップ

投稿2020/08/16 07:46

編集2020/08/16 13:31

AndroidでXamarin.Androidでアプリ内課金を行っているのですが、
AIDL から Google Play Billing Libraryへの移行が必要とのことで、
対応中なのですが、最初から壁にぶち当たり前に進めていません。

開発環境は、下記の通りです。

開発ソフト:Microsoft Visual Studio Community 2019
開発言語:Xamarin.Android
NuGet:Xamarin.Android.Google.Billing.Clinetを利用
(以前は、Plugin.InAppBillingを使っていました。)

困っていることは、

「BuyActivity」と「BillingSupport」というクラスを作り、
「BuyActivity」の「Resume」の中で、「BillingSupport」のインスタンスを作成しています。

この後、「BuyActivity」の中の「BuyInApp」関数を呼び出して、「BillingSupport.LoadPurchases_InApp」関数で
商品の読み込みを行おうとしているのですが、「QuerySkuDetailsAsync」関数が
応答がないようで、「OnSkuDetailsResponse」が呼び出されませんでした。
そのため、「SkuDetails」がnullのままとなり、処理が継続できません。

Googleの開発サイトなどを参照しているのですが、Xamarin.Androidの事例が
あまり見つからず、解決方法が分かっておりません。

試したこと、確認したことは下記の通りです。

1)「OnBillingSetupFinished」はOKがかえってきている。
2)QuerySkuDetailsAsyncをWait()すると、応答がないままフリーズする。
3)予約アイテム「android.test.purchased」を使っても応答はないまま。

以上です。

どなたか、お分かりになる方いらっしゃいましたら、
ご教授よろしくお願いいたします。

ソース抜粋

C#

1using System; 2using System.Collections.Generic; 3using System.Threading.Tasks; 4using Android.App; 5using Android.BillingClient.Api; 6using Android.Content; 7 8 class BillingSupport : Java.Lang.Object, IPurchasesUpdatedListener, IBillingClientStateListener, ISkuDetailsResponseListener, IConsumeResponseListener 9 { 10 Context Context; 11 private BillingClient billingClient; 12 public IList<SkuDetails> SkuDetails; 13 14 #region 購入開始 15 public BillingSupport(Activity activity) 16 { 17 Context = activity.ApplicationContext; 18 billingClient = BillingClient.NewBuilder(Context).EnablePendingPurchases().SetListener(this).Build(); 19 billingClient.StartConnection(this); 20 } 21 22 public void OnBillingSetupFinished(BillingResult p0) 23 { 24 if (p0.ResponseCode == BillingResponseCode.Ok) 25 { 26 Console.WriteLine("BILLING | startConnection | RESULT OK"); 27 // The BillingClient is ready. You can query purchases here. 28 } 29 else 30 { 31 Console.WriteLine("BILLING | startConnection | RESULT: $billingResponseCode"); 32 } 33 } 34 35 public void OnBillingServiceDisconnected() 36 { 37 Console.WriteLine("BILLING | onBillingServiceDisconnected | DISCONNECTED"); 38 // Try to restart the connection on the next request to 39 // Google Play by calling the startConnection() method. 40 } 41 42 #endregion 43 44 #region 商品の読み込み 45 //public void LoadPurchases_InApp() 46 //{ 47 48 // if (billingClient.IsReady) 49 // { 50 // List<string> skuList = new List<string>(); 51 // skuList.Add("android.test.purchased"); 52 // skuList.Add("android.test.canceled"); 53 // skuList.Add("android.test.item_unavailable"); 54 // SkuDetailsParams.Builder paramse = SkuDetailsParams.NewBuilder(); 55 // paramse.SetSkusList(skuList).SetType(BillingClient.SkuType.Inapp); 56 // billingClient.QuerySkuDetailsAsync(paramse.Build());(★応答がない) 57 // } 58 //} 59 //変更 REV001 60 public async Task<QuerySkuDetailsResult> LoadPurchases_InApp() 61 { 62 if (BillingClient == null || !BillingClient.IsReady) 63 { 64 await ConnectAsync(); 65 } 66 67 IList<string> skuList = new JavaList<string> 68 { 69 "android.test.purchased", 70 "android.test.canceled", 71 "android.test.item_unavailable" 72 }; 73 74 SkuDetailsParams paramse = SkuDetailsParams.NewBuilder().SetSkusList(skuList).SetType(BillingClient.SkuType.Inapp).Build(); 75 76 var querySkuDetailsResult = await BillingClient.QuerySkuDetailsAsync(paramse); 77 return querySkuDetailsResult; 78 } 79 } 80 //<=== 変更 REV001 81 82 public void OnSkuDetailsResponse(BillingResult p0, IList<SkuDetails> p1) 83 { 84 if (p0.ResponseCode == BillingResponseCode.Ok) 85 { 86 Console.WriteLine("querySkuDetailsAsync, responseCode: $responseCode"); 87 InitProductAdapter(p1); 88 } 89 else 90 { 91 Console.WriteLine("Can't querySkuDetailsAsync, responseCode: $responseCode"); 92 } 93 } 94 public void InitProductAdapter(IList<SkuDetails> skuDetails) 95 { 96 this.SkuDetails = skuDetails; 97 } 98 #endregion 99 100 101 #region 商品の購入 102 public void PurchaseInApp(SkuDetails skuDetails) 103 { 104 BillingFlowParams billingFlowParams = 105 BillingFlowParams.NewBuilder() 106 .SetSkuDetails(skuDetails) 107 .Build(); 108 109 billingClient.LaunchBillingFlow(this.Context as Activity, billingFlowParams); 110 } 111 112 //Response code 7 in OnPurchasesUpdated. It means: Item Already Owned. 113 public void OnPurchasesUpdated(BillingResult p0, IList<Purchase> p1) 114 { 115 if (p0.ResponseCode == BillingResponseCode.Ok && p1 != null) 116 { 117 foreach (Purchase purchase in p1) 118 { 119 HandlePurchase(purchase); 120 } 121 } 122 else if (p0.ResponseCode == BillingResponseCode.UserCancelled) 123 { 124 // ユーザーが購入フローをキャンセルした場合に発生したエラーを処理します。 125 } 126 else 127 { 128 // 他のエラー コードを処理します。 129 } 130 } 131 132 public void HandlePurchase(Purchase purchase) 133 { 134 if (purchase.PurchaseState == PurchaseState.Purchased) 135 { 136 // ユーザーに権利を付与します。 137 138 // 購入がまだ承認されていない場合は、購入を承認します。 139 if (!purchase.IsAcknowledged) 140 { 141 AcknowledgePurchaseParams acknowledgePurchaseParams = 142 AcknowledgePurchaseParams.NewBuilder() 143 .SetPurchaseToken(purchase.PurchaseToken) 144 .Build(); 145 billingClient.AcknowledgePurchase(acknowledgePurchaseParams, (IAcknowledgePurchaseResponseListener)this); 146 } 147 148 } 149 else if (purchase.PurchaseState == PurchaseState.Pending) 150 { 151 // Here you can confirm to the user that they've started the pending 152 // purchase, and to complete it, they should follow instructions that 153 // are given to them. You can also choose to remind the user in the 154 // future to complete the purchase if you detect that it is still 155 // pending. 156 } 157 } 158 #endregion 159 160 #region アイテム消費 161 public void ConsumePurchases(string purchaseToken) 162 { 163 ConsumeParams consumeParams = 164 ConsumeParams.NewBuilder() 165 .SetPurchaseToken(purchaseToken) 166 .Build(); 167 billingClient.ConsumeAsync(consumeParams); 168 } 169 170 public void OnConsumeResponse(BillingResult p0, string p1) 171 { 172 if (p0.ResponseCode == BillingResponseCode.Ok && p1 != null) 173 { 174 Console.WriteLine("onPurchases Updated consumeAsync, purchases token removed: $purchaseToken"); 175 } 176 else 177 { 178 Console.WriteLine("onPurchases some troubles happened: $responseCode"); 179 } 180 } 181 182 #endregion 183 }

C#

1  public class BuyActivity : Activity 2 { 3 BillingSupport billingSupport; 4 5 protected override void OnCreate(Bundle savedInstanceState) 6 { 7 //省略 8 } 9 10 protected override void OnResume() 11 { 12 base.OnResume(); 13 14 #region Google Play 請求サービス起動 15 billingSupport = new BillingSupport(this); 16 #endregion 17 } 18 19     //private void BuyInApp() 20 //{ 21 // //商品の詳細情報を取得 22 // billingSupport.LoadPurchases_InApp(); 23 24 // //商品を購入 25 // billingSupport.PurchaseInApp(billingSupport.SkuDetails[0]);//★ここでSkuDetailsがnullになる 26 //} 27 //変更 REV001 ===> 28 private async Task BuyInApp() 29 { 30 //商品の詳細情報を取得 31 var response = await billingSupport.LoadPurchases_InApp(); 32 33 //商品を購入/消費 34 billingSupport.PurchaseInApp(billingSupport.SkuDetails[0]); 35 } 36 //<=== 変更 REV001 37  }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

課金の実装はしたことがないのでわかりませんが、
QuerySkuDetailsAsyncConsumeAsyncを呼び出している箇所で、非同期(async/await)の対応を行ってみてはいかがでしょうか。

C#のTaskと非同期処理についてまとめる

投稿2020/08/16 12:20

takapi_cs

総合スコア349

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sunmo

2020/08/16 13:34

ご助言いただきありがとうございます。 ソースに「REV001」のリビジョンを付けて修正したのですが、結果は同じでした。 「QuerySkuDetailsAsync」を呼び出すと、「OnSkuDetailsResponse」が呼び出されると思っているのですが、これが呼ばれず、商品情報が取得できずNULLになっています。
sunmo

2020/08/16 14:18

先ほどの件をヒントに調べていたら、「OnSkuDetailsResponse」は呼ばれないのですが、「QuerySkuDetailsAsync」の戻り値にSkuDetailsの情報が入っておりました! こちらの内容で、次のステップに進めれそうです。AndroidとXamarinで使い方が違うんですね・・・ ありがとうございました。
takapi_cs

2020/08/16 14:22

解決のヒントになったようでなによりです。
guest

0

自己解決

「QuerySkuDetailsAsync」の戻り値が、OK、NGの結果だけでなく、
「SkuDetails」の情報も入っておりました。下記で目的の情報を取得できました。
AndroidとXamarinで作りが若干違うことに気が付いた瞬間でした。

C#

1 private async Task BuyInApp() 2 { 3 //商品の詳細情報を取得 4 QuerySkuDetailsResult response = await billingSupport.LoadPurchases_InApp(); 5 6 //商品を購入/消費 7 billingSupport.PurchaseInApp(response.SkuDetails[0]); 8 }

投稿2020/08/16 14:24

sunmo

総合スコア10

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問