本文來自同步博客。html
運行時權限屬於比較熟悉的話題不深刻展開。除了support
包可讓應用完成運行時權限,github
上也有好多擴展。用得比較多的是Google
官方的EasyPermissions
。java
私有文件安全性的變更官方文檔提到了三點反作用,詳見文檔。下面記錄開發中碰見的兩點。android
在調用照片拍照、調用包管理器安裝apk等場景下都須要跨應用共享文件。在版本N
以前,直接使用「file://+文件路徑」的方式就能夠共享。git
可是在N
以後,這樣操做會拋出異常FileUriExposedException。github
實際上在共享文件時,接受共享的應用可能並無向系統申請讀取文件的權限,也可能沒有訪問該文件的權限。若是擁有者應用經過修改文件的權限,讓其餘任何應用均可以訪問它,這顯然是不安全的。安全
N
要求使用「content://+文件路徑」的方式共享文件,並在共享的那一刻生成針對指定應用的臨時權限。這種分享私有文件方法,Google
推薦使用FileProvider完成。ide
參考其餘博客,這裏記錄兩個注意點:工具
FileProvider
是support
包提供的功能,並不須要檢查Android的版本進行區分處理。統一使用FileProvider
向外共享文件便可。FileProvider
的Available Files
的配置須要注意path
、name
、以及paths
裏面的不一樣標籤的意義。不少使用者混淆了,詳細請參考官方文檔。下圖是某網友的總結。DownloadManager
的COLUMN_LOCAL_FILENAME
字段限制N
之前的應用能夠訪問COLUMN_LOCAL_FILENAME
字段,可是以後的版本若訪問該字段,將報SecurityException。ui
有一種不推薦的方式可讓應用繼續訪問這個字段:在下載文件時,經過DownloadManager.Request.setDestinationInExternalFilesDir()
或DownloadManager.Request.setDestinationInExternalPublicDir()
把文件存儲在公共目錄。google
Google
推薦使用ContentResolver.openFileDescriptor()
。
而我在開發中碰到須要獲取下載文件最終存儲的完整路徑的場景,下面記錄個人處理方式:
String path = ""; if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) { String fileUri = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)); if (fileUri != null) { path = Uri.parse(fileUri).getPath(); } } else { //Android 7.0以上的方式:請求獲取寫入權限,這一步報錯過期的方式:DownloadManager.COLUMN_LOCAL_FILENAME int fileNameIdx = c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME); path = c.getString(fileNameIdx); }
O
開始屏蔽了全局的「安裝未知應用」設置開關,而是將之做爲權限與每一個應用綁定。任何須要安裝APK的應用須要在AndroidManifest中註冊android.permission.REQUEST_INSTALL_PACKAGES
權限,不然將沒法安裝應用。
能夠選擇使用ACTION_MANAGE_UNKNOWN_APP_SOURCES
發起 Intent
操做,預先將用戶引導至安裝未知應用權限界面。也可使用PackageManager.canRequestPackageInstalls()
,查詢此權限的狀態。
很慶幸也很不幸,我負責的項目沒有檢測到使用了非SDK接口。
有關非SDK接口相關介紹參考這篇文章。
文中提到的veridex
工具須要本身下載Android
的源代碼,具體操做參考官方文檔。