Android: implement application version update

〇. Preface

As a basic function of Android applications , application version update is a must for every application, and there are many ways to implement this function. Some time ago, our project was revised, and the logic of application update was reorganized. The function itself is relatively simple, but there are still many possible abnormal situations, and we hereby record them.

1. Use OkHttp to update the application version

There are three main methods: first, check whether there is a new version, then download the APK file, and finally install the new APK.

Here's how to detect new versions:

    /**
     * 检测是否有新的版本,如有则进行下载更新:
     * 1. 请求服务器, 获取数据;2. 解析json数据;3. 判断是否有更新;4. 弹出升级弹窗或直接进入主页面
     */
    private void checkVersion() {
        showLaunchInfo("正在检测是否有新版本...", false);
        String checkUrl = "http://localhost:8080/AndroidAPK/AndroidUpdate.json";

        OkHttpClient okHttpClient = new OkHttpClient();//创建 OkHttpClient 对象
        Request request = new Request.Builder().url(checkUrl).build();//创建 Request
        okHttpClient.newCall(request).enqueue(new Callback() {//发送请求
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                Log.w(TAG, "onFailure: e = " + e.getMessage());
                mProcess = 30;
                showLaunchInfo("新版本检测失败,请检查网络!", true);
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) {
                try {
                    Log.w(TAG, "onResponse: response = " + response);
                    mProcess = 30;
                    final ResponseBody responseBody = response.body();
                    if (response.isSuccessful() && responseBody != null) {
                        final String responseString = responseBody.string();
                        Log.w(TAG, "onResponse: responseString = " + responseString);
                        //解析json
                        final JSONObject jo = new JSONObject(responseString);
                        final String versionName = jo.getString("VersionName");
                        final int versionCode = jo.getInt("VersionCode");
                        final String versionDes = jo.getString("VersionDes");
                        final String versionUrl = jo.getString("VersionUrl");
                        //本地版本号和服务器进行比对, 如果小于服务器, 说明有更新
                        if (BuildConfig.VERSION_CODE < versionCode) {
                            //本地版本小于服务器版本,存在新版本
                            showLaunchInfo("检测到新版本!", false);
                            progressBar.setProgress(mProcess);
                            //有更新, 弹出升级对话框
                            showUpdateDialog(versionDes, versionUrl);
                        } else {
                            showLaunchInfo("该版本已是最新版本,正在初始化项目...", true);
                        }
                    } else {
                        showLaunchInfo("新版本检测失败,请检查服务!", true);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    showLaunchInfo("新版本检测出现异常,请检查服务!", true);
                }
            }
        });
    }

Here's how to download the APK file:

    private void downloadNewApk(String apkName) {
        showLaunchInfo("检测到新版本,正在下载...", false);
        final File downloadDir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
        if (downloadDir != null && downloadDir.exists() && downloadDir.isDirectory()) {
            //删除(/storage/emulated/0/Android/data/包名/files/Download)文件夹下的所有文件,避免一直下载文件堆积
            File[] files = downloadDir.listFiles();
            if (files != null) {
                for (final File file : files) {
                    if (file != null && file.exists() && file.isFile()) {
                        boolean delete = file.delete();
                    }
                }
            }
        }
        //显示进度条
        final ProgressDialog dialog = new ProgressDialog(this);
        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//水平方向进度条, 可以显示进度
        dialog.setTitle("正在下载新版本...");
        dialog.setCancelable(false);
        dialog.show();
        //APK文件路径
        final String url = "http://localhost:7090/AndroidAPK/" + apkName;
        Request request = new Request.Builder().url(url).build();
        new OkHttpClient().newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                e.printStackTrace();
                String strFailure = "新版本APK下载失败";
                showLaunchInfo(strFailure, false);
                showFailureDialog(strFailure, apkName);
                dialog.dismiss();
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) {
                try {
                    final ResponseBody responseBody = response.body();
                    if (response.isSuccessful() && responseBody != null) {
                        final long total = responseBody.contentLength();
                        final InputStream is = responseBody.byteStream();
                        final File file = new File(downloadDir, apkName);
                        final FileOutputStream fos = new FileOutputStream(file);

                        int len;
                        final byte[] buf = new byte[2048];
                        long sum = 0L;
                        while ((len = is.read(buf)) != -1) {
                            fos.write(buf, 0, len);
                            sum += len;
                            float downloadProgress = (sum * 100F / total);
                            dialog.setProgress((int) downloadProgress);//下载中,更新进度
                            progressBar.setProgress(mProcess + (int) (downloadProgress * 0.7));
                        }
                        fos.flush();
                        responseBody.close();
                        is.close();
                        fos.close();
                        installAPKByFile(file);//下载完成,开始安装
                    } else {
                        String strFailure = "新版本APK获取失败";
                        showLaunchInfo(strFailure, false);
                        showFailureDialog(strFailure, apkName);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    String strException = "新版本APK下载安装出现异常";
                    showLaunchInfo(strException, false);
                    showFailureDialog(strException, apkName);
                } finally {
                    /*正常应该在finally中进行关流操作,以避免异常情况时没有关闭IO流,导致内存泄露
                     *因为本场景下异常情况可能性较小,为了代码可读性直接在正常下载结束后关流
                     */
                    dialog.dismiss();//dialog消失
                }
            }
        });
    }

Here's how to install a new APK:

    /**
     * 7.0以上系统APK安装
     */
    private void installAPKByFile(File file) {
        showLaunchInfo("新版本下载成功,正在安装中...", false);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        //intent.putExtra("pwd", "soft_2694349");//根据密码判断升级文件是否允许更新
        intent.addCategory(Intent.CATEGORY_DEFAULT);
        Uri uri = FileProvider.getUriForFile(this, "com.lxb.demo0325.fileProvider", file);
        //intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        startActivityForResult(intent, REQUEST_INSTALL);
    }

As above, the code is not difficult, mainly it is the judgment of various possible exceptions. For the integrity of the code, I uploaded the entire application version update demo: https://github.com/beita08/AppUpdate

Among them, the update file of the server configuration can be in the form of Json:

{
    "VersionName":"3.1.1.2",
    "VersionCode":545,
    "VersionDes":"发现新版本, 赶紧更新吧!",
    "VersionUrl":"ApkName"
}

References: https://www.cnblogs.com/xiaoxiaoqingyi/p/7003241.html

2. Use third-party services to update the application version

As a general unified function, application version update can also be performed using services provided by third parties. The most commonly used one is Tencent's bugly.

Tencent Bugly is a three-party service provided by Tencent for developers. It mainly includes three major functions: exception reporting, operation statistics, and application upgrade. For us, we can use its application upgrade and exception reporting functions. The official website address is: https:/ /bugly.qq.com/v2/. First of all, to use the Bugly function, you need to integrate its related SDK on the client side:

Bugly function introduction:

1. Application upgrade:

Upload our updated apk file to the bugly background, set the distribution strategy (optional mandatory upgrade and distribution limit, etc., and also fill in the update description), and the client will download it when it detects that there is a new version in the bugly background.

Application upgrade official website introduction link: https://bugly.qq.com/docs/introduction/app-upgrade-introduction/?v=20180709165613

2. Abnormal reporting

After the client is integrated, the abnormal problems that occur during the use of online users will be aggregated to the bugly background for automatic summary and classification, which is convenient for analyzing the problems that occur on the user end. (This log is on the client device), the original intention of bugly is to summarize abnormal information.

Abnormal reporting official website introduction link: https://bugly.qq.com/docs/introduction/bugly-introduction/?v=20181014122344#_3

Bugly advantages and disadvantages analysis:

advantage:

1. The application upgrade does not need to occupy our own server resources after using third-party services, and the concurrent upgrade is also guaranteed.

2. Abnormal reporting can monitor the abnormal situation of the user end, which is difficult for us to detect by ourselves.

shortcoming:

1. Information security issues: the client needs to integrate the relevant SDK and upload our APK file to a third-party server;

2. When updating the application, the tablet terminal needs to connect to the bugly background external network;

3. The apk files in our various regions need to be differentiated to avoid cross-linking when downloading (all are downloaded from the bugly background).

 

 

 

Guess you like

Origin blog.csdn.net/beita08/article/details/115251372