36

私は最初のアプリを完成させようとしています。最後に残っているのは IAP 課金を実装することです。そのため、現在このトピックについてかなり多くのことを読んでいます (暗号化、難読化などのセキュリティ上の懸念を含む)。

私のアプリは無料版で、IAP を介してフル バージョンにアップグレードできるため、管理された購入アイテム「プレミアム」は 1 つだけです。これについていくつか質問があります。

Google IAP API の例 (trivialdrivesample) では、MainActivity に常に IAP チェックがあり、ユーザーがプレミアム バージョンを購入したかどうかを確認します。

mHelper.queryInventoryAsync(mGotInventoryListener);

私の最初の懸念: これは、ユーザーがアプリの起動時に常にインターネット/データ接続を持っている必要があることを意味し、プレミアム バージョンに切り替えることができますか? ユーザーがインターネットに接続していない場合はどうなりますか? 彼は私が推測するライトバージョンを使いますが、それは私が迷惑だと思うでしょう.

そこで、isPremium ステータスをローカルに、SharedPrefs またはアプリ データベースに保存する方法を考えました。さて、サーバー側の検証を行うためのサーバーを所有していないため、ハッカーがアプリをリバース エンジニアリングするのを止められないことはわかっています。

それにもかかわらず、どこかに「isPremium」フラグを保存することはできません。

そこで、次のようなことを考えていました。

  • ユーザーがプレミアムを購入
  • アプリは IMEI/デバイス ID を取得し、ハードコードされた文字列キーを使用して XOR エンコードし、それをアプリ データベースにローカルに保存します。

ユーザーがアプリを再度起動すると、次のようになります。

  • アプリはエンコードされた文字列をデータベースから取得し、デコードして、decodedString == IMEI かどうかを確認します。はいの場合 -> プレミアム
  • いいえの場合、ユーザーがプレミアムを購入したかどうかを確認するために、通常の queryInventoryAsync が呼び出されます。

そのアプローチについてどう思いますか?私はそれが超安全ではないことを知っていますが、私にとっては、アプリがハッキングされないことよりも(インターネット接続が必須の場合のように)ユーザーがイライラしないことが重要です(とにかく不可能です). 他にコツはありますか?

私が現在手がかりを持っていないもう1つのことは、ユーザーがアプリをアンインストール/再インストールしたときにトランザクションステータスを復元する方法です. APIにはそのためのメカニズムがいくつかあることを知っています。さらに、アプリを介してデータベースをエクスポートおよびインポートできます(したがって、エンコードされたisPremiumフラグもエクスポート/インポート可能になります)。わかりました、それは別の質問になると思います。その時が来たら ;-)

このアプローチに対する考えやコメントは大歓迎です。それは良い解決策だと思いますか? または、何かが足りない/間違った方向に進んでいますか?

4

4 に答える 4

18

私も同じ調査を行っていましたが、テスト中に、Google が必要なすべてのキャッシングを行っているため、保存する必要がないことがわかりました (調査はしていませんが)。可能な限り(彼らの利益にもなると考えています!)

だからここに私がすることがあります

// Done in onCreate
mHelper = new IabHelper(this, getPublicKey());

mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
      if (!result.isSuccess()) {
         // Oh noes, there was a problem.
         Log("Problem setting up In-app Billing: " + result);
      } else {
         Log("onIabSetupFinished " + result.getResponse());
         mHelper.queryInventoryAsync(mGotInventoryListener);
     }
    }
});

// Called by button press
private void buyProUpgrade() {
    mHelper.launchPurchaseFlow(this, "android.test.purchased", 10001,   
           mPurchaseFinishedListener, ((TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId());
}

// Get purchase response
private IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
    public void onIabPurchaseFinished(IabResult result, Purchase purchase) 
    {
       if (result.isFailure()) {
          Log("Error purchasing: " + result);
          return;
       }      
       else if (purchase.getSku().equals("android.test.purchased")) {
      Log("onIabPurchaseFinished GOT A RESPONSE.");
              mHelper.queryInventoryAsync(mGotInventoryListener);
      }
    }
};

// Get already purchased response
private IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
    public void onQueryInventoryFinished(IabResult result,
       Inventory inventory) {

       if (result.isFailure()) {
         // handle error here
           Log("Error checking inventory: " + result); 
       }
       else {
         // does the user have the premium upgrade?        
         mIsPremium = inventory.hasPurchase("android.test.purchased");        
         setTheme();

         Log("onQueryInventoryFinished GOT A RESPONSE (" + mIsPremium + ").");
       }
    }
};

それで、ここで何が起こりますか?

IAB がセットアップされstartSetup、 が正常に完了すると (インターネット接続で一度実行され、正しくセットアップされている限り、常に成功します) を呼び出しqueryInventoryAsyncて、既に購入されているものを見つけます (これが既に購入されている場合)。オンライン中に呼び出され、オフライン中は常に機能します)。

そのため、購入が正常に完了した場合 (オンラインでのみ実行可能)、オンライン中に呼び出さqueryInventoryAsyncれたことを確認するために呼び出します。

購入に関係するものを保存する必要がなくなり、アプリがハッキングされにくくなります。

私はこれを多くの方法でテストしました。機内モード、デバイスの電源を入れ直したとき、それを台無しにする唯一のことは、電話のいくつかの Google アプリのデータを消去することです (起こりそうにありません!)。

さまざまな経験がある場合は、これに貢献してください。私のアプリはまだ初期テスト段階です。

于 2013-03-22T11:39:57.383 に答える
7

スナークからのコメントを含め、ne0 の回答を静的メソッドにリファクタリングしました。

アプリの起動時にこのメソッドを呼び出します - で機能を有効にする必要がありますTODO

/**
 * This is how you check with Google if the user previously purchased a non-consumable IAP
 * @param context App Context
 */
public static void queryPlayStoreForPurchases(Context context)
{
    final IabHelper helper = new IabHelper(context, getPublicKey());

    helper.startSetup(new IabHelper.OnIabSetupFinishedListener() 
    {
         public void onIabSetupFinished(IabResult result) 
         {
               if (!result.isSuccess()) 
               {
                   Log.d("InApp", "In-app Billing setup failed: " + result);
               } 
               else 
               {  
                    helper.queryInventoryAsync(false, new IabHelper.QueryInventoryFinishedListener()
                    {
                        public void onQueryInventoryFinished(IabResult result, Inventory inventory)
                        {
                            // If the user has IAP'd the Pro version, let 'em have it.
                            if (inventory.hasPurchase(PRO_VERSION_SKU))
                            {
                                //TODO: ENABLE YOUR PRO FEATURES!! 

                                Log.d("IAP Check", "IAP Feature enabled!");
                            }
                            else
                            {
                                Log.d("IAP Check", "User has not purchased Pro version, not enabling features.");

                            }
                        }
                    });
               }
         }
    });
}

これは、ユーザーがアイテムを購入した場合、再起動後もネットワーク接続なしで機能します。

于 2015-08-10T23:28:50.253 に答える
4

このシステムを使用してハッキングできないようにすることは不可能であることをすでに知っているので、ハッキングを防止しようとしないことをお勧めします。あなたが提案しているものは「隠すことによるセキュリティ」として知られており、通常は悪い考えです。

私のアドバイスはqueryInventoryAsync()、最初に試して、インターネットに接続されていない場合にのみ「isPremium」フラグを確認することです。

アプリ内購入の代わりに、無料アプリとプレミアムアプリを別々に用意するなど、これを実現する他の方法もいくつか考えられます。他の人がこれをどのように処理するか、そしてグーグルが利用できるツールは調査を正当化するかもしれません。

queryInventoryAsyncログインしたユーザーの購入を追跡するため、アンインストールと再インストールが自動的に考慮されます。

于 2013-01-27T03:59:13.333 に答える