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. webpack入门(2)

    webpack入门(2) ps:每个案例都是基于前一个案例改造的 webpack入门(1) 戳这里 案例源码戳这里 十二.ProvidePlugin 自动加载模块 new webpack.Provid ...

  2. Java中流-----个人总结心得

    流 字符流 字节流 缓冲区 数据流---用于传输数据.IO流---Input/Output流.数据从外部流向程序---输入流:数据从程序流向外部的时候--输出流.读取一个文件---数据从文件流向程序- ...

  3. CentOS7给终端配置快捷键【转发】

    1.打开Applications,选择System Tools 2.选择Setting进入如下面界面,选择Keyboard 3.选择Keyboard,进入如下面界面,再点击Shortcuts 4.再点 ...

  4. CentOS下nginx php mysql 环境搭建

    CentOS下搭建PHP运行环境. 首先是在虚拟机上装好一个命令行的CentOS,如果只是弄服务器的话,不要装图形界面,会比较卡. 一.安装编译工具及库文件 yum -y install make z ...

  5. 自学Zabbix3.8.1.1-可视化Visualisation-Graphs简单图表

    自学Zabbix3.8.1.1-可视化Visualisation-Graphs简单图表 Zabbix提供了一些简单的图表,用于可视化由项目收集的数据. 用户不需要进行配置工作来查看简单的图表.他们是由 ...

  6. Hadoop:Rack Awareness

    副本的放置对HDFS可靠性和性能至关重要. 优化副本放置HDFS有别于其他大多数分布式文件系统. 这是一个功能,需要大量的调优和经验. 基于机架感知(rack awareness)的副本放置策略的目的 ...

  7. 「mysql优化专题」主从复制面试宝典!面试官都没你懂得多!(11)

    内容较多,可先收藏,目录如下: 一.什么是主从复制 二.主从复制的作用(重点) 三.主从复制的原理(重中之重) 四.三步轻松构建主从 五.必问面试题干货分析(最最重要的点) 一.什么是主从复制(技术文 ...

  8. 关于close和shutdown

    我们知道TCP是全双工的,可以在接收数据的同时发送数据.假设有主机A在和主机B通信,可以认为是在两者之间存在两个管道.就像这样:A ---------> BA <--------- B 1 ...

  9. 查看系统分区df,查看、设置、修改、删除ACL权限

    df [root@localhost ~]# df -h 文件系统 容量 已用 可用 已用% 挂载点 /dev/sda5 16G 1.4G 15G 9% / devtmpfs 479M 0 479M ...

  10. PL/SQL Developer使用技巧(部分)

    PL/SQL Developer使用技巧(部分) 关键字自动大写 在sql命令窗口中输入SQL语句时,想要关键字自动大写,引人注目该怎么办呢? 一步设置就可以达成了.点击Tools->Prefe ...