新しいバージョンが利用可能になったときにAndroidアプリを強制的に更新する


100

Google Playストアにアプリを持っています。更新バージョンが利用可能になると、古いバージョンは使用できなくなります。つまり、ユーザーがアプリを更新しないと、アプリにアクセスできません。新しいバージョンが利用可能になったときに、ユーザーにアプリの更新を強制するにはどうすればよいですか?


1
このオープンソースのGitHubプロジェクト(MAHAndroidUpdater)は、この機能を完全に提供しています。それを試してください、非常に簡単です。github.com/hummatli/MAHAndroidUpdater
Sattar Hummatli 16

回答:


99

ここでの別の回答におけるScott Helmeのポイントに同意します。ただし、アプリの使用を継続するにはユーザーに更新を絶対に必要とする極端な状況(セキュリティの問題、APIの重大な変更など)では、単純なバージョン管理APIを提供できます。APIは次のようになります。

versionCheck API:

リクエストパラメータ:

  • int appVersion

応答

  1. boolean forceUpgrade
  2. boolean recommendUpgrade

アプリの起動時に、現在のアプリのバージョンを渡すこのAPIを呼び出して、バージョン管理API呼び出しの応答を確認できます。

の場合forceUpgradetrue、ユーザーにアプリの終了を許可するか、Google Playストアにアクセスしてアプリをアップグレードするかのオプションを含むポップアップダイアログを表示します。

そうでない場合recommendUpgradetrue、更新するか、アプリの使用を継続するかを選択するポップアップダイアログを表示します。

この強制アップグレード機能が導入されている場合でも、絶対に必要でない限り、引き続き古いバージョンをサポートする必要があります。


アプリが起動し、recommendUpgradeがtrueになるたびにポップアップを表示しますか?(UXの観点から)または、ポップアップを1回だけ表示し、ユーザーがアップグレードを拒否した場合は再度表示しないようにします。
Aneesh

8
推奨されるアップグレードについては、ユーザーが拒否した場合は再度表示しないようにしてください。また、「ユーザーがアプリを開いた回数n回」を表示することもできます。自分でn値を決定して実装することができます。
Michael

3
より良いソリューションimoは、すべてのAPI呼び出しのヘッダーでアプリのバージョンを体系的に渡し、APIがバージョンが古くなっていることを検出した場合に特定のステータスコードを返すようにすることです。アプリ内で処理します。これは、このチェックのためにさらに別の専用APIを呼び出す必要があり、このAPI呼び出しがアプリ/サービス内でいつどこで行われるべきかを正確に把握する必要があるよりも優れています。
Raphael C

@RaphaelCこれは本当にサーバー側の実装に依存します。状況によっては、すべてのAPIのバージョンをチェックするフィルターを追加するのも完全ではありません。
9月GH

4
@SepGHの事情は変わっており、AndroidではAPIを提供しています。これを使用して、ユーザーにアップグレードを強制し、最小バージョンにアップグレードしない場合にアプリの使用をブロックすることができます: developer.android.com/guide/ app-bundle / in-app-updates
Raphael C

55

これを試してください:まず、playstoreリンクへのリクエストコールを作成し、そこから現在のバージョンをフェッチして、それを現在のバージョンと比較する必要があります。

String currentVersion, latestVersion;
Dialog dialog;
private void getCurrentVersion(){
 PackageManager pm = this.getPackageManager();
        PackageInfo pInfo = null;

        try {
            pInfo =  pm.getPackageInfo(this.getPackageName(),0);

        } catch (PackageManager.NameNotFoundException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        currentVersion = pInfo.versionName;

   new GetLatestVersion().execute();

}

private class GetLatestVersion extends AsyncTask<String, String, JSONObject> {

        private ProgressDialog progressDialog;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected JSONObject doInBackground(String... params) {
            try {
//It retrieves the latest version by scraping the content of current version from play store at runtime
                Document doc = Jsoup.connect(urlOfAppFromPlayStore).get();
                latestVersion = doc.getElementsByClass("htlgb").get(6).text();

            }catch (Exception e){
                e.printStackTrace();

            }

            return new JSONObject();
        }

        @Override
        protected void onPostExecute(JSONObject jsonObject) {
            if(latestVersion!=null) {
                if (!currentVersion.equalsIgnoreCase(latestVersion)){
                   if(!isFinishing()){ //This would help to prevent Error : BinderProxy@45d459c0 is not valid; is your activity running? error
                    showUpdateDialog();
                    }
                }
            }
            else
                background.start();
            super.onPostExecute(jsonObject);
        }
    }

private void showUpdateDialog(){
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("A New Update is Available");
        builder.setPositiveButton("Update", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse
                        ("market://details?id=yourAppPackageName")));
                dialog.dismiss();
            }
        });

        builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                background.start();
            }
        });

        builder.setCancelable(false);
        dialog = builder.show();
    }

1
これには、外部ライブラリJSoupを追加するための使用が必要になると思いますか?
アブラハムフィリップ

1
はい、しかしそれはhtml divページを取得するためのものです。つまり、この機能を実現するためにサードパーティのライブラリを使用する必要はないかもしれません。JSoupなしでそのhtml要素をスクレイプできれば、それでも機能します
AshuKingSharma

1
itempropの値を変更した場合はどうなりますか?
asokバズ

1
彼らがitemprop値を変更した場合、それは私のアプリにも影響します。私はそれをすぐにサポートするように私の回答を編集します。そのため、それまでは心配ありません:)
AshuKingSharma '14

素敵なsetCancelable(false)
Kai Wang

46

新しいバージョンが出たらすぐに古いバージョンのサポートを停止しないでください。これはひどいユーザー体験をもたらします。正当な理由により、これを行うソフトウェアベンダーは存在しません。

ユーザーがその時点で更新できない、または更新したくない場合はどうなりますか?彼らは単にあなたのアプリを使用することができません、それは悪いことです。

Googleはそのようなバージョントラッキングのオプションを提供していないため、独自にロールする必要があります。アプリがチェックできる現在のライブバージョンを返す単純なWebサービスで十分です。その後、バージョンを更新すると、アプリはそれが古いことを認識します。これを使用して、Google Playに依存するよりも早くアップデートがあることをユーザーに知らせることをお勧めします。アプリの動作を妨げるために実際に使用するのではなく、ユーザーに更新を促すだけです。


2
@ashrafulこれまたはいずれかの回答で質問が解決した場合は、チェックマークをクリックして受け入れることを検討してください。これは、解決策が見つかったことをより広いコミュニティに示し、回答者と自分の両方にある程度の評判を与えます。これを行う義務はありません。
スフィアン2015

答えは、存在するソフトウェアベンダーの数を主観的に判断したものです。それを定量化できますか?
Lou Morda、2015

1
アプリストアまたはプレイストアから現在のアプリバージョンを取得することは可能ですか?または、サーバーに最新のアプリバージョンを保持する必要があるかどうか。現在、サーバーで最新のアプリバージョンを返すようにサービスコールを行っていますが、アプリの公開中にサーバーを更新する必要があるたびに問題が発生します。したがって、各ストアから現在のバージョン番号を取得することは可能ですか?
subha 2016年

2
Supercellは、ゲームの最新バージョンのみをサポートしています。新しいバージョンをGoogle Playにプッシュした後、古いクライアントが接続しようとすると、サーバーから「更新が必要」という応答が返され、接続が閉じられたことがわかります。彼らはこれを毎年複数回行っています。したがって、「ゲーム会社」を「ソフトウェアベンダー」として数えたくない場合を除いて、1つを知っていることになります。彼らがまだ数百万ドルを稼いでいることを考えると、この恐ろしいユーザーエクスペリエンスはショーストッパーではないようです。 。
2016

@Subhaはい、それは可能です。しかし、そのための公式のAPIはないため、Webページをこする必要があります。これは、Webページが変更された場合に破損する可能性があることも意味します。私が書いたサードパーティ製のアプリでそれを行い、ここに答えとしてかなり単純なコード投稿しました。現在、コードはPlayページとiTunesページの両方で機能します。しかし、本番環境では、GoogleやAppleのページの形式に依存する必要はなく、サーバー上の最新のアプリバージョンを自動的に更新するソリューションを探す方がよいでしょう。
2016

27

Googleチームのソリューション

Android 5.0以降、これは新しいGoogle Play In Appアップデートメカニズムを通じて簡単に実現できます。要件は、バージョン1.5.0以降のPlay Coreライブラリがあり、apksの代わりにApp Bundles idstributionを使用することです。

ライブラリは、ユーザーに更新について通知する2つの異なる方法を提供します。

  1. アプリがバックグラウンドで更新されている間、ユーザーがアプリを使い続けることができる場合の柔軟性。

  2. 即時-ユーザーがアプリを更新するまでアプリを入力できないブロック画面。

それを実装する次のステップがあります:

  1. アップデートの可用性を確認する
  2. 更新を開始
  3. 更新ステータスのコールバックを取得します
  4. 更新を処理する

これらの手順の実装はすべて公式サイトで詳細に説明されています:https : //developer.android.com/guide/app-bundle/in-app-updates


16

スコットとマイケルの答えは正しいです。サポートする最小バージョン番号を提供するサービスをホストし、インストールされているバージョンと比較します。あなたはうまくいけばこれを使う必要はないはずですが、あるバージョンがそこにある場合、深刻な欠陥のために絶対に殺さなければならないので、それは命の恩人です。

次に何をするかというコードを追加したかっただけです。次に、Google Playインテントを起動し、アップグレードする必要があることをユーザーに尋ねた後、ストアで新しいバージョンに移行する方法を示します。

public class UpgradeActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_upgrade);
        final String appName = "com.appname";
        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id="+appName)));

            }
        });
    }
}

各リリースでアップグレードを強制する必要がある場合は、設計を再検討する必要があります。


11

Googleはアプリ内アップデートライブラリ(https://developer.android.com/guide/app-bundle/in-app-updates)を導入しました。これはLollipop +で動作し、ユーザーに素晴らしいアップデートを要求する機能を提供しますダイアログ(FLEXIBLE)または必須の全画面メッセージ(IMMEDIATE)。

後者を実装する必要があります。これは次のようになります。 ここに画像の説明を入力してください

私はこの回答のすべてのコードをカバーしました:https//stackoverflow.com/a/56808529/5502121


1
これが一番の答えです!
fvaldivia

この機能は実際には、ユーザーがアプリを起動したときにPlayキャッシュが最新であることを前提としています。つまり、キャッシュ内のアプリのバージョン番号がPlaystoreの最新のデプロイメントのバージョン番号と同じでない場合、ユーザーにプロンプ​​トを表示しません。
kiran01bm

6

これについては、FirebaseのRemote Config機能を確認することを強くお勧めします。

パラメータapp_version_enabledを使用して実装し、次のような「Androidバージョンの無効化」条件を設定しました。

applies if App ID == com.example.myapp and App version regular expression ^(5.6.1|5.4.2) 

パラメータのデフォルトは「true」ですが、無効なAndroidバージョンの値はfalseです。無効にしたAndroidバージョンの正規表現では、|{version name}括弧内に別のバージョンを追加するだけで、無効なバージョンをさらに追加できます。

次に、構成でバージョンが有効になっているかどうかを確認します-ユーザーにアップグレードを強制するアクティビティを起動します。アプリを外部から起動できるのは2か所だけです(私のデフォルトのランチャーアクティビティとインテント処理アクティビティ)。Remote Configはキャッシュベースで機能するため、キャッシュを無効にするために必要な時間が経過していない場合、アプリの「無効な」バージョンはすぐにはキャプチャされませんが、次の場合は最大12時間です推奨されるキャッシュ有効期限値。


これは非常に良いオプションです。「無効」なバージョンのサブセットを指定することで、アプリにセキュリティの問題や大きなパフォーマンスの問題が発生した場合に、自分をすばやく保護できます。すべてのバージョンのサポートを継続できますが、必要に応じて特定のバージョンを禁止できます。
Terry

6

公式にこれのためにAndroid APIを提供しています。

APIは現在、少数のパートナーでテストされており、間もなくすべての開発者が利用できるようになります。

Update APIが利用可能になりました-https://developer.android.com/guide/app-bundle/in-app-updates



1
このAPIは利用できますか?
Yayayaya

私はそれをグーグルし、このdeveloper.android.com/guide/app-bundle/in-app-updates
Chulo

この機能は実際には、ユーザーがアプリを起動したときにPlayキャッシュが最新であることを前提としています。つまり、キャッシュ内のアプリのバージョン番号がPlaystoreの最新のデプロイメントのバージョン番号と同じでない場合、ユーザーにプロンプ​​トを表示しません。
kiran01bm

3

ローカルのバージョンコードを確認し、PlayストアのAPKを

try {
        versionChecker VersionChecker = new versionChecker();
        String versionUpdated = VersionChecker.execute().get().toString();
        Log.i("version code is", versionUpdated);


        PackageInfo packageInfo = null;
        try {
            packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        int version_code = packageInfo.versionCode;
        String version_name = packageInfo.versionName;
        Log.i("updated version code", String.valueOf(version_code) + "  " + version_name);
        if (version_name != versionUpdated) {
            String packageName = getApplicationContext().getPackageName();//
            UpdateMeeDialog updateMeeDialog = new UpdateMeeDialog();
            updateMeeDialog.showDialogAddRoute(MainActivity.this, packageName);
            Toast.makeText(getApplicationContext(), "please updated", Toast.LENGTH_LONG).show();
        }
    } catch (Exception e) {
        e.getStackTrace();
    }

バージョンチェックのクラスを実装する

class versionChecker extends AsyncTask<String, String, String> {
String newVersion;

@Override
protected String doInBackground(String... params) {

    try {
        newVersion = Jsoup.connect("https://play.google.com/store/apps/details?id=+YOR_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();
    } catch (IOException e) {
        e.printStackTrace();
    }

    return newVersion;
}
}

更新用のDialobボックス

public class UpdateMeeDialog {

ActivityManager am;
TextView rootName;
Context context;
Dialog dialog;
String key1,schoolId;
public void showDialogAddRoute(Activity activity, final String packageName){
    context=activity;
    dialog = new Dialog(context);

    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.setCancelable(false);
    dialog.setContentView(R.layout.dialog_update);
    am = (ActivityManager)activity.getSystemService(Context.ACTIVITY_SERVICE);

    Button cancelDialogue=(Button)dialog.findViewById(R.id.buttonUpdate);
    Log.i("package name",packageName);
    cancelDialogue.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent=new Intent(Intent.ACTION_VIEW);                
    intent.setData(Uri.parse("https://play.google.com/store/apps/details?
    id="+packageName+"&hl=en"));
            context.startActivity(intent);
        }
    });
    dialog.show();
}
}

ダイアログのレイアウト

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#d4e9f2">


<TextView
    android:layout_width="match_parent"
    android:layout_height="40dp"

    android:text="Please Update First..!!"
    android:textSize="20dp"
    android:textColor="#46a5df"
    android:textAlignment="center"
    android:layout_marginTop="50dp"
    android:id="@+id/textMessage"
    />
<LinearLayout
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:weightSum="1"
    android:layout_marginTop="50dp"
    android:layout_below="@+id/textMessage"
    android:layout_height="50dp">

    <Button
        android:id="@+id/buttonUpdate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="Update"
        android:background="#67C6F1"
        android:textAlignment="center" />
</LinearLayout>


2

アップグレードのために独自のプロセスを定義することをお勧めします。

  1. サーバーからアプリ(ios、android)の最新バージョンを提供するWebサービスを作成します。
  2. または、アプリで使用したWebサービス(ログインなど)は、サーバーから最新のアプリバージョンを返します。
  3. アプリが#1または2からバージョンを取得すると、アプリはそれをローカル/現在のアプリバージョンとクロスチェックします。違いがある場合は、次のようにアラートを表示できます。

AndroidおよびiOS: 最新のアプリバージョンが利用可能な場合、「最新バージョンが利用可能です。機能を追加するには、アップグレードボタンをクリックしてください」というアラートが表示されます(「アップガード」と「いいえありがとうございます」ボタンでアラートが表示されます)。 playstore / Appstoreと最新バージョンを開きます。

 --- we can do upgrade compulsory or optionally.

アップグレードプロセスの前に、dbスキーマの変更がある場合は、適切なdb移行プロセスを処理したことを確認してください。


1

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


1

ここで間違いなく言及すべきことは、間もなくリリースされるアプリ内アップデートAPIです。

このAPIには2つのオプションがあります。1つ目は、ユーザーが更新がすぐに適用されるのを待つことを期待する場合の重要な更新の全画面表示です。2番目のオプションは柔軟な更新です。つまり、ユーザーは更新のダウンロード中もアプリを使い続けることができます。更新フローを完全にカスタマイズして、アプリの一部のように感じることができます。


1

アプリバージョンにリモート構成を使用し、起動アクティビティを常にチェックインすることをお勧めします。現在のアプリバージョンはリモートバージョンと同じか、アプリストアからの更新を強制しない場合はそうではありません。

シンプルなロジックハッピーコーディング

https://firebase.google.com/docs/remote-config/android


1

Play Core Libraryアプリ内アップデートを使用してこれに取り組むことができます。アップデートが利用可能かどうかを確認し、シームレスに利用できる場合はインストールできます。

アプリ内アップデートは、APK拡張ファイル(.obbファイル)を使用するアプリと互換性がありません。柔軟なダウンロードか、Google Playが更新のダウンロードとインストールを処理する即時更新のどちらかを選択できます。

dependencies {
    implementation 'com.google.android.play:core:1.5.0'
    ...
}

この回答を参照してくださいhttps://stackoverflow.com/a/58212818/7579041


0

これは、アプリで変数に保持されているバージョン番号と同様に現在のアプリのバージョンがサーバー側で保持され、ユーザーがアプリを開くたびに最初のリクエストを送信して、アプリが見つかったかどうかを確認することによって行うことができます。一致しても何もしないで、単にユーザーがアプリを使用できるようにします。それ以外の場合は、Google Playstoreにインテントを起動するか、アプリのウェブビューウィンドウを開きます(window.open( " https://play.google.com/store/apps/details?id= package_name "、 '_system'、 'location = yes');)そして、自動更新が有効になっていない場合、Google Playstoreが実行する更新を要求するボタンが自動的に表示されます。


0

更新可能な現在のアプリの新しいバージョンがあることをユーザーに通知できます。また、この条件に該当する場合は、アプリへのログインをブロックできます。

これがあなたに解決策を提供するかどうか確認してください。


0

ええと、アプリページ(Google Playアプリページ)からバージョンコードをこするなど、この問題には多くの解決策がある可能性があります。

しかし、私はあなたにペニーの費用がかからず、魔法のように機能する究極のソリューションを紹介します。

  1. アプリの最新バージョンのコードをFirebase Remote
    Configパネルに保存するだけです
  2. アプリが開かれるたびにそのバージョンコード値をフェッチします
  3. 次のコードで取得できるアプリの現在のバージョンコードと比較します。

    private int getCurrentVersionCode() {
    try {
        return getPackageManager().getPackageInfo(getPackageName(), 0).versionCode;
    } catch (NameNotFoundException e) {
        e.printStackTrace();
    }
    return -1;

    }

取得したバージョンコードが現在のバージョンより大きい場合は、アプリの更新を要求するAlertDialogを表示します。それ以外の場合、アプリはすでに更新されています。

そのため、新しいバージョンを公開するときはいつでも、その新しいバージョンのコードをFirebase Remote構成パネルに配置する必要があります

Firebase Remote Configを使用してユーザーにアプリを強制的に更新する方法に関するチュートリアル全体を読むことができます


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.