如何使用Android的应用内更新API?

时间:2019-05-01 17:04:51

标签: android google-play auto-update in-app-update

我最近遇到了Google Play提供的一种新的应用更新流程。我喜欢无缝流程来更新Android应用程序。我在Hotstar应用程序中观察到以下提到的步骤。

  1. 从底部弹出显示更新的卡
  2. 当我单击“更新Hotstar”按钮时,会弹出一个对话框(似乎是Google Play提供的对话框)

enter image description here

  1. 在应用运行时在后台开始下载
  2. 下载完成后,一个SnackBar弹出,显示可以安装的应用程序
  3. 安装后应用重新启动

enter image description here

我该如何实现?必须有一种与Google Play交流的方式。我浏览了许多博客。但是,没有找到任何解决方案。如果用户禁用了自动应用程序更新,这对于开发人员来说可能是一个很棒的功能。

7 个答案:

答案 0 :(得分:3)

正式文档: https://developer.android.com/guide/app-bundle/in-app-updates

约束:应用内更新仅适用于运行Android 5.0(API级别21)或更高版本的设备

步骤1:添加依赖项:

 let interval = CMTime(value: 1, timescale: 2)
            player?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using: { (progressTime) in

                let seconds = CMTimeGetSeconds(progressTime)
                let secondString = String(format: "%02d", Int(seconds) % 60)
                let minutString = String(format: "%02d", Int(seconds) / 60)
                self.currentTimeLabel.text = "\(minutString):\(secondString)"

第2步:检查更新的可用性,并开始检查是否可用

dependencies {

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

第3步:收听更新状态

mAppUpdateManager = AppUpdateManagerFactory.create(this);

mAppUpdateManager.registerListener(installStateUpdatedListener);

mAppUpdateManager.getAppUpdateInfo().addOnSuccessListener(appUpdateInfo -> {

        if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
                && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)){

            try {    
                    mAppUpdateManager.startUpdateFlowForResult(
                            appUpdateInfo, AppUpdateType.FLEXIBLE, MainActivity.this, RC_APP_UPDATE);
                }

            } catch (IntentSender.SendIntentException e) {
                e.printStackTrace();
            }

        } else if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED){
            popupSnackbarForCompleteUpdate();
        } else {
            Log.e(TAG, "checkForAppUpdateAvailability: something else");
        }
    });

第4步:获取更新状态的回调

InstallStateUpdatedListener installStateUpdatedListener = new 
  InstallStateUpdatedListener() {
    @Override
    public void onStateUpdate(InstallState state) {
        if (state.installStatus() == InstallStatus.DOWNLOADED){
            popupSnackbarForCompleteUpdate();
        } else if (state.installStatus() == InstallStatus.INSTALLED){
            if (mAppUpdateManager != null){
          mAppUpdateManager.unregisterListener(installStateUpdatedListener);
            }

        } else {
            Log.i(TAG, "InstallStateUpdatedListener: state: " + state.installStatus());
        }
    }
};

第5步:灵活更新

@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    if (requestCode == RC_APP_UPDATE) {
        if (resultCode != RESULT_OK) {
            Log.e(TAG, "onActivityResult: app download failed");
        }
    }
}

答案 1 :(得分:2)

Android今天正式向所有人宣布了应用内更新。 https://developer.android.com/guide/app-bundle/in-app-updates

答案 2 :(得分:1)

尝试执行此操作,在接受的答案中引用的官方Google文档在语法上不正确。经过了一些研究,但我终于找到了正确的语法:

代替:

// Creates an instance of the manager.
AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context);

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

// Checks that the platform will allow the specified type of update.
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
  // For a flexible update, use AppUpdateType.FLEXIBLE
  && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
              // Request the update.

    appUpdateManager.startUpdateFlowForResult(
        // Pass the intent that is returned by 'getAppUpdateInfo()'.
        appUpdateInfo,
        // Or 'AppUpdateType.FLEXIBLE' for flexible updates.
        AppUpdateType.IMMEDIATE,
        // The current activity making the update request.
        this,
        // Include a request code to later monitor this update request.
        MY_REQUEST_CODE);
}

执行以下操作:

    private AppUpdateManager appUpdateManager;
    ...
    // onCreate(){ 
    // Creates instance of the manager.
    appUpdateManager = AppUpdateManagerFactory.create(mainContext);

    // Don't need to do this here anymore
    // Returns an intent object that you use to check for an update.
    //Task<AppUpdateInfo> appUpdateInfo = appUpdateManager.getAppUpdateInfo();

    appUpdateManager
            .getAppUpdateInfo()
            .addOnSuccessListener(
                    appUpdateInfo -> {

                        // Checks that the platform will allow the specified type of update.
                        if ((appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE)
                                && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE))
                        {
                            // Request the update.
                            try {
                                appUpdateManager.startUpdateFlowForResult(
                                        appUpdateInfo,
                                        AppUpdateType.IMMEDIATE,
                                        this,
                                        REQUEST_APP_UPDATE);
                            } catch (IntentSender.SendIntentException e) {
                                e.printStackTrace();
                            }
                        }
                    });

然后,在安装过程中挂起的情况下,在onResume()重写中编写类似的代码:

//Checks that the update is not stalled during 'onResume()'.
//However, you should execute this check at all entry points into the app.
@Override
protected void onResume() {
    super.onResume();

    appUpdateManager
            .getAppUpdateInfo()
            .addOnSuccessListener(
                    appUpdateInfo -> {

                        if (appUpdateInfo.updateAvailability()
                                == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
                            // If an in-app update is already running, resume the update.
                            try {
                                appUpdateManager.startUpdateFlowForResult(
                                        appUpdateInfo,
                                        AppUpdateType.IMMEDIATE,
                                        this,
                                        REQUEST_APP_UPDATE);
                            } catch (IntentSender.SendIntentException e) {
                                e.printStackTrace();
                            }
                        }
                    });
}

答案 3 :(得分:1)

请尝试一次。

步骤1:在build.gradle文件中,添加以下库

implementation 'com.google.android.play:core:1.6.4'

第2步:在类(Ex MainActivity.java)中声明以下变量

    private AppUpdateManager mAppUpdateManager;
    private int RC_APP_UPDATE = 999;
    private int inAppUpdateType;
    private com.google.android.play.core.tasks.Task<AppUpdateInfo> appUpdateInfoTask;
    private InstallStateUpdatedListener installStateUpdatedListener;

步骤3:在onCreate()方法中,添加以下代码(初始化变量)

        // Creates instance of the manager.
        mAppUpdateManager = AppUpdateManagerFactory.create(this);
        // Returns an intent object that you use to check for an update.
        appUpdateInfoTask = mAppUpdateManager.getAppUpdateInfo();
        //lambda operation used for below listener
        //For flexible update
        installStateUpdatedListener = installState -> {
            if (installState.installStatus() == InstallStatus.DOWNLOADED) {
                popupSnackbarForCompleteUpdate();
            }
        };
        mAppUpdateManager.registerListener(installStateUpdatedListener);

第4步:在活动的onDestroy()方法中,只需取消注册侦听器

 @Override
    protected void onDestroy() {
        mAppUpdateManager.unregisterListener(installStateUpdatedListener);
        super.onDestroy();
    }

第5步:在onResume()中,我们需要通过以下代码监听“灵活”更新和“立即更新”。

@Override
        protected void onResume() {
           try {   
  mAppUpdateManager.getAppUpdateInfo().addOnSuccessListener(appUpdateInfo -> {
        if (appUpdateInfo.updateAvailability() == 
           UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
           // If an in-app update is already running, resume the update.
                       try {
                            mAppUpdateManager.startUpdateFlowForResult(
                                    appUpdateInfo,
                                    inAppUpdateType,
                                    this,
                                    RC_APP_UPDATE);
                        } catch (IntentSender.SendIntentException e) {
                            e.printStackTrace();
                        }
                    }
                });


  mAppUpdateManager.getAppUpdateInfo().addOnSuccessListener(appUpdateInfo -> {
     //For flexible update            
       if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
                        popupSnackbarForCompleteUpdate();
                    }
                });
            } catch (Exception e) {
                e.printStackTrace();
            }

            super.onResume();
    }

步骤6:在onActivityResult()中,我们需要处理用户点击操作(仅用于灵活更新)

 @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_APP_UPDATE) {
            //when user clicks update button
            if (resultCode == RESULT_OK) {
                Toast.makeText(MainActivity.this, "App download starts...", Toast.LENGTH_LONG).show();
            } else if (resultCode != RESULT_CANCELED) {
                //if you want to request the update again just call checkUpdate()
                Toast.makeText(MainActivity.this, "App download canceled.", Toast.LENGTH_LONG).show();
            } else if (resultCode == RESULT_IN_APP_UPDATE_FAILED) {
                Toast.makeText(MainActivity.this, "App download failed.", Toast.LENGTH_LONG).show();
            }
        }
}

第7步:创建一种方法来检查更新是否可用并开始更新(立即更新)

private void inAppUpdate() {

        try {
            // Checks that the platform will allow the specified type of update.
            appUpdateInfoTask.addOnSuccessListener(new OnSuccessListener<AppUpdateInfo>() {
                @Override
                public void onSuccess(AppUpdateInfo appUpdateInfo) {
                    if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
                            // For a flexible update, use AppUpdateType.FLEXIBLE
                            && appUpdateInfo.isUpdateTypeAllowed(inAppUpdateType)) {
                        // Request the update.

                        try {
                            mAppUpdateManager.startUpdateFlowForResult(
                                    // Pass the intent that is returned by 'getAppUpdateInfo()'.
                                    appUpdateInfo,
                                    // Or 'AppUpdateType.FLEXIBLE' for flexible updates.
                                    inAppUpdateType,
                                    // The current activity making the update request.
                                    MainActivity.this,
                                    // Include a request code to later monitor this update request.
                                    RC_APP_UPDATE);
                        } catch (IntentSender.SendIntentException ignored) {

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

    }

第8步:精细地创建一个小吃对话框或任何警报,以向用户显示已下载弹性更新并准备进行更新(需要使用操作来启动更新-仅用于弹性更新)

private void popupSnackbarForCompleteUpdate() {
        try {
        Snackbar snackbar =
            Snackbar.make(
                    findViewById(R.id.id_of_root_loyout),
                    "An update has just been downloaded.\nRestart to update",
                    Snackbar.LENGTH_INDEFINITE);

    snackbar.setAction("INSTALL", view -> {
        if (mAppUpdateManager != null){
            mAppUpdateManager.completeUpdate();
        }
    });
snackbar.setActionTextColor(getResources().getColor(R.color.install_color));
    snackbar.show();

        } catch (Resources.NotFoundException e) {
            e.printStackTrace();
        }
    } 

第9步:现在,无论您要开始检查更新的位置如何,都可以使用应用内更新类型(灵活或立即)来调用该方法。

//For Immediate 
inAppUpdateType = AppUpdateType.IMMEDIATE; //1
inAppUpdate();

//For Flexible 
inAppUpdateType = AppUpdateType.FLEXIBLE; //0
inAppUpdate();

要记住的要点:

  1. 该灵活更新将首先下载,然后会通知用户下载已完成,然后用户必须开始更新(以上第8步中给出的选项)。

  2. Google Play控制台中有一个选项可以测试应用内共享,只需我们可以上传常规apk(无需签名的apk)进行测试即可。 https://support.google.com/googleplay/android-developer/answer/9303479?hl=en

  3. 需要在测试设备Play商店应用中启用应用内共享选项。 How to Enable Internal App Sharing for Android?

  4. 仍然,Play商店中的任何问题,只需清除缓存并清除数据,然后重新启动设备一次即可。

答案 4 :(得分:0)

我的猜测是,它是由应用本身而非Google Play控制的。我已经开发了一些应用程序,这些应用程序在启动时会进行API调用,以读取“最新”版本号以及该版本是否为“强制性”更新,并将其与正在运行的应用程序版本进行比较。如果有新版本可用,则向用户显示一个对话框,类似于您显示的对话框(尽管他们的对话框要好得多),提醒用户有可用的更新。如果更新为“强制性”,则该消息告诉他们必须先更新应用程序,然后才能继续。如果他们单击“更新”,则会将他们带到“应用程序商店”页面,在该页面上,他们将照常启动下载更新,然后退出该应用程序。如果他们单击“关闭”,则该应用程序将退出。如果该更新不是强制性的,则询问他们是否要立即更新或继续。如果他们单击“更新”,则会将他们带到“应用程序商店”页面,在该页面上,他们将照常启动下载更新,然后退出该应用程序。如果他们单击“继续”,则它们将被带入该应用程序的现有版本中。

我不确定他们如何管理后台下载,然后在退出应用程序之前启动了应用程序更新。那将非常好,但是我们上面的方法也非常简单,并且为开发人员提供了很多功能。

答案 5 :(得分:0)

Google正在测试this blog post中所述的应用内更新API的早期版本。

目前仅对某些早期测试合作伙伴可用,但最终应对所有开发人员可用。请密切关注Android开发者博客以及Play控制台中的公告。

答案 6 :(得分:0)