Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/csharp-4.0/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用Android';什么是应用程序内更新API?_Android_Google Play_Auto Update_In App Update - Fatal编程技术网

如何使用Android';什么是应用程序内更新API?

如何使用Android';什么是应用程序内更新API?,android,google-play,auto-update,in-app-update,Android,Google Play,Auto Update,In App Update,我最近遇到了一种新的应用程序更新流,它是由Google Play API提供的。我喜欢这种无缝流程来更新Android应用程序。我在Hotstar应用程序中观察到了以下提到的步骤 从底部弹出一张卡片,显示更新可用 当我点击“更新Hotstar”按钮时,弹出一个对话框(好像是由Google Play提供的) 下载是在应用程序运行时在后台启动的 下载完成后,弹出一个SnackBar,显示应用程序已准备好安装 安装后应用程序重新启动 我怎样才能做到这一点?必须有一种与Google Play沟通的方

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

  • 从底部弹出一张卡片,显示更新可用
  • 当我点击“更新Hotstar”按钮时,弹出一个对话框(好像是由Google Play提供的)
  • 下载是在应用程序运行时在后台启动的
  • 下载完成后,弹出一个SnackBar,显示应用程序已准备好安装
  • 安装后应用程序重新启动

  • 我怎样才能做到这一点?必须有一种与Google Play沟通的方式。我浏览了很多博客。但是,没有找到任何解决方案。如果用户禁用了自动应用程序更新,这对开发人员来说可能是一个很棒的功能。

    我猜它是由应用程序本身控制的,而不是由Google Play控制的。我开发了一些应用程序,可以在启动时调用API来读取“最新”版本号以及该版本是否为“强制”更新,并将其与正在运行的应用程序版本进行比较。如果有新版本可用,则会向用户显示一个与您显示的对话框类似的对话框(尽管他们的对话框更好),提醒用户更新可用。如果更新是“强制”的,则消息会告诉他们在继续之前必须更新应用程序。如果他们单击更新,那么他们将被带到应用商店页面,在那里他们像往常一样开始下载更新,应用程序将退出。如果他们单击“关闭”,应用程序将退出。如果更新不是强制性的,则会询问他们是现在更新还是继续。如果他们单击更新,那么他们将被带到应用商店页面,在那里他们像往常一样开始下载更新,应用程序将退出。如果他们单击“继续”,那么他们将被带到应用程序的现有版本中


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

    谷歌正在测试应用程序更新API的早期版本,如中所述


    它现在只对一些早期测试合作伙伴可用,但最终应该对所有开发人员可用。请关注Android开发者博客和Play console中的公告。

    Android今天正式向所有人发布了应用内更新

    更新: 在单个活动中处理即时和灵活的更新;科特林路

    import android.app.Activity
    import android.content.Intent
    import android.content.IntentSender
    import android.os.Bundle
    import android.widget.Toast
    import androidx.appcompat.app.AppCompatActivity
    import androidx.core.content.ContextCompat
    import com.google.android.material.snackbar.Snackbar
    import com.google.android.play.core.appupdate.AppUpdateManager
    import com.google.android.play.core.appupdate.AppUpdateManagerFactory
    import com.google.android.play.core.install.InstallState
    import com.google.android.play.core.install.InstallStateUpdatedListener
    import com.google.android.play.core.install.model.AppUpdateType
    import com.google.android.play.core.install.model.InstallStatus
    import com.google.android.play.core.install.model.UpdateAvailability
    import timber.log.Timber
    
    class BaseUpdateCheckActivity : AppCompatActivity() {
    
        private val appUpdateManager: AppUpdateManager by lazy { AppUpdateManagerFactory.create(this) }
        private val appUpdatedListener: InstallStateUpdatedListener by lazy {
            object : InstallStateUpdatedListener {
                override fun onStateUpdate(installState: InstallState) {
                    when {
                        installState.installStatus() == InstallStatus.DOWNLOADED -> popupSnackbarForCompleteUpdate()
                        installState.installStatus() == InstallStatus.INSTALLED -> appUpdateManager.unregisterListener(this)
                        else -> Timber.d("InstallStateUpdatedListener: state: %s", installState.installStatus())
                    }
                }
            }
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.main_ad_view)
            checkForAppUpdate()
        }
    
        private fun checkForAppUpdate() {
            // Returns an intent object that you use to check for an update.
            val appUpdateInfoTask = appUpdateManager.appUpdateInfo
    
            // Checks that the platform will allow the specified type of update.
            appUpdateInfoTask.addOnSuccessListener { appUpdateInfo ->
                if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) {
                    // Request the update.
                    try {
                        val installType = when {
                            appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE) -> AppUpdateType.FLEXIBLE
                            appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE) -> AppUpdateType.IMMEDIATE
                            else -> null
                        }
                        if (installType == AppUpdateType.FLEXIBLE) appUpdateManager.registerListener(appUpdatedListener)
    
                        appUpdateManager.startUpdateFlowForResult(
                                appUpdateInfo,
                                installType!!,
                                this,
                                APP_UPDATE_REQUEST_CODE)
                    } catch (e: IntentSender.SendIntentException) {
                        e.printStackTrace()
                    }
                }
            }
        }
    
    
        override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
            super.onActivityResult(requestCode, resultCode, data)
            if (requestCode == APP_UPDATE_REQUEST_CODE) {
                if (resultCode != Activity.RESULT_OK) {
                    Toast.makeText(this,
                            "App Update failed, please try again on the next app launch.",
                            Toast.LENGTH_SHORT)
                            .show()
                }
            }
        }
    
        private fun popupSnackbarForCompleteUpdate() {
            val snackbar = Snackbar.make(
                    findViewById(R.id.drawer_layout),
                    "An update has just been downloaded.",
                    Snackbar.LENGTH_INDEFINITE)
            snackbar.setAction("RESTART") { appUpdateManager.completeUpdate() }
            snackbar.setActionTextColor(ContextCompat.getColor(this, R.color.accent))
            snackbar.show()
        }
    
    
        override fun onResume() {
            super.onResume()
            appUpdateManager
                    .appUpdateInfo
                    .addOnSuccessListener { appUpdateInfo ->
    
                        // If the update is downloaded but not installed,
                        // notify the user to complete the update.
                        if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
                            popupSnackbarForCompleteUpdate()
                        }
    
                        //Check if Immediate update is required
                        try {
                            if (appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
                                // If an in-app update is already running, resume the update.
                                appUpdateManager.startUpdateFlowForResult(
                                        appUpdateInfo,
                                        AppUpdateType.IMMEDIATE,
                                        this,
                                        APP_UPDATE_REQUEST_CODE)
                            }
                        } catch (e: IntentSender.SendIntentException) {
                            e.printStackTrace()
                        }
                    }
        }
    
        companion object {
            private const val APP_UPDATE_REQUEST_CODE = 1991
        }
    }
    

    源代码要点:

    步骤1:添加依赖项(build.gradle(app)):

    dependencies {
    
        implementation 'com.google.android.play:core:1.7.3'
        ...
    }
    
    步骤2:检查更新可用性,如果可用,则启动更新

    private AppUpdateManager mAppUpdateManager;
    private static final int RC_APP_UPDATE = 11;
    
    InstallStateUpdatedListener installStateUpdatedListener = new 
      InstallStateUpdatedListener() {
        @Override
        public void onStateUpdate(InstallState state) {
            if (state.installStatus() == InstallStatus.DOWNLOADED){
                //CHECK THIS if AppUpdateType.FLEXIBLE, otherwise you can skip
                popupSnackbarForCompleteUpdate();
            } else if (state.installStatus() == InstallStatus.INSTALLED){
                if (mAppUpdateManager != null){
              mAppUpdateManager.unregisterListener(installStateUpdatedListener);
                }
    
            } else {
                Log.i(TAG, "InstallStateUpdatedListener: state: " + state.installStatus());
            }
        }
    };
    
    private void popupSnackbarForCompleteUpdate() {
    
        Snackbar snackbar =
                Snackbar.make(
                        findViewById(R.id.coordinatorLayout_main),
                        "New app is ready!",
                        Snackbar.LENGTH_INDEFINITE);
    
        snackbar.setAction("Install", view -> {
            if (mAppUpdateManager != null){
                mAppUpdateManager.completeUpdate();
            }
        });
    
        
    snackbar.setActionTextColor(getResources().getColor(R.color.install_color));
        snackbar.show();
    }
    
    在onStart()方法中:

    步骤3:收听更新状态

    private AppUpdateManager mAppUpdateManager;
    private static final int RC_APP_UPDATE = 11;
    
    InstallStateUpdatedListener installStateUpdatedListener = new 
      InstallStateUpdatedListener() {
        @Override
        public void onStateUpdate(InstallState state) {
            if (state.installStatus() == InstallStatus.DOWNLOADED){
                //CHECK THIS if AppUpdateType.FLEXIBLE, otherwise you can skip
                popupSnackbarForCompleteUpdate();
            } else if (state.installStatus() == InstallStatus.INSTALLED){
                if (mAppUpdateManager != null){
              mAppUpdateManager.unregisterListener(installStateUpdatedListener);
                }
    
            } else {
                Log.i(TAG, "InstallStateUpdatedListener: state: " + state.installStatus());
            }
        }
    };
    
    private void popupSnackbarForCompleteUpdate() {
    
        Snackbar snackbar =
                Snackbar.make(
                        findViewById(R.id.coordinatorLayout_main),
                        "New app is ready!",
                        Snackbar.LENGTH_INDEFINITE);
    
        snackbar.setAction("Install", view -> {
            if (mAppUpdateManager != null){
                mAppUpdateManager.completeUpdate();
            }
        });
    
        
    snackbar.setActionTextColor(getResources().getColor(R.color.install_color));
        snackbar.show();
    }
    
    步骤4:获取更新状态的回调

    @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");
            }
        }
    }
    
    步骤5:灵活更新

    private AppUpdateManager mAppUpdateManager;
    private static final int RC_APP_UPDATE = 11;
    
    InstallStateUpdatedListener installStateUpdatedListener = new 
      InstallStateUpdatedListener() {
        @Override
        public void onStateUpdate(InstallState state) {
            if (state.installStatus() == InstallStatus.DOWNLOADED){
                //CHECK THIS if AppUpdateType.FLEXIBLE, otherwise you can skip
                popupSnackbarForCompleteUpdate();
            } else if (state.installStatus() == InstallStatus.INSTALLED){
                if (mAppUpdateManager != null){
              mAppUpdateManager.unregisterListener(installStateUpdatedListener);
                }
    
            } else {
                Log.i(TAG, "InstallStateUpdatedListener: state: " + state.installStatus());
            }
        }
    };
    
    private void popupSnackbarForCompleteUpdate() {
    
        Snackbar snackbar =
                Snackbar.make(
                        findViewById(R.id.coordinatorLayout_main),
                        "New app is ready!",
                        Snackbar.LENGTH_INDEFINITE);
    
        snackbar.setAction("Install", view -> {
            if (mAppUpdateManager != null){
                mAppUpdateManager.completeUpdate();
            }
        });
    
        
    snackbar.setActionTextColor(getResources().getColor(R.color.install_color));
        snackbar.show();
    }
    
    步骤6:不要忘记注销侦听器(在onStop方法中)

    注意:在应用程序的任何一个活动中添加此侦听器,最好是在MainActivity(主页)中添加。

    对于测试,您可以使用
    FakeAppUpdateManager

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


    官方文档:

    为了实现这一点,在接受的答案中引用的谷歌官方文档在语法上是不正确的。经过一些研究,我终于找到了正确的语法:

    而不是:

    // 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);
    }
    
    请试试这个

    步骤1:在build.gradle文件中添加以下库(请检查并更新最新的播放代码插件版本)

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

    步骤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()中,我们需要处理用户单击操作(仅适用于灵活更新)

    步骤7:创建一个方法来检查更新是否可用并启动更新(立即更新)

    步骤9:现在,无论何时开始检查更新,都可以使用应用程序内更新类型(灵活或立即)调用该方法

    //For Immediate 
    inAppUpdateType = AppUpdateType.IMMEDIATE; //1
    inAppUpdate();
    
    //For Flexible 
    inAppUpdateType = AppUpdateType.FLEXIBLE; //0
    inAppUpdate();
    
    要记住的要点:

  • 灵活更新将首先下载,然后通知用户下载已完成,然后用户必须开始更新(步骤8中给出的选项)

  • google play控制台中有一个选项可以测试应用程序共享,我们可以上传普通的apk(无需签名的apk)进行测试。

  • 需要在测试设备play store应用程序中启用应用内共享选项。

  • 不过,如果play store出现任何问题,只需清除缓存和数据,然后重新启动设备一次,然后再试一次


  • 尝试使用这些库,在这些库中只需几行代码即可实现


    谢谢您抽出时间。我们可以在应用程序中轻松开发此功能。但是你必须把用户带到游戏商店。然而,如果你能猜到的话,Google Play也有一些回调。这就是为什么他们能够在下载完成时显示SnackBar。酷!Google Play似乎正在与选定的合作伙伴测试应用内更新API。想在它可用时查看它。。。它被称为应用程序内更新API,并由选定的合作伙伴进行测试。我也在等这个。不幸的是,谷歌喜欢发布需要很长时间才能发布的功能和产品。我正在运行一些测试,但似乎无法正常工作。我总是得到UpdateAvailability.UPDATE\u作为响应。有什么我遗漏的吗?@kevintresuelo我想你的应用应该发布在Play store上。对于测试,请降低版本
     @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();
                }
            }
    }
    
    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();
            }
    
        }
    
    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();
            }
        } 
    
    //For Immediate 
    inAppUpdateType = AppUpdateType.IMMEDIATE; //1
    inAppUpdate();
    
    //For Flexible 
    inAppUpdateType = AppUpdateType.FLEXIBLE; //0
    inAppUpdate();