0

下面的代碼工作正常的棉花糖前的設備,但不是在棉花糖。沒有這樣的文件或目錄只在Android 6.0

這些都是在清單

<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; 
    } 
+1

使用'運行時間爲Permission' *在Android 6.0 *這裏指https://developer.android.com/training/permissions/requesting.html使用。 –

回答

1

給運行時讀取棉花糖或較新版本的寫入權限。 做象下面這樣: -

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; 
    } 
+0

謝謝,按預期工作。 –

1

你需要安裝/更新的慣例

時的Android 6.0(API級別23)開始採取應用程序的權限在運行時,而不是採取,用戶授予權限 應用正在運行,而不是在安裝應用時。這 方法簡化了應用程序的安裝過程,因爲用戶沒有 需要在安裝時授予權限或更新應用

如需更多幫助:Requesting Permissions at Run Time

通過專注於文檔和後做一些谷歌搜索,最後我編譯了下面的代碼來有效地處理運行時權限

要使其工作,您需要按照以下說明操作:

調用此方法檢查用戶是否授予存儲權限? 如果沒有,那麼你需要請求它

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); 
} 
2

從Android 6.0(API級別23)開始,用戶在應用程序運行時爲應用程序授予權限,而不是在安裝應用程序時授予應用程序權限。

這就是爲什麼它的工作原理在-棒棒糖前期版本,並且不會對API的權限23.在Android清單單單是不夠的,你需要將它們在運行時添加爲好。請參閱here for more details.

+0

感謝您的回答。但將targetSdkVersion更改爲22解決了我的問題。這是錯的嗎? –

+0

是的,沒有。你總是可以迴歸到一個更低的API並且它可以工作,但是它不是更好的做到這一點,所以它使用更新的SDK(API 23)構建,它也可以使用它嗎?通過選擇較低的目標SDK來忽略問題並不是一個好習慣,最好跟上最新的東西。 :) – Vucko

0

我不是爲您提供直接的代碼,這一點,但這裏是有原因的API級別23引入一個新的許可結構,下面更安全的東西短,但赤身描述,在文檔here

開始在Android 6.0(API級別23)中,用戶在應用程序運行時嚮應用程序授予權限,而不是在安裝應用程序時授予應用程序權限。此方法簡化了應用程序安裝過程,因爲用戶在安裝或更新應用程序時無需授予權限。它還使用戶可以更好地控制應用程序的功能;例如,用戶可以選擇給相機應用程序訪問相機,但不能訪問設備位置。用戶可以隨時撤銷權限,只需轉到應用的「設置」屏幕即可。

代碼是好的,只需要添加一些東西,那就是運行時權限存儲。

閱讀this blog瞭解深處的一切約運行時權限給了我一個清晰的圖片,希望它也可以幫助你。

感謝