看板 AndroidDev 關於我們 聯絡資訊
我是抓取 nordic nrftoolbox 的 source code。 https://goo.gl/5WxUPB 任務是利用這 code 抓取 bin file 來做 firmware 更新,客戶嫌麻煩說還要loader 去選擇檔案,想要寫死路徑。 dfuActivity 主要是在 663 行 final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 最後在 433 行回傳,可以看到裡面大部分就只是利用 loader 選取的 data來獲取 uri 分析uri對以下填值 mFileType = mFileTypeTmp; mFilePath = null; mFileStreamUri = null; 接著我會經過 452 行的 else if,最後準備要更新時要執行的地方是 743行 裡面的參數就是這些變數。 我用官方沒改的 code ,在449行用 Log.d("",""+uri.toString);印出已經load下的檔案uri content://com.android.externalstorage.documents/document/primary%3ANordic%20Semiconductor%2Fnrf52832_xxaa_s132.bin 接著我開始改 code 我就直接用上面這串 利用 Uri.parser("xxxxx") 來丟到 743行的 mFileStreamUri 最後APK卻說找不到檔案,我懷疑是 URI的轉換問題讓APK無法找到bin file,另 一個可能就是464行的restartLoader的問題,我把455~464 663~665 mark掉了。 也就是不透過其他APP例如檔案管理APK來載入檔案,直接寫死要上傳的檔案的uri 既然客戶希望按個 button,就可以不用開啟 loader 選取檔案,那麼有沒有辦法是 下了 Intent intent = new Intent(Intent.ACTION_GET_CONTENT); startActivity(intent, SELECT_FILE_REQ)); 可以不用由客戶去選檔,就指定給他路徑了呢? 還有我的URI可以這樣 assign嗎...?-->主要還是想知道為啥找不到檔案 如果有甚麼資訊或指教請不吝說明,謝謝。 ----------------------------------------------------------------------------- 更新1: 查看了 logcat 出現了權限相關訊息 6-20 11:49:38.395 19930 19941 E DatabaseUtils: Writing exception to parcel 06-20 11:49:38.395 19930 19941 E DatabaseUtils: java.lang.SecurityException: Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/document/primary%3ANordic%20Semiconductor%2Fnrf52832_xxaa_s132.bin from pid=20023, uid=10259 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission() 更新2: 他下面還有關於 DfuBaseService 一樣權限的問題..,我下個步驟是要抓這個 DfuBaseService 的 code 在 mainifest.xml加上權限看看 6-20 12:20:55.858 21818 21831 E DatabaseUtils: java.lang.SecurityException: Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/document/primary%3ANordic%20Semiconductor%2Fnrf52832_xxaa_s132.bin from pid=21436, uid=10259 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission() 06-20 12:20:55.858 21818 21831 E DatabaseUtils: at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:608) 06-20 12:20:55.858 21818 21831 E DatabaseUtils: at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:483) 06-20 12:20:55.858 21818 21831 E DatabaseUtils: at android.content.ContentProvider$Transport.enforceFilePermission(ContentProvider.java:474) 06-20 12:20:55.858 21818 21831 E DatabaseUtils: at android.content.ContentProvider$Transport.openTypedAssetFile(ContentProvider.java:419) 06-20 12:20:55.858 21818 21831 E DatabaseUtils: at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:319) 06-20 12:20:55.858 21818 21831 E DatabaseUtils: at android.os.Binder.execTransact(Binder.java:565) 06-20 12:20:55.859 21436 21845 E DfuBaseService: A security exception occurred while opening file 06-20 12:20:55.859 21436 21845 E DfuBaseService: java.lang.SecurityException: Permission Denial: reading com.android.externalstorage.ExternalStorageProvider uri content://com.android.externalstorage.documents/document/primary%3ANordic%20Semiconductor%2Fnrf52832_xxaa_s132.bin from pid=21436, uid=10259 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission() 更新3: 我將 DFU library 抓下來,在mainifest.xml加上 <uses-permission android:name="android.permission.MANAGE_DOCUMENT 無效... 有沒有啥解法...?感謝 更新4: 這是某段註解,就像s大說的可以用file或者content。 * The URI returned from application may be in 'file' or 'content' schema. 'File' schema allows us to create a File object and read details from if * directly. Data from 'Content' schema must be read by Content Provider. To do that we are using a Loader.*/ 我的APP 獲得到的 content,最後給 dfu library內的 DfuBaseService來讀取,讀取不了 的原因是因為沒有權限。我可以理解為- DfuBaseService 沒有那個權限,而這個權限 是由系統的Loader提供的嗎? ACTION_GET_CONTENT一發出,會可以讓我選擇適合的 檔案管理APK來載入檔案,所以說這個權限是由這個檔案管理的APK提供的嗎? 這個權限到底是 loader 給的還是檔案管理apk給的~"~? 是系統的loader吧? 所以我的app才需要實作loader相關的function? -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 58.115.110.197 ※ 文章網址: https://www.ptt.cc/bbs/AndroidDev/M.1497886262.A.A02.html ※ 編輯: gn00618777 (61.220.69.181), 06/20/2017 10:17:43 ※ 編輯: gn00618777 (61.220.69.181), 06/20/2017 12:01:05
ssccg: 就沒權限存取那個位置的檔案啊 06/20 12:57
ssccg: 這個URI是個content uri,是跟系統的DocumentProvider取 06/20 13:03
※ 編輯: gn00618777 (61.220.69.181), 06/20/2017 13:30:52 ※ 編輯: gn00618777 (61.220.69.181), 06/20/2017 14:57:31
gn00618777: 或是我可以設定 ACTION_GET_CONTENT後可以直接存取 06/20 15:12
gn00618777: 某個特定的檔案嗎,不用經由客戶來選? 06/20 15:13
gn00618777: setDataAndType好像也不能直接選取到我要的檔案.. 06/20 15:13
ssccg: MANAGE_DOCUMENTS不是第三方App可以要的權限 06/20 15:14
ssccg: 問題不是在用ACTION_GET_CONTENT要,而是你要到的這個URI 06/20 15:18
ssccg: 是content uri。你現在要存取的這個檔案是你可以控制的? 直 06/20 15:20
ssccg: 接看它放在哪然後用file://的URI就可以了吧 06/20 15:20
gn00618777: s大感謝你的回覆。 你說可以控制的是指檔案格式還是 06/20 15:33
gn00618777: 存放位址還是 URI 的 scheme? 06/20 15:34
gn00618777: 從S大的回覆是指這個 bin 我可以用 file://的URI去設? 06/20 15:37
gn00618777: 經你一說我有看DfuActivity 有關於判斷得到的uri是屬 06/20 15:44
gn00618777: 於 sheme 是 file 或是 content的設置 06/20 15:44
ssccg: content是找某個ContentProvider要,必須符合該Provider的 06/20 15:48
ssccg: 限制,例如現在這個com.android.externalstorage.documents 06/20 15:48
ssccg: 要求app必須就是當初用ACTION_GET_CONTENT跟它要的那個app 06/20 15:50
ssccg: file是看如果是app自己的目錄就沒任何限制,如果是共用的目 06/20 15:52
ssccg: 錄要READ_EXTERNAL_STORAGE權限,如果是系統目錄就不能存取 06/20 15:53
ssccg: 用content的可能還是對應到某個檔案,但是用content去存取 06/20 15:54
ssccg: 跟直接用file存取,遇到的限制就會不同 06/20 15:54
ssccg: 如果你能控制那檔案放哪,就放在能取的地方然後用file 06/20 15:57
※ 編輯: gn00618777 (61.220.69.181), 06/20/2017 16:17:40
gn00618777: s大,我有更新4,請您看一下我的理解對不對? 06/20 16:18
※ 編輯: gn00618777 (61.220.69.181), 06/20/2017 16:21:17 ※ 編輯: gn00618777 (61.220.69.181), 06/20/2017 16:25:02
ssccg: 不知道你說的loader是指哪個... 06/20 16:32
ssccg: ACTION_GET_CONTENT回來的uri的權限是檔案管理app給的,但 06/20 16:32
ssccg: 是檔案管理app裡面實作當然有可能是再跟別人取的 06/20 16:34
ssccg: 重點是你到底能不能直接存取那個檔案? 還是除了那個content 06/20 16:35
ssccg: URI以外你現在根本不知道那個檔案在哪? 06/20 16:35
gn00618777: 那個檔案存放的地方我可以決定,事實上我剛剛在搜尋 06/20 16:59
gn00618777: 怎樣將我要load的檔案轉成用file://表示的URI 06/20 17:00
gn00618777: 目前我用 File file = new File(Runtime.getExternal) 06/20 17:01
gn00618777: StorageDirectory().toString() + "/Download/", name 06/20 17:02
gn00618777: 再用file.exists()先確認有沒有存在 06/20 17:02
gn00618777: 再用 Uri uri = Uri.fromFile(tmpFile); 06/20 17:03
gn00618777: 還不確定能不能用此Uri來更新 firmware,稍後測試 06/20 17:04
paulku: 我工作上是惡搞啦 ASSETS複製出去後在指定那位置更新 06/20 17:45
paulku: 更新成功後在onTransferCompleted階段刪檔 06/20 17:46
paulku: 這樣就不太用大改程式了....只是要多要讀寫權限就是了 06/20 17:47
paulku: 反正跟客戶說 因為更新設備 所以要讀寫檔案就呼嚨過去了.. 06/20 17:47
paulku: 這是不好的示範就是了..... 06/20 17:47
gn00618777: 天啊 我成功了>"<<>"< 太感謝了.....真的是很感謝.. 06/20 18:05
gn00618777: 不太懂P大說的內容.. 06/20 18:06
gn00618777: 那這樣content的使用時機是啥,file://比較好用阿.. 06/20 18:07
ssccg: asset如果在同個app不用複製,用file:///android_assets/可 06/20 18:32
ssccg: 以直接存取 06/20 18:33
ssccg: content是跟ContentProvider要,ContentProvider的實作不一 06/20 18:35
ssccg: 定是取檔案,可能從任何地方來,跟file是不同的概念 06/20 18:36
bukiya: Android N上uri有限制file://的使用,要注意一下 06/20 18:47
gn00618777: p大以啥限制?我目前就是在N上開發 06/20 18:53
ssccg: N之後不能share file uri給別的app,在同一個app裡沒關係 06/20 18:57
gn00618777: 了解,謝謝分享 06/21 16:00