效果图##
DownloadManager(主角)##
作用:下载管理器是一个处理长时间运行的HTTP下载的系统服务。客户端可能要求将URI下载到特定的目标文件。下载管理器将在后台进行下载。
过程:在MainActivity中开启IntentService服务,在IntentService中进行下载操作,完成后发出广播,在MainActivity中接收广播并进行安装apk
两个内部类
class | DownloadManager.Query | 用来过滤下载管理器查询 |
class | DownloadManager.Request | 这个类包含请求新下载所必需的所有信息 |
布局情况
只有一个按钮
开启服务
当点击按钮的时候,进行开启服务
//DownloadService继承于IntentService,一会说明
Intent serviceIntent = new Intent(MainActivity.this, DownloadService.class);
//写入你的apk下载地址,下面这个地址只是模拟的
serviceIntent.setData(Uri.parse("http://..../vooloc.apk"));
//开启服务,不要写成了startActivity;
startService(serviceIntent);
新建DownloadService类继承于IntentService##
重写方法onHandleIntent ( Intent intent )
1.Request设定
/*获取下载地址*/
String url = intent.getDataString();
/*获取DownloadManager对象*/
DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
/*指定APK缓存路径和应用名称,比如我这个路径就是/storage/emulated/0/Download/vooloc.apk*/
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "vooloc.apk");
/*设置网络下载环境为wifi或者移动数据*/
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
/*设置显示通知栏,下载完成后通知栏自动消失*/
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
/*设置通知栏标题*/
request.setTitle("下载");
/*设置这个下载的描述,显示在通知中*/
request.setDescription("应用正在下载");
/*设置类型为.apk*/
request.setMimeType("application/vnd.android.package-archive");
/*获得唯一下载id*/
long requestId = downloadManager.enqueue(request);
2.Query设定
//将id放进Intent
Intent localIntent = new Intent(BROADCAST_ACTION);
localIntent.putExtra(EXTENDED_DATA_STATUS, requestId);
//查询下载信息
DownloadManager.Query query = new DownloadManager.Query();
//只包括带有给定id的下载。
query.setFilterById(requestId);
3.进行下载
try {
boolean isGoging = true;
while (isGoging) {
Cursor cursor = downloadManager.query(query);
if (cursor != null && cursor.moveToFirst()) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch (status) {
//如果下载状态为成功
case DownloadManager.STATUS_SUCCESSFUL:
isGoging = false;
//调用LocalBroadcastManager.sendBroadcast将intent传递回去
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
mLocalBroadcastManager.sendBroadcast(localIntent);
break;
}
}
if (cursor != null) {
cursor.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
5.别忘了在清单文件(AndroidManifest)注册服务
<service
android:name=".DownloadService"
android:exported="false">
<intent-filter>
<action android:name="com.example.android.threadsample.BROADCAST" />
</intent-filter>
</service>
回到MainActivity,注册广播##
private void regist() {
IntentFilter intentFilter = new IntentFilter(DownloadService.BROADCAST_ACTION);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, intentFilter);
}
新建类MyReceiver继承于BroadcastReceiver##
/*找到下载好的apk*/
File file=new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),"vooloc.apk");
/*获取权限*/
try {
Runtime.getRuntime().exec("chmod 777"+file.getCanonicalPath());
} catch (IOException e) {
e.printStackTrace();
}
/*由于没有在Activity环境下启动Activity,设置下面的标签*/
intent = new Intent(Intent.ACTION_VIEW);
/*如果设置,这个活动将成为这个历史堆栈上的新任务的开始*/
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
/*判读版本是否在7.0以上*/
if(Build.VERSION.SDK_INT>=24){
/*7.0及以上的版本,私有目录被限制访问*/
Uri apkUri = FileProvider.getUriForFile(context, "com.example.yx.downloadapk.FileProvider", file);
/*添加这一句表示对目标应用临时授权该Uri所代表的文件*/
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
}else{
/*7.0以下的版本*/
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
}
startActivity(intent);
取消广播
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
申请权限
Android6.0开始,危险权限需要动态申请!!!
刚好这里的第二个权限是危险权限…
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
动态申请权限
//动态申请权限
private void requestPermission() {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
}
适配7.0
由于Android7.0以上私有目录被限制访问,还要做些其他工作
打开清单文件(AndroidManifest),加上这段
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.yx.downloadapk.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
第二行的格式 android:authorities=“包名.FileProvider”
接下来在res文件夹下新建xml文件夹
在XML文件夹中新建file_paths.xml
在file_paths.xml写入
<?xml version="1.0" encoding="utf-8"?>
<resources>
<paths>
<external-path path="" name="download"/>
</paths>
</resources>
完整代码
MainActivity
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
MyReceiver receiver = new MyReceiver();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//动态申请权限
requestPermission();
//初始化数据
initView();
//注册广播
regist();
}
//动态申请权限
private void requestPermission() {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
}
//初始化数据
private void initView() {
Button btn_download = (Button) findViewById(R.id.btn_download);
btn_download.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//DownloadService继承IntentService,一会说明
Intent serviceIntent = new Intent(MainActivity.this, DownloadService.class);
//写入你的apk下载地址,下面这个地址只是模拟的
serviceIntent.setData(Uri.parse("http://..../vooloc.apk"));
//开启服务,不要写成了startActivity(serviceIntent);
startService(serviceIntent);
}
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "vooloc.apk");
//获取权限
try {
Runtime.getRuntime().exec("chmod 777" + file.getCanonicalPath());
} catch (IOException e) {
e.printStackTrace();
}
// 由于没有在Activity环境下启动Activity,设置下面的标签
intent = new Intent(Intent.ACTION_VIEW);
//如果设置,这个活动将成为这个历史堆栈上的新任务的开始
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//判读版本是否在7.0以上
if (Build.VERSION.SDK_INT >= 24) {
//7.0以上的版本
Uri apkUri = FileProvider.getUriForFile(context, "com.example.yx.downloadapk.FileProvider", file);
//添加这一句表示对目标应用临时授权该Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
} else {
//7.0以下的版本
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
}
startActivity(intent);
}
}
//注册广播
private void regist() {
IntentFilter intentFilter = new IntentFilter(DownloadService.BROADCAST_ACTION);
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
LocalBroadcastManager.getInstance(this).registerReceiver(receiver, intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
}
}
DownloadService
public class DownloadService extends IntentService {
private static final String TAG = "DownloadService";
public static final String BROADCAST_ACTION = "com.example.android.threadsample.BROADCAST";
public static final String EXTENDED_DATA_STATUS = "com.example.android.threadsample.STATUS";
private LocalBroadcastManager mLocalBroadcastManager;
public DownloadService() {
super("DownloadService");
}
@Override
protected void onHandleIntent(@Nullable Intent intent) {
//获取下载地址
String url = intent.getDataString();
Log.i(TAG, url);
//获取DownloadManager对象
DownloadManager downloadManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
//指定APK缓存路径和应用名称,比如我这个路径就是/storage/emulated/0/Download/vooloc.apk
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "vooloc.apk");
//设置网络下载环境为wifi或者移动数据
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE);
//设置显示通知栏,下载完成后通知栏自动消失
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
//设置通知栏标题
request.setTitle("下载");
//设置这个下载的描述,显示在通知中
request.setDescription("应用正在下载");
//设置类型为.apk
request.setMimeType("application/vnd.android.package-archive");
//获得唯一下载id
long requestId = downloadManager.enqueue(request);
//将id放进Intent
Intent localIntent = new Intent(BROADCAST_ACTION);
localIntent.putExtra(EXTENDED_DATA_STATUS, requestId);
//查询下载信息
DownloadManager.Query query = new DownloadManager.Query();
//只包括带有给定id的下载。
query.setFilterById(requestId);
try {
boolean isGoging = true;
while (isGoging) {
Cursor cursor = downloadManager.query(query);
if (cursor != null && cursor.moveToFirst()) {
int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch (status) {
//如果下载状态为成功
case DownloadManager.STATUS_SUCCESSFUL:
isGoging = false;
//调用LocalBroadcastManager.sendBroadcast将intent传递回去
mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
mLocalBroadcastManager.sendBroadcast(localIntent);
break;
}
}
if (cursor != null) {
cursor.close();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
样例网盘下载
IDE环境不同,直接导入我的项目可能会报红,目的不是去直接使用我的代码,只是为了方便观看,可以在自己的IDE环境下自己写一遍运行看看