DownloadManager下載APK並安裝(適配7.0,免費下載)
阿新 • • 發佈:2019-02-09
效果圖
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環境下自己寫一遍執行看看