天天看點

Android調用相機無法執行onActivityResult或data為null

最近項目中調用系統相機時遇到了這麼個問題:紅米手機無法執行onActivityResult回調,部分華為手機無法擷取到照片資料,最後各種分析,各種網上搜尋資料折騰了好久,最後終于把問題解決,當看到問題的最終原因時,我也是醉了,簡直就是坑爹坑大發了。

最開始用紅米手機調用系統相機的時,當我拍照完成點選那個勾勾始終無法傳回到前面的界面上,也就是無法調用onActivityResult函數取到拍照的照片,在網上搜尋了一圈,沒找到解決辦法,都說是紅米的系統問題,無法解決,項目比較緊張,剛好客戶的手機全部是統一型号的華為榮耀6Plus,這個問題丢着暫時沒管了。

後來現場同僚批量測試機器時,發現有3台手機可以拍照,但是在onActivityResult回調中擷取到的照片資料為null,但是其他的同型号手機又沒這個問題,這問題看着真是坑爹啊。

遠端調試代碼後發現,我在調用系統相機時設定的照片存放目錄無法建立成功,我調用系統相機的代碼如下:

  1. public void takePicture() {
  2. //照片存放目錄
  3. File file = new File(mPicDirectory);
  4. if(!file.exists()) {//目錄不存在則建立該目錄及其不存在的父目錄
  5. file.mkdirs();
  6. }
  7. Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
  8. mPicName = getPictureName();//擷取照片名稱
  9. mPicPath = mPicDirectory + mPicName;//照片存儲路徑
  10. //将照片儲存到mPicPath位置
  11. intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mPicPath)));
  12. startActivityForResult(intent, CODE_RESULT_TAKE_PHOTO);
  13. }

我調試的時候在onActivityResult回調裡通過照片路徑擷取Bitmap對象的時候發現擷取到的Bitmap對象一直為null,是以就猜想是不是照片沒儲存成功,我在檔案管理系統裡去找這個照片的時候發現,連照片存儲目錄mPicDirectory都不存在,我再次跟蹤代碼發現file.mkdirs()始終傳回的都是false。看來問題的最終原因是這個:無法建立目錄和檔案(華為手機系統在拍照輸出的時候,如果輸出檔案路徑不存在時竟然沒有任何提示和異常,這點對于發現問題的根源有點困難)。然後我又去檢查了權限、手機設定裡面的權限等所有有可能涉及的問題,結果依然沒有效果。既然這些都不是導緻目錄建立失敗的原因,那會不會是目錄路徑本身不正确呢,我的目錄路徑是這樣擷取的:

  1. String mPicDirectory = FileManager.getPath() + Configuration.SYS_PHOTO_PATH;
  2. //FileManager的部分代碼是這樣的,這個代碼是以前的同僚寫的,沒有細看過:
  3. public static String getPath(){
  4. boolean sdCardExist = Environment.getExternalStorageState()
  5. .equals(android.os.Environment.MEDIA_MOUNTED); //判斷sd卡是否存在
  6. return !sdCardExist ? MOBILE_PATH : SD_PATH;
  7. }
  8. //sdcard路徑
  9. private static String SD_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();
  10. //應用資料路徑
  11. public static final String MOBILE_PATH = Environment.getDataDirectory().getAbsolutePath();
  12. //這裡有一段靜态代碼塊
  13. static{
  14. File f = new File("/storage/sdcard1");
  15. if(f.exists()){
  16. long size = getFreeSize("/storage/sdcard1");
  17. long sd0Size = getFreeSize("/storage/sdcard0");
  18. if(size > sd0Size){
  19. SD_PATH = "/storage/sdcard1";
  20. }
  21. }
  22. }

當我看到上面的靜态代碼塊的時候,我立馬就知道了問題的原因,靜态代碼塊中做了一個剩餘空間判斷,選取的是空間比較大的那個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寫入、删除、讀寫權限:

  1. //檔案建立、删除權限
  2. <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
  3. //檔案讀寫權限,隻針對于手機記憶體的SDCard,對外接SDCard無效
  4. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

歡迎通路我的獨立部落格:http://ittiger.cn