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

本文demo下载:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=121

1. 运行前准备

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

2. 本实例运行效果图: 

2.1 启动应用程序

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

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

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

    }

本文demo下载:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=121

Android App版本自动更新的更多相关文章

  1. Android(2)—Mono For Android App版本自动更新

    0.前言 公司Android查询的项目已经开始,整体采用Java后台+App前台来实现,由于项目小,App这块就我一个人开发,首先需要研究的是:Android版本的更新升级问题:本人经过近一周的学习整 ...

  2. Android(3)—Mono For Android App版本自动更新(2)

    0.前言 这篇博文是上一篇的延续,主要是修改上一个版中的BUG和优化一些待完善的项,也算是结贴,当然还有需要完善的,等日后项目中用到的时候再单独写出来吧,本篇主要写升级改进的部分: 改进1.修复[BU ...

  3. Android实现App版本自动更新

    现在很多的App中都会有一个检查版本的功能.例如斗鱼TV App的设置界面下: 当我们点击检查更新的时候,就会向服务器发起版本检测的请求.一般的处理方式是:服务器返回的App版本与当前手机安装的版本号 ...

  4. 如何实现已发布app的自动更新

    要实现app的自动更新,做两件事情就可以搞定 1.获取当前手机中的app版本号 我们可以通过查询mainbundle中的获取CFBundleVersion NSDictionary *infoDict ...

  5. C#.Net版本自动更新程序及3种策略实现

    C#.Net版本自动更新程序及3种策略实现 C/S程序是基于客户端和服务器的,在客户机编译新版本后将文件发布在更新服务器上,然后建立一个XML文件,该文件列举最新程序文件的版本号及最后修改日期.如程序 ...

  6. 获取 Android APP 版本信息工具类(转载)

    获取 Android APP 版本信息工具类 获取手机APP版本信息工具类 1.获取版本名称 2.获取版本号 3.获取App的名称 package com.mingyue.nanshuibeidiao ...

  7. Android 版本自动更新

    截图如下: 代码实现如下: package com.update.apk; import java.io.BufferedReader; import java.io.File; import jav ...

  8. 【Android 应用开发】Android应用的自动更新模块

    . 作者 :万境绝尘  转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/18964835 . 软件的自动更新一般都与Splash界 ...

  9. 安卓程序代写 网上程序代写[原]Android应用的自动更新模块

    软件的自动更新一般都与Splash界面绑定在一起, 由于需要维护的软件界面很复杂, 一个Activity中嵌入ViewPager, 并且逻辑比较复杂, 索性重新写一个Activity, 现在的软件都很 ...

随机推荐

  1. anaconda不能安装python的包问题

    在点了n次,重启应用多次之后,安装包(apply)之后还是没有反应,依然心平气和的我突然想到用管理员模式打开,结果就可以愉快的装包了,估计创建新的环境也是要管理员打开的.

  2. 增加tomcat的缓存

    起因是我做了一个批量压缩图片的功能,在服务器上跑这个功能的时候,发现服务器有警告.警告的内容大概如下.  XX....  to the cache because there was insuffic ...

  3. 用maven建立java web项目

    1.在eclipse的菜单栏选择File->New->Other->Maven->Maven ,并在第一个框打勾,然后点击下一步 2.转换为java的Dynamic Web P ...

  4. 【功能代码】---3 JS判断字符串是否包含某个字符串

    JS判断字符串是否包含某个字符串 var str ="abc"; if(str.indexOf("bc")>-1){ alert('str中包含bc字符串 ...

  5. iOS手势之pinch

    今天用地图的时候有用到pinch 捏合手势 通过捏合手势动作可以很轻松的来改变视图元素的一个比例 手势的动作状态有如下三种,一般是按照顺序来进行转换的. 1. UIGestureRecognizerS ...

  6. 配置SQL Server on Linux(2)

    1. 前言 前一篇配置SQL Server on Linux(1),地址:http://www.cnblogs.com/fishparadise/p/8125203.html ,是关于更改数据库排序规 ...

  7. 微信小程序教学第三章(含视频):小程序中级实战教程:列表-页面逻辑处理

    § 页面逻辑处理 本文配套视频地址: https://v.qq.com/x/page/n0554dndrez.html 开始前请把 ch3-2 分支中的 code/ 目录导入微信开发工具 修改 ind ...

  8. INITTAB 配置文件

    Inittab 文件详解       init的进程号是1(ps -aux | less),从这一点就能看出,init进程是系统所有进程的起点,Linux在完成核内引导以后,就开始运行init程序. ...

  9. > library('ggplot2') Error in loadNamespace(i, c(lib.loc, .libPaths()), versionCheck = vI[[i]]) : 不存在叫‘colorspace’这个名字的程辑包

    > library('ggplot2')Error in loadNamespace(i, c(lib.loc, .libPaths()), versionCheck = vI[[i]]) : ...

  10. linux下查看系统属性

    inux下查看系统属性1.查看cpu信息查看所有cpu信息:cat /proc/cpuinfo查看cpu类型: grep "model name" /proc/cpuinfo2.查 ...