前言
每个Android App都会有版本更新的功能,而下载功能Google官方推荐使用 DownloadManager
服务, 一起来看看如何使用DownloadManager实现版本更新的功能。
使用DownloadManager
/**
* 下载Apk, 并设置Apk地址,
* 默认位置: /storage/sdcard0/Download
*
* @param context 上下文
* @param downLoadUrl 下载地址
* @param infoName 通知名称
* @param description 通知描述
*/
@SuppressWarnings("unused")
public static void downloadApk(
Context context,
String downLoadUrl,
String description,
String infoName) {
DownloadManager.Request request;
try {
request = new DownloadManager.Request(Uri.parse(appUrl));
} catch (Exception e) {
e.printStackTrace();
return;
}
request.setTitle(infoName);
request.setDescription(description);
//在通知栏显示下载进度
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
request.allowScanningByMediaScanner();
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
}
//设置保存下载apk保存路径
request.setDestinationInExternalPublicDir(CommonCons.SAVE_APP_LOCATION, CommonCons.SAVE_APP_NAME);
Context appContext = context.getApplicationContext();
DownloadManager manager = (DownloadManager)
appContext.getSystemService(Context.DOWNLOAD_SERVICE);
//进入下载队列
manager.enqueue(request);
}
当DownloadManager下载完成后会发出一个广播 android.intent.action.DOWNLOAD_COMPLETE,创建一个广播接收者,处理自动提示安装:
/**
* 安装下载接收器
* Created by maimingliang on 2016/8/11.
*/
public class InstallReceiver extends BroadcastReceiver {
private static final String TAG = "InstallReceiver";
// 安装下载接收器
@Override public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
installApk(context);
}
}
// 安装Apk
private void installApk(Context context) {
try {
Intent i = new Intent(Intent.ACTION_VIEW);
String filePath = CommonCons.APP_FILE_NAME;
i.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}catch (Exception e){
Log.e(TAG,"安装失败");
e.printStackTrace();
}
}
可以看出,实现起来其实是很容易的。不过要注意下面的几个坑:
坑一
图上报错的原因是 targetSdkVersion >=23 导致的,在API23以后引入了动态权限的概念。
如何解决?有两种方式:
方法一:
把build.gradle 文件中的targetSdkVersion < 23。这种方式也是最简单的。
方法二:
动态的获取权限:
@TargetApi(23)
private void getPersimmions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ArrayList<String> permissions = new ArrayList<String>();
/*
* 读写权限和电话状态权限非必要权限(建议授予)只会申请一次,用户同意或者禁止,只会弹一次
*/
// 读写权限
if (addPermission(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
permissionInfo += "Manifest.permission.WRITE_EXTERNAL_STORAGE Deny \n";
}
if (permissions.size() > 0) {
requestPermissions(permissions.toArray(new String[permissions.size()]), SDK_PERMISSION_REQUEST);
}
}
}
@TargetApi(23)
private boolean addPermission(ArrayList<String> permissionsList, String permission) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { // 如果应用没有获得对应权限,则添加到列表中,准备批量申请
if (shouldShowRequestPermissionRationale(permission)){
return true;
}else{
permissionsList.add(permission);
return false;
}
}else{
return true;
}
}
@TargetApi(23)
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// TODO Auto-generated method stub
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
坑二
有两种原因:
原因一:
没有权限读取这个文件或者文件路径错误。
解决方案:
把apk的路径固定死
String filePath = CommonCons.APP_FILE_NAME;
原因二:
单独设置data和type,如下:
i.setData(Uri.parse("file://" + filePath));
i.setType( "application/vnd.android.package-archive");
坑三
没有设置FLAG_ACTIVITY_NEW_TASK
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
坑四
APK签名不一致, 比如之前是debug版 现在你更新安装release版 .
DownloadManager 下载完 apk 自动提示安装Demo
END.