OpenIABライブラリをAndroidアプリケーションに統合した経験

この記事では、 英語の学習に役立つAndroidアプリケーションにOpenIABライブラリを統合した経験を共有したいと思います 。 誰も知らない場合、OpenIABは、特定のストアのAPIの実装の詳細から抽象化して、さまざまなアプリケーションストアのアプリ内購入を接続できるライブラリです。









OpenIABは、次の原則に基づいて開発されています。



*ライブラリAPIは、Google Playのアプリ内課金APIに可能な限り類似する必要があります。

* 1つのAPKファイルは、サポートされているすべてのアプリストアで機能するはずです。

*支払いを行う際の仲介者なし。 これは、トランザクションを処理するサードパーティが存在しないことを意味します。 ライブラリの内部では、すべてのトランザクションは同じGoogle Play、Yandex.Storeおよびその他のネイティブストアアプリケーションによって処理されます。 実際、OpenIABは、さまざまなアプリストアのAPIを1つのAPIに導くレイヤーであり、アプリケーションで使用します。



接続プロセス



OpenIABライブラリーをプロジェクトに接続する



ライブラリAPIを使用するには、もちろん、それをプロジェクトに接続する必要があります。 これを行うには、いくつかの方法があります。

1. jarライブラリファイルをここ(http://www.onepf.org/openiab)からダウンロードし、Eclipseプロジェクトのlibフォルダーに配置します。

2. gitリポジトリ(git clone github.com/onepf/OpenIAB.git )からプロジェクトを複製し、ライブラリプロジェクトとしてプロジェクトに接続します。

最初のオプションはよりシンプルで、これを使用します。



ライブラリがアプリケーションストアとやり取りするには、インターネット接続が必要になるため、AndroidManifest.xmlに許可<uses-permission android:name = "android.permission.INTERNET" />を追加することを忘れないでください。



<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ... <!-- permissions to download files and billing support --> <uses-permission android:name="android.permission.INTERNET" /> ... </manifest>
      
      







これでライブラリのプロジェクトへの接続が完了しました。アプリケーションストアで動作するようにライブラリを構成します。



カスタマイズ



アプリケーションはYandex.Storeを介して配布され、この特定のストアの例でライブラリをセットアップすることを検討します。 まず、私たちが販売したいものを作成する必要があります。 これを行うには、開発者コンソール(https://developer.store.yandex.ru)Yandexに移動し、そこで新しいアプリケーションを作成します。 次に、「アプリケーションでのショッピング」セクションで、ユーザーに提供する仮想商品の各アイテムのエントリを作成する必要があります。 他のパラメーターの中でも特に、各購入を追加するとき、IDを示す必要があります。 アプリケーションストアと対話するときにこれらのIDを使用します。



購入がストアの側面に存在するようになったので、Yandex.Storeを操作するためのアプリケーションを準備するときが来ました。 最も明白なことは、すぐにコードを表示することです。



 public class DictActivity extends Activity { //    API . private OpenIabHelper mIABHelper; private boolean isIABHelperSetup = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dict); //  API. OpenIabHelper.Options.Builder builder = new OpenIabHelper.Options.Builder() .setCheckInventory(true) .addPreferredStoreName(OpenIabHelper.NAME_YANDEX) .setVerifyMode(OpenIabHelper.Options.VERIFY_EVERYTHING) .addStoreKeys(SettingsManager.STORE_KEYS_MAP); //  . mIABHelper = new OpenIabHelper(this, builder.build()); mIABHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { public void onIabSetupFinished(IabResult result) { if(!result.isSuccess()) { isIABHelperSetup = false; //TODO:      . return; } if(mIABHelper != null) { isIABHelperSetup = true; //API   . } } }); } @Override public void onDestroy() { super.onDestroy(); if(mIABHelper != null) mIABHelper.dispose(); mIABHelper = null; } }
      
      







mIABHelperは、ライブラリAPIにアクセスするためのまさにそのオブジェクトです。 その構成は、OpenIabHelper.Options構造体をコンストラクターに渡すことによって行われます。 考えられる最も便利な設定を見てみましょう。

-setCheckInventory(ブール値checkInventory)。 彼はOpenIABライブラリに、利用可能な各アプリケーションストアに接続し、そこからユーザーが利用できる購入のリストを取得し、受信したデータに基づいて、このストアが今後の作業に適しているかどうかを判断します。

-addPreferredStoreName(String ... storeNames)。 利用可能なストアの使用を優先します。 同時に複数の店舗で購入できる場合に役立ちます。

-addStoreKeys(Map <String、String> storeKeys)。 Yandex.Storeを含む多くのアプリケーションストアは、アプリケーションに送信されるメッセージに署名します。 したがって、署名をチェックすることにより、アプリケーションはメッセージが偽物ではないことを常に確認できます。 署名を検証するには、公開キーが使用されます。公開キーは、通常、特定のアプリケーションストアの開発者のコ​​ンソールから取得できます。 このオプションを使用すると、使用するストアの公開鍵を設定できます。

-setVerifyMode(int verifyMode)。 ストアメッセージを分析するときの署名検証モードを定義します。 次の3つのモードを使用できます。

* OpenIabHelper.Options.VERIFY_EVERYTHING-常に署名を検証します。 ストアに公開鍵が指定されていない場合、それを使用することはできません。

* OpenIabHelper.Options.VERIFY_SKIP-署名を検証しません。 アプリケーションではなくサーバーで購入を処理する場合に便利です。

* OpenIabHelper.Options.VERIFY_ONLY_KNOWN-addStoreKeysオプション(Map <String、String> storeKeys)などを使用して、このストアに公開キーが指定されている場合にのみ署名を確認します。



OpenIabHelper.startSetupメソッド(IabHelper.OnIabSetupFinishedListener)は、ライブラリ初期化プロセスを開始します。 これは非同期呼び出しであり、操作の結果は、渡されたオブジェクトのonIabSetupFinished()メソッドに返されます。



アプリケーションでYandex.Storeを使用して購入できるように、プロジェクトマニフェストファイルで適切なアクセス許可を与える必要があります。

 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ... <!-- permissions to download files and billing support --> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="org.onepf.openiab.permission.BILLING" /> ... </manifest>
      
      







フレームの準備ができました。何かを販売する準備がほぼ整いました。



購入処理



購入プロセスを開始するには、電話をかける必要があります

OpenIabHelper.launchPurchaseFlow(アクティビティact、String sku、int requestCode、IabHelper.OnIabPurchaseFinishedListenerリスナー)。

 ... if((mIABHelper != null) && isIABHelperSetup) { String sku = "duct_1"; mIABHelper.launchPurchaseFlow(DictActivity.this, sku, 10001, mPurchaseFinishedListener); } ...
      
      







ここに

act-購入が行われるアクティビティ。

skuは、アプリケーションストアで購入を登録するときに指定したものと同じIDです。

requestCode-ストアアクティビティを呼び出すコード。

listener-操作の結果を処理するリスナー。



OpenIABライブラリ自体はリクエストを行いませんが、選択したストアのアプリケーションへの呼び出しを委任するだけです。 私たちの場合、Yandex.Storeはそのようなアプリケーションになります。 したがって、launchPurchaseFlow()を呼び出した後、ユーザーは対応するストアのアプリケーションにリダイレクトされ、購入トランザクションが実行されます。 ユーザーが購入を確認または確認しないと、アクティビティのonActivityResult()メソッドで結果を取得します。 OpenIABライブラリが受信した回答を解釈するために、この回答をそれに渡す必要があります。 これは、handleActivityResult(int requestCode、int resultCode、Intent data)を呼び出すことで実行されます。 このメソッドは、ストアアプリケーションから受信したデータを解釈し、署名を検証し、リスナーのlaunchPurchaseFlow()呼び出しで指定されたonIabPurchaseFinished(IabResult結果、Purchase purchase)メソッドに制御を渡します。



 public class DictActivity extends Activity { ... private void makePurchase() { if((mIABHelper != null) && isIABHelperSetup) { String sku = "duct_1"; mIABHelper.launchPurchaseFlow(DictActivity.this, sku, 10001, mPurchaseFinishedListener); } } ... @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if((mIABHelper == null) || !mIABHelper.handleActivityResult(requestCode, resultCode, data)) super.onActivityResult(requestCode, resultCode, data); } ... private OnIabPurchaseFinishedListener mPurchaseFinishedListener = new OnIabPurchaseFinishedListener() { public void onIabPurchaseFinished(IabResult result, Purchase purchase) { if(result.isFailure()) { //TODO: -   ,    . return; } //   String purchaseName = purchase.getSku(); markPurchaseAsConfirmed(purchaseName); } }; private void markPurchaseAsConfirmed(String purchase) { //TODO:           //  UI . } }
      
      







これで、ユーザーは私たちの仮想製品の幸せな所有者になる機会があり、アプリケーションに最後の仕上げを追加する時です...



ショッピング状態を復元する



通常、アプリケーションストアはいくつかのタイプの製品をサポートします。 最も一般的なタイプは、消耗品、非消耗品、サブスクリプションです。 消費品には、たとえばゲーム内通貨が含まれます。 ユーザーは、消費された商品を数回購入できます。 非消耗品の例は、アプリケーションの追加機能です。 ユーザーは一度支払い、常に使用します。



私たちの場合、ユーザーが追加の辞書を購入できるようにしますが、これは論理的には非消耗品でなければなりません。非消耗品の特性は、プログラムの特定のコピーではなく、ユーザーアカウントに関連付けられていることです。 つまり、ユーザーが1つのアカウントで複数のデバイスにアプリケーションをインストールした場合でも、商品を購入できるのは1回だけであり、購入した商品はこれらすべてのデバイスで利用できる必要があります。 したがって、ユーザーが新しくインストールされたアプリケーションでそれらを使用できるように、既に購入した商品に関する情報をアプリケーションストアから受信できる必要があります。 さらに、購入トランザクションの処理プロセスは非常に複雑であり、ネットワークを介したデータの転送とシステム自体内のいくつかのアプリケーションの相互作用を伴います。 いつでも、何かがうまくいかないことがあります。 最悪の場合、アプリケーションストアの観点から購入を行った後、アプリケーションで購入を処理する前に障害が発生する可能性があります。 この場合、アプリケーションストアで購入済みとしてリストされますが、ユーザーはアプリケーションで目的の製品を受け取りません。 このような状況を処理するための呼び出しが提供されています。

queryInventoryAsync(IabHelper.QueryInventoryFinishedListenerリスナー)。



このメソッドは、ユーザーが購入した商品の可用性についてアプリケーションストアに非同期要求を行い、リスナーリスナーに応答を返します。 良い解決策は、OpenIABライブラリが初期化された直後にこのメソッドを呼び出すことです。



 public class DictActivity extends Activity { ... @Override public void onIabSetupFinished(IabResult result) { if(!result.isSuccess()) { isIABHelperSetup = false; //TODO:      . return; } if(mIABHelper != null) { isIABHelperSetup = true; //API   . //    . mIABHelper.queryInventoryAsync(mGotInventoryListener); } } ... private QueryInventoryFinishedListener mGotInventoryListener = new QueryInventoryFinishedListener() { @Override public void onQueryInventoryFinished(IabResult result, Inventory inventory) { if (result.isFailure()) { //TODO:   . return; } //        . List<Purchase> purchases = inventory.getAllPurchases(); for(Purchase p : purchases) { String sku = p.getSku(); if(!isPurchaseConfirmed(sku)) markPurchaseAsConfirmed(sku); } } }; private boolean isPurchaseConfirmed(String purchase) { //TODO:  true,      , //  false. } private void markPurchaseAsConfirmed(String purchase) { //TODO:    ,   ,    //  UI . } }
      
      







すべて一緒に



 public class DictActivity extends BaseActivity { //    API . private OpenIabHelper mIABHelper; private boolean isIABHelperSetup = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dict); //  API. OpenIabHelper.Options.Builder builder = new OpenIabHelper.Options.Builder() .setCheckInventory(true) .addPreferredStoreName(OpenIabHelper.NAME_YANDEX) .setVerifyMode(OpenIabHelper.Options.VERIFY_EVERYTHING) .addStoreKeys(SettingsManager.STORE_KEYS_MAP); //  . mIABHelper = new OpenIabHelper(this, builder.build()); mIABHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { public void onIabSetupFinished(IabResult result) { if(!result.isSuccess()) { isIABHelperSetup = false; //TODO:      . return; } if(mIABHelper != null) { isIABHelperSetup = true; //API   . //    . mIABHelper.queryInventoryAsync(mGotInventoryListener); } } }); final Button buy = (Button)findViewById(R.id.buy); buy.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if((mIABHelper != null) && isIABHelperSetup) { String payload = "payload"; String sku = "duct_1"; mIABHelper.launchPurchaseFlow(DictActivity.this, sku, 10001, mPurchaseFinishedListener, payload); } } }); } @Override public void onDestroy() { super.onDestroy(); if(mIABHelper != null) mIABHelper.dispose(); mIABHelper = null; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if((mIABHelper == null) || !mIABHelper.handleActivityResult(requestCode, resultCode, data)) super.onActivityResult(requestCode, resultCode, data); } private OnIabPurchaseFinishedListener mPurchaseFinishedListener = new OnIabPurchaseFinishedListener() { public void onIabPurchaseFinished(IabResult result, Purchase purchase) { if (result.isFailure()) { showMessage("Error purchasing: " + result); return; } String purchaseName = purchase.getSku(); markPurchaseAsConfirmed(purchaseName); } }; private QueryInventoryFinishedListener mGotInventoryListener = new QueryInventoryFinishedListener() { @Override public void onQueryInventoryFinished(IabResult result, Inventory inventory) { if (result.isFailure()) { //TODO:   . return; } //        . List<Purchase> purchases = inventory.getAllPurchases(); for(Purchase p : purchases) { String sku = p.getSku(); if(!isPurchaseConfirmed(sku)) markPurchaseAsConfirmed(sku); } } }; private void markPurchaseAsConfirmed(String purchase) { //TODO:    ,   ,    //  UI . } private boolean isPurchaseConfirmed(String purchase) { //TODO:  true,      , //  false. } }
      
      







おわりに



Google Playインフラストラクチャ以外のアプリケーションでお金を稼ぐ場合は、OpenIABが必要です。 新しいアプリケーションストアの接続はわずか数行のコードで実行されます。APIとGoogle Billing APIの類似性により、Google Playから迅速に移行できます。



参照資料



github.com/onepf/OpenIABはGitHubのプロジェクトです。

www.engwords.net/en-たとえば、 Yandex.StoreのOpenIABが組み込まれたアプリケーションサイト



All Articles