Andorid 11調(diào)用系統(tǒng)裁剪

隨著各大廠商對android11的升級推送,現(xiàn)在已經(jīng)有了一定android11的機型,關(guān)于android11的適配網(wǎng)上有很多相關(guān)的文章
這里主要強調(diào)下android11的分區(qū)存儲一般情況下遇到的問題。
一般非垃圾清理類app或者沒有特殊需求的app,主要在調(diào)用圖片裁剪會遇到android11的問題。
如小米10:

小米10裁剪.jpg

小米10裁剪報錯.jpg

小米10報錯:保存時發(fā)生錯誤,保存失敗
糾其原因就是android11在更新后,會強制使用分區(qū)存儲:
在tagSdk<30(29未忽略分區(qū)存儲情況下requestLegacyExternalStorage=true)其他應(yīng)用,無法訪問app私有目錄下的文件;所以導(dǎo)致了上圖出現(xiàn)系統(tǒng)裁剪應(yīng)用,無法訪問app下的裁剪副本,這里就講到了系統(tǒng)裁剪功能流程:
1:在拍照或者相冊中拿到圖片的uri
2:創(chuàng)建圖片intent傳入ImageType:intent.setDataAndType(uri, "image/*")
3:創(chuàng)建裁剪輸出路徑:intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.parse("file://"+ mOnputFile.getAbsolutePath()));
4:裁剪完成后的圖片文件就是mOnputFile
這里在android11上出錯就是在第3步驟上,內(nèi)置系統(tǒng)裁剪應(yīng)用無法訪問自己的app私有目錄下的圖片(這里大多數(shù)應(yīng)用在訪問圖片文件的時候應(yīng)該都是采用fileprovider創(chuàng)建的私有目錄的uri吧)
我們應(yīng)用的文件存儲的內(nèi)置路徑是:
storage/emulated/0/Android/data/com.xx.xxxx/cache
可以看到com.xx.xxxx就是內(nèi)置的私有目錄
所以,在android11上,通過fileprovider創(chuàng)建的uri path只要改為公域,系統(tǒng)裁剪應(yīng)用就可以訪問裁剪過后,公域圖片地址:
storage/emulated/0/Pictures
可以看到?jīng)]有包名。
獲取公域地址方法:

String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath()

完整代碼,這里以相冊為例:

    // 啟動相冊
    public void openAlbum() {
        Intent intent_album = new Intent("android.intent.action.GET_CONTENT");
        intent_album.setType("image/*");
        startActivityForResult(intent_album, ICON_FROM_ALBUM);
    }

啟動相冊后,在onActivityResult里獲取uri

  case ICON_FROM_ALBUM:
        //從相冊選擇
      if (data == null || data.getData() == null) {
        return;
      }
      clipPhoto(Uri.fromFile(new File(ImageFileUtils.getPath(this, data.getData()))
   )); //裁剪圖片
 break;

圖片裁剪,這里在tagSdk低于30的情況下做判斷,注意7.0的通過provider的uri來訪問媒體

 //裁剪圖片
    private void clipPhoto(Uri uri) {
        Intent intent = new Intent("com.android.camera.action.CROP");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            uri = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".fileprovider", new File(uri.getPath()));
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        }
        intent.setDataAndType(uri, "image/*");
        // 下面這個crop=true是設(shè)置在開啟的Intent中設(shè)置顯示的VIEW可裁剪
        intent.putExtra("crop", "true");
        // aspectX aspectY 是寬高的比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // outputX outputY 是裁剪圖片寬高
        intent.putExtra("outputX", 150);
        intent.putExtra("outputY", 150);
        intent.putExtra("circleCrop", true);
        if (Build.VERSION.SDK_INT >= 30) {
            //android 11以上,將文件創(chuàng)建在公有目錄
            String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath();
            //storage/emulated/0/Pictures
            mOnputFile = new File(path, System.currentTimeMillis() + ".png");
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.parse("file://" + mOnputFile.getAbsolutePath()));
        } else {
            //storage/emulated/0/Android/data/com.xxxxx/cache
            mOnputFile = new File(sdPath, System.currentTimeMillis() + ".png");
            intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.parse("file://" + mOnputFile.getAbsolutePath()));
        }
        startActivityForResult(intent, ICON_CROP);
    }

依然在onActivityResult中處理

case ICON_CROP:
  //mOnputFile就是裁剪副本,這里簡單地判斷下文件,可以處理裁剪圖片的顯示,或者上傳
    break;

最后結(jié)果:


成功.jpg

總結(jié):app在Android11系統(tǒng)上強制使用分區(qū)存儲,私有目錄下的文件無法被訪問,如果有大量文件的話,要做數(shù)據(jù)遷移(就是將需要共享的文件從上述的私有目錄移到共有目錄下),這里網(wǎng)上有很多相關(guān)的文章。

題外話:還有如果用到umeng分享的話,在android11的設(shè)備上分享圖片也會有問題類似的問題,具體可以更新新的umeng shareSdk,友盟已經(jīng)做了相關(guān)適配。

demo地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容