最近項目中調用系統相機時遇到了這麼個問題:紅米手機無法執行onActivityResult回調,部分華為手機無法擷取到照片資料,最後各種分析,各種網上搜尋資料折騰了好久,最後終于把問題解決,當看到問題的最終原因時,我也是醉了,簡直就是坑爹坑大發了。
最開始用紅米手機調用系統相機的時,當我拍照完成點選那個勾勾始終無法傳回到前面的界面上,也就是無法調用onActivityResult函數取到拍照的照片,在網上搜尋了一圈,沒找到解決辦法,都說是紅米的系統問題,無法解決,項目比較緊張,剛好客戶的手機全部是統一型号的華為榮耀6Plus,這個問題丢着暫時沒管了。
後來現場同僚批量測試機器時,發現有3台手機可以拍照,但是在onActivityResult回調中擷取到的照片資料為null,但是其他的同型号手機又沒這個問題,這問題看着真是坑爹啊。
遠端調試代碼後發現,我在調用系統相機時設定的照片存放目錄無法建立成功,我調用系統相機的代碼如下:
- public void takePicture() {
- //照片存放目錄
- File file = new File(mPicDirectory);
- if(!file.exists()) {//目錄不存在則建立該目錄及其不存在的父目錄
- file.mkdirs();
- }
- Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
- mPicName = getPictureName();//擷取照片名稱
- mPicPath = mPicDirectory + mPicName;//照片存儲路徑
- //将照片儲存到mPicPath位置
- intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mPicPath)));
- startActivityForResult(intent, CODE_RESULT_TAKE_PHOTO);
- }
我調試的時候在onActivityResult回調裡通過照片路徑擷取Bitmap對象的時候發現擷取到的Bitmap對象一直為null,是以就猜想是不是照片沒儲存成功,我在檔案管理系統裡去找這個照片的時候發現,連照片存儲目錄mPicDirectory都不存在,我再次跟蹤代碼發現file.mkdirs()始終傳回的都是false。看來問題的最終原因是這個:無法建立目錄和檔案(華為手機系統在拍照輸出的時候,如果輸出檔案路徑不存在時竟然沒有任何提示和異常,這點對于發現問題的根源有點困難)。然後我又去檢查了權限、手機設定裡面的權限等所有有可能涉及的問題,結果依然沒有效果。既然這些都不是導緻目錄建立失敗的原因,那會不會是目錄路徑本身不正确呢,我的目錄路徑是這樣擷取的:
- String mPicDirectory = FileManager.getPath() + Configuration.SYS_PHOTO_PATH;
- //FileManager的部分代碼是這樣的,這個代碼是以前的同僚寫的,沒有細看過:
- public static String getPath(){
- boolean sdCardExist = Environment.getExternalStorageState()
- .equals(android.os.Environment.MEDIA_MOUNTED); //判斷sd卡是否存在
- return !sdCardExist ? MOBILE_PATH : SD_PATH;
- }
- //sdcard路徑
- private static String SD_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
- //應用資料路徑
- public static final String MOBILE_PATH = Environment.getDataDirectory().getAbsolutePath();
- //這裡有一段靜态代碼塊
- static{
- File f = new File("/storage/sdcard1");
- if(f.exists()){
- long size = getFreeSize("/storage/sdcard1");
- long sd0Size = getFreeSize("/storage/sdcard0");
- if(size > sd0Size){
- SD_PATH = "/storage/sdcard1";
- }
- }
- }
當我看到上面的靜态代碼塊的時候,我立馬就知道了問題的原因,靜态代碼塊中做了一個剩餘空間判斷,選取的是空間比較大的那個sdcard路徑,而且代碼都是寫死的
Environment.getExternalStorageDirectory().getAbsolutePath()
系統這個代碼是擷取手機裡的内置SDCard的路徑,我的紅米手機自己又額外插了一張記憶體卡,這個是手機的外接SDCard,用
Environment.getExternalStorageDirectory()
擷取到隻是手機自帶的外置SDCard路徑,不能擷取自己插入的記憶體卡路徑,我的手機通過
Environment.getExternalStorageDirectory()
方式擷取的路徑是
/storage/sdcard0
(我手機内置的SDCard),而通過可用空間比較之後發現該卡的可用空間少于
/storage/sdcard1
(我自己插入的SDCard),是以最終路徑變成了
/storage/sdcard1
,而在Android4.4以上後,不允許三方App對外接的SDCard進行操作,是以我們隊最後得到的這個目錄是沒有寫入權限的,是以我建立照片存儲目錄的時候一直失敗,是以拍照的時候照片資料沒有地方可以輸出,華為手機是直接展現在照片資料無法擷取,而紅米手機則是直接不允許傳回到前面的調用界面。
Google在Android中限制三方App操作外接SDCard的原文如下:
The WRITE_EXTERNAL_STORAGE permission must only grant write access to the primary external storage on a device. Apps must not be allowed to write to secondary external storage devices, except in their package-specific directories as allowed by synthesized permissions.
後來想了想,調用相機這麼簡單的一個功能,紅米的系統應該不可能給閹割掉,是以出了問題還是老老實實的先找自己代碼的問題吧。至于那個外接SDCard的寫入權限還有待尋找答案。
系統内置SDCard寫入、删除、讀寫權限:
- //檔案建立、删除權限
- <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
- //檔案讀寫權限,隻針對于手機記憶體的SDCard,對外接SDCard無效
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
歡迎通路我的獨立部落格:http://ittiger.cn