Android 關於6.0,7.0許可權的那點事
前言:最近把專案 targetSdkVersion 從22直接升級到27,因此就需要對新的動態許可權相關問題進行一籮筐的操作。寫這篇文章總結一下。
我在專案裡用的是EasyPermission工具類進行的動態許可權判斷。首先,在build.gradle中新增依賴:
implementation 'pub.devrel:easypermissions:1.1.3'
然後就是對自己用到的動態許可權進行判斷啦。我這邊用到的許可權是
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
在這裡就需要建一個工具類了,對相同的許可權組中的許可權進行分類。
public class PermissionUtil { public static final String[] REQUEST_PERMISSIONS = {Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS , Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION , Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_PHONE_STATE , Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final String CAMERA = Manifest.permission.CAMERA; public static final String READ_CONTACTS = Manifest.permission.READ_CONTACTS; public static final String ACCESS_FINE_LOCATION = Manifest.permission.ACCESS_FINE_LOCATION; public static final String ACCESS_COARSE_LOCATION = Manifest.permission.ACCESS_COARSE_LOCATION; public static final String RECORD_AUDIO = Manifest.permission.RECORD_AUDIO; public static final String READ_PHONE_STATE = Manifest.permission.READ_PHONE_STATE; public static final String READ_EXTERNAL_STORAGE = Manifest.permission.READ_EXTERNAL_STORAGE; public static final String WRITE_EXTERNAL_STORAGE = Manifest.permission.WRITE_EXTERNAL_STORAGE; /** * 定位相關許可權 **/ public static final String[] REQUEST_LOCATION_PERMISSIONS = {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION , Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; /** * 拍照相關許可權 */ public static final String[] REQUEST_PHOTO_PERMISSIONS = {Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; /** * 檔案讀寫 */ public static final String[] REQUEST_FILE_PERMISSIONS = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; /** * 語音相關 */ public static final String[] REQUEST_VOICE_PERMISSIONS = {Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; /** * 申請許可權時的許可權分類申請,0全部,1拍照相關,2定位相關,3檔案相關,4語音相關 * Activity時使用 */ public static void requestPermissionMethod(Activity activity, Context mContext, int flag, int requestCode) { List<String> perms = new ArrayList<>(); switch (flag) { case 0: if (!EasyPermissions.hasPermissions(activity, CAMERA)) { perms.add(CAMERA); } if (!EasyPermissions.hasPermissions(activity, READ_CONTACTS)) { perms.add(READ_CONTACTS); } if (!EasyPermissions.hasPermissions(activity, ACCESS_FINE_LOCATION)) { perms.add(ACCESS_FINE_LOCATION); } if (!EasyPermissions.hasPermissions(activity, ACCESS_COARSE_LOCATION)) { perms.add(ACCESS_COARSE_LOCATION); } if (!EasyPermissions.hasPermissions(activity, RECORD_AUDIO)) { perms.add(RECORD_AUDIO); } if (!EasyPermissions.hasPermissions(activity, READ_PHONE_STATE)) { perms.add(READ_PHONE_STATE); } if (!EasyPermissions.hasPermissions(activity, READ_EXTERNAL_STORAGE)) { perms.add(READ_EXTERNAL_STORAGE); } if (!EasyPermissions.hasPermissions(activity, WRITE_EXTERNAL_STORAGE)) { perms.add(WRITE_EXTERNAL_STORAGE); } break; case 1: if (!EasyPermissions.hasPermissions(activity, CAMERA)) { perms.add(CAMERA); } if (!EasyPermissions.hasPermissions(activity, READ_EXTERNAL_STORAGE)) { perms.add(READ_EXTERNAL_STORAGE); } if (!EasyPermissions.hasPermissions(activity, WRITE_EXTERNAL_STORAGE)) { perms.add(WRITE_EXTERNAL_STORAGE); } break; case 2: if (!EasyPermissions.hasPermissions(activity, ACCESS_FINE_LOCATION)) { perms.add(ACCESS_FINE_LOCATION); } if (!EasyPermissions.hasPermissions(activity, ACCESS_COARSE_LOCATION)) { perms.add(ACCESS_COARSE_LOCATION); } if (!EasyPermissions.hasPermissions(activity, READ_PHONE_STATE)) { perms.add(READ_PHONE_STATE); } if (!EasyPermissions.hasPermissions(activity, READ_EXTERNAL_STORAGE)) { perms.add(READ_EXTERNAL_STORAGE); } if (!EasyPermissions.hasPermissions(activity, WRITE_EXTERNAL_STORAGE)) { perms.add(WRITE_EXTERNAL_STORAGE); } break; case 3: if (!EasyPermissions.hasPermissions(activity, READ_EXTERNAL_STORAGE)) { perms.add(READ_EXTERNAL_STORAGE); } if (!EasyPermissions.hasPermissions(activity, WRITE_EXTERNAL_STORAGE)) { perms.add(WRITE_EXTERNAL_STORAGE); } break; case 4: if (!EasyPermissions.hasPermissions(activity, RECORD_AUDIO)) { perms.add(RECORD_AUDIO); } if (!EasyPermissions.hasPermissions(activity, READ_EXTERNAL_STORAGE)) { perms.add(READ_EXTERNAL_STORAGE); } if (!EasyPermissions.hasPermissions(activity, WRITE_EXTERNAL_STORAGE)) { perms.add(WRITE_EXTERNAL_STORAGE); } break; default: break; } int size = perms.size(); EasyPermissions.requestPermissions(activity, “需要您同意以下許可權。”, requestCode, (String[]) perms.toArray(new String[size])); } /** * 申請許可權時的許可權分類申請,0全部,1拍照相關,2定位相關,3檔案相關,4語音相關 * Fragment使用 */ public static void requestPermissionMethodForF(Fragment fragment, Context mContext, int flag, int requestCode) { List<String> perms = new ArrayList<>(); switch (flag) { case 0: if (!EasyPermissions.hasPermissions(mContext, CAMERA)) { perms.add(CAMERA); } if (!EasyPermissions.hasPermissions(mContext, READ_CONTACTS)) { perms.add(READ_CONTACTS); } if (!EasyPermissions.hasPermissions(mContext, ACCESS_FINE_LOCATION)) { perms.add(ACCESS_FINE_LOCATION); } if (!EasyPermissions.hasPermissions(mContext, ACCESS_COARSE_LOCATION)) { perms.add(ACCESS_COARSE_LOCATION); } if (!EasyPermissions.hasPermissions(mContext, RECORD_AUDIO)) { perms.add(RECORD_AUDIO); } if (!EasyPermissions.hasPermissions(mContext, READ_PHONE_STATE)) { perms.add(READ_PHONE_STATE); } if (!EasyPermissions.hasPermissions(mContext, READ_EXTERNAL_STORAGE)) { perms.add(READ_EXTERNAL_STORAGE); } if (!EasyPermissions.hasPermissions(mContext, WRITE_EXTERNAL_STORAGE)) { perms.add(WRITE_EXTERNAL_STORAGE); } break; case 1: if (!EasyPermissions.hasPermissions(mContext, CAMERA)) { perms.add(CAMERA); } if (!EasyPermissions.hasPermissions(mContext, READ_EXTERNAL_STORAGE)) { perms.add(READ_EXTERNAL_STORAGE); } if (!EasyPermissions.hasPermissions(mContext, WRITE_EXTERNAL_STORAGE)) { perms.add(WRITE_EXTERNAL_STORAGE); } break; case 2: if (!EasyPermissions.hasPermissions(mContext, ACCESS_FINE_LOCATION)) { perms.add(ACCESS_FINE_LOCATION); } if (!EasyPermissions.hasPermissions(mContext, ACCESS_COARSE_LOCATION)) { perms.add(ACCESS_COARSE_LOCATION); } if (!EasyPermissions.hasPermissions(mContext, READ_PHONE_STATE)) { perms.add(READ_PHONE_STATE); } if (!EasyPermissions.hasPermissions(mContext, READ_EXTERNAL_STORAGE)) { perms.add(READ_EXTERNAL_STORAGE); } if (!EasyPermissions.hasPermissions(mContext, WRITE_EXTERNAL_STORAGE)) { perms.add(WRITE_EXTERNAL_STORAGE); } break; case 3: if (!EasyPermissions.hasPermissions(mContext, READ_EXTERNAL_STORAGE)) { perms.add(READ_EXTERNAL_STORAGE); } if (!EasyPermissions.hasPermissions(mContext, WRITE_EXTERNAL_STORAGE)) { perms.add(WRITE_EXTERNAL_STORAGE); } break; case 4: if (!EasyPermissions.hasPermissions(mContext, RECORD_AUDIO)) { perms.add(RECORD_AUDIO); } if (!EasyPermissions.hasPermissions(mContext, READ_EXTERNAL_STORAGE)) { perms.add(READ_EXTERNAL_STORAGE); } if (!EasyPermissions.hasPermissions(mContext, WRITE_EXTERNAL_STORAGE)) { perms.add(WRITE_EXTERNAL_STORAGE); } break; default: break; } int size = perms.size(); EasyPermissions.requestPermissions(fragment, “需要您同意以下許可權。”, requestCode, (String[]) perms.toArray(new String[size])); } }
在工具類中首先把用到的許可權都宣告出來,然後有 兩個方法分別用在Activity和Fragment中,方法都是一樣的,只是引數區別,
然後就是在Activity中的使用啦。
在這裡以拍照為例:
首先讓Activity或者Fragment重寫 onRequestPermissionsResult 方法,在這個方法裡使用EasyPermission去申請許可權
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { // EasyPermissions handles the request result. EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this); super.onRequestPermissionsResult(requestCode, permissions, grantResults); }
然後讓Activity或者Fragment實現 EasyPermissions.PermissionCallbacks 這個介面中有兩個方法,
@Override public void onPermissionsGranted(int requestCode, @NonNull List<String> perms) { if (requestCode == RESULT_LOAD_PHOTO_PERMISSIONS && EasyPermissions.hasPermissions(this, PermissionUtil.REQUEST_PHOTO_PERMISSIONS)) { goCamera(); } } @Override public void onPermissionsDenied(int requestCode, @NonNull List<String> perms) { new AppSettingsDialog.Builder(this).setTitle("提示").setRationale("缺少必要許可權,應用可能無法正常工作,是否前往設定頁面進行設定?").build().show(); }
第一個方法 onPermissionsGranted 顧名思義,許可權申請通過了 ,這個方法只會在給使用者彈出了申請許可權的懸浮框之後 點選允許時會呼叫,如果使用者在點選拒絕之後 選擇了 不再詢問,那麼這個方法就不會再被呼叫了。
這個時候 第二個方法 onPermissionsDenied 就派上了用場,如果使用者拒絕了許可權或者點選不再詢問之後,再次申請了許可權都會呼叫這個方法,在這個方法裡,我們給使用者一個彈出框去詢問是否到應用設定頁面進行許可權設定。
對於這兩個方法,再多說一句,假如我申請了5個許可權,同意了兩個,拒絕了三個。那麼 onPermissionsGranted 中返回過來的perms(同意的許可權集合)的size就會是2.onPermissionsDenied 就是三個。
好了,繼續說許可權的問題。在 onPermissionsGranted 方法中,我們用requestCode進行了判斷,判斷是否是點選相機而發起的許可權申請,並且相機的相關許可權全部打開了。我們就會去呼叫goCamera這個方法去拍照。
/** * 去往相機 */ private void goCamera() { long photoName = System.currentTimeMillis(); File cameraFile = new File(saveDir.getPath(), photoName + ".jpg"); if (!saveDir.exists()) { saveDir.mkdirs(); } if (cameraFile.exists()) { cameraFile.delete(); } Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); Uri uri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(this, "android.file.path", cameraFile); } else { uri = Uri.fromFile(cameraFile); } cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri); startActivityForResult(cameraIntent, RESULT_LOAD_IMAGE_FORCAMERA); }
在這個方法裡就用到了7.0的檔案許可權的相關修改。對於7.0許可權的問題使用方法就不細說了。網上一大堆。舉個特例,如果在7.0上使用別的應用開啟下載的檔案。需要加上
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
這個屬性。
end。