应用程序下载,并在通知栏提醒下载完成。过程大概分成三步:
此过程兼容了Android 7.0权限限制安装功能,Android 7.0 因为设置了“私有目录被限制访问”,“StricMode API”等安全机制,因此安装时会产生FileUriExposedException错误,此错误用FileProvider解决。
在AndroidMenifest.xml文件中注册provider,向外提供数据的组件。其中exported="false"必须设置成false,否则会报安全异常;grantUriPermissions="true"表示授予Uri临时访问权限;authorities组件标识,一般以包名开头。
指定共享的目录。在res文件下创建一个xml目录,再在xml目录下创建一个名为file_paths的资源文件。其中,file-path 表示Context.getFilesDir(),external-path表示Environment.getExternalStorageDirectory(),cache-path表示 getCacheDir()。
//path="" 表示共享根目录以及根目录下所有文件
使用FileProvider ,主要代码片段如下
Uri apkUri = FileProvider.getUriForFile(context,"com.nxyuntui.testproject.fileprovider",file);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
RxPermission 第三方动态库申请权限
首先gradle中添加动态库,接着申请权限。
implementation 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar'
implementation 'io.reactivex:rxjava:1.1.6'
//申请sd卡权限,targetSdkVersion>=23,需要动态申请
RxPermissions.getInstance(this)
//申请权限
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.subscribe(new Action1() {
@Override
public void call(Boolean aBoolean) {
if (aBoolean){
//请求成功
startDownload(downloadUrl);
}else{
//请求失败回收当前服务
stopSelf();
}
}
});
整体示例如下 :
AndroidMenifest.xml
DownLoadService.java
public class DownLoadService extends Service {
private BroadcastReceiver receiver;
private DownloadManager dm;
private long enqueue;
private String downloadUrl = "http://downapp.baidu.com";
@Override
public void onCreate() {
super.onCreate();
Log.i("DownLoadService","--onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("DownLoadService","--onStartCommand");
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
install(context);
stopSelf(); //销毁当前service
}
};
registerReceiver(receiver,new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
//申请sd卡权限,targetSdkVersion>=23,需要动态申请
RxPermissions.getInstance(this)
//申请权限
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.subscribe(new Action1() {
@Override
public void call(Boolean aBoolean) {
if (aBoolean){
//请求成功
startDownload(downloadUrl);
}else{
//请求失败回收当前服务
stopSelf();
}
}
});
return Service.START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i("DownLoadService","--onDestroy");
unregisterReceiver(receiver);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
public static void install(Context context){
File file = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"myApp.apk");
Intent intent = new Intent(Intent.ACTION_VIEW);
//没有在Activity环境下启动activity,设置如下标签
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (Build.VERSION.SDK_INT >= 24){
Uri apkUri = FileProvider.getUriForFile(context,
"com.nxyuntui.testproject.fileprovider",file);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri,"application/vnd.android.package-archive");
}else{
intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
}
context.startActivity(intent);
}
private void startDownload(String downloadUrl){
//获得系统下载器
dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
//设置下载地址
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downloadUrl));
//设置下载文件的类型
request.setMimeType("application/vnd.android.package-archive");
//设置下载存放的文件夹和文件名称
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,"myApp.apk");
//设置下载时或下载完成时,通知栏是否显示
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setTitle("下载新版本");
//执行下载,并返回任务唯一id
enqueue = dm.enqueue(request);
}
}
MainActivity.java
oncreat()里面调用此方法即可。
public void download(View view){
Log.i("MainActivity","--下载服务");
Intent intent = new Intent(this,DownLoadService.class);
startService(intent);
}
activity_main.xml