[英]Android 6.0 even with permission 777 chmod cannot read file in data directory
[英]No such file or Directory only in Android 6.0
下面的代碼在Marshmallow之前的設備上運行良好,但在Marshmallow中卻無法正常運行。
這些是清單中的權限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
這是代碼
public void saveImageToSDCard(Bitmap bitmap) {
File myDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
pref.getGalleryName());
myDir.mkdirs();
Random generator = new Random();
int n = 10000;
n = generator.nextInt(n);
String fname = "Wallpaper-" + n + ".jpg";
File file = new File(myDir, fname);
if (file.exists())
file.delete();
try {
FileOutputStream out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
Uri uri = getImageContentUri(_context,file);
Log.d(TAG, "Wallpaper saved to: " + file.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
}
當我手動允許存儲權限時,相同的代碼也有效
這是Nitesh Pareek提供的解決方案。
private boolean hasPermissions(Context context, String[] permissions) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
String[] PERMISSIONS = new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE};
if (!hasPermissions(this, PERMISSIONS)) {
ActivityCompat.requestPermissions(this, PERMISSIONS, 11);
return;
}
在運行時為棉花糖或更高版本提供讀寫權限。 像下面這樣:
String[] PERMISSIONS = new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE};
if (!hasPermissions(this, PERMISSIONS)) {
ActivityCompat.requestPermissions(this, PERMISSIONS, 11);
return;
}
private boolean hasPermissions(Context context, String... permissions) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
您需要在運行時獲取應用程序權限,而不是按常規安裝/更新
從Android 6.0(API級別23)開始,用戶在應用程序運行時(而不是在安裝應用程序時)授予應用程序權限。 這種方法簡化了應用程序的安裝過程,因為用戶在安裝或更新應用程序時無需授予權限
有關更多幫助: 在運行時請求權限
通過專注於文檔並經過一些Google搜索,終於我編譯了下面的代碼以有效地處理運行時權限
要使其正常工作,您需要按照以下說明進行操作:
調用此方法以檢查用戶是否授予了存儲權限? 如果沒有,那么您需要提出要求
public static boolean isStoragePermissionGranted(Activity activity) {
boolean flag = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
flag = activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
return flag;
}
調用此方法以請求存儲權限
public static void requestStoragePermission(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (isStoragePermissionGranted(activity)) {
return;
}
// Fire off an async request to actually get the permission
// This will show the standard permission request dialog UI
activity.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_STORAGE_PERMISSION);
}
}
在您的活動中實現此方法以處理權限回調的響應
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_CODE_STORAGE_PERMISSION:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (grantResults.length > 0) {
if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
boolean shouldShowRationale = shouldShowRequestPermissionRationale(permissions[0]);
if (!shouldShowRationale) {
// user denied flagging NEVER ASK AGAIN, you can either enable some fall back,
// disable features of your app or open another dialog explaining again the permission and directing to
// the app setting
dialogReasonStoragePermissionToSettings(this);
} else if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permissions[0])) {
// user denied WITHOUT never ask again, this is a good place to explain the user
// why you need the permission and ask if he want to accept it (the rationale)
dialogReasonStoragePermission(this);
}
} /*else {
// Do on permission granted work here
}*/
}
}
break;
}
}
public static void dialogReasonStoragePermission(final Activity activity) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage(activity.getString(R.string.reason_storage_permission));
builder.setCancelable(false);
builder.setPositiveButton("Retry", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
requestStoragePermission(activity);
}
});
builder.setNegativeButton("Dismiss", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
public static void dialogReasonStoragePermissionToSettings(final Activity activity) {
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setMessage(activity.getString(R.string.reason_storage_permission));
builder.setCancelable(false);
builder.setPositiveButton("Go to Settings", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
goToAppDetailsForPermissionSettings(activity);
}
});
builder.setNegativeButton("Dismiss", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
private static final int REQUEST_CODE_APP_DETAILS_PERMISSION_SETTING = 3995;
private static void goToAppDetailsForPermissionSettings(Activity activity) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
intent.setData(uri);
activity.startActivityForResult(intent, REQUEST_CODE_APP_DETAILS_PERMISSION_SETTING);
}
我沒有為此提供直接代碼,但這是API級別23引入新的Permission結構以提高安全性的原因,以下是對事物的簡短但浪費的描述,在此處的文檔中
從Android 6.0(API級別23)開始,用戶在應用程序運行時(而不是在安裝應用程序時)授予應用程序權限。 這種方法簡化了應用程序的安裝過程,因為用戶在安裝或更新應用程序時無需授予權限。 它還使用戶可以更好地控制應用程序的功能。 例如,用戶可以選擇授予攝像頭應用訪問攝像頭的權限,但不授予設備位置的訪問權限。 通過轉到應用程序的“設置”屏幕,用戶可以隨時撤消權限。
代碼很好,只是您必須添加一些其他內容,即存儲的運行時權限 。
閱讀此博客,以了解有關Runtime Permissions的所有內在知識,它給我帶來了清晰的畫面,希望對您有所幫助。
謝謝
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.