Android应用中apk下载更新,适用于android 9及以下安卓版本。
直接上代码:
一、在主配置文件中写权限。
//在此加入
//在res文件夹下新建package命名为xml,新建xml文件命名为files_paths
二、创建 files_paths.xml
三、创建 UpdateVersionController.java
public class UpdateVersionController {
private Button cancelBtn;
private Context context;
private int info;
private int info3;
private int versionCode;//当前版本号
private Dialog dialog; //提示用户更新的dialog
private ProgressDialog pd; //下载进度条
public static UpdateVersionController getInstance(Context context) {
return new UpdateVersionController(context);
}
public UpdateVersionController(Context context) {
this.context = context;
}
/*
* 记得运行该方法
*/
public void forceCheckUpdateInfo(){
//获取版本号,这个版本号为未更新的版本号
versionCode = getVerCode(context);
//获取app新版版本信息,添加网络请求
new Thread(new Runnable() {
@Override
public void run() {
/*
*用的Volley框架,Volley可以自己搜索下载jar包,下面是使用Volley获取GET请求的方法
*/
RequestQueue mQueue= Volley.newRequestQueue(context);
JsonObjectRequest mreq=new JsonObjectRequest(Request.Method.GET,“获取版本号的网址”,new Response.Listener() {
@Override
public void onResponse(JSONObject jsonObject) {
String tt=jsonObject.toString(); //把获取的jsonObject转为String类型
Gson gson=new Gson(); //这里我用的是Gson解析,可以自己搜索gson的jar包下载使用
AppVersion nt=gson.fromJson(tt, AppVersion.class); //这里的AppVersion是网络获取版本号的网址中json数据的实体类,tt是网络获取的数据,用该方法实现json解析
//关于实体类:从服务器网址获取的json数据,通过搜索json自动生成实体类下载复制。并 implement Serializable ,添加构造方法
info=nt.getVNumber(); //通过nt获取实体类里的版本号,为String类型
info3=nt.getIsForce(); //通过nt获取是否强制更新,为String类型
Log.e("版本",""+versionCode);//建议输出一下版本号,进行对比
//更新app版本号比对,info新版本号和当前的版本号versionCode做对比,如果新版本号大于本版本就运行更新方法showUpdataDialog()
if ( info > versionCode) {
showUpdataDialog();
} else {
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError volleyError) {
Log.e("*****", String.valueOf(volleyError));
}
});
mQueue.add(mreq);
}
}).start();
}
/**
* 弹出对话框提示用户更新
*/
protected void showUpdataDialog() {
dialog = new Dialog(context, android.R.style.Theme_Dialog);
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
dialog.setContentView(R.layout.activity_updater);
dialog.setCanceledOnTouchOutside(false);
dialog.setCancelable(false);
((TextView) dialog.findViewById(R.id.content)).setText("是否进行更新?");
cancelBtn = (Button) dialog.findViewById(R.id.cancel);
cancelBtn.setVisibility("0".equals(info3) ? View.GONE : View.VISIBLE);
// 取消更新
cancelBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
// 确认更新
dialog.findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
downLoadApk();
}
});
dialog.show();
}
/**
* 步骤三:下载文件
*/
private void downLoadApk() {
// 进度条对话框
pd = new ProgressDialog(context);
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMessage("下载中...");
pd.setCanceledOnTouchOutside(false);
pd.setCancelable(false);
// 监听返回键--防止下载的时候点击返回
pd.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
Toast.makeText(context, "正在下载请稍后", Toast.LENGTH_SHORT).show();
return true;
} else {
return false;
}
}
});
// Sdcard不可用
if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
Toast.makeText(context, "SD卡不可用", Toast.LENGTH_SHORT).show();
} else {
pd.show();
//下载的子线程
new Thread() {
@Override
public void run() {
try {
// 在子线程中下载APK文件
File file = getFileFromServer(“下载apk的网址 ”, pd);
sleep(1000);
// 安装APK文件
OpenFileUtil.openFileByPath(context,file.toString());
pd.dismiss(); // 结束掉进度条对话框
} catch (Exception e) {
Toast.makeText(context, "文件下载失败了", Toast.LENGTH_SHORT).show();
pd.dismiss();
e.printStackTrace();
}
}
}.start();
}
}
/**
* 从服务器下载apk
*/
public File getFileFromServer(String path, ProgressDialog pd) throws Exception {
// 如果相等的话表示当前的sdcard挂载在手机上并且是可用的
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
// 获取到文件的大小
pd.setMax(conn.getContentLength() / 1024);
InputStream is = conn.getInputStream();
String p = PathUtils.path;
File file = new File(p+ "/update/aaaa.apk");
Log.e("File路径",""+file);
//判断文件夹是否被创建
boolean mkdirs;
if (!file.getParentFile().exists()) {
mkdirs = file.getParentFile().mkdirs();
}
FileOutputStream fos = new FileOutputStream(file);
BufferedInputStream bis = new BufferedInputStream(is);
byte[] buffer = new byte[1024];
int len;
int total = 0;
while ((len = bis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
total += len;
// 获取当前下载量
pd.setProgress(total / 1024);
}
fos.close();
bis.close();
is.close();
return file;
} else {
return null;
}
}
/**
* 获取版本号
*/
public static int getVerCode(Context context) {
int verCode = -1;
try {
// 获取packagemanager的实例
PackageManager packageManager = context.getPackageManager();
// getPackageName()是你当前类的包名,0代表是获取版本信息
PackageInfo packInfo = packageManager.getPackageInfo(
context.getPackageName(), 0);
verCode = packInfo.versionCode;
} catch (Exception e) {
e.printStackTrace();
}
return verCode;
}
}
三、创建OpenFileUtil.java 打开任意文件也可以使用该类
public class OpenFileUtil {
private static final String[][] MATCH_ARRAY={
//{后缀名, 文件类型}
{".3gp", "video/3gpp"},
{".apk", "application/vnd.android.package-archive"},
{".asf", "video/x-ms-asf"},
{".avi", "video/x-msvideo"},
{".bin", "application/octet-stream"},
{".bmp", "image/bmp"},
{".c", "text/plain"},
{".class", "application/octet-stream"},
{".conf", "text/plain"},
{".cpp", "text/plain"},
{".doc", "application/msword"},
{".docx", "application/msword"},
{".xls", "application/msword"},
{".xlsx", "application/msword"},
{".exe", "application/octet-stream"},
{".gif", "image/gif"},
{".gtar", "application/x-gtar"},
{".gz", "application/x-gzip"},
{".h", "text/plain"},
{".htm", "text/html"},
{".html", "text/html"},
{".jar", "application/java-archive"},
{".java", "text/plain"},
{".jpeg", "image/jpeg"},
{".jpg", "image/jpeg"},
{".js", "application/x-javascript"},
{".log", "text/plain"},
{".m3u", "audio/x-mpegurl"},
{".m4a", "audio/mp4a-latm"},
{".m4b", "audio/mp4a-latm"},
{".m4p", "audio/mp4a-latm"},
{".m4u", "video/vnd.mpegurl"},
{".m4v", "video/x-m4v"},
{".mov", "video/quicktime"},
{".mp2", "audio/x-mpeg"},
{".mp3", "audio/x-mpeg"},
{".mp4", "video/mp4"},
{".mpc", "application/vnd.mpohun.certificate"},
{".mpe", "video/mpeg"},
{".mpeg", "video/mpeg"},
{".mpg", "video/mpeg"},
{".mpg4", "video/mp4"},
{".mpga", "audio/mpeg"},
{".msg", "application/vnd.ms-outlook"},
{".ogg", "audio/ogg"},
{".pdf", "application/pdf"},
{".png", "image/png"},
{".pps", "application/vnd.ms-powerpoint"},
{".ppt", "application/vnd.ms-powerpoint"},
{".prop", "text/plain"},
{".rar", "application/x-rar-compressed"},
{".rc", "text/plain"},
{".rmvb", "audio/x-pn-realaudio"},
{".rtf", "application/rtf"},
{".sh", "text/plain"},
{".tar", "application/x-tar"},
{".tgz", "application/x-compressed"},
{".txt", "text/plain"},
{".wav", "audio/x-wav"},
{".wma", "audio/x-ms-wma"},
{".wmv", "audio/x-ms-wmv"},
{".wps", "application/vnd.ms-works"},
{".xml", "text/plain"},
{".z", "application/x-compress"},
{".zip", "application/zip"},
{"", "*/*"}
};
/**
* 根据路径打开文件
* @param context 上下文
* @param path 文件路径
*/
public static void openFileByPath(Context context, String path) {
if(context==null||path==null)
return;
Intent intent = new Intent();
//设置intent的Action属性
intent.setAction(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(Intent.CATEGORY_DEFAULT);
//文件的类型
String type = "";
for(int i =0;i < MATCH_ARRAY.length;i++){
//判断文件的格式
if(path.contains(MATCH_ARRAY[i][0])){
type = MATCH_ARRAY[i][1];
break;
}
}
try {
File out = new File(path);
Uri fileURI;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// 由于7.0以后文件访问权限,可以通过定义xml在androidmanifest中申请,也可以直接跳过权限
// 通过定义xml在androidmanifest中申请
// fileURI = FileProvider.getUriForFile(context,
// "com.lonelypluto.zyw_test.provider",
// out);
// 直接跳过权限
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
fileURI = Uri.fromFile(out);
}else{
fileURI = Uri.fromFile(out);
}
//设置intent的data和Type属性
intent.setDataAndType(fileURI, type);
//跳转
if (context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
context.startActivity(intent);
} else {
Toast.makeText(context, "没有找到对应的程序", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) { //当系统没有携带文件打开软件,提示
Toast.makeText(context, "无法打开该格式文件", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}
三、PathUtils .java
public class PathUtils {
public static String path = null;
}
四、程序入口MainActivity.java
private UpdateVersionController controller=new UpdateVersionController(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
PathUtils.path = getExternalFilesDir(null).toString();
controller.forceCheckUpdateInfo();//运行该方法
if (Build.VERSION.SDK_INT>=23&&checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO},1);
requestPermissions(new String[]{Manifest.permission.INTERNET},1);
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
requestPermissions(new String[]{Manifest.permission.ACCESS_NETWORK_STATE},1);
requestPermissions(new String[]{Manifest.permission.ACCESS_WIFI_STATE},1);
requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE},1);
requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},1);
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},1);
requestPermissions(new String[]{Manifest.permission.CAMERA},1);
requestPermissions(new String[]{Manifest.permission.GET_TASKS},1);
requestPermissions(new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES},1);
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},1);
}
}
完成了。