简体   繁体   English

Android 11, Java | 外部存储权限@SDK >29

[英]Android 11, Java | External Storage permission @SDK >29

As you may already know, Google has changed the guidelines for access rights to external storage, among other things.您可能已经知道,Google 已经更改了外部存储访问权限的准则等。 Tried all tips and tricks from google docu, but it didn't work for me.尝试了谷歌文档中的所有提示和技巧,但它对我不起作用。 The app crashes, once I clicked to "Backup" button and to "OK".一旦我单击“备份”按钮和“确定”,应用程序就会崩溃。 I have no more ideas to fix the problem.我没有更多的想法来解决这个问题。 Now I turn to you experts.现在我请教各位专家。 I am happy about every tip.我对每一个小费都很满意。

  • Android 11 Android 11
  • TargetSDK 31目标SDK 31

I'll be sharing the relevant codes to make them as clear as possible.我将分享相关代码以使它们尽可能清晰。

Manifest:显现:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" tools:ignore="ScopedStorage"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Utils.java实用程序.java

public static Boolean askForReadPermission(final Activity activity, final PermissionCallback permissionCallback, View view){
        if(android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Nammu.checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)){
        return true;
    }
    else{
        final String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};

        if (Nammu.shouldShowRequestPermissionRationale(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            Snackbar.make(view, activity.getString(R.string.error_permission_backup),
                    Snackbar.LENGTH_INDEFINITE)
                    .setAction("OK", new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            Nammu.askForPermission(activity, permissions, permissionCallback);
                        }
                    }).show();
        } else {
            Nammu.askForPermission(activity, permissions, permissionCallback);
        }
        return false;
    }
}
public static String getStorageDir(){
        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myApp";
        File f = new File(path);
        if(!f.exists()) if(!f.mkdirs()) return null;
        return f.getAbsolutePath();
    }
public static String getStorageDirForBackup(){
        String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/My_Backup";
        File f = new File(path);
        if(!f.exists()) if(!f.mkdirs()) return null;
        return f.getAbsolutePath();
        }

Backup.java备份.java

public class RealmBackup {

    private static final String TAG = "Backuplog";
    private final String EXPORT_REALM_FILE_NAME = "backup.realm";


    private final Activity activity;
    private final Realm realm;

    public RealmBackupRestore(Activity activity, Realm realm) {
        this.activity = activity;
        this.realm = realm;
    }

    @SuppressLint("StaticFieldLeak")
    public void backup() {
        new AsyncTask<Void, Void, Boolean>() {  


            private SweetAlertDialog dialog;

            @Override
            protected void onPreExecute() {
                dialog = new SweetAlertDialog(activity, SweetAlertDialog.PROGRESS_TYPE);
                dialog.setContentText(activity.getString(R.string.settings_do_backup));
                dialog.setTitleText("");
                dialog.show();
            }

            @Override
            protected Boolean doInBackground(Void... params) {
                Realm realm = Realm.getDefaultInstance();

                File exportRealmFile;
                exportRealmFile = new File(Utils.getStorageDir(), EXPORT_REALM_FILE_NAME);
                               realm.writeCopyTo(exportRealmFile);

                File zipFile = new File(Utils.getStorageDirForBackup(), "backup_" + System.currentTimeMillis() + ".zip");
                zipFile.delete();


                File wholeDirectory = new File(Utils.getStorageDir() + "/");

                ZipUtil.pack(wholeDirectory, zipFile);

                exportRealmFile.delete();
                realm.beginTransaction();
                Objects.requireNonNull(Settings.getSettings(realm)).setLastBackup(new Date());
                realm.commitTransaction();    

                realm.close();
                return true;
            }

            @Override
            protected void onPostExecute(Boolean result) {
                dialog.cancel();

                    
                AlertDialog.Builder alertBuilder = new AlertDialog.Builder(activity);
                alertBuilder
                        .setMessage(activity.getString(R.string.settings_backup_stored))
                        .setNeutralButton(activity.getString(R.string.generell_ok), new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {

                            }
                        })
                        .show();
            }
        }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    }
   

    private String dbPath(){
        return realm.getPath();
    }
}

FragmentBackup.java片段备份.java

backup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getContext());
                alertBuilder
                        .setMessage(R.string.settings_backup_store_dialog)
                        .setPositiveButton(R.string.generell_ok, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                if(!Utils.askForReadPermission(getActivity(), permissionCallbackBackup ,backup))return;
                                realmBackupRestore.backup();
                            }
                        })
                        .setNegativeButton(R.string.generell_cancel, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {

                            }
                        })
                        .show();
            }
        });

Logcat:日志猫:

2021-12-28 16:38:54.375 28406-28575/devs.myApp E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
    Process: devs.myApp, PID: 28406
    java.lang.RuntimeException: An error occurred while executing doInBackground()
        at android.os.AsyncTask$4.done(AsyncTask.java:415)
        at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
        at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
        at java.util.concurrent.FutureTask.run(FutureTask.java:271)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:923)
     Caused by: io.realm.exceptions.RealmFileException: Unable to open a realm at path '/backup.realm'. Please use a path where your app has read-write permissions. (open("/backup.realm") failed: Read-only file system) (/backup.realm) in /home/cc/repo/realm/release/realm/realm-library/src/main/cpp/io_realm_internal_OsSharedRealm.cpp line 407 Kind: PERMISSION_DENIED.
        at io.realm.internal.OsSharedRealm.nativeWriteCopy(Native Method)
        at io.realm.internal.OsSharedRealm.writeCopy(OsSharedRealm.java:343)
        at io.realm.BaseRealm.writeCopyTo(BaseRealm.java:274)
        at io.realm.Realm.writeCopyTo(Realm.java:135)
        at devs.myApp.utils.RealmBackupRestore$1.doInBackground(RealmBackupRestore.java:65)
        at devs.myApp.utils.RealmBackupRestore$1.doInBackground(RealmBackupRestore.java:45)
        at android.os.AsyncTask$3.call(AsyncTask.java:394)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 
        at java.lang.Thread.run(Thread.java:923) 

Try to add in manifest尝试添加清单

    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>

and also ask user to give file manage permission at run time in-app并要求用户在应用程序内运行时授予文件管理权限

String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myApp";字符串路径 = Environment.getExternalStorageDirectory().getAbsolutePath() + "/myApp";

On an Android 11+ device apps cannot create their own folders in root of external storage.在 Android 11+ 设备上,应用程序无法在外部存储的根目录中创建自己的文件夹。

Instead try to create your own folder in public Documents dorectory for instance.例如,尝试在公共文档目录中创建自己的文件夹。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我想从外部存储中获取所有文档文件,但在 android 11 中没有管理存储权限 - i want to get all documents file from external storage with out manage storage permission in android 11 如何将文件保存到 Android Q (API 29) 上的公共(外部)存储? - How to save file to public (external) storage on Android Q (API 29)? 如何在不使用管理外部存储权限的情况下在 android 11 范围存储中获取手机存储中可用的所有 pdf 文件 - how to get all pdf file available in my phone storage in android 11 scope storage without using manage external storage permission 如何在不使用“MANAGE_EXTERNAL_STORAGE”权限的情况下删除音频文件 Android 11+ - How to delete audio file without using "MANAGE_EXTERNAL_STORAGE" permission Android 11+ 在 Android 11+ 上自动加载没有 MANAGE_EXTERNAL_STORAGE 权限的字幕 - Auto load subtitles without MANAGE_EXTERNAL_STORAGE permission on Android 11+ Android READ_EXTERNAL_STORAGE 权限不起作用 - Android READ_EXTERNAL_STORAGE permission not working Android-允许使用相机并写入外部存储 - Android - Permission to use Camera and Write to External Storage Android HTC / Sony外部存储权限被拒绝 - Android HTC/Sony External Storage Permission Denied Android 的 READ_EXTERNAL_STORAGE 权限 - READ_EXTERNAL_STORAGE permission for Android 如何在android 11中实现存储权限。有人可以分享一个在java中实现的例子吗 - How to implement storage permission in android 11. Can someone share an example implemented in java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM