当新版本可用时强制更新 Android 应用程序

我在谷歌商店里有个应用程序。当更新版本可用时,旧版本将变得不可用——也就是说,如果用户不更新应用程序,他们就不会进入应用程序。当新版本可用时,我如何强迫用户更新应用程序?

264100 次浏览

你不应该在新版本出来的时候就停止支持旧版本。这将导致糟糕的用户体验。我不知道任何软件供应商存在这样做,很好的理由。

如果此时用户不能更新或不想更新,会发生什么情况?他们只是不能使用你的应用程序,这很糟糕。

谷歌没有提供任何版本跟踪的选项,所以你必须自己动手。一个简单的 Web 服务来返回当前的活动版本,您的应用程序可以检查将是足够的。然后你可以更新版本,应用程序就会知道它已经过时了。我只建议使用这个来让你的用户知道有一个更新比依赖于谷歌播放更快。它不应该真的被用来阻止应用程序的工作,只是提示用户更新。

我同意 Scott Helme 在另一个回答中的观点。但是在一些极端的情况下(安全问题,API 破坏变化...) ,您绝对需要用户更新来继续使用应用程序,您可以提供一个简单的版本化 API。API 应该是这样的:

Version Check API:

请求参数:

  • int appVersion

回应

  1. boolean forceUpgrade
  2. boolean recommendUpgrade

当您的应用程序启动时,您可以调用这个传递当前应用程序版本的 API,并检查版本控制 API 调用的响应。

如果 forceUpgradetrue,则显示一个弹出对话框,其中包含让用户退出应用程序或到 Google Play Store 升级应用程序的选项。

否则,如果 recommendUpgradetrue,显示弹出对话框与选项更新或继续使用应用程序。

即使有了这种强制升级能力,您也应该继续支持旧版本,除非绝对需要。

斯科特和迈克尔的答案是正确的。承载提供您支持的最小版本号的服务,并将其与安装的版本进行比较。你应该希望永远不需要使用这一点,但它是一个生命保存,如果有一些版本,你绝对必须杀死由于一些严重的缺陷。

我只是想添加下一步要做什么的代码。下面是您如何启动谷歌播放意图,并采取他们的新版本在商店后,提示用户,他们必须升级。

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


}
});
}
}

如果必须对每个版本进行强制升级,那么您应该重新考虑您的设计。

最好定义我们自己的升级过程。

  1. 创建一个 Web 服务,提供最新版本的应用程序(ios,android)从我们的服务器。
  2. 或者你在应用程序中使用的任何 Web 服务(例如登录)都会从服务器返回最新的应用程序版本。
  3. 一旦应用程序将获得版本从 # 1或2。应用程序将与本地/当前版本进行交叉检查。如果有不同,我们可以显示如下警告,

安卓和 iOS: 如果最新的应用程序版本可用,那么它将显示警报为“最新版本可用更多功能,升级点击升级按钮”(警报与“ Upgarde”和“ No。“谢谢”按钮。) 然后应用程序将重定向到 playstore/Appstore,并打开最新版本。

 --- we can do upgrade compulsory or optionally.

在升级过程之前,如果有任何 db 模式更改,请确保您处理了正确的 db 迁移过程。

试试这个: 首先,您需要对 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();
}

为了迫使应用程序用户更新,如果一个更新在市场上可用,你应该首先检查应用程序的市场版本,并比较它与设备上的应用程序的版本。如果它们不同,那么它可能是一个可用的更新。在这篇文章中,我写下了在设备上获取当前市场版本和当前版本的代码,并将它们进行了比较。我还演示了如何显示更新对话框并将用户重定向到更新页面。请访问这个链接: https://stackoverflow.com/a/33925032/5475941只要确保在对话框中只显示用户更新按钮,而不显示取消按钮。在这种情况下,他将被迫更新,然后才能使用该应用程序。

你可以做到这一点,通过做一个版本号之间的匹配,保持在应用程序在一个变量和类似的当前应用程序版本保持在服务器端,每次用户打开应用程序,第一个请求应该发送检查,如果它发现匹配什么也不做,否则让用户使用你的应用程序发射一个意图到谷歌播放商店或打开一个网络视图窗口到你的应用程序(windows. open (“ https://play.google.com/store/apps/details?id=package_name”,“ _ system”,“ location = yes”) ;) ,在那里他们会自动有按钮要求更新,这是谷歌播放商店为你做的,如果你。

您可以通知您的用户,有一个新版本的当前应用程序可以更新。此外,如果这个条件是真实的,您可以阻止登录在应用程序。

请看看 这个是否为您提供了解决方案。

我强烈建议为此检查 Firebase 的远程配置功能。

我使用一个参数-app _ version _ enable-来实现它,条件是“禁用的 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}

然后我只需检查配置是否显示版本已启用——我启动了一个强制用户升级的活动。我检查了应用程序只能从外部启动的两个地方(我的默认启动器活动和意图处理活动)。由于 Remote Config 是在缓存的基础上工作的,如果缓存失效所需的时间没有过去,它不会立即捕获“禁用”版本的应用程序,但是如果按照它们推荐的缓存过期时间,这个时间最多是12个小时。

检查本地和播放商店 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>

谷歌官方为此提供了一个 Android API。

该 API 目前正在少数合作伙伴中进行测试,并将很快对所有开发人员开放。

更新 现在可以使用 API 了-< a href = “ https://developer.android.com/guide/app-bundle/in-app-update”rel = “ norefrer”> https://developer.android.com/guide/app-bundle/in-app-updates

这里应该明确提到的是即将发布的 应用程序内部更新 API

这个 API 有两个选项; 第一个选项是,当您期望用户等待立即应用更新时,可以获得关键更新的全屏体验。第二个选项是灵活的更新,这意味着用户可以在下载更新时继续使用应用程序。你可以完全自定义更新流程,让它看起来像你的应用程序的一部分。

来自 Google 团队的解决方案

从 Android 5.0开始,通过新的 Google Play In App 更新机制很容易实现。这些要求是要有1.5.0以上版本的 Play Core 库,并且使用 App Bundles iddistribution 代替 apks。

该库为您提供了两种不同的方式来通知用户有关更新:

  1. 灵活,当用户可以继续使用应用程序,而它是在后台更新。

  2. 即时阻塞屏幕,不允许用户进入应用程序,直到他们更新它。

下一步将采取以下步骤:

  1. 检查更新可用性
  2. 开始更新
  3. 获取更新状态的回调
  4. 处理更新

所有这些步骤的实现都在官方站点 https://developer.android.com/guide/app-bundle/in-app-updates上进行了详细描述

这个问题可以有很多解决方案,比如从 App Page (Google Play App Page)中提取版本代码,等等。

但是我要向你们展示一个最终的解决方案,它不需要花费一分钱,而且会像魔法一样起作用。

  1. 只需在 FirebaseRemote 上保存应用程序的最新版本代码
    配置面板
  2. 无论应用程序何时存在,都可以获取该版本代码值 打开了
  3. 将其与应用程序的当前版本代码进行比较,您可以通过以下代码获得该版本代码

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

    }

如果获取的版本代码大于当前版本,则显示一个 AlertDialog,要求更新应用程序。否则,应用程序已经更新。

因此,无论何时推出新版本,都需要将新版本代码放在 FirebaseRemote 配置面板中

你可以在 如何强制用户使用 Firebase 远程配置更新应用程序上阅读整个教程

对应用程序版本使用远程配置是个好主意,并且总是检查启动活动是否当前应用程序版本与远程版本相同,如果不强制从应用程序商店更新的话。.

简单的逻辑愉快的编码. 。

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

Google 推出了 In-app 更新库(https://developer.android.com/guide/app-bundle/in-app-updates) ,它可以在 Lollipop + 上工作,你可以通过一个漂亮的对话框(FLEXIBLE)或者强制性的全屏信息(IMMEDIATE)请求用户更新。

您需要实现后者。 下面是它看起来的样子: enter image description here

我在这个答案中覆盖了所有的代码: https://stackoverflow.com/a/56808529/5502121

Google 发布了 Play Core 库的应用程序内部更新。

我实现了一个轻量级库来轻松实现应用程序内部的更新。 您可以在下面的链接中找到关于如何强制用户执行更新的示例。

Https://github.com/dnkaratzas/android-inapp-update#forced-updates

您可以使用 Play Core Library In-app 更新来解决这个问题。您可以检查更新可用性,并在可用时无缝地安装它们。

应用程序内的更新与使用 APK 扩展文件的应用程序不兼容(。文件)。你可以选择灵活的下载或即时更新,由 Google Play 负责下载和安装更新。

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

请参考此答案 https://stackoverflow.com/a/58212818/7579041

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

if(compareArray){
return false;
}


if(!compareArray){
for(var i=0;i<activeVersionArr.length;i++){
if(activeVersionArr[i]!==currentVersionArr[i]){
if(activeVersionArr[i] > currentVersionArr[i]){
return true;
}else{
return false;
}
}
}
}

我使用了一种简单的方法来解决这个问题:

  1. 创建 Firebase 数据库
  2. 添加最新版本
  3. 如果版本与安装的版本不同,则显示安装更新的弹出窗口。这对我来说再合适不过了。

您可以使用这里提到的答案来实现同样的目标,但是如果您正在寻找一种易于集成的内置解决方案。你可以用 Https://appupgrade.dev/ 服务强制更新你的手机应用程序。 您需要为您想要在应用程序升级服务中更新的应用程序版本创建新版本,并选择是要强制执行还是仅仅想让用户知道新版本可用。

enter image description here

在此之后,您需要从您的应用程序调用所需的详细信息,如您的应用程序版本,平台,环境和应用程序名称的应用程序升级应用程序接口。 API 将返回您的详细信息。.这个应用程序是否需要更新。根据响应,您可以显示弹出式窗口在您的应用程序。您可以在应用程序启动时调用此 API,也可以定期检查更新。您甚至可以提供自定义消息。 空气污染指数回应:

enter image description here

看到响应有强制更新为真。所以在应用程序处理显示弹出窗口。 enter image description here

您可以在这里找到完整的用户文档。 Https://appupgrade.dev/docs

谢谢。

在我看来,最简单的方法是创建一个 API,其中包含应用程序的最新版本。然后在应用程序中创建一个对话框,并检查应用程序在人机上的版本是否与 API 上的版本相等。如果没有,显示对话框,并要求用户更新商店上的应用程序。此对话框将导航到商店中的应用程序仪表板