使用DownloadManager来处理App下载功能的方式已经不算什么新鲜事,但我再真正使用时,却不断踩到坑,这也许就是许多人不推崇用它的原因吧,在此我说一些自己的处理方式。
先看整个代码:
public class UpdateService extends Service {
private String mPath;
private long mEnqueue;
public UpdateService() {
}
/**
* 安卓系统下载类
**/
DownloadManager manager;
/**
* 接收下载完的广播
**/
DownloadCompleteReceiver receiver;
/**
* 初始化下载器
**/
private void initDownManager() {
receiver = new DownloadCompleteReceiver();
//设置下载地址
Uri parse = Uri.parse(mPath);
DownloadManager.Request down = new DownloadManager.Request(parse);
// 设置允许使用的网络类型,这里是移动网络和wifi都可以
down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
// 下载时,通知栏显示途中
down.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
// 显示下载界面
down.setVisibleInDownloadsUi(true);
// 设置下载后文件存放的位置
File saveFile = new File(Environment.getExternalStorageDirectory(), "youjintang.apk");
down.setDestinationUri(Uri.fromFile(saveFile));
// down.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, "youjintang.apk");
// 将下载请求放入队列
mEnqueue = manager.enqueue(down);
Util.putLongValue(this, "DownloadManagerId", mEnqueue);
//注册下载广播
registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mPath = intent.getStringExtra("path");
// mPath = "http://gdown.baidu.com/data/wisegame/fd84b7f6746f0b18/baiduyinyue_4802.apk";
// 判断文件是否已存在。
File File = new File(Environment.getExternalStorageDirectory(), "youjintang.apk");
if (File.exists()) {
File.delete();
}
if (mPath != null && (!"".equals(mPath)) && mPath.endsWith(".apk")) {
if (isNeedDownloadAgain()) {
Toast.makeText(getApplicationContext(), "开始下载最新版App...", Toast.LENGTH_SHORT).show();
// 调用下载
initDownManager();
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
// 注销下载广播
if (receiver != null) unregisterReceiver(receiver);
super.onDestroy();
}
// 接受下载完成后的intent
class DownloadCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//判断是否下载完成的广播
if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
//获取下载的文件id
long downId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
// mHelper.putLong("DownloadManagerId",downId);
Log.d("kodulf", "id=" + downId);
//自动安装apk
Uri uriForDownloadedFile = manager.getUriForDownloadedFile(downId);
Log.d("kodulf", "uri=" + uriForDownloadedFile);
installApkNew(uriForDownloadedFile);
//停止服务并关闭广播
UpdateService.this.stopSelf();
}
}
//安装apk
protected void installApkNew(Uri uri) {
Intent intent = new Intent();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
intent.setAction(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
} else {
intent.setAction(Intent.ACTION_DEFAULT);
intent.addCategory(Intent.CATEGORY_DEFAULT);
File apkFile = queryDownloadedApk();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
}
//执行动作
// android.os.Process.killProcess(android.os.Process.myPid());
try {
startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 转换文件格式,适配版本系统
public File queryDownloadedApk() {
File targetApkFile = null;
if (mEnqueue != -1) {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(mEnqueue);
query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
Cursor cur = manager.query(query);
if (cur != null) {
if (cur.moveToFirst()) {
String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
if (!uriString.isEmpty()) {
targetApkFile = new File(Uri.parse(uriString).getPath());
}
}
cur.close();
}
}
return targetApkFile;
}
// 判断是否需要再次启动DownloadManager
private boolean isNeedDownloadAgain() {
boolean isNeedDownloadAgain = true;
DownloadManager.Query query = new DownloadManager.Query();
manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
long id = Util.getLongValue(this, "DownloadManagerId", -1L);
// Toast.makeText(getApplicationContext(), "id..."+id, Toast.LENGTH_SHORT).show();
if (id != -1) {
query.setFilterById(id);
Cursor cursor = manager.query(query);
if (cursor != null && cursor.moveToFirst()) {
int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
int status = cursor.getInt(columnIndex);
int columnReason = cursor.getColumnIndex(DownloadManager.COLUMN_REASON);
int reason = cursor.getInt(columnReason);
switch (status) {
case DownloadManager.STATUS_FAILED:
switch (reason) {
case DownloadManager.ERROR_CANNOT_RESUME:
//some possibly transient error occurred but we can't resume the download
break;
case DownloadManager.ERROR_DEVICE_NOT_FOUND:
//no external storage device was found. Typically, this is because the SD card is not mounted
break;
case DownloadManager.ERROR_FILE_ALREADY_EXISTS:
//the requested destination file already exists (the download manager will not overwrite an existing file)
break;
case DownloadManager.ERROR_FILE_ERROR:
//a storage issue arises which doesn't fit under any other error code
break;
case DownloadManager.ERROR_HTTP_DATA_ERROR:
//an error receiving or processing data occurred at the HTTP level
break;
case DownloadManager.ERROR_INSUFFICIENT_SPACE://sd卡满了
//here was insufficient storage space. Typically, this is because the SD card is full
break;
case DownloadManager.ERROR_TOO_MANY_REDIRECTS:
//there were too many redirects
break;
case DownloadManager.ERROR_UNHANDLED_HTTP_CODE:
//an HTTP code was received that download manager can't handle
break;
case DownloadManager.ERROR_UNKNOWN:
//he download has completed with an error that doesn't fit under any other error code
break;
}
isNeedDownloadAgain = true;
break;
case DownloadManager.STATUS_PAUSED:
switch (reason) {
case DownloadManager.PAUSED_QUEUED_FOR_WIFI:
//the download exceeds a size limit for downloads over the mobile network and the download manager is waiting for a Wi-Fi connection to proceed
break;
case DownloadManager.PAUSED_UNKNOWN:
//the download is paused for some other reason
break;
case DownloadManager.PAUSED_WAITING_FOR_NETWORK:
//the download is waiting for network connectivity to proceed
break;
case DownloadManager.PAUSED_WAITING_TO_RETRY:
//the download is paused because some network error occurred and the download manager is waiting before retrying the request
break;
}
isNeedDownloadAgain = false;
break;
case DownloadManager.STATUS_PENDING:
isNeedDownloadAgain = false;
// Toast.makeText(getApplicationContext(), "STATUS_PENDING...", Toast.LENGTH_SHORT).show();
break;
case DownloadManager.STATUS_RUNNING:
Toast.makeText(getApplicationContext(), "正在下载...", Toast.LENGTH_SHORT).show();
isNeedDownloadAgain = false;
break;
case DownloadManager.STATUS_SUCCESSFUL:
//the download has successfully completed
isNeedDownloadAgain = true;
// isNeedDownloadAgain = false;
// installApk(id, downloadManager, mContext);
break;
}
}
}
return isNeedDownloadAgain;
}
}
遇到的问题和处理方法:
1.重复点击下载多次开启Downloadmanager问题:通过获取它的状态判断处理。
2.Downloadmanager本身解决了7.0的ur文件权限问题,所以不需fileprovider;但安装时候仍要判断系统版本,版本小于7.0转换 文件类型安装。
3.如果用户不安装下次下载文件名改变的问题:判断文件是否存在。