摘要:本文将带你了解Android应用开发之Android应用版本更新,断点下载并安装方法,希望本文对大家学Android有所帮助。
本文将带你了解Android应用开发之Android应用版本更新,断点下载并安装方法,希望本文对大家学Android有所帮助。
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'
.权限
<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"/>
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; }}
18.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<messagebean>() { }.getType(); HttpUtils.getInstance().getData("https://www.xieast.com/api/checkversion.php", type, new NetCallBack() { //成功的方法 @Override public void Success(Object o) { //强转成我们所需的数据集合 MessageBeanmessageBean = (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>
本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之Android频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号