App在开发过程中,随着业务场景的不断增多,功能的不断完善,早期下载App的用户便无法体验最新的功能,为了能让用户更及时的体验App最新版本,在App开发过程加入App自动更新功能便显得尤为重要。更新apk主要分为二类: (1)用户点击更新后,前台进行下载,下载过程中用户无法操作 (2)后台进行下载,下载完成后,service回调进行apk的安装,下载过程中用户可操作,本来讲解第一种

     1. 运行前准备

    本文附带实例: 实例中会下载一个应用程序(本公司的另一个产品:优鲜派 无病毒,请安心测试), 如果用户需要体验自动下载其它的产品,请自行配置apk下载路径:  将下图中的url路径换成自己的apk路径即可, apk的路径可以到360或者应用宝的官方网站上获取

Android集成自动更新 android自动更新版本_版本号

 2. 本实例运行效果图: 

        2.1 启动应用程序

Android集成自动更新 android自动更新版本_python_02

 2.2 点击 更新 操作, 开始下载最新版本apk,进度条显示下载进度

Android集成自动更新 android自动更新版本_Android集成自动更新_03

2.3 apk下载完成之后,自动安装下载的apk包, 注意下图的箭头处的意思

Android集成自动更新 android自动更新版本_Android集成自动更新_04

3.代码讲解

      3.1 程序启动后, 调用后台接口获取最新apk版本信息(包括版本号与版本需要升级功能信息), 将最新版本号与当前apk版本号进行比较,如果版本号不一致,则弹出提示框,提示用户新版本中包含哪些最新信息, 用户根据自动需要选择是否更新

       获得当前apk版本号:

public static int getVersion(Context context) {
        try {
            PackageManager manager = context.getPackageManager();
            PackageInfo info = manager.getPackageInfo(context.getPackageName(),
                    0);
            String version = info.versionName;
            int versioncode = info.versionCode;
            return versioncode;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

由于无法模拟与后台的交互,这里将网络版本号写死,比当前apk版本号要大,模拟更新的场景

       弹出对话框,提示新版本新功能

private void getVersion(final int vision) {
    //         {"data":{"content":"其他bug修复。","id":"2","api_key":"android",
    //         // "version":"2.1"},"msg":"获取成功","status":1}
            String data = "";
            //网络请求获取当前版本号和下载链接
            //实际操作是从服务器获取
            //demo写死了
     
            String newversion = "2.1";//网络版本号
            String content = "\n" +
                    "就不告诉你我们更新了什么-。-\n" +
                    "\n" +
                    "----------万能的分割线-----------\n" +
                    "\n" +
                    "(ㄒoㄒ) 被老板打了一顿,还是来告诉你吧:\n" +
     
                    "1.下架商品误买了?恩。。。我搞了点小动作就不会出现了\n" +
                    "2.侧边栏、弹框优化 —— 这个你自己去探索吧,总得留点悬念嘛-。-\n";//更新内容
     
            double newversioncode = Double
                    .parseDouble(newversion);
            int cc = (int) (newversioncode);
     
            System.out.println(newversion + "v" + vision + ",,"
                    + cc);
            if (cc != vision) {
                if (vision < cc) {
                    System.out.println(newversion + "v"
                            + vision);
                    // 版本号不同
                    ShowDialog(vision, newversion, content, url);
                }
            }
        }

  3.2 在弹出的对话框,用户点击"更新"与"取消"操作

          更新时构建进度条页面

private void ShowDialog(int vision, String newversion, String content, final String url) {
            new android.app.AlertDialog.Builder(this)
                    .setTitle("版本更新")
                    .setMessage(content)
                    .setPositiveButton("更新", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                            pBar = new CommonProgressDialog(MainActivity.this);
                            pBar.setCanceledOnTouchOutside(false);
                            pBar.setTitle("正在下载");
                            pBar.setCustomTitle(LayoutInflater.from(
                                    MainActivity.this).inflate(
                                    R.layout.title_dialog, null));
                            pBar.setMessage("正在下载");
                            pBar.setIndeterminate(true);
                            pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
                            pBar.setCancelable(true);
                            // downFile(URLData.DOWNLOAD_URL);
                            final DownloadTask downloadTask = new DownloadTask(
                                    MainActivity.this);
                            downloadTask.execute(url);
                            pBar.setOnCancelListener(new DialogInterface.OnCancelListener() {
                                @Override
                                public void onCancel(DialogInterface dialog) {
                                    downloadTask.cancel(true);
                                }
                            });
                        }
                    })
                    .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            dialog.dismiss();
                        }
                    })
                    .show();
        }


 3.3 开启线程类下载应用程序,将下载进度显示到进度条上

         线程启动前调用:   onPreExecute

         线程下载apk过程:  onPostExecute

         进度条更新:       onProgressUpdate

         下载apk完成回调:  onPostExecute

class DownloadTask extends AsyncTask<String, Integer, String> {
 
    private Context context;
    private PowerManager.WakeLock mWakeLock;
 
    public DownloadTask(Context context) {
        this.context = context;
    }
 
    @Override
    protected String doInBackground(String... sUrl) {
        InputStream input = null;
        OutputStream output = null;
        HttpURLConnection connection = null;
        File file = null;
        try {
            URL url = new URL(sUrl[0]);
            connection = (HttpURLConnection) url.openConnection();
            connection.connect();
            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                return "Server returned HTTP "
                        + connection.getResponseCode() + " "
                        + connection.getResponseMessage();
            }
 
            int fileLength = connection.getContentLength();
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                file = Environment.getExternalStorageDirectory();
                if (!file.exists()) {
                    // 判断父文件夹是否存在
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                }
                file = new File(file, DOWNLOAD_NAME);
            } else {
                Toast.makeText(MainActivity.this, "sd卡未挂载", Toast.LENGTH_LONG).show();
            }
            input = connection.getInputStream();
            output = new FileOutputStream(file);
            byte data[] = new byte[4096];
            long total = 0;
            int count;
            while ((count = input.read(data)) != -1) {
                // allow canceling with back button
                if (isCancelled()) {
                    input.close();
                    return null;
                }
                total += count;
                // publishing the progress....
                if (fileLength > 0) // only if total length is known
                    publishProgress((int) (total * 100 / fileLength));
                output.write(data, 0, count);
 
            }
        } catch (Exception e) {
            System.out.println(e.toString());
            return e.toString();
 
        } finally {
            try {
                if (output != null)
                    output.close();
                if (input != null)
                    input.close();
            } catch (IOException ignored) {
                ignored.toString();
            }
            if (connection != null)
                connection.disconnect();
        }
        return null;
    }
 
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // take CPU lock to prevent CPU from going off if the user
        // presses the power button during download
        PowerManager pm = (PowerManager) context
                .getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                getClass().getName());
        mWakeLock.acquire();
        pBar.show();
    }
 
    @Override
    protected void onProgressUpdate(Integer... progress) {
        super.onProgressUpdate(progress);
        // if we get here, length is known, now set indeterminate to false
        pBar.setIndeterminate(false);
        pBar.setMax(100);
        pBar.setProgress(progress[0]);
    }
 
    @Override
    protected void onPostExecute(String result) {
        mWakeLock.release();
        pBar.dismiss();
        if (result != null) {
            // 申请多个权限。
            AndPermission.with(MainActivity.this)
             .requestCode(REQUEST_CODE_PERMISSION_SD)
             .permission(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE)
            // rationale作用是:用户拒绝一次权限,再次申请时先征求用户同意,再打开授权对话框,避免用户勾选不再提示。
             .rationale(rationaleListener
             ).send();
            Toast.makeText(context, "您未打开SD卡权限" + result, Toast.LENGTH_LONG).show();
        } else {
            update(context);
        }
 
    }
}

4. 安装下载完的apk包

private void update(Context context) {
        //安装应用
        Log.i("lxl  update->","update");
     
        File apkFile = new File(Environment.getExternalStorageDirectory(), DOWNLOAD_NAME);
     
        Intent intent =new Intent(Intent.ACTION_VIEW);
     
        if (apkFile == null || context == null) {
            Log.i("lxl  update->","null.");
            throw new NullPointerException();
        }
     
        if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.N) {
     
                Uri contentUri = FileProvider.getUriForFile(context.getApplicationContext(),
                        BuildConfig.APPLICATION_ID + ".fileProvider",apkFile);
     
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
     
                intent.setDataAndType(contentUri,"application/vnd.android.package-archive");
                Log.i("lxl  update->",">>>==Build.VERSION_CODES.N");
     
        }else{
     
          intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
     
          intent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
            Log.i("lxl  update->","<<<<<  Build.VERSION_CODES.N");
        }
     
        startActivity(intent);
     
    }