admin管理员组文章数量:1532323
2023年12月13日发(作者:)
使用Download Provider 进行文件下载全攻略
Android内部提供了一个DownloadProvider,是一个非常完整的下载工具,提供了很好的外部接口可以被其他应用程序调用,来完成下载工作。同时也提供和很好的下载、通知、存储等机制。
在Android的Browser等工具里面都用到了这个DownloadProvider。
但是很遗憾的是,这个DownloadProvider不对app开发人员开放,只作为内部使用。
我们现在去探究如何将DownloadProvider拿来给自己用。
让我们先找到DownloadProvider不能用的原因:
先找到它的源代码,在这个位置:/packages/providers/DownloadProvider
打开文件,里面有几个自定义的权限
1.
2. android:name="_DOWNLOAD_MANAGER" 3. android:label="@string/permlab_downloadManager" 4. android:description="@string/permdesc_downloadManager" 5. android:protectionLevel="signatureOrSystem" /> 6. 7. android:name="_DOWNLOAD_MANAGER_ADVANCED" 8. android:label="@string/permlab_downloadManagerAdvanced" 9. android:description="@string/permdesc_downloadManagerAdvanced" 10. android:protectionLevel="signatureOrSystem" /> 11. 12. android:name="_CACHE_FILESYSTEM" 13. android:label="@string/permlab_cacheFilesystem" 14. android:description="@string/permdesc_cacheFilesystem" 15. android:protectionLevel="signature" /> 16. 17. android:name="_DOWNLOAD_COMPLETED_INTENTS" 18. android:label="@string/permlab_downloadCompletedIntent" 19. android:description="@string/permdesc_downloadCompletedIntent" 20. android:protectionLevel="signature" /> 复制代码 这几个权限里面都是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 因为是系统app,你可以先给/system以root权限,然后将这个app替换掉。 (作为一个用户app安装也可以,不过重启以后就没有了) 使用类似 # mount -t ubifs -o remount ubi0:system /system 或者 # mount -o remount ubi0:system /system 给/system rw权限。 然后通过adb push 将 push到 /system/app/下。系统会自动替换这个app。 4)写一个工程来使用DownloadProvider. 直接贴源码了: 1. package nload; 2. 3. import tFoundException; 4. import ; 5. import ty; 6. import tResolver; 7. import tValues; 8. import t; 9. import ; 10. import ; 11. import l; 12. /** 13. * @author lixinso 14. * 使用DownloadProvider 15. */ 16. public class DownloadActivity extends Activity { 17. @Override 18. public void onCreate(Bundle savedInstanceState) { 19. te(savedInstanceState); 20. setContentView(); 21. 22. //String url = "192.168.200.76:8080/webserver/dancing-skeleton.3gp"; 23. String contentDisposition = "attachment; filename="dancing-skeleton.3gp""; 24. String mimetype = "video/3GPP"; 25. 26. String filename = ileName(url,contentDisposition, mimetype); 27. 28. URI uri = null; 29. 30. try { 31. // Undo the percent-encoding that KURL may have done. 32. String newUrl = new String((es())); 33. // Parse the url into pieces 34. WebAddress w = new WebAddress(newUrl); 35. String frag = null; 36. String query = null; 37. String path = ; 38. // Break the path into path, query, and fragment 39. if (() > 0) { 40. // Strip the fragment 41. int idx = dexOf('#'); 42. if (idx != -1) { 43. frag = ing(idx + 1); 44. path = ing(0, idx); 45. } 46. idx = dexOf('?'); 47. if (idx != -1) { 48. query = ing(idx + 1); 49. path = ing(0, idx); 50. } 51. } 52. uri = new URI(e, nfo, , , path, 53. query, frag); 54. } catch (Exception e) { 55. //Log.e(LOGTAG, "Could not parse url for download: " + url, e); 56. return; 57. } 58. 59. ContentValues values = new ContentValues(); 60. ("uri", ng()); 61. ("useragent", "Mozilla/5.0 (linux; U; Android 1.5; en-us; SDK Build/CUPCAKE) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1"); 62. ("notificationpackage", getPackageName()); 63. ("notificationclass", "HelloWorld"); 64. ("visibility", 1); 65. ("mimetype", mimetype); 66. ("hint", filename); 67. ("description", t()); 68. ("total_bytes", 1349528); 69. ("destination", 1); 70. 71. 72. 73. //这些参数参考:DownloadProvider工程中的: 74. //public static DownloadFileInfo generateSaveFile( 75. // Context context, 76. // String url, 77. // String hint, 78. // String contentDisposition, 79. // String contentLocation, 80. // String mimeType, 81. // int destination, 82. // int contentLength) throws FileNotFoundException { 83. //以及: framework里的; 84. 85. 86. ContentResolver mResolver = getContentResolver(); 87. (("content://downloads/download"), values); 88. 89. } 90. } 91. 92. 93. 94. package="nload" 95. android:versionCode="1" 96. android:versionName="1.0"> 97. android:label="@string/app_name"> 98. 99. android:label="@string/app_name"> 100. 101. 102. android:name="ER" /> 103. 104. 105. 106. 107. 108. 109. android:name="_CACHE_FILESYSTEM" /> 110. android:name="E_BOOT_COMPLETED" /> 111. android:name="_DOWNLOAD_MANAGER" /> 112. android:name="_DOWNLOAD_MANAGER_ADVANCED" /> 113. 114. android:name="_DOWNLOAD_COMPLETED_INTENTS" /> 115. android:name="_NETWORK_STATE" /> 116. 117. android:name="_EXTERNAL_STORAGE" /> 118. 119. 120. 复制代码 代码里面引用了ParseException和WebAddress两个类,可以从Android源代码里找到copy进来,在这里frameworks/base/core/java/android/net。代码里面有几个地方比较重要的: a) 通过往DownloadProvider提供的ContentProvider “content://downloads/download” 中插入数据就能触发DownloadProvider的执行。 b) ("destination", 1); 是下载文件存储在什么地方, 如果没有这个参数,默认保存在sdcard的download 下面 ( 中的 DEFAULT_DL_SUBDIR = "/download" ) 如果指定为1,是往内存的 /cache目录下存东西 (在/frameworks/base/core/java/android/provider/中定义, public static final int DESTINATION_CACHE_PARTITION = 1; ) b) 注意Manifest中的一堆权限: ACCESS_DOWNLOAD_MANAGER是最基本的权限,这样可以使用DownloadProvider下载。 如果需要destination=1,则需要 ACCESS_DOWNLOAD_MANAGER权限。(中的注释 : All file types are allowed, and only the initiating application can access the file (indirectly through a content provider). This requires the _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): tyException: unauthorized destination code 09-16 17:16:38.062: ERROR/DatabaseUtils(763): at (:277) 09-16 17:16:38.062: ERROR/DatabaseUtils(763): at tProvider$(:150) 09-16 17:16:38.062: ERROR/DatabaseUtils(763): at sact(:140) 09-16 17:16:38.062: ERROR/DatabaseUtils(763): at ansact(:287) 09-16 17:16:38.062: ERROR/DatabaseUtils(763): at (Native Method) 09-16 17:16:38.102: DEBUG/AndroidRuntime(4086): Shutting down VM因为中有这段代码: if (dest != null) { if (getContext().checkCallingPermission(SION_ACCESS_ADVANCED) != SION_GRANTED && dest != ATION_EXTERNAL && dest != ATION_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,发现竟然也是可以调用的。 不过这种方法在模拟器上成功了,但是在真机上没成功,可能还有些问题没解决。第一种方法是完全成功的。
版权声明:本文标题:使用Download Provider 进行文件下载全攻略 内容由热心网友自发贡献,该文观点仅代表作者本人,
转载请联系作者并注明出处:https://m.elefans.com/xitong/1702457628a7935.html,
本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论