Принудительное обновление приложения Android, когда доступна новая версия

102

У меня есть приложение в магазине Google Play. Когда доступна версия обновления, более старая версия станет непригодной для использования, то есть, если пользователи не обновят приложение, они не войдут в приложение. Как я могу заставить пользователей обновить приложение, когда станет доступна новая версия?

ашрафул
источник
1
Этот проект GitHub с открытым исходным кодом (MAHAndroidUpdater) полностью обеспечивает эту функциональность. Попробуйте, очень просто. github.com/hummatli/MAHAndroidUpdater
Саттар Хумматли

Ответы:

99

Я согласен с точкой зрения Скотта Хельма в другом ответе здесь. Но в некоторых экстремальных ситуациях (проблемы с безопасностью, критические изменения API ...), когда вам абсолютно необходимо, чтобы пользователи обновили, чтобы продолжить использование приложения, вы можете предоставить простой API управления версиями. API будет выглядеть так:

versionCheck API:

Параметры запроса:

  • int appVersion

отклик

  1. boolean forceUpgrade
  2. boolean recommendUpgrade

Когда ваше приложение запускается, вы можете вызвать этот API, который передает текущую версию приложения, и проверить ответ на вызов API управления версиями.

Если forceUpgradeесть true, показать всплывающее диалоговое окно с параметрами или позволить пользователю выйти из приложения, или перейти в Google Play Store , чтобы обновить приложение.

В противном случае , если recommendUpgradeесть true, отобразить всплывающее диалоговое окно с параметрами для обновления или продолжения использования приложения.

Даже при наличии этой возможности принудительного обновления вы должны продолжать поддерживать более старые версии, если в этом нет крайней необходимости.

Майкл
источник
Вы бы показывали всплывающее окно каждый раз при запуске приложения и рекомендовали бы обновить его? (с точки зрения UX) Или просто покажите всплывающее окно один раз и больше не показывайте, если пользователь откажется от обновления.
Аниш
8
Что касается рекомендованного обновления, я думаю, вы не должны показывать его снова, если пользователь отказался. Вы также можете показать это «один раз каждые n раз, когда пользователь открывает приложение». Вы можете сами определить значение n и реализовать его.
Майкл
3
Лучшее решение - это систематически передавать версию приложения в заголовке всех вызовов API, а затем заставить API возвращать определенный код состояния, если он обнаруживает, что версия устарела. а затем обработайте его внутри приложения. это лучше, чем вызывать еще один выделенный API для этой проверки и точно выяснять, когда и где этот вызов API должен выполняться внутри приложения / службы.
Raphael C
@RaphaelC Это действительно зависит от реализации на стороне вашего сервера. Также не идеально добавлять фильтр, который в некоторых ситуациях проверяет версию на всех API.
Сен GH
4
@SepGH с тех пор все изменилось, и теперь Android предлагает API, который вы можете использовать, чтобы заставить пользователя выполнить обновление и заблокировать его от продолжения использования приложения, если он не обновится до минимальной версии: developer.android.com/guide/ app-bundle / in-app-updates
Raphael C
56

попробуйте это: сначала вам нужно сделать запрос на ссылку 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();
    }
AshuKingSharma
источник
1
Думаю, для этого потребуется добавить внешнюю библиотеку JSoup?
Авраам Филипп
1
Да, но это было бы для получения страницы div html. Я хотел сказать, что вам может не понадобиться использовать какую-либо стороннюю библиотеку для достижения этой функциональности, если вы можете очистить этот html-элемент без JSoup, он все равно будет работать
AshuKingSharma
1
что, если они изменят значение itemprop ??
asok Buzz
1
Если они изменят значение itemprop, это также повлияет на мои приложения, я бы отредактировал свой ответ, чтобы поддержать это немедленно, так что не беспокойтесь до тех пор :)
AshuKingSharma
Отличный наборCancelable (false)
Кай Ван
48

Вы не должны прекращать поддержку более старой версии, как только выходит новая версия. Это приведет к ужасному пользовательскому опыту. Я не знаю ни одного поставщика программного обеспечения, который бы делал это по уважительной причине.

Что произойдет, если пользователь не может или не хочет обновлять в это время? Они просто не могут использовать ваше приложение, и это плохо.

Google не предоставляет никаких опций для отслеживания версий, поэтому вам придется использовать собственную. Достаточно простой веб-службы для возврата текущей действующей версии, которую может проверить ваше приложение. Затем вы можете обновить версию, и приложение узнает, что она устарела. Я бы рекомендовал использовать это только для того, чтобы ваши пользователи знали, что есть обновление, быстрее, чем это зависит от Google Play. На самом деле его не следует использовать для предотвращения работы приложения, просто чтобы предложить пользователю обновить его.

Скотт Хельм
источник
2
@ashraful, если этот или любой ответ помог решить ваш вопрос, примите его , нажав галочку. Это указывает широкому сообществу на то, что вы нашли решение, и дает некоторую репутацию как автору, так и вам. Это не обязательно.
Суфиан
Ответ зависит от того, сколько поставщиков программного обеспечения ВЫ ЗНАЕТЕ. Вы можете это количественно оценить?
Лу Морда
1
Можно ли получить текущую версию приложения из магазина приложений или магазина игр? или нужно ли мне хранить последнюю версию приложения на моем сервере? Потому что прямо сейчас у меня есть сервисный вызов на моем сервере, чтобы вернуть последнюю версию приложения, но трудность заключается в том, что каждый раз нужно обновлять сервер при публикации приложения. Следовательно, можно ли получить текущий номер версии в соответствующих магазинах?
subha 07
2
Supercell поддерживает только последнюю версию своих игр. После того, как они отправят новую версию в Google Play, любой старый клиент, пытающийся подключиться, получит ответ сервера «необходимо обновить» и увидит, что соединение закрыто. Они делают это несколько раз в год. Так что, если вы не хотите считать «игровую компанию» «поставщиком программного обеспечения», теперь вы знаете одного :) Учитывая, что они все еще зарабатывают пару миллионов долларов каждый день, очевидно, этот ужасный пользовательский опыт не является препятствием для шоу. .
Arjan
@Subha Да, это возможно. Но для него нет официального API, поэтому вам нужно очистить веб-страницы. Это также означает, что он может сломаться, если веб-страница изменится. Я сделал это в стороннем приложении, которое написал и разместил здесь довольно простой код в качестве ответа . В настоящее время код будет работать как для страниц Play, так и для iTunes. Однако в производственной среде может быть лучше поискать решение, которое автоматически обновляло бы последнюю версию приложения на сервере, вместо того, чтобы полагаться на формат страниц в Google или Apple?
Arjan
27

Решение от команды Google

Начиная с Android 5.0, это легко сделать с помощью нового механизма обновлений Google Play In App. Требования заключаются в том, чтобы иметь библиотеку Play Core версии 1.5.0+ и использовать idstribution App Bundles вместо apks.

Библиотека предоставляет вам 2 разных способа уведомить пользователей об обновлении:

  1. Гибкость, когда пользователи могут продолжать использовать приложение, пока оно обновляется в фоновом режиме.

  2. Немедленно - экран блокировки, который не позволяет пользователю войти в приложение, пока он не обновит его.

Следующие шаги по его реализации:

  1. Проверить наличие обновлений
  2. Начать обновление
  3. Получите обратный звонок для обновления статуса
  4. Обработать обновление

Все эти шаги по реализации подробно описаны на официальном сайте: https://developer.android.com/guide/app-bundle/in-app-updates

Gaket
источник
16

Ответы Скотта и Майкла верны. Разместите службу, которая предоставляет минимальный номер версии, которую вы поддерживаете, и сравните ее с установленной версией. Надеюсь, вам никогда не придется использовать это, но это спасение, если есть какая-то версия, которую вы обязательно должны убить из-за серьезной ошибки.

Я просто хотел добавить код, что делать дальше. Вот как вы затем запускаете Google Play Intent и переносите их в свою новую версию в магазине после того, как пользователю предложили обновить.

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)));

            }
        });
    }
}

Вам следует пересмотреть свой дизайн, если вам нужно принудительно обновлять каждый выпуск.

Bsautner
источник
11

Google представил библиотеку обновлений в приложении ( https://developer.android.com/guide/app-bundle/in-app-updates ), она работает на Lollipop + и дает вам возможность запрашивать у пользователя обновление с красивым диалоговое окно (ГИБКИЙ) или с обязательным полноэкранным сообщением (НЕМЕДЛЕННО).

Вам нужно реализовать последнее. Вот как это будет выглядеть: введите описание изображения здесь

Я рассмотрел весь код в этом ответе: https://stackoverflow.com/a/56808529/5502121

Кирилл Кармазин
источник
1
Это лучший ответ!
fvaldivia
Эта функция на самом деле полагается на то, что кеш Play обновляется, когда пользователь запускает ваше приложение, т.е. если номер версии вашего приложения в кеше не совпадает с номером версии вашего последнего развертывания в Playstore, тогда он не будет запрашивать пользователя.
kiran01bm
7

Официально Google предоставляет для этого Android API.

В настоящее время API тестируется с несколькими партнерами и скоро станет доступным для всех разработчиков.

Обновление API уже доступно - https://developer.android.com/guide/app-bundle/in-app-updates

Чуло
источник
2
См. Также: android-developers.googleblog.com/2018/11/…
albert c braun
1
Доступен ли теперь этот API?
Yayayaya
Я Google это и нашел , что это developer.android.com/guide/app-bundle/in-app-updates
чуло
Эта функция на самом деле полагается на то, что кэш 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», но для параметра Disabled Android Versions установлено значение false. В моем регулярном выражении для отключенных версий Android вы можете добавить больше отключенных версий, просто указав другую |{version name}в этих скобках.

Затем я просто проверяю, говорит ли конфигурация, что версия включена или нет - у меня есть действие, которое я запускаю, вынуждая пользователя выполнить обновление. Я проверяю только два места, где приложение может быть запущено извне (мое действие по умолчанию для запуска и действие по обработке намерений). Поскольку Remote Config работает на основе кеша, он не будет немедленно захватывать «отключенные» версии приложения, если не прошло необходимое время для того, чтобы кеш стал недействительным, но это не более 12 часов, если вы собираетесь их рекомендуемое значение срока действия кеша.

Chantell Osejo
источник
Это очень хороший вариант. Указав подмножество «отключенных» версий, вы можете быстро защитить себя, если у приложения возникнут проблемы с безопасностью или серьезные проблемы с производительностью. Это позволяет вам продолжать поддерживать каждую версию, но при необходимости запретить конкретную версию.
Terry
3

проверить код версии локального и игрового магазина 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;
}
}

диалоговое окно для обновления

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) с нашего сервера.
  2. Или любая веб-служба, которую вы использовали в приложении (например, вход в систему), вернет последнюю версию приложения с сервера.
  3. Как только приложение получит версию с №1 или 2. Приложение проверит ее с помощью локальной / текущей версии приложения. если есть разница, мы можем показать предупреждение следующим образом:

Android и iOS: если доступна последняя версия приложения, будет отображаться предупреждение как «Доступна последняя версия с дополнительными функциями. Для обновления нажмите кнопку обновления» (предупреждение с помощью кнопки «Upgarde» и «Нет. Спасибо»). Затем приложение будет перенаправлено на playstore / Appstore, и он откроет последнюю версию.

 --- we can do upgrade compulsory or optionally.

Перед процессом обновления убедитесь, что вы выполнили правильный процесс миграции базы данных, если есть какие-либо изменения схемы базы данных.

Сандип
источник
1

Для принуждения пользователя приложения к обновлению, если обновление доступно на рынке, вы должны сначала проверить версию приложения на рынке и сравнить ее с версией приложения на устройстве. Если они разные, возможно, доступно обновление. В этом посте я записал код для получения текущей версии маркета и текущей версии на устройстве и сравнения их между собой. Я также показал, как показать диалог обновления и перенаправить пользователя на страницу обновления. Посетите эту ссылку: https://stackoverflow.com/a/33925032/5475941 Просто убедитесь, что в диалоговом окне вы показываете только кнопку обновления пользователя и не показываете ему кнопку отмены. В этом случае он будет вынужден выполнить обновление, прежде чем он сможет использовать приложение.

Мохаммад
источник
1

Здесь обязательно стоит упомянуть о скором выпуске In-app Updates API .

У вас будет два варианта использования этого API; первый - это полноэкранный режим для критических обновлений, когда вы ожидаете, что пользователь будет ждать немедленного применения обновления. Второй вариант - гибкое обновление, что означает, что пользователь может продолжать использовать приложение, пока обновление загружено. Вы можете полностью настроить процесс обновления, чтобы он выглядел как часть вашего приложения.

Марко Гайич
источник
1

Рекомендуется использовать удаленную конфигурацию для версии приложения и всегда проверять при запуске, является ли текущая версия приложения такой же, как удаленная версия, или нет, если не принудительное обновление из магазина приложений.

Простая логика счастливого кодирования ..

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

Нирадж Сингх
источник
1

Вы можете использовать встроенные обновления основной библиотеки Play, чтобы решить эту проблему. Вы можете проверить наличие обновлений и установить их, если они доступны.

Обновления внутри приложения несовместимы с приложениями, использующими файлы расширения APK (файлы .obb). Вы можете выбрать гибкую загрузку или немедленные обновления, которые Google Play позаботится о загрузке и установке обновления за вас.

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

Обратитесь к этому ответу https://stackoverflow.com/a/58212818/7579041

Амин Пинджари
источник
0

вы можете сделать это, выполнив сопоставление между номером версии, который хранится в приложении в переменной, и аналогично текущая версия приложения хранится на стороне сервера, и каждый раз, когда пользователь открывает приложение, следует отправлять первый запрос, чтобы проверить, что, если он нашел сопоставление ничего не делает, просто позволяет пользователю использовать ваше приложение, иначе запускать намерение в игровой магазин Google или открывать окно веб-просмотра для вашего приложения (window.open (" https://play.google.com/store/apps/details?id= package_name ", '_system', 'location = yes');) и там у них автоматически будет кнопка с запросом обновления, что делает для вас магазин Google Play, если у вас нет автоматических обновлений.

Шива2492
источник
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.

Вакас Юнис
источник
0

Google выпустил обновления в приложении для библиотеки Play Core.

Я реализовал легкую библиотеку, чтобы легко внедрять обновления в приложении. По следующей ссылке вы можете найти пример того, как заставить пользователя выполнить обновление.

https://github.com/dnKaratzas/android-inapp-update#force-updates

dKaratzas
источник
0

var activeVersion = "3.9.2";

var currentVersion = "3.9.1";

var activeVersionArr = activeVersion.split ("."); var currentVersionArr = currentVersion.split (".");

var compareArray = JSON.stringify (activeVersionArr) == JSON.stringify (currentVersionArr);

если (compareArray) {вернуть ложь; }

if (! compareArray) {for (var i = 0; i <activeVersionArr.length; i ++) {
if (activeVersionArr [i]! == currentVersionArr [i]) {
if (activeVersionArr [i]> currentVersionArr [i]) { вернуть истину; } else {вернуть ложь; }
}}}

Кешав Гера
источник