当前位置: 移动技术网 > IT编程>移动开发>Android > Android应用版本更新,断点下载并安装方法

Android应用版本更新,断点下载并安装方法

2018年10月26日  | 移动技术网IT编程  | 我要评论

韩剧直播,火星情报局3播出时间,獭兔价钱

android应用版本更新,断点下载并安装方法。

1.依赖:

//《okhttp网络请求依赖》
implementation 'com.squareup.okhttp3:okhttp:3.10.0'
//《gson解析依赖》
implementation 'com.google.code.gson:gson:2.8.2'
//《butterknife依赖(黄油刀)》
implementation 'com.jakewharton:butterknife:8.8.1'
annotationprocessor 'com.jakewharton:butterknife-compiler:8.8.1'
2.权限
<uses-permission android:name="android.permission.internet"/>
<uses-permission android:name="android.permission.mount_unmount_filesystems"
    tools:ignore="protectedpermissions" />
<uses-permission android:name="android.permission.write_external_storage"/>

<uses-permission android:name="android.permission.read_external_storage"/>

3.封装的外层bean

package com.example.dell.versionupdatedemo05.bean;

public class messagebean{
    private boolean success;
    private string msg;
    private t data;

    public boolean getsuccess() {
        return success;
    }

    public void setsuccess(boolean success) {
        success = success;
    }

    public string getmsg() {
        return msg;
    }

    public void setmsg(string msg) {
        this.msg = msg;
    }

    public t getdata() {
        return data;
    }

    public void setdata(t data) {
        this.data = data;
    }
}
4.封装的内层bean
package com.example.dell.versionupdatedemo05.bean;

public class versioninfo {
    private int last_must_update;//需强制更新的版本
    private int last_version;//需更新的版本
    private string md5;//md5码
    private string url;//下载地址

    public int getlast_must_update() {
        return last_must_update;
    }

    public void setlast_must_update(int last_must_update) {
        this.last_must_update = last_must_update;
    }

    public int getlast_version() {
        return last_version;
    }

    public void setlast_version(int last_version) {
        this.last_version = last_version;
    }

    public string getmd5() {
        return md5;
    }

    public void setmd5(string md5) {
        this.md5 = md5;
    }

    public string geturl() {
        return url;
    }

    public void seturl(string url) {
        this.url = url;
    }
}


5.定义成功与失败的接口

package com.example.dell.versionupdatedemo05;

//定义成功与失败的方法
public interface netcallback {
    void success(object o);
    void error(throwable t);
}

6.网络请求的工具类

package com.example.dell.versionupdatedemo05.utils;

import android.os.handler;
import com.example.dell.versionupdatedemo05.netcallback;
import com.google.gson.gson;
import java.io.ioexception;
import java.lang.reflect.type;
import okhttp3.call;
import okhttp3.callback;
import okhttp3.okhttpclient;
import okhttp3.request;
import okhttp3.response;

public class httputils {
    //1.创建一个私有的静态的单列模式
    private static volatile httputils instance;
    //13.创建一个公有的handler
    public handler handler = new handler() {};
    private final okhttpclient client;
    //2.创建一个私有的构造方法
    private httputils(){
        //9.创建okhttpclient
        client = new okhttpclient();
    }
    //3.提供一个公有的静态方法
    public static httputils getinstance(){
        //4.判空
        if(instance==null){
            //5.添加同步锁
            synchronized (httputils.class){
                if(null==instance){
                    //6.双向判空后 进行创建
                    instance = new httputils();
                }
            }
        }
        //7.返回instance
        return instance;
    }
    //8.创建一个方法 进行请求数据
    public void getdata(string url, final type type, final netcallback netcallback){
        //10.创建request对象
        final request request = new request.builder()
                .url(url)
                .get()
                .build();
        //11.创建call对象
        call call = client.newcall(request);
        //12.进行异步请求
        call.enqueue(new callback() {
            //失败的方法
            @override
            public void onfailure(call call,final ioexception e) {
                //19.将失败的信息进行返回
                handler.post(new runnable() {
                    @override
                    public void run() {
                        netcallback.error(new throwable(e));
                    }
                });
            }
            //成功的方法
            @override
            public void onresponse(final call call, response response) throws ioexception {
                //14.创建netcallback的接口
                // 15.解析数据
                string data = response.body().string();
                //16.使用gson进行解析
                gson gson = new gson();
              final  object o = gson.fromjson(data, type);
                //17.使用handler发送消息
                handler.post(new runnable() {
                    @override
                    public void run() {
                        //18.将传给的信息进行返回
                        netcallback.success(o);
                    }
                });
            }
        });
    }
}
7.获取应用版本的工具类
package com.example.dell.versionupdatedemo05.utils;

import android.content.context;
import android.content.pm.packageinfo;
import android.content.pm.packagemanager;

public class versionutils {
    //创建方法 得到本地版本
    public static int getversioncode(context context){
        //拿到包的管理器
        packagemanager packagemanager = context.getpackagemanager();
        packageinfo packageinfo=null;
        try {
            //通过包名拿到版本号
            packageinfo = packagemanager.getpackageinfo(context.getpackagename(), 0);
        } catch (packagemanager.namenotfoundexception e) {
            e.printstacktrace();
        }
        //返回版本号
        return packageinfo.versioncode;
    }
}
8.md5判断的工具类
package com.example.dell.versionupdatedemo05.utils;

import java.io.file;
import java.io.fileinputstream;
import java.math.biginteger;
import java.security.messagedigest;

public class filemd5utils {
    public static string getfilemd5(file file) {
        if (!file.isfile()) {
            return null;
        }
        messagedigest digest = null;
        fileinputstream in = null;
        byte buffer[] = new byte[1024];
        int len;
        try {
            digest = messagedigest.getinstance("md5");
            in = new fileinputstream(file);
            while ((len = in.read(buffer, 0, 1024)) != -1) {
                digest.update(buffer, 0, len);
            }
            in.close();
        } catch (exception e) {
            e.printstacktrace();
            return null;
        }
        biginteger bigint = new biginteger(1, digest.digest());
        return bigint.tostring(16);
    }
}

9.activity

package com.example.dell.versionupdatedemo05;

import android.app.progressdialog;
import android.content.dialoginterface;
import android.content.intent;
import android.content.sharedpreferences;
import android.net.uri;
import android.os.bundle;
import android.os.environment;
import android.support.v7.app.alertdialog;
import android.support.v7.app.appcompatactivity;
import android.util.log;
import android.widget.button;
import android.widget.textview;
import android.widget.toast;
import com.example.dell.versionupdatedemo05.bean.messagebean;
import com.example.dell.versionupdatedemo05.bean.versioninfo;
import com.example.dell.versionupdatedemo05.utils.filemd5utils;
import com.example.dell.versionupdatedemo05.utils.httputils;
import com.example.dell.versionupdatedemo05.utils.versionutils;
import com.google.gson.reflect.typetoken;
import java.io.file;
import java.io.ioexception;
import java.io.inputstream;
import java.io.randomaccessfile;
import java.lang.reflect.type;
import butterknife.bindview;
import butterknife.butterknife;
import butterknife.onclick;
import okhttp3.call;
import okhttp3.callback;
import okhttp3.okhttpclient;
import okhttp3.request;
import okhttp3.response;

public class mainactivity extends appcompatactivity {

    @bindview(r.id.mian_show)
    textview mian_show;
    @bindview(r.id.mian_btn)
    button mian_btn;
    private boolean ismust = false;//定义状态默认为false
    private file file;//初始化地址
    private progressdialog dialog;//初始化下载进度条
    private static final int intent_apk = 0x123;//创建十六进制数
    private sharedpreferences sp;//数据存储
    private long filelength = 0;//初始化数据总汉长度为0
    private boolean issaved = false;//定义标识 是否已经存储过长度

    @override
    protected void oncreate(bundle savedinstancestate) {
        super.oncreate(savedinstancestate);
        setcontentview(r.layout.activity_main);
        butterknife.bind(this);
        //初始化sharedpreferences
        sp = getsharedpreferences("info",mode_private);
        filelength = sp.getlong("length",0);
        issaved = sp.getboolean("is_saved",false);//初始化没有存储

        //判断外置存储是否挂载
        if(environment.getexternalstoragestate().equals(environment.media_mounted)){
            //若挂载 则创建存放位置(sdk中)
            file externalstoragedirectory = environment.getexternalstoragedirectory();
            string path = externalstoragedirectory.getabsolutepath() + file.separator + "new.apk";
            log.e("+++++存入路径", "oncreate: "+path );
            file = new file(path);
            //判断文件是否存在 不存在则创建
            if(!file.exists()){
                try {
                    file.createnewfile();
                } catch (ioexception e) {
                    e.printstacktrace();
                }
            }
        }

        //创建下载进度条
        dialog = new progressdialog(this);
        dialog.setprogressstyle(progressdialog.style_horizontal);//进度条样式为水平
        dialog.setmax(100);//设置最大值为100
        dialog.settitle("下载");
    }

    //点击时 进行版本检查
    @onclick(r.id.mian_btn)
    public void onviewclicked() {
        //创建检测版本有无更新的方法
        checkversion();
    }

    //定义检测版本有无更新的方法
    private void checkversion() {
        type type = new typetoken>() {
        }.gettype();
        httputils.getinstance().getdata("https://www.xieast.com/api/checkversion.php", type, new netcallback() {
            //成功的方法
            @override
            public void success(object o) {
                //强转成我们所需的数据集合
                messagebean messagebean = (messagebean) o;
                //log.e("+++++", "success: "+messagebean.getmsg());
                versioninfo info = messagebean.getdata();
                //创建判断当前版本是否需要更新的方法
                isneedupdate(info);
            }
            //失败的方法
            @override
            public void error(throwable t) {
                log.e("+++++", "error: " + t.getmessage());
            }
        });
    }

    //定义判断当前版本是否需要更新的方法
    private void isneedupdate(final versioninfo info) {
        //拿到当前的版本号
        int currentversioncode = versionutils.getversioncode(this);
        //判断当前版本号是否小于网络请求的需更新的版本号
        if (currentversioncode < info.getlast_version()) {
            //创建弹出对话框
            alertdialog.builder builder = new alertdialog.builder(this)
                    .settitle("版本更新")
                    .setmessage("检查到新的版本");
            //需要更新 判断当前的版本是否小于等于网络请求的需强制更新的版本号
            if (currentversioncode < info.getlast_must_update()) {
                //需强制更新 将状态值变成false
                ismust = false;
                builder.setpositivebutton("立即更新", new dialoginterface.onclicklistener() {
                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //创建更新apk文件的方法
                        downloadapk(info.geturl(),info.getmd5());
                        //设置监听事件
                    }
                }).setoncancellistener(new dialoginterface.oncancellistener() {
                    @override
                    public void oncancel(dialoginterface dialog) {
                        // 若不想更新 则点击模拟器返回按钮 关闭页面
                        finish();
                    }
                });
            } else {
                //可更新  不更新则将状态值变成false
                ismust = true;
                builder.setpositivebutton("更新", new dialoginterface.onclicklistener() {
                    @override
                    public void onclick(dialoginterface dialog, int which) {
                        //创建更新apk文件的方法
                        downloadapk(info.geturl(),info.getmd5());
                    }
                    //也可不更新
                }).setnegativebutton("取消", null);
            }
            //显示弹出框
            alertdialog dialog = builder.create();
            //设置强制更新时 弹出框点外部不会消失
            //ismust为true 失去焦点不隐藏
            dialog.setcanceledontouchoutside(ismust);//设置弹出框失去焦点是否隐藏,即点击屏蔽其它地方是否隐藏
            dialog.show();
        } else {
            // 吐司提示
            toast.maketext(this, "当前版本已经是最新版本了!", toast.length_short).show();
        }
    }

    //更新下载apk文件的方法
    private void downloadapk(string url, final string md5) {
        log.e("+++++", "downloadapk: 开始下载" );
        string range = "";//定义变量
        //进行判断
        if(issaved){
            //若存储过文件总长度 则直接将总长度赋给range即可
            range = "bytes="+file.length()+"-"+filelength;
        }else{
            //若没有存储过 则直接指定range为0
            range = "bytes="+file.length()+"-";
        }

        //使用原生okhttpclient进行请求
        okhttpclient client = new okhttpclient();
        final request request = new request.builder()
                .url(url)
                .addheader("range",range)
                .get()
                .build();
        call call = client.newcall(request);
        //下载是显示进度条
        dialog.show();
        call.enqueue(new callback() {
            @override //失败
            public void onfailure(call call, ioexception e) {
                dialog.dismiss();//失败时,进度条不显示
                log.e("+++++", "onfailure:下载失败 ");
            }

            @override //成功
            public void onresponse(call call, response response) throws ioexception {
                long contentlength =0;
                if(filelength==0){
                    //得到数据的总长度
                    contentlength = response.body().contentlength();
                    //并存入数据存储中
                    sp.edit().putlong("length",contentlength).commit();
                }else{
                    contentlength =filelength;
                }

                log.e("++++文件大小", "onresponse: "+contentlength);
                int length = 0;
                long sum = file.length() ;//定义一个总长度
                //创建随机存储的类 rw:可读可写模式
                randomaccessfile raf = new randomaccessfile(file,"rw");
                //移动到目前已经下载的文件大小的位置
                raf.seek(sum);
                //拿到流文件  inputstream输入流:往内存写数据
                inputstream inputstream = response.body().bytestream();
                //按照2048个字节进行写入
                byte[] bytes = new byte[2048];
                //循环写入
                while ((length = inputstream.read(bytes,0,bytes.length))!=-1){
                    sum+=length;//每次循环读取的数据赋给sum
                    raf.write(bytes,0,length);
                    raf.seek(sum);
                     //总长度*100/文件长度 = 进度
                    int progress = (int) (sum * 100 / contentlength);
                    //子线程不能更新ui,但是dialog内部已经回调到主线程了
                    dialog.setprogress(progress);//将进度赋给进度条
                    if(progress>99){
                        //下载完成 安装apk  并关闭dialog
                        dialog.dismiss();
                        //创建校验md5值的方法
                        checkapk(file,md5);
                        break;//循环完毕 跳出循环
                    }
                }
                //关流
                inputstream.close();
            }
        });
    }
    //创建校验md5的方法
    private void checkapk(file file, string md5) {
        //校验成功后再进行安装
        string filemd5 = filemd5utils.getfilemd5(file);
        log.e("+++++", "checkapk:源文件的md5值 "+filemd5 );
        log.e("+++++", "checkapk: 下载的md5值"+md5 );
        //tolowercase:全部转为小写  equalsignorecase:忽略大小写
        if(filemd5.equalsignorecase(md5)) {
            installapk(file);//创建安装apk方法
        }else{
            log.e("++++", "checkapk:文件不合法 " );
        }
    }

    //安装apk的方法
    private void installapk(file file) {
        log.e("++++", "installapk:进行安装 " );
        intent intent = new intent();
        intent.setaction(intent.action_view);
        intent.addcategory(intent.category_default);
        intent.setdataandtype(uri.fromfile(file),"application/vnd.android.package-archive");
        intent.setflags(intent.flag_activity_new_task);//启动另一个任务栈
        startactivityforresult(intent,intent_apk);
        system.exit(0);//安装完成后 退出即可
    }
}
10.主布局
xml version="1.0" encoding="utf-8"?>
<linearlayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <textview
        android:id="@+id/mian_show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="hello world!" />
    <button
        android:id="@+id/mian_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="版本检查"/>

linearlayout>

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网