web-dev-qa-db-ja.com

AndroidアプリにGoogle Playライセンスを実装するにはどうすればよいですか?

標準のAndroid-Developerライセンスライブラリ instructions を見ましたが、概要ではプロセスのいくつかの重要な手順が省略されているようで、何かを動作させる方法を完全に説明できません。

Androidアプリでライセンスライブラリを設定するために動作する明示的な操作セットを提供して、ユーザーが使用を許可する前にGoogle Playでアプリの支払いを行っていることを確認できますか?

39
Code_Insanity

私はしばらくの間、アプリにライセンスを実装することに取り組んでおり、最終的には機能させています。始めるのに役立つと思うものと、見つけた問題や解決策をみんなと共有したかった。以下にリンクしたAndroid devチュートリアルは大丈夫ですが、それは私にとってはあまり有用ではなかったので、チュートリアルを作成することにしました。お楽しみください。

開発者ページへのリンク こちら

1.はじめに

必要なもの。

1.1 Base64固有のアプリケーションキー

入手方法:

a。開発者コンソールに移動します。 リンク

b。アプリのアプリケーションドラフトをまだ作成していない場合は、今すぐ作成してください。

c。ドラフトを作成したら、_.apk_をアルファまたはベータとしてアップロードすることをお勧めします。未公開のままにします。

d。 _Services & APIs_をクリックします

e。下にスクロールして_YOUR LICENSE KEY FOR THIS APPLICATION_を見つけます

f。次のようにキーをアプリにコピーします。

_private static final String BASE64_PUBLIC_KEY = "YOUR LICENSE KEY FOR THIS APPLICATION"; 
_

スペースがないことを確認してください。

1.2 A塩

a。塩とは?

salt は、パスワードをハッシュする際の追加入力であるランダムデータです。これらは、 辞書攻撃 および レインボーテーブル 攻撃に対する防御に使用されます。

b。どうすれば入手できますか?

これ は、ランダムなソルトを生成するのに適したリンクです。 正確に 20のランダムな整数があるはずなので、生成するランダムな文字列の量に_20_を入れてください。各文字列は_2_文字長でなければなりません(この例では、する必要があります)。数字を確認し、同一の文字列が許可されていることを確認します。負の数も可能です。冗長性を削除してみてください。 _00 -> 0_、一貫性のため。

c。塩はどこに入れますか?

変数を宣言するときは、ランダムなソルトを除き、このコードを挿入するだけです。

_private static final byte[] SALT = new byte[] {YOUR RANDOM SALT, COMMA SEPARATED, 20 INTEGERS};
_

2. LVL(ライセンス)ライブラリをEclipseと必要なコードにインポートする

2.1ライブラリのインポート

a。 _Android SDK Manager_を開きます

b。 Extrasに移動します

c。 _Google Play Licensing Library_をインストールします

d。 SDKマネージャーの上部にリストされているSDKインストールパスを見つけます。

e。そこに着いたら、_<sdk>/extras/google/play_licensing_に移動します

f。 Eclipseでfileをクリックしてからimportをクリックしてから_Existing Android Code Into Workspace_をクリックし、ファイルパスの入力を求められたら、_play_licensing_フォルダーに移動してlibrary

g。 libraryという名前のプロジェクトがインポートされたら、それを右クリックし、propertiesを押します。左側の[Android]をクリックして下に移動し、_Is Library_を確認してから[適用]をクリックします。これにより、Eclipseは、このプロジェクトコードをライブラリとして使用できることを認識します。

h。ライセンスを追加するアプリを右クリックし、プロパティをクリックして、Androidを押します。一番下に移動してlibraryをクリックし、ビルドパスに追加します。これにより、ライブラリが_Android Dependencies_フォルダーにインポートされます。

私。プロジェクトは次のステップに進むように設定されています。

2.2 SALTおよびKEYとともに宣言する変数

_private Handler mHandler;
private LicenseChecker mChecker;
private LicenseCheckerCallback mLicenseCheckerCallback;
boolean licensed;
boolean checkingLicense;
boolean didCheck;
_

2.3コード

このコードをアプリの下部近くに貼り付けます。この実装は、ライセンスが有効でない場合にユーザーに通知し、アプリの購入または終了を促すメッセージを表示します。

_    private void doCheck() {

        didCheck = false;
        checkingLicense = true;
        setProgressBarIndeterminateVisibility(true);

        mChecker.checkAccess(mLicenseCheckerCallback);
    }


    private class MyLicenseCheckerCallback implements LicenseCheckerCallback {

        @Override
        public void allow(int reason) {
            // TODO Auto-generated method stub
            if (isFinishing()) {
                // Don't update UI if Activity is finishing.
                return;
            }               
            Log.i("License","Accepted!");       

                //You can do other things here, like saving the licensed status to a
                //SharedPreference so the app only has to check the license once.

            licensed = true;
            checkingLicense = false;
            didCheck = true;

        }

        @SuppressWarnings("deprecation")
        @Override
        public void dontAllow(int reason) {
            // TODO Auto-generated method stub
             if (isFinishing()) {
                    // Don't update UI if Activity is finishing.
                    return;
                }
                Log.i("License","Denied!");
                Log.i("License","Reason for denial: "+reason);                                                                              

                        //You can do other things here, like saving the licensed status to a
                        //SharedPreference so the app only has to check the license once.

                licensed = false;
                checkingLicense = false;
                didCheck = true;               

                showDialog(0);

        }

        @SuppressWarnings("deprecation")
        @Override
        public void applicationError(int reason) {
            // TODO Auto-generated method stub
            Log.i("License", "Error: " + reason);
            if (isFinishing()) {
                // Don't update UI if Activity is finishing.
                return;
            }
            licensed = true;
            checkingLicense = false;
            didCheck = false;

            showDialog(0);
        }


    }

    protected Dialog onCreateDialog(int id) {
        // We have only one dialog.
        return new AlertDialog.Builder(this)
                .setTitle("UNLICENSED APPLICATION DIALOG TITLE")
                .setMessage("This application is not licensed, please buy it from the Play Store.")
                .setPositiveButton("Buy", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(
                                "http://market.Android.com/details?id=" + getPackageName()));
                        startActivity(marketIntent);
                        finish();
                    }
                })
                .setNegativeButton("Exit", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                })
                .setNeutralButton("Re-Check", new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        doCheck();
                    }
                })

                .setCancelable(false)
                .setOnKeyListener(new DialogInterface.OnKeyListener(){
                    public boolean onKey(DialogInterface dialogInterface, int i, KeyEvent keyEvent) {
                        Log.i("License", "Key Listener");
                        finish();
                        return true;
                    }
                })
                .create();

    }
_

2.4デバイスIDの取得

これについては、過去にsim serialまたはTelephonyManager.getDeviceId();を使用するかどうかについて議論がありましたが、次のコードを使用してデバイスの_Android_ID_を最大限に取得することをお勧めします互換性。

_String deviceId = Secure.getString(getContentResolver(), Secure.Android_ID);
Log.i("Device Id", deviceId);  //AN EXAMPLE OF LOGGING THAT YOU SHOULD BE DOING :)
_

2.5ライセンスチェッカーの作成

a。 doCheck();を呼び出す前に、このコードをアプリに配置して、すべてが正しく作成されることを確認する必要があります。

_mHandler = new Handler();
mLicenseCheckerCallback = new MyLicenseCheckerCallback();
mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, new   AESObfuscator(SALT, getPackageName(), deviceId)), BASE64_PUBLIC_KEY);
_

LVLの実装を行っていたときに、ライセンスに問題がある場合は、_mChecker = new LicenseChecker(this..._の最初のthisgetApplicationContext()に変更できると読みました。それなしで動作しますが、念のため。

2.6許可の追加

a。アプリケーションmanifestファイルに追加する必要がある2つの権限があります。

_<uses-permission Android:name="Android.permission.INTERNET"/>  
<uses-permission Android:name="com.Android.vending.CHECK_LICENSE"/>        
_

2.7適切なインポートがあることを確認してください!

おそらく既にこれを行っていますが、確認するのに適した場所であると考えました。

2.8チェックするライセンスを呼び出す方法

a。ライセンスを確認したいときはいつでもdoCheck();を呼び出すだけです。たとえば、アプリが最初に実行されている場合、チェックを行います。

3.公開する前にライセンスをテストして、機能することを確認するにはどうすればよいですか?

3.1テストデバイスの設定

a。私はテストにも使用する個人の電話を持っています。電話に登録するGoogleアカウントは1つだけにすることをお勧めします。歴史的には、これにより少し簡単になります。 _Settings -> Accounts_にアクセスして、アカウントを確認できます。

3.2開発者コンソールの構成

a。開発者コンソールを開き、左側のSettingsに移動します。

b。 _License Testing_を検索

c。メールアドレスが_Gmail accounts with testing access_の下にリストされていることを確認してください

d。これで、テストの目的に合わせて、テストの応答を好きなものに変更できます。アプリはそれに応じて応答する必要があります。 SharedPrefsを使用してデータを保存している場合は、テストするたびにアプリデータをクリアする必要があることに注意してください。 テスト応答を変更した後、必ず[保存]をクリックしてください。そうしないと何も起こりません。 このことを何度も忘れてしまい、片頭痛になってしまいました。そして、その臭い保存ボタンを見ました。笑。

4.試すべきこと

4.1条件付きライセンスチェック

a。 didCheckデータをSharedPreferencesに保存している場合、このコードを試すことができます。

_ if(didCheck==false){
        Toast.makeText(this, "Checking application license...",     Toast.LENGTH_SHORT).show();
        doCheck();
        Log.i("Checking!", "Checking license!");
    }   
_

4.2 SharedPreferencesを使用したSecurePreferencesの暗号化

a。これに移動します link

b。 _SecurePreferences.Java_のコードをコピーして、プロジェクトとまったく同じ名前のクラスに貼り付けます。

c。これの実装に関する情報については_ReadMe.md_を読んでください。

5.トラブルシューティング

ライセンスが問題を解決するための頭痛の種の1つである場合があります。たとえば、ネットワークの問題やサーバーの問題が原因で、髪を引き裂きたい場合があります。適切なロギングを使用するとこれに役立ちます。問題がある場合はサーバーの応答コードを取得し、サーバーまたはアプリにトレースできます。私はこれを複数の機会に行わなければなりませんでした。

5.1アプリからサーバーから何も返せない

可能な修正:

a。アプリに正しいKEYがあることを確認してください。

b。進行状況の各ステップを記録していることを確認してください

c。ライセンスサービスのログを確認してください。何かがうまくいかなかった場所を特定するのに役立ちます。

d。 allow()およびdontAllow()およびapplicationError()に_@Override_タグがあることを確認してください。

5.2テスト応答で設定した内容に関係なく、アプリは常にLICENSEDまたは_NOT_LICENSED_と表示します

a。これに対する最善の治療法は、ただ待つことです。短期間で多くのテストを行うと、常に再試行コードであるサーバーコード_291_が送信されるようです。私は一晩待って、翌朝はすべてうまくいった。

b。 Google PlayアプリとGoogle Play Servicesアプリのデータ(キャッシュだけでなく)をクリアできます。次に、再生を開き、すべてのライセンスを受け入れて、再試行します。

c。アプリのデータを消去します。

5.3デバッグ用のサーバー応答コードのリスト

ログに記録する場合は、_int reason_のこれらの10進数値を取得する必要があります。この表を使用して、サーバーが実際にアプリに送信しているものを参照します。

_LICENSED = Hex: 0x0100, Decimal: 256
NOT_LICENSED = Hex: 0x0231, Decimal: 561
RETRY = Hex: 0x0123, Decimal: 291
LICENSED_OLD_KEY = Hex: 0x2, Decimal: 2
ERROR_NOT_MARKET_MANAGED = Hex: 0x3, Decimal: 3
ERROR_SERVER_FAILURE = Hex: 0x4, Decimal: 4
ERROR_OVER_QUOTA = Hex: 0x5, Decimal: 5
ERROR_CONTACTING_SERVER = Hex: 0x101, Decimal: 257
ERROR_INVALID_PACKAGE_NAME = Hex: 0x102, Decimal: 258 
ERROR_NON_MATCHING_UID = Hex: 0x103, Decimal: 259
_

5.4さらに余裕があります!彼らが来ます!

これが皆さんのお役に立てば幸いです!私は頭痛の種と修正をできるだけ多くの皆さんと共有しようとしましたが、これが役立つことを願っています!

エラーが発生した場合、できるだけ早く修正できるように、必ずそれらについて教えてください!

152
Code_Insanity