我們使用手機的時候經常會看到應用程式提示升級,大部分應用內部都需要實現升級提醒和應用程式文件(APK文件)下載。
一般寫法都差不多,比如在啟動app的時候,通過api接口獲得伺服器最新的版本號,然後和本地的版本號比較,來判斷是否需要彈出提示框下載,當然也可以通過推送的自定義消息來實現。
我們這裡主要討論的是應用程式下載,並在通知欄提醒下載完成。
實現過程大致分為三步:
創建一個service
在service啟動的時候創建一個廣播接受者,用於接受下載完成的廣播
當BroadcastReceiver接受到下載完成的廣播時,開始執行安裝。
主要通過系統提供的DownloadManager進行下載,DownloadManager下載完成會發送廣播,具體使用看下面完整的代碼。下面創建新的文件DownloadService.java
上面代碼使用了RxPermissions第三方庫動態申請權限,需要在app/build.gradle文件中進行配置
記得要配置服務
最後在MainActivity中添加按鈕,執行操作。運行結果:
當下載的時候,會有通知欄進度條提示。下載完成會提示安裝。不過當前程序如果在Android7.0上就會報錯。下面是報錯的日誌:
Caused by: android.os.FileUriExposedException
這是由於Android7.0執行了「StrictMode API 政策禁」的原因,不過小夥伴們不用擔心,可以用FileProvider來解決這一問題,
現在我們就來一步一步的解決這個問題。
Android 7.0錯誤原因隨著Android版本越來越高,Android對隱私的保護力度也越來越大。
比如:Android6.0引入的動態權限控制(Runtime Permissions),Android7.0又引入「私有目錄被限制訪問」,「StrictMode API 政策」。
這些更改在為用戶帶來更加安全的作業系統的同時也為開發者帶來了一些新的任務。如何讓你的APP能夠適應這些改變而不是crash,是擺在每一位Android開發者身上的責任。
「私有目錄被限制訪問「 是指在Android7.0中為了提高私有文件的安全性,面向 Android N 或更高版本的應用私有目錄將被限制訪問。這點類似iOS的沙盒機制。
" StrictMode API 政策" 是指禁止向你的應用外公開 file:// URI。 如果一項包含文件 file:// URI類型 的 Intent 離開你的應用,應用失敗,並出現 FileUriExposedException 異常。
上面用到的代碼中的Uri.fromFile 其實就是生成一個file://URL。
一旦我們通過這種辦法打開其它程序(這裡打開系統包安裝器)就認為file:// URI類型的 Intent 離開你的應用。這樣程序就會發生異常。
接下來就用FileProvider來解決這一問題。
使用FileProvider使用FileProvider的大致步驟如下:
第一步:
在AndroidManifest.xml清單文件中註冊provider,因為provider也是Android四大組件之一,可以簡單把它理解為向外提供數據的組件,這種組件在實際開發中用的頻率並不高,四大組件都可以在清單文件中進行配置。
注意:
exported:要求必須為false,為true則會報安全異常。
grantUriPermissions:true,表示授予 URI 臨時訪問權限。
authorities 組件標識,按照江湖規矩,都以包名開頭,避免和其它應用發生衝突。
第二步:指定共享的目錄
上面配置文件中 android:resource="@xml/file_paths" 指的是當前組件引用 res/xml/file_paths.xml 這個文件。
我們需要在資源(res)目錄下創建一個xml目錄,然後創建一個名為「file_paths」(名字可以隨便起,只要和在manifest註冊的provider所引用的resource保持一致即可)的資源文件,內容如下:
<files-path/>代表的根目錄: Context.getFilesDir()
<external-path/>代表的根目錄: Environment.getExternalStorageDirectory()
<cache-path/>代表的根目錄: getCacheDir()
上述代碼中path="",是有特殊意義的,它代碼根目錄,也就是說你可以向其它的應用共享根目錄及其子目錄下任何一個文件了。
如果你將path設為path="pictures",那麼它代表著根目錄下的pictures目錄(eg:/storage/emulated/0/pictures),如果你向其它應用分享pictures目錄範圍之外的文件是不行的。
第三步:使用FileProvider
上述準備工作做完之後,現在我們就可以使用FileProvider了。
我們需要將上述安裝APK代碼修改為如下
上述代碼中主要有兩處改變:
將之前Uri改成了有FileProvider創建一個content類型的Uri。
添加了
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)來對目標應用臨時授權該Uri所代表的文件。
上述代碼通過FileProvider的Uri getUriForFile (Context context, String authority, File file)靜態方法來獲取Uri
該方法中authority參數就是清單文件中註冊provider時填寫的authority
android:authorities="com.yll520wcf.test.fileprovider"。
按照上面步驟修改就可以兼容Android7.0了。