隨著各大廠商對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)適配。