Android Studio 開発 - Android11 以降のバージョンの動的アプリケーションの問題 (ファイルの読み取りと書き込み、写真、カメラ呼び出しなど)

これは Android 携帯電話のアップグレードに使用されます。現在は Android13 バージョンです。許可の問題により敏感になる可能性があります。しばらく前に、以前の方法は Android11 の新しいバージョンには適用できないことが開発によって判明しました。

読み取りおよび書き込み権限を申請する最善の方法は、設定にジャンプすることです。始めましょう。

1 つ目は AndroidManifest.xml ファイルの権限です。

<!--    android13的图片、音频、视频的权限-->
    <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
    <uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
    <uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

    <!--存储权限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
        tools:ignore="ScopedStorage" />

<!--    打开相机权限-->
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    
<!--    网络权限-->
    <uses-permission android:name="android.permission.INTERNET" />
    

次に、許可申請の状況について説明します。2つの状況があります。

最初のケースは、アクティビティで直接権限を申請することです。

2 番目のケースは、Fragment で許可を申請する場合です。

最初のケースはより単純で、android11 より前の許可アプリケーションによると、次のようになります。

//首先定义请求变量  
private static final String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
//请求状态码,请求码的作用是与回调函数进行匹配的,这样就可以对不同权限操作进行不同的提示
private static final int REQUEST_EXTERNAL_STORAGE = 1;

//使用ActivityCompat.requestPermissions进行动态权限申请
ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);

//然后Activity会有一个回调函数,可以在这个回调函数做一些提示
//如下重写onRequestPermissionsResult方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { //申请文件读写权限
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_EXTERNAL_STORAGE:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    havePermission = true;
                    Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
                } else {
                    havePermission = false;
                    Toast.makeText(this, "授权被拒绝!", Toast.LENGTH_SHORT).show();
                }
                break;
            case REQUEST_PERMISSION_CODE_33:
                Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
                break;
        }

 完全なコード例は次のとおりです

public class MainActivity extends AppCompatActivity {
     private static final String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
    //请求状态码
    private static final int REQUEST_EXTERNAL_STORAGE = 1;

    //创建Activity生命周期
    protected void onCreate(Bundle savedInstanceState) {

    }

    //获取Activity焦点的生命周期
    @Override
    protected void onResume() {
        super.onResume();
        checkPermission();
    }

     private AlertDialog dialog;

    private void checkPermission() {
        //检查权限(NEED_PERMISSION)是否被授权 PackageManager.PERMISSION_GRANTED表示同意授权
            //这里是android7以上就需要动态申请权限
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    //申请权限
                    if (dialog != null) {
                        dialog.dismiss();
                        dialog = null;
                    }
                    dialog = new AlertDialog.Builder(this)
                            .setTitle("提示")//设置标题
                            .setMessage("请开启文件访问权限,否则无法正常使用应用!")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    dialog.dismiss();
                                    ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
                                }
                            }).create();
                    dialog.show();
                } else {
                    havePermission = true;
                    
                }
            } else {
                //android6以下不需要动态申请权限
                havePermission = true;
                
            }
        
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { //申请文件读写权限
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_EXTERNAL_STORAGE:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    havePermission = true;
                    Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
                } else {
                    havePermission = false;
                    Toast.makeText(this, "授权被拒绝!", Toast.LENGTH_SHORT).show();
                }
                break;
            case REQUEST_PERMISSION_CODE_33:
                Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
                break;
        }

 以下は、Fragment で動的に権限を申請する 2 番目のケースです。Fragment は、Activity にアタッチされたページに相当するため、Fragment 内でのコールバック関数の処理はなく、そのため、Fragment が配置されている Activity のアクティビティ オブジェクトを使用する必要があります。たとえば、Fragment の定義は次のようになります。

public class PersonFragment extends Fragment {
    //定义一个Activity对象,用于给MainActivity赋值
    public static Activity context;
    private static final String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,Manifest.permission.CAMERA};
    //请求状态码
    private static final int REQUEST_EXTERNAL_STORAGE = 1;
}

 @Override
 public void onStart() {
     super.onStart();
     
   checkPermission();
    }

     private AlertDialog dialog;

    private void checkPermission() {
        //检查权限(NEED_PERMISSION)是否被授权 PackageManager.PERMISSION_GRANTED表示同意授权
            //这里是android7以上就需要动态申请权限
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    //申请权限
                    if (dialog != null) {
                        dialog.dismiss();
                        dialog = null;
                    }
                    dialog = new AlertDialog.Builder(this)
                            .setTitle("提示")//设置标题
                            .setMessage("请开启文件访问权限,否则无法正常使用应用!")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    dialog.dismiss();
                                    ActivityCompat.requestPermissions(context, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
                                }
                            }).create();
                    dialog.show();
                } else {
                    havePermission = true;
                    
                }
            } else {
                //android6以下不需要动态申请权限
                havePermission = true;
                
            }
        
    }

次に、MainActivity で上記の Fragment にアクティビティ オブジェクトを割り当て、許可を申請する際に Fragment が MainActivity のコールバック関数を操作できるようにします。MainActivity のコード例は次のとおりです。

public class MainActivity extends AppCompatActivity {
    //这里的请求码要和Fragment的请求码一致
    private static final int REQUEST_EXTERNAL_STORAGE = 1;

    //创建Activity生命周期
    protected void onCreate(Bundle savedInstanceState) {

        PersonFragment.context = MainActivity.this

    }


@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { //申请文件读写权限
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_EXTERNAL_STORAGE:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    havePermission = true;
                    Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
                } else {
                    havePermission = false;
                    Toast.makeText(this, "授权被拒绝!", Toast.LENGTH_SHORT).show();
                }
                break;
            case REQUEST_PERMISSION_CODE_33:
                Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
                break;
        }

上記の例は、一部の友達が理解していない人のために、パーミッションアプリケーションとコールバック関数の関係を説明するためのものです. 以下は、android7、android11、android13以下の動的パーミッションアプリケーションの状況です

1. ファイルの読み取りおよび書き込み権限がコードに直接アップロードされます

public class MainActivity extends AppCompatActivity {

     //申请的权限放进数组里
     private static final String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
    //请求状态码
    private static final int REQUEST_EXTERNAL_STORAGE = 1;

    //创建Activity生命周期
    protected void onCreate(Bundle savedInstanceState) {

    }

    //获取Activity焦点的生命周期
   
    @Override
    protected void onResume() {
        super.onResume();
        checkPermission();
    }

    private AlertDialog dialog;

    private void checkPermission() {
        //检查权限(NEED_PERMISSION)是否被授权 PackageManager.PERMISSION_GRANTED表示同意授权
        //这里是android11以上的读写权限申请
        //需要通过Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION跳转到权限设置打开权限
        if (Build.VERSION.SDK_INT >= 30) {
            if (!Environment.isExternalStorageManager()) {
                if (dialog != null) {
                    dialog.dismiss();
                    dialog = null;
                }
                dialog = new AlertDialog.Builder(this)
                        .setTitle("提示")//设置标题
                        .setMessage("请开启文件访问权限,否则无法正常使用本应用!")
                        .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int i) {
                                dialog.dismiss();
                            }
                        })
                        .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                dialog.dismiss();
                                Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
                                startActivity(intent);
                            }
                        }).create();
                dialog.show();
            } else {
                havePermission = true;
                
            }
        } else {
            //这里就是android7到android11的权限申请
            //直接通过ActivityCompat.requestPermissions就可以
            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
                if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                    //申请权限
                    if (dialog != null) {
                        dialog.dismiss();
                        dialog = null;
                    }
                    dialog = new AlertDialog.Builder(this)
                            .setTitle("提示")//设置标题
                            .setMessage("请开启文件访问权限,否则无法正常使用应用!")
                            .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    dialog.dismiss();
                                    ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
                                }
                            }).create();
                    dialog.show();
                } else {
                    havePermission = true;
                  
                }
            } else {
                //android7以下的不需要动态申请权限
                havePermission = true;
               
            }
        }
    }

    //权限申请成功后的回调函数,可以做提示或其他
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { //申请文件读写权限
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode) {
            case REQUEST_EXTERNAL_STORAGE:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    havePermission = true;
                    Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
                } else {
                    havePermission = false;
                    Toast.makeText(this, "授权被拒绝!", Toast.LENGTH_SHORT).show();
                }
                break;
            case REQUEST_PERMISSION_CODE_33:
                Toast.makeText(this, "授权成功!", Toast.LENGTH_SHORT).show();
                break;
        }
    }

2. フォトアルバムとカメラ権限の申請状況

Android 13 は、フォト アルバムを画像アプリケーション、ビデオ アプリケーション、オーディオ アプリケーションの 3 つの権限に分割しているため、ここで特別である可能性があります。

private static final String[] PERMISSIONS_STORAGE = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA};
//请求状态码
private static final int REQUEST_EXTERNAL_STORAGE = 1;

//android13相册权限申请变量    
private static final String[] PERMISSIONS_STORAGE_33 = {Manifest.permission.READ_MEDIA_IMAGES, Manifest.permission.READ_MEDIA_AUDIO, Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.CAMERA};
//请求状态码
private static final int REQUEST_PERMISSION_CODE_33 = 2;

権限配列は異なる場合があります。android13 以下の読み取りおよび書き込み権限を適用するだけで十分ですが、android13 はこれら 3 つの権限を動的に適用する必要がある場合があるため、コードは次のとおりです。ここでは Fragment を使用して権限を適用します。

@RequiresApi(api = Build.VERSION_CODES.TIRAMISU)
@SuppressLint("StaticFieldLeak")
public class PersonFragment extends Fragment {
    //MainActivity的activity对象
    public static Activity context;
      @Override
    public void onStart() {
        super.onStart();
        ifHaveAlbumPermission(context)

    }    

    //打开相册
    private void openFile() {

        Intent intentFromGallery = new Intent();
        // 设置文件类型
        intentFromGallery.setType("image/*");//选择图片
        intentFromGallery.setAction(Intent.ACTION_GET_CONTENT);
        
        //你需要使用系统提供的startActivityForResult(Intent intent,int requestCode)方法调用MainActivity的回调函数
        context.startActivityForResult(intentFromGallery, REQUEST_PICTURE_CODE);


    }

    // 判断是否有文件存储权限
    private void ifHaveAlbumPermission(Activity activity) {

        if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_MEDIA_IMAGES) != PackageManager.PERMISSION_GRANTED) {
            //android13权限申请
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {

                ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE_33, REQUEST_PERMISSION_CODE_33);
                openFile();
            } else {
                //android13以下的权限申请
                ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
            }
        } else {
            openFile();
        }
       
    }

}

上記はほぼ完成です、カメラの状況は似ています、他のブロガーが書いたものを読むことができます

おすすめ

転載: blog.csdn.net/m0_59799878/article/details/130795891