web-dev-qa-db-ja.com

プロンプトAndroidアプリのユーザーが現在のバージョン<>マーケットバージョンの場合にアプリを更新する

私のAndroidアプリバージョン0.1が現在ユーザーの電話にインストールされているとしましょう。彼らが私のアプリを起動するたびに、Androidマーケットで利用可能な別のバージョンがあるかどうかを確認したいのですが、このバージョンが0.2だとしましょう。これら2つのバージョンの間に不一致がある場合は、ユーザーにアプリをアップグレードするように求めるダイアログボックスを表示します。

Android Market自体からユーザーへの通知手順が存在することは完全に理解していますが、アナリティクスデータに関する限り、ユーザーにアプリの新しいバージョンにアップグレードするよう通知することはあまり効果的ではありません。

どんな洞察も非常に役に立ちます。 StackOverflowersに感謝します。

23
Aakash

2019年現在、アプリを更新する最善の方法は、Playコアライブラリ(1.5.0以降)によって提供されるアプリ内更新を使用することです。これはLollipop以降で機能しますが、公平を期すと、Kit-Katは現在のところ7%未満であり、間もなく完全になくなります。このコードは、バージョンチェックなしでKit-Katで安全に実行でき、クラッシュしません。

公式ドキュメント: https://developer.Android.com/guide/app-bundle/in-app-updates

アプリ内アップデートには、FlexibleImmediateの2種類があります。

Flexibleはダイアログウィンドウでうまく表示されます: enter image description here

一方、Immediateでは、アプリをフルスクリーンメッセージで引き続き使用するには、アプリを更新する必要があります(このページは閉じることができます):

enter image description here

重要:現時点では、アプリで展開する更新の種類を選択することはできませんDeveloper Play Consoleのリリースセクション。しかし、どうやら、彼らはすぐにそのオプションを私たちに与えるでしょう。私がテストしたものから、現在、onSuccessListenerで両方のタイプが利用可能になっています。

コードにboth型を実装してみましょう。

モジュールbuild.gradleに、次の依存関係を追加します。

dependencies {
    implementation 'com.google.Android.play:core:1.6.1'//for new version updater
}

MainActivity.class

private static final int REQ_CODE_VERSION_UPDATE = 530;
private AppUpdateManager appUpdateManager;
private InstallStateUpdatedListener installStateUpdatedListener;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

   checkForAppUpdate();
}

@Override
protected void onResume() {
    super.onResume();
    checkNewAppVersionState();
}

@Override
public void onActivityResult(int requestCode, final int resultCode, Intent intent) {
    super.onActivityResult(requestCode, resultCode, intent);

    switch (requestCode) {

        case REQ_CODE_VERSION_UPDATE:
            if (resultCode != RESULT_OK) { //RESULT_OK / RESULT_CANCELED / RESULT_IN_APP_UPDATE_FAILED
                L.d("Update flow failed! Result code: " + resultCode);
                // If the update is cancelled or fails,
                // you can request to start the update again.
                unregisterInstallStateUpdListener();
            }

            break;
    }
}

@Override
protected void onDestroy() {
    unregisterInstallStateUpdListener();
    super.onDestroy();
}


private void checkForAppUpdate() {
    // Creates instance of the manager.
    appUpdateManager = AppUpdateManagerFactory.create(AppCustom.getAppContext());

    // Returns an intent object that you use to check for an update.
    Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();

    // Create a listener to track request state updates.
    installStateUpdatedListener = new InstallStateUpdatedListener() {
        @Override
        public void onStateUpdate(InstallState installState) {
            // Show module progress, log state, or install the update.
            if (installState.installStatus() == InstallStatus.DOWNLOADED)
                // After the update is downloaded, show a notification
                // and request user confirmation to restart the app.
                popupSnackbarForCompleteUpdateAndUnregister();
        }
    };

    // Checks that the platform will allow the specified type of update.
    appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
        if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
            // Request the update.
            if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)) {

                // Before starting an update, register a listener for updates.
                appUpdateManager.registerListener(installStateUpdatedListener);
                // Start an update.
                startAppUpdateFlexible(appUpdateInfo);
            } else if (appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE) ) {
                // Start an update.
                startAppUpdateImmediate(appUpdateInfo);
            }
        }
    });
}

private void startAppUpdateImmediate(AppUpdateInfo appUpdateInfo) {
    try {
        appUpdateManager.startUpdateFlowForResult(
                appUpdateInfo,
                AppUpdateType.IMMEDIATE,
                // The current activity making the update request.
                this,
                // Include a request code to later monitor this update request.
                MainActivity.REQ_CODE_VERSION_UPDATE);
    } catch (IntentSender.SendIntentException e) {
        e.printStackTrace();
    }
}

private void startAppUpdateFlexible(AppUpdateInfo appUpdateInfo) {
    try {
        appUpdateManager.startUpdateFlowForResult(
                appUpdateInfo,
                AppUpdateType.FLEXIBLE,
                // The current activity making the update request.
                this,
                // Include a request code to later monitor this update request.
                MainActivity.REQ_CODE_VERSION_UPDATE);
    } catch (IntentSender.SendIntentException e) {
        e.printStackTrace();
        unregisterInstallStateUpdListener();
    }
}

/**
 * Displays the snackbar notification and call to action.
 * Needed only for Flexible app update
 */
private void popupSnackbarForCompleteUpdateAndUnregister() {
    Snackbar snackbar =
            Snackbar.make(drawerLayout, getString(R.string.update_downloaded), Snackbar.LENGTH_INDEFINITE);
    snackbar.setAction(R.string.restart, new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            appUpdateManager.completeUpdate();
        }
    });
    snackbar.setActionTextColor(getResources().getColor(R.color.action_color));
    snackbar.show();

    unregisterInstallStateUpdListener();
}

/**
 * Checks that the update is not stalled during 'onResume()'.
 * However, you should execute this check at all app entry points.
 */
private void checkNewAppVersionState() {
    appUpdateManager
            .getAppUpdateInfo()
            .addOnSuccessListener(
                    appUpdateInfo -> {
                        //FLEXIBLE:
                        // If the update is downloaded but not installed,
                        // notify the user to complete the update.
                        if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
                            popupSnackbarForCompleteUpdateAndUnregister();
                        }

                        //IMMEDIATE:
                        if (appUpdateInfo.updateAvailability()
                                == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
                            // If an in-app update is already running, resume the update.
                            startAppUpdateImmediate(appUpdateInfo);
                        }
                    });

}

/**
 * Needed only for FLEXIBLE update
 */
private void unregisterInstallStateUpdListener() {
    if (appUpdateManager != null && installStateUpdatedListener != null)
        appUpdateManager.unregisterListener(installStateUpdatedListener);
}

これで完了です。

テスト。docs を読んで、Google Playのテストトラックで適切にテストする方法を理解してください。

短い話:

  1. リリース証明書を使用してアプリに署名し、アプリのリリースの下のDeveloper Play Consoleの公開トラックの1つにアップロードします(アルファ/ベータ/その他のカスタムクローズドトラック)。

  2. [テスターの管理]セクションのリリーストラックページで、テスターのリストを作成して追加し、チェックボックスをオンにしたことを確認します! -開発者アカウントのメールはテスターアカウントでもあり、テストに使用できるため、この手順はオプションです。

  3. テスターのリストの下に「オプトインURL」があります-このURLをコピーしてテスターに​​渡すか、自分で開いてください。そのページに移動して、テストの提案を受け入れます。アプリへのリンクがあります。 (Playストアでアプリを検索できないため、ブックマークしてください)

  4. そのリンクを使用してデバイスにアプリをインストールします。

  5. build.gradledefaultConfig { versionCode k+1 }のバージョンをインクリメントし、別の署名済みapkをビルドします。ビルド>署名済みバンドル/ APKを生成......を発行トラックにアップロードします。

  6. 待って... 1時間? 2時間?トラックに公開される前に.

  7. デバイス上のPlayストアアプリのキャッシュをクリアします。問題は、Playアプリがインストール済みアプリと利用可能なアップデートに関する詳細をキャッシュするため、キャッシュをクリアする必要があることです。そのためには、次の2つの手順を実行します。

7.1。 [設定]> [アプリ]> [Google Playストア]> [ストレージ]> [キャッシュを消去]に移動します。

7.2。 Playストアアプリを開き、メインメニューを開き、[マイアプリとゲーム]を選択すると、アプリに新しいアップデートが表示されます。

表示されない場合は、新しいアップデートがすでにトラックでリリースされていることを確認してください(ブックマークされたページに移動し、それを使用してPlayストアのアプリリストを開いて、そこに表示されているバージョンを確認します)。また、アップデートが公開されると、デベロッパーPlay Consoleの右上に通知が表示されます(ベルのアイコンに赤い点が表示されます)。

それが役に立てば幸い。

24
Kirill Karmazin

Androidマーケットはクローズドシステムであり、いつでも壊れる可能性のある非公式のAPIしかありません。

あなたの最善の策は、あなたが自分のWebサーバーでファイル(xml、jsonまたは単純なテキスト)をホストすることです。この場合、マーケットに投稿するときに、アプリの現在のバージョンを更新するだけです。

その後、アプリは起動時にそのファイルをフェッチするだけでよく、現在インストールされているアプリのバージョン番号が低いかどうかを確認し、遅れていることをユーザーに警告するダイアログを表示します。

16
Yahel

承認済みの回答で提案されているように、現在のアプリバージョンをバックエンドサーバーに保存しないようにする場合に使用できるもう1つのオプションは、 Googleタグマネージャー (GTM)を使用することです。

すでにGoogle Analytics SDKを使用している場合は、GTMも含まれています。

GTMでは、アプリのコンテナに最新のリリースバージョンを指定する値を定義できます。例えば:

{
   "latestAppVersion": 14,
   ...
}

次に、アプリの起動時にその値をクエリし、新しいバージョンがある場合はユーザー更新ダイアログのリマインダーを表示できます。

Container container = TagManager.getInstance(context).openContainer(myContainerId);
long latestVersionCode = container.getLong("latestAppVersion");

// get currently running app version code
PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
long versionCode = pInfo.versionCode;

// check if update is needed
if(versionCode < latestVersionCode) {
   // remind user to update his version
}
5
luben

Android Market APIのクエリに使用できるこのライブラリを見てください。

http://code.google.com/p/Android-market-api/

4
Ollie C

これを使用できますAndroid Library: https://github.com/danielemaddaluno/Android-Update-Checker 。これは、非同期でチェックする再利用可能な計測器を提供することを目的としていますストアにアプリの新しいリリースされたアップデートが存在します。これは、Jsoup( http://jsoup.org/ )を使用して、アプリページを解析する新しいアップデートが実際に存在するかどうかをテストすることに基づいていますGoogle Playストア:

private boolean web_update(){
    try {       
        String curVersion = applicationContext.getPackageManager().getPackageInfo(package_name, 0).versionName; 
        String newVersion = curVersion;
        newVersion = Jsoup.connect("https://play.google.com/store/apps/details?id=" + package_name + "&hl=en")
                .timeout(30000)
                .userAgent("Mozilla/5.0 (Windows; U; WindowsNT 5.1; en-US; rv1.8.1.6) Gecko/20070725 Firefox/2.0.0.6")
                .referrer("http://www.google.com")
                .get()
                .select("div[itemprop=softwareVersion]")
                .first()
                .ownText();
        return (value(curVersion) < value(newVersion)) ? true : false;
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
}

そして、「値」関数として、次のようになります(値が0〜99の場合に機能します)。

private long value(String string) {
    string = string.trim();
    if( string.contains( "." )){ 
        final int index = string.lastIndexOf( "." );
        return value( string.substring( 0, index ))* 100 + value( string.substring( index + 1 )); 
    }
    else {
        return Long.valueOf( string ); 
    }
}

バージョン間の不一致を確認するだけの場合は、次のように変更できます。

"value(curVersion)<value(newVersion)" with "value(curVersion)!= value(newVersion)"

4
madx
    My working Kotlin code for force App update: 

    var appUpdateManager: AppUpdateManager? = null
    const val FLEXIABLE_UPADTE: Int = 101
    const val FORCE_UPDATE: Int = 102
    const val APP_UPDATE_CODE: Int = 500

    override fun onCreate {
    // Get updateType from Webservice.
     updateApp(updateType)
    }

    private fun updateApp(statusCode: Int) {
        appUpdateManager = AppUpdateManagerFactory.create(this@MainActivity)

        val appUpdateInfoTask = appUpdateManager?.appUpdateInfo

        appUpdateInfoTask?.addOnSuccessListener { appUpdateInfo ->
            if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
            ) {
                if ((statusCode == Constants.FORCE_UPDATE))
                    appUpdateManager?.startUpdateFlowForResult(
                        appUpdateInfo, AppUpdateType.IMMEDIATE, this, Constants.APP_UPDATE_CODE
                    )
                else if (statusCode == Constants.FLEXIABLE_UPADTE)
                    appUpdateManager?.startUpdateFlowForResult(
                        appUpdateInfo, AppUpdateType.FLEXIBLE, this, Constants.FLEXIABLE_UPADTE
                    )
            }
        }
    }

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {

 try {
            if (requestCode == Constants.APP_UPDATE_CODE && resultCode == Activity.RESULT_OK) {
                if (resultCode != RESULT_OK) {
                    appUpdateCompleted()
                }
            }
        } catch (e: Java.lang.Exception) {

        }
}

 private fun appUpdateCompleted() {
       Snackbar.make(
    findViewById(R.id.activity_main_layout),
    "An update has just been downloaded.",
    Snackbar.LENGTH_INDEFINITE
).apply {
    setAction("RESTART") { appUpdateManager.completeUpdate() }
    setActionTextColor(resources.getColor(R.color.snackbar_action_text_color))
    show()
}

    }
0
BAIJU SHARMA

Androidアプリのユーザーがアプリを更新するように求める現在のバージョンが市場のバージョンと等しくない場合は、最初に市場のアプリのバージョンを確認し、デバイス上のアプリのバージョンと比較する必要があります。それらが異なる場合、アップデートが利用可能である可能性があります。この投稿では、デバイスの現在のバージョンの市場と現在のバージョンを取得するコードを書き留めて、それらを比較します。また、更新ダイアログを表示してリダイレクトする方法も示しました更新ページへのユーザー。このリンクにアクセスしてください: https://stackoverflow.com/a/33925032/5475941

0
Vahid