[轉]使用Download Provider 進行檔案下載全攻略
Android內部提供了一個DownloadProvider,是一個非常完整的下載工具,提供了很好的外部介面可以被其他應用程式呼叫,來完成下載工作。同時也提供和很好的下載、通知、儲存等機制。
在Android的Browser等工具裡面都用到了這個DownloadProvider。
但是很遺憾的是,這個DownloadProvider不對app開發人員開放,只作為內部使用。
我們現在去探究如何將DownloadProvider拿來給自己用。
讓我們先找到DownloadProvider不能用的原因:
先找到它的原始碼,在這個位置:/packages/providers/DownloadProvider
開啟AndroidManifest.xml檔案,裡面有幾個自定義的許可權
這幾個許可權裡面都是android:protectionLevel="signatureOrSystem" 或者 android:protectionLevel="signature", 這個意思是隻有你的app擁有system許可權,或者和系統一樣的簽名,才能呼叫它。
這裡是問題的關鍵。那我們有兩種思路:
一種思路是:將這個protectionLevel改成normal,重新編譯DownloadProvider工程,讓其他app可以直接呼叫。
另一種思路是:將你自己的app弄成system許可權或者和系統一樣的簽名。
前一種思路已經完全成功了,第二種思路驗證了一部分。
先看第一種思路的辦法:
1)先將上面幾個許可權都改成:android:protectionLevel="normal"
2)重新編譯DownloadProvider
mmm packages/providers/DownloadProvider
3) 將編譯後的apk替換現有的apk
因為DownloadProvider.apk是系統app,你可以先給/system以root許可權,然後將這個app替換掉。 (作為一個使用者app安裝也可以,不過重啟以後就沒有了)
使用類似 # mount -t ubifs -o remount ubi0:system /system 或者 # mount -o remount ubi0:system /system 給/system rw許可權。
然後通過adb push 將DownloadProvider.apk push到 /system/app/下。系統會自動替換這個app。
4)寫一個工程來使用DownloadProvider.
直接貼原始碼了:
程式碼裡面引用了ParseException和WebAddress兩個類,可以從Android原始碼裡找到copy進來,在這裡frameworks/base/core/java/android/net。程式碼裡面有幾個地方比較重要的:
a) 通過往DownloadProvider提供的ContentProvider “content://downloads/download” 中插入資料就能觸發DownloadProvider的執行。
b) values.put("destination", 1); 是下載檔案儲存在什麼地方, 如果沒有這個引數,預設儲存在sdcard的download 下面 (Constants.java 中的 DEFAULT_DL_SUBDIR = "/download" )
如果指定為1,是往記憶體的 /cache目錄下存東西 (在/frameworks/base/core/java/android/provider/Downloads.java中定義, public static final int DESTINATION_CACHE_PARTITION = 1; )
b) 注意Manifest中的一堆許可權: ACCESS_DOWNLOAD_MANAGER是最基本的許可權,這樣可以使用DownloadProvider下載。
如果需要destination=1,則需要 ACCESS_DOWNLOAD_MANAGER許可權。(Downloads.java中的註釋 : All file types are allowed, and only the initiating
application can access the file (indirectly through a content provider). This requires the android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED permission.)如果沒有這個許可權,在往 content://downloads/download插入的時候有許可權問題報錯:
09-16 17:16:38.062: ERROR/DatabaseUtils(763): Writing exception to parcel
09-16 17:16:38.062: ERROR/DatabaseUtils(763): java.lang.SecurityException: unauthorized destination code
09-16 17:16:38.062: ERROR/DatabaseUtils(763): at com.android.providers.downloads.DownloadProvider.insert(DownloadProvider.java:277)
09-16 17:16:38.062: ERROR/DatabaseUtils(763): at android.content.ContentProvider$Transport.insert(ContentProvider.java:150)
09-16 17:16:38.062: ERROR/DatabaseUtils(763): at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:140)
09-16 17:16:38.062: ERROR/DatabaseUtils(763): at android.os.Binder.execTransact(Binder.java:287)
09-16 17:16:38.062: ERROR/DatabaseUtils(763): at dalvik.system.NativeStart.run(Native Method)
09-16 17:16:38.102: DEBUG/AndroidRuntime(4086): Shutting down VM因為DownloadProvider.java中有這段程式碼:
if (dest != null) {
if (getContext().checkCallingPermission(Downloads.PERMISSION_ACCESS_ADVANCED)
!= PackageManager.PERMISSION_GRANTED
&& dest != Downloads.DESTINATION_EXTERNAL
&& dest != Downloads.DESTINATION_CACHE_PARTITION_PURGEABLE) {
throw new SecurityException("unauthorized destination code");
}
所以:要往/cache目錄下存東西,一定要記得這個許可權哦。實際執行起來,只加這個許可權往/cache下存東西還不夠,就又把其他一堆許可權都加上了,具體哪些有用還沒細看。5) 將這個app直接以普通app安裝上去,執行,可以看到下載成功到/cache裡了。
第二種思路就是想辦法獲得system許可權或者簽名:
這樣不修改DownloadProvider的程式碼,不動它。
而是將自己編寫的app做完以後放到/packages/app目錄下和整個系統一起編譯,將其編譯到img中的系統app下 這樣編譯完成以後執行,使用編譯的img執行模擬器。在模擬器中啟動自己寫的呼叫DownloadProvider的app,發現竟然也是可以呼叫的。
不過這種方法在模擬器上成功了,但是在真機上沒成功,可能還有些問題沒解決。第一種方法是完全成功的。
相關文章
- 透過dns進行檔案下載DNS
- Download ProviderIDE
- 關於使用自動指令碼進行檔案下載指令碼
- 使用GnuPG對檔案進行加密(轉)加密
- 將多個檔案壓縮成zip檔案進行下載
- Retrofit2.0使用——帶進度下載檔案
- 使用 PHP 進行建立檔案並在下載後進行刪除PHP
- Mac下利用SSH進行傳輸檔案(轉)Mac
- 使用PHP下載檔案PHP
- C#如何使用HttpClient對大檔案進行斷點上傳和下載C#HTTPclient斷點
- 使用readfile()下載檔案
- android 系統下載 Download Manager(二)Download Manager使用詳情Android
- 【轉】c++ http下載檔案C++HTTP
- vue/js實現檔案流下載,檔案下載進度監聽VueJS
- 多執行緒下載檔案執行緒
- [轉載]上傳下載全攻略jspSmartUploadJS
- 【CLI】使用 Curl 下載檔案實時進度條顯示
- Linux或者國產OS下使用HHDESK進行檔案管理Linux
- 如何使用curl命令下載檔案
- 使用 header 頭下載檔案Header
- Golang 使用http Client下載檔案GolangHTTPclient
- 使用jQuery 完成ajax 檔案下載jQuery
- 使用Servlet實現檔案下載Servlet
- 使用SecureCRT上傳下載檔案Securecrt
- Python展示檔案下載進度條Python
- Android下載檔案(一)下載進度&斷點續傳Android斷點
- 檔案下載
- koa2基於stream(流)進行檔案上傳和下載
- Vue實現點選按鈕進行檔案下載(後端Java)Vue後端Java
- 如何使用post請求下載檔案
- Android檔案下載之進度檢測Android
- 介面返回二進位制檔案的下載。
- windows下ftp定時執行批次下載檔案,windows下ftp定時執行批次下載檔案的一種方法WindowsFTP
- 轉化成Access檔案下載的例項
- node使用multer進行檔案上傳
- Android原生下載(下篇)多檔案下載+多執行緒下載Android執行緒
- 00、下載檔案
- Ajax 下載檔案