首先學習下FileProvider
看這里 http://www.reibang.com/p/e05f35fbb569
整理下方便用到的時候直接copy怔揩,先這樣,以后有空再改琼稻。
安裝的代碼
權限
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
fun installCheck(context: Context,file: File) {
if (!file.exists()) {
return
}
//下邊這部分不一定需要
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (context.getPackageManager().canRequestPackageInstalls()) {
} else {
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + context.getPackageName()))
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(intent)
return
}
}
installApk(context, file)
}
//安裝apk吮螺,兼容7.0
private fun installApk(context: Context, file: File) {
if (!file.exists()) {
return
}
val intent = Intent(Intent.ACTION_VIEW)
// 沒有在Activity環(huán)境下啟動Activity,設置下面的標簽
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
var uri: Uri
//版本在7.0以上是不能直接通過uri訪問的
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//參數1 上下文, 參數2 Provider主機地址和清單文件中保持一致 參數3 共享的文件
uri = FileProvider.getUriForFile(context, "com.charlie.fileProvider", file)
//添加這一句表示對目標應用臨時授權該Uri所代表的文件
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
} else {
uri = Uri.fromFile(file)
}
intent.setDataAndType(uri, "application/vnd.android.package-archive")
// intent.setDataAndType(Uri.parse("file://" + file.toString()), "application/vnd.android.package-archive");
context.startActivity(intent)
}
FileProvider的配置
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.charlie.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths">
</meta-data>
</provider>
file_path.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!--Context.getFilesDir().-->
<files-path
name="filepath"
path="filepath"/>
<!-- getCacheDir().-->
<cache-path
name="cachepath"
path="cachepath"/>
<!-- Environment.getExternalStorageDirectory().-->
<external-path
name="externalpath"
path="/"/>
<!-- Context.getExternalCacheDir(). -->
<external-cache-path
name="externalcachepath"
path="externalcachepath"/>
<!--Context#getExternalFilesDir(String) Context.getExternalFilesDir(null). -->
<external-files-path
name="externalfilespath"
path="externalfilespath"/>
</paths>
使用系統(tǒng)下載
工具類
import java.io.File;
import android.app.DownloadManager;
import android.app.DownloadManager.Request;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.net.Uri;
import android.os.Environment;
import android.text.TextUtils;
import android.util.Log;
public abstract class FileDownManager {
private DownloadManager downloadManager;
private String fileName;
private String saveDir;
public static String DOWNLOAD_SP_NAME = "download_sp_name";
public Context mContext;
public abstract Context getContext();
public SharedPreferences getSp() {
return getContext().getSharedPreferences(DOWNLOAD_SP_NAME, Context.MODE_PRIVATE);
}
public abstract String savedFileName(String url, String newVersion);
public abstract String savedFileDir();
public File getSavedFile() {
return new File(Environment.getExternalStorageDirectory(),saveDir+"/"+fileName);
}
public static String downloadKey = "downID";
public static String downloadVersionKey = "version";
public long getDownloadID() {
return getSp().getLong(downloadKey, -1);
}
public String getDownloadVersion() {
return getSp().getString(downloadVersionKey, "0");
}
public void downOrSuccessAction(String url, String newVersion) {
saveDir = savedFileDir();
fileName = savedFileName(url, newVersion);
downloadManager = (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE);
String downVersion = getSp().getString(downloadVersionKey, null);
if (TextUtils.equals(newVersion, downVersion)) {
long id = getSp().getLong(downloadKey, -1);
if (id == -1) {
down(url, newVersion);
} else {
query(url, id, newVersion);
}
} else {
getSp().edit().putString(downloadVersionKey, newVersion).commit();
down(url, newVersion);
}
}
private void down(String url, String newVersion) {
Uri resource = Uri.parse(url);
DownloadManager.Request request = new DownloadManager.Request(resource);
request.setAllowedNetworkTypes(Request.NETWORK_MOBILE | Request.NETWORK_WIFI);
request.setAllowedOverRoaming(false);
// set file mime type
// MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
// String mimeString =
// mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url));
// request.setMimeType(mimeString);
// show notification on the state bar
request.setVisibleInDownloadsUi(true);
request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
// set the saving file's directory and name
request.setDestinationInExternalPublicDir(saveDir, fileName);
requestCustom(request);
try {
long id = downloadManager.enqueue(request);
getSp().edit().putLong(downloadKey, id).commit();
} catch (Exception e) {
e.printStackTrace();
enableDownloadManager(getContext());
}
}
public void requestCustom(DownloadManager.Request request) {
}
private void query(String url, long id, String newVersion) {
System.out.println("query========="+url+"==="+id+"==="+newVersion);
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(id);
Cursor c = downloadManager.query(query);
if(c==null) {
System.out.println("cursor null============");
redownload(url, id, newVersion);//download record history was cleared
}
else if (c.moveToFirst()) {
int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
switch (status) {
case DownloadManager.STATUS_PAUSED:
Log.v("down", "STATUS_PAUSED");
case DownloadManager.STATUS_PENDING:
Log.v("down", "STATUS_PENDING");
case DownloadManager.STATUS_RUNNING:
Log.v("down", "STATUS_RUNNING");
break;
case DownloadManager.STATUS_SUCCESSFUL:
Log.v("down", "STATUS_SUCCESSFUL");
String name=c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
String uri=c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
String uri_d=c.getString(c.getColumnIndex(DownloadManager.COLUMN_URI));//the http url address
//name=/storage/emulated/0/justdelete/apkdown/appname1.2.apk
//file:///storage/emulated/0/justdelete/apkdown/appname1.2.apk
File savedFile=getSavedFile();
System.out.println("name="+name+"=="+uri+"==="+uri_d+"====="+savedFile.getAbsolutePath());
if (savedFile.exists()) {
downloadSuccess(savedFile);
} else {
System.out.println("file not exist");
redownload(url, id, newVersion);
}
break;
case DownloadManager.STATUS_FAILED:
Log.v("down", "STATUS_FAILED");
redownload(url, id, newVersion);
break;
default:
Log.v("down", "STATUS_====="+status);
break;
}
}else {
System.out.println("===================cursor size 0");
redownload(url, id, newVersion);
}
}
private void redownload(String url, long id, String newVersion) {
// if file not exist or download failed,redownload.
downloadManager.remove(id);
getSp().edit().remove(downloadKey).commit();
down(url, newVersion);
}
protected void downloadSuccess(File downloadFile) {
System.out.println("downloadfile size======"+downloadFile.length());
}
public static void enableDownloadManager(Context context) {
try {
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:com.android.providers.downloads"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
}
然后對于不同的下載類型繼承工具類饶囚,修改key值即可
如下舉了2種例子帕翻,一種下載apk鸠补,一種下載一個zip文件
apk類型下載
import java.io.File;
import android.content.Context;
public class APKDownloadManager extends FileDownManager{
public static APKDownloadManager apkDownloadManager;
public static APKDownloadManager getInstance(Context context) {
if(apkDownloadManager==null) {
synchronized (APKDownloadManager.class) {
if(apkDownloadManager==null) {
apkDownloadManager=new APKDownloadManager();
}
}
}
apkDownloadManager.mContext=context;
return apkDownloadManager;
}
public APKDownloadManager() {
downloadKey="apk_down_id";
downloadVersionKey="apk_version";
}
@Override
public Context getContext() {
if(mContext==null) {
mContext=MyApplication.application;
}
return mContext;
}
@Override
public String savedFileDir() {
return "justdelete/apkdown";
}
@Override
public String savedFileName(String url, String newVersion) {
return "appname"+newVersion+".apk";
}
@Override
protected void downloadSuccess(File downloadFile) {
super.downloadSuccess(downloadFile);
//安裝apk,7.0以上需要權限嘀掸,并且uri獲取也需要fileprovider
System.out.println("apk download success================="+downloadFile.getAbsolutePath());
}
}
zip文件類型下載
import java.io.File;
import android.content.Context;
public class MapDownloadManager extends FileDownManager{
public static MapDownloadManager mapDownloadManager;
public static MapDownloadManager getInstance(Context context) {
if(mapDownloadManager==null) {
synchronized (MapDownloadManager .class) {
if(mapDownloadManager==null) {
mapDownloadManager=new MapDownloadManager();
}
}
}
mapDownloadManager.mContext=context;
return mapDownloadManager;
}
public MapDownloadManager() {
downloadKey="map_down_id";
downloadVersionKey="map_version";
}
@Override
public Context getContext() {
if(mContext==null) {
mContext=MyApplication.application;
}
return mContext;
}
@Override
public String savedFileName(String url, String newVersion) {
return "map"+newVersion+".zip";
}
@Override
public String savedFileDir() {
return "justdelete/savedMap";
}
@Override
protected void downloadSuccess(File downloadFile) {
//map download success
System.out.println("map download success=============="+downloadFile.getAbsolutePath());
}
}
然后是廣播
import java.io.File;
import java.util.Arrays;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.text.TextUtils;
public class FileDownloadReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
System.out.println("intent======action====" + intent.getAction());
if (TextUtils.equals(intent.getAction(), DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
long reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if (reference == -1) {
return;
}
String filePath = getFilePath(context, reference);
File file = new File(filePath);
if (file.exists() && file.length() > 0) {
APKDownloadManager apkDownloadManager = APKDownloadManager.getInstance(context);
if (reference == apkDownloadManager.getDownloadID()) {
apkDownloadManager.downloadSuccess(file);
return;
}
MapDownloadManager mapDownloadManager = MapDownloadManager.getInstance(context);
if (reference == mapDownloadManager.getDownloadID()) {
mapDownloadManager.downloadSuccess(file);
return;
}
}
} else if (TextUtils.equals(intent.getAction(), DownloadManager.ACTION_NOTIFICATION_CLICKED)) {
long[] ids=intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
System.out.println("ids=============="+Arrays.toString(ids));
}
}
private String getFilePath(Context context, long id) {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(id);
Cursor c = ((DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE)).query(query);
if (c != null && c.moveToFirst()) {
String name = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
return name;
}
return "";
}
}
注冊廣播紫岩,權限添加,click那個action測試用的,可以不要
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<receiver android:name=".FileDownloadReceiver">
<intent-filter >
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
<action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"/>
</intent-filter>
</receiver>
下載代碼睬塌,判斷是否需要下載邏輯就看實際情況了
APKDownloadManager.getInstance(null).downOrSuccessAction("http://d2.eoemarket.com/app0/38
/38199/apk/1957269.apk?channel_id=426", "1.4");
代碼說明
這個是設置下載的文件保存的文件夾泉蝌,以及文件的名字的,需要注意第一個參數是sdcard根目錄下的目錄的名字揩晴。你可以隨便起個"AAA/BBB/CCC"都可以勋陪。
request.setDestinationInExternalPublicDir(saveDir, fileName);
點到代碼里看下,系統(tǒng)建議是用它自帶的那些目錄,都分門別類了硫兰,比如Environment.DIRECTORY_DOWNLOADS就是Download目錄了诅愚。不過上邊也說了,你隨便寫個目錄也可以
public Request setDestinationInExternalPublicDir(String dirType, String subPath) {
File file = Environment.getExternalStoragePublicDirectory(dirType);
//goon
* @param type The type of storage directory to return. Should be one of
* {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
* {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
* {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
* {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
* {@link #DIRECTORY_DCIM}. May not be null.
*
* @return Returns the File path for the directory. Note that this
* directory may not yet exist, so you must make sure it exists before
* using it such as with {@link File#mkdirs File.mkdirs()}.
*/
public static File getExternalStoragePublicDirectory(String type) {
throwIfUserRequired();
return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
}
打開下載管理器應用界面
downloadManager.enqueue(request)
上邊的代碼進行了異常處理劫映,因為如果下載管理器沒有啟動的話违孝,會拋出異常,我們在這里就調用下邊的代碼打開下載管理器頁面泳赋,讓用戶手動啟動.當然中間你可以添加一個彈框雌桑,告訴用戶點擊啟動按鈕。
/**
* Start activity to Settings to enable DownloadManager.
*/
public static void enableDownloadManager(Context context) {
try {
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:com.android.providers.downloads"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
系統(tǒng)下載通知的一些參數說明
還可以監(jiān)聽通知欄的點擊事件,添加如下的action即可祖今,這個是文件沒下完的時候點擊事件校坑,下載完再點擊通知欄,系統(tǒng)會自己處理相應的文件的衅鹿。
public final static String ACTION_NOTIFICATION_CLICKED = "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
下載完成的監(jiān)聽
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
通知欄可見性參數
request.setNotificationVisibility(Request.VISIBILITY_VISIBLE);
4種:下載中可見撒踪,始終不可見,下載中和完成都可見,只有完成的時候可見
/**
* This download is visible but only shows in the notifications
* while it's in progress.
*/
public static final int VISIBILITY_VISIBLE = 0;
/**
* This download is visible and shows in the notifications while
* in progress and after completion.
*/
public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 1;
/**
* This download doesn't show in the UI or in the notifications.
*/
public static final int VISIBILITY_HIDDEN = 2;
/**
* This download shows in the notifications after completion ONLY.
* It is usuable only with
* {@link DownloadManager#addCompletedDownload(String, String,
* boolean, String, String, long, boolean)}.
*/
public static final int VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION = 3;
需要注意大渤,設置不可見的時候需要權限
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/>
題外話
下邊的方法可以跳轉到下載歷史記錄頁面
Intent intent=new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
startActivity(intent);
下載異常
測試的時候到jira上找個apk地址制妄,結果下載完一直提示我解析失敗,我瀏覽器可以正常下載啊泵三。
后來換了個瀏覽器耕捞,才發(fā)現這地址需要登陸的,我默認的瀏覽器是登陸狀態(tài)烫幕,所以可以正常下俺抽。手機端因為沒有登陸,其實下了個html文件回來较曼。