簡體   English   中英

僅在Android 6.0中沒有此類文件或目錄

[英]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;
    }

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

這就是為什么它工作在棒棒糖之前的版本,並且不會對API的權限23.在Android清單本身是不夠的,你需要將它們在運行時添加為好。 有關更多詳細信息,請參見此處。

在運行時為棉花糖或更高版本提供讀寫權限。 像下面這樣:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM