1、定义一个下载工具类
public class DownloadManagerUtil {
private Context mContext;
public DownloadManagerUtil(Context context) {
mContext = context;
}
public long download(String url, String title, String desc) {
Uri uri = Uri.parse(url);
DownloadManager.Request req = new DownloadManager.Request(uri);
//设置WIFI下进行更新
//req.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
//下载中和下载完后都显示通知栏
req.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
//使用系统默认的下载路径 此处为应用内 /android/data/packages ,所以兼容7.0
String apkName;
if(url.endsWith(".apk")){
apkName = url.substring(url.lastIndexOf("/"));
}else {
apkName = "sswl_game_"+System.currentTimeMillis()+".apk";
}
req.setDestinationInExternalFilesDir(mContext, Environment.DIRECTORY_DOWNLOADS, apkName);
req.setVisibleInDownloadsUi(true);
//通知栏标题
req.setTitle(title);
//通知栏描述信息
req.setDescription(desc);
//设置类型为.apk
req.setMimeType("application/vnd.android.package-archive");
//获取下载任务ID
DownloadManager dm = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
long loadId = dm.enqueue(req);
Log.i("min77","loadId = "+loadId);
return loadId;
}
/**
* 下载前先移除前一个任务,防止重复下载
*
* @param downloadId
*/
public void clearCurrentTask(long downloadId) {
DownloadManager dm = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
try {
dm.remove(downloadId);
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
}
}
}
2、定义一个receiver接收下载进度的广播
public class DownloadReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
//下载完成跳转去安装apk
long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
installApk(context, id);
} else if (intent.getAction().equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)) {
//处理 如果还未完成下载,用户点击Notification ,跳转到下载中心
Intent viewDownloadIntent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
viewDownloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(viewDownloadIntent);
}
}
private static void installApk(Context context, long downloadApkId) {
try {
DownloadManager dm = (DownloadManager)context.getSystemService(Context.DOWNLOAD_SERVICE);
Intent paramIntent = new Intent("android.intent.action.VIEW");
//获取当前下载id数据库游标
Cursor cursor = dm.query(new DownloadManager.Query().setFilterById(new long[] { downloadApkId }));
cursor.moveToFirst();
//获取下载apk文件uri的列数
int fileUriIdx = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI);
//获取下载apk文件uri
String fileUri = cursor.getString(fileUriIdx);
paramIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri;
// 7.0+ 需要将file://的uri转换为更安全的content://,并且增加读取uri权限
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
String path="";
if (fileUri != null) {
path = Uri.parse(fileUri).getPath();
}
uri = FileProvider.getUriForFile(context, context.getPackageName() + ".sswl.provider", new File(path));
paramIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// //兼容8.0
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// boolean hasInstallPermission = context.getPackageManager().canRequestPackageInstalls();
// if (!hasInstallPermission) {
// startInstallPermissionSettingActivity(context);
// return;
// }
// }
}else {
uri = Uri.parse(fileUri);
}
//设置打开apk格式文件
paramIntent.setDataAndType(uri, "application/vnd.android.package-archive");
if(!TextUtils.isEmpty(DownloadManagerUtil.apkMd5)){
//服务端有下发MD5
ParcelFileDescriptor parcelFileDescriptor = context.getContentResolver().openFileDescriptor(uri, "rw");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
fileDescriptor.sync();
if(fileDescriptor.valid()){
//正常获取到fileDescriptor对象
FileInputStream fis = new FileInputStream(fileDescriptor);
String md5 = Md5Utils.getFileMD5(fis);
Log.i("min77","md5 = "+md5);
if (DownloadManagerUtil.apkMd5.equalsIgnoreCase(md5)) {
//计算出的MD5一致
handleDownloadedApk(context, paramIntent);
}else {
ToastUtils.show(context, ResourceUtil.getString(context,"com_sswl_apk_md5_error"));
// 要是系统下载器下载的apk MD5不对,则跳转到外部浏览器下载
Uri uri1 = Uri.parse(DownloadManagerUtil.downloadUrl);
Intent intent = new Intent(Intent.ACTION_VIEW, uri1);
context.startActivity(intent);
}
}else {
handleDownloadedApk(context, paramIntent);
Log.e("min77"," fileDescriptor1.valid() = "+fileDescriptor.valid());
}
}else {
handleDownloadedApk(context, paramIntent);
}
} catch (Exception e) {
e.printStackTrace();
openLocalDir(context);
}
}
/**
* 处理下载好的apk
* @param context
* @param paramIntent
*/
private static void handleDownloadedApk(Context context, Intent paramIntent) {
if (paramIntent.resolveActivity(context.getPackageManager()) != null) {
//存在安装apk的activity,则打开安装界面
context.startActivity(paramIntent);
} else {
//不存在安装apk的activity,则打开apk所在目录
openLocalDir(context);
}
DownloadManagerUtil.apkMd5 = "";
}
/**
* 跳转到设置-允许安装未知来源-页面
*/
@TargetApi(Build.VERSION_CODES.O)
private static void startInstallPermissionSettingActivity(Context context) {
//后面跟上包名,可以直接跳转到对应APP的未知来源权限设置界面。使用startActivityForResult 是为了在关闭设置界面之后,获取用户的操作结果,然后根据结果做其他处理
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + context.getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
private static void openLocalDir(Context context){
//调用系统文件管理器打开指定路径目录
//获取到指定文件夹,这里为:/storage/emulated/0/Android/data/你的包 名/files/Download
File file = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
//7.0以上跳转系统文件需用FileProvider,参考链接:https://blog.csdn.net/growing_tree/article/details/71190741
Uri uri = FileProvider.getUriForFile(context,context.getPackageName() + ".sswl.provider",file);
intent.setData(uri);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
2、记得在AndroidManifest.xml中声明
1)声明访问网络权限、读写外部存储权限、安装apk权限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- android 8.0+ 需要这个权限才能安装apk -->
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
2)声明receiver下载广播接收器
<receiver android:name=".receiver.DownloadReceiver">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
<action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED" />
</intent-filter>
</receiver>