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. 自学Zabbix3.5-监控项item

    itemItems是从主机里面获取的所有数据.通常情况下item为监控项,一般网络设备.服务器加入了zabbix监控,就需要监控它的cpu负载,那么实现这个方法的东西就叫item. 1. item构成 ...

  2. Eclipse中Spring插件的安装

    java中为了方便学习使用SSH框架,框架插件的安装是非常必要的. 本博文记录了自己安装Spring插件的过程: 本机环境:win8 64bit eclipse版本:4.5.2 MARS 插件版本:S ...

  3. 在nginx上部署vue项目(history模式);

    在nginx上部署vue项目(history模式): vue-router 默认是hash模式,使用url的hash来模拟一个完整的url,当url改变的时候,页面不会重新加载.但是如果我们不想has ...

  4. 《软件开发者路线图:从学徒到高手》【PDF】下载

    <软件开发者路线图:从学徒到高手>[PDF]下载链接: https://u253469.ctfile.com/fs/253469-231196346 图书简介 作为一名软件开发者,你在奋力 ...

  5. Swift3.0 创建工程常用的类、三方、以及扩展 1.5

    搭建项目常用的方法属性,欢迎追加 三方: source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' use_framew ...

  6. Fiori缓存与它的清除

    最近在修改已有的Fiori应用,遇到了缓存上的一点问题,导致对Fiori应用的代码修改不能在前端页面生效.现将自己查到的一篇好资料翻译过来,以供参考.以下为正文. 2017.12.19更新:最近又遇到 ...

  7. scala写算法-用小根堆解决topK

    topK问题是指从大量数据中获取最大(或最小)的k个数,比如从全校学生中寻找成绩最高的500名学生等等. 本问题可采用小根堆解决.思路是先把源数据中的前k个数放入堆中,然后构建堆,使其保持堆序(可以简 ...

  8. 瞎j8封装第二版之用xml文件来代理dao接口

    也是重新整理了之前的那篇 模仿Mybatis用map per.xml实现Dao层接口的功能 话不多说直接上代码 首先是结构 依赖pom.xml <?xml version="1.0&q ...

  9. windows 下共享内存使用方法示例

    windows下共享内存使用方法较 linux 而言微微复杂 示例实现的功能 有一个视频文件,一块内存区域 : 程序 A,将该视频写入该内存区域 : 程序 B,从该内存区域读取该视频 : 代码模块实现 ...

  10. 调用CMD命令的一个.NET工具类(MyWindowsCmd)

    功能大概描述一下如果直接StandardOutput.ReadToEnd()这种方法,有很多限制 这类方式必须把命令全部执行一次写入并标记为exit,而且返回内容的获取会一直等待,如果在主线程里使用会 ...