46

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

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

4

1 に答える 1

178

私はしばらくの間、アプリにライセンスを実装することに取り組んできましたが、ついに機能しました。始めるのに役立つとわかったいくつかのことと、見つけたいくつかの問題と解決策をみんなと共有したかった. 以下にリンクした 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. 塩とは?

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

b. どうすれば取得できますか?

これは、ランダム ソルトを生成するための適切なリンクです。正確に20 個のランダムな整数が存在する必要がある20ため、生成するランダムな文字列の量を入力します。各文字列は2文字の長さである必要があります (この例では使用されていますが、そうである必要はありません)。数字を確認し、同一の文字列が許可されていることを確認します。負の数になることもあります。00 -> 0一貫性を保つために、冗長性を取り除くようにしてください。

c. 塩はどこに入れるの?

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

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

2. Eclipse への LVL (ライセンス) ライブラリのインポートと必要なコード

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

a. 開けるAndroid SDK Manager

b. に行くExtras

c. インストールGoogle Play Licensing Library

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

e. そこに着いたら、次の場所に移動します。<sdk>/extras/google/play_licensing

f. Eclipse で をクリックしfileてから、ファイル パスを尋ねられたら、フォルダに移動して をクリックします。importExisting Android Code Into Workspaceplay_licensinglibrary

g. という名前のプロジェクトlibraryがインポートされたら、それを右クリックして を押しますpropertiesAndroid左側をクリックして一番下に移動し、 にチェックを入れてからIs Library、適用をクリックします。これにより、このプロジェクト コードをライブラリとして使用できることが eclipse に通知されます。

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

私。プロジェクトは次のステップに進む準備ができています。

SALT2.2 andとともに宣言する変数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 シリアルを使用するかどうかについていくつかの議論がありましたが、互換性を最大限に高めるために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 の実装を行っていたとき、ライセンスに問題がある場合はthisto の最初をmChecker = new LicenseChecker(this...変更できることを読みgetApplicationContext()ました。

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 使用中の暗号SharedPreferencesSecurePreferences

a. このリンクに移動します。

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

c. ReadMe.mdこれを実装する方法については、 をお読みください。

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

ライセンシングは、問題が発生する可能性のある問題が他にもたくさんあるという理由だけで、トラブルシューティングを行う上で頭の痛い問題になる可能性があります。たとえば、髪を引き裂きたくなるようなネットワークの問題やサーバーの問題が発生している可能性があります。適切なログを使用すると、これに役立ちます。問題が発生した場合は、サーバーの応答コードを取得して、サーバーまたはアプリまで追跡できます。私は何度もこれをしなければなりませんでした。

5.1 アプリがサーバーから何も返せません

考えられる修正:

a. アプリに正しいKEY.

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

c. ライセンス サービスからのログを確認してください。どこで問題が発生したかを把握するのに役立ちます。

d. allow()dontAllow()とタグapplicationError()があることを確認してください。@Override

5.2テスト応答で設定した内容に関係なく、アプリは常にLICENSEDorと言うNOT_LICENSED

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

b. Google Play アプリと Google Play サービス アプリのデータ (キャッシュだけでなく) を消去できます。次に、再生を開き、すべてのライセンスに同意して、もう一度やり直してください。

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 さらに余裕が!彼らは来るでしょう!

これが皆さんのお役に立てば幸いです!頭痛の種と修正点をできる限り皆さんと共有しようとしましたが、これがお役に立てば幸いです!

エラーが発生した場合は、できるだけ早く修正できるように、必ずお知らせください。

于 2013-08-20T01:45:22.937 に答える