想了解更多内容,鸿蒙请访问:
和华为官方合作共建的系统现权限请限请鸿蒙技术社区
https://harmonyos.51cto.com
本文正在参与优质创作者激励
桃夭是上实鸿蒙系统上的一款权限请求框架,对请求权限的求框求框代码进行高度封装,极大的架桃架简化了申请权限的代码逻辑,同时支持在Ability、夭权FractionAbility、鸿蒙AbilitySlice、系统现权限请限请Fractiion里面申请权限。上实
源码
建议大家把源码下载下来看看。架桃架
每次申请权限的时候,都需要经过以上几个步骤,当申请的权限越来越多,大量的重复代码就出现了。为了减少重复代码,我封装了一个权限请求框架,权限请求框架取名为桃夭。
如下代码,先添加依赖,然后你只需要告知权限请求框架你需要什么权限,权限请求框架就会告知你权限申请成功还是失败。你不需要手动判断是否有权限,不需要弹窗告知用户申请权限的原因,不需要判断用户是否点击了不再提醒,不需要跳转设置页面让用户开启权限,不需要重写onRequestPermissionsFromUserResult方法。框架把这些代码逻辑都给做了,你只需要关注权限申请成功还是失败。服务器租用
申请权限变得如此之简单。
添加依赖
api io.gitee.zhongte:taoyao:1.0.1申请权限
// 申请多设备协同权限 EasyPermission.requestPermission(this, EasyPermission.DISTRIBUTED_DATASYNC, new PermissionAction() { @Override public void onGranted(List<String> permissions) { // 权限申请成功 } @Override public void onDenied(List<String> permissions) { // 权限申请失败 } }, SystemPermission.DISTRIBUTED_DATASYNC);申请权限的时候可能会涉及到两个弹窗,一个弹窗是用来告知用户申请权限的原因,另一个弹窗是用来告知用户去设置页面开启权限,这两个弹窗在不同的应用里面可能长得不一样,所以这两个弹窗并没有被封装到桃夭框架里面,而是需要使用者根据你的弹窗样式对桃夭进行二次封装,我在源码里面对桃夭框架进行了二次封装,大家可以把源码下载下来,参考下我是如何对桃夭框架进行二次封装的。二次封装完成后,就可以愉快的使用上面的代码申请权限了。
5、1 检测申请的权限是否在配置文件中声明
申请的权限必须在配置文件中声明,否则桃夭会直接抛异常。如何检测申请的权限是否在配置文件中声明。高防服务器
如下代码,获取bundleManager对象,通过bundleManager对象获取应用信息,之后就可以获取应用在配置文件中声明的权限了。
/** * 获取在配置文件中声明的权限 * * @param context 上下文 * @return 在配置文件中声明的权限 */ private List<String> getConfigPermissions(Context context) { // 获取bundleManager对象 IBundleManager bundleManager = context.getBundleManager(); String bundleName = context.getBundleName(); try { // 获取应用信息 BundleInfo bundleInfo = bundleManager.getBundleInfo(bundleName, IBundleManager.GET_BUNDLE_WITH_REQUESTED_PERMISSION); // 获取应用在配置文件中声明的权限 List<String> reqPermissionDetails = bundleInfo.reqPermissions; if (reqPermissionDetails == null || reqPermissionDetails.isEmpty()) { throw new IllegalStateException("请在配置文件中声明要申请的权限"); } return reqPermissionDetails; } catch (RemoteException e) { e.printStackTrace(); } return new ArrayList<>(); }获取到在配置文件中声明的权限后,就可以判断申请的权限是否在配置文件中了
/** * 检查申请的权限是否在配置文件中声明 * * @param permissions 要申请的权限 */ private void checkPermissions(String... permissions) { if (permissions == null || permissions.length == 0) { throw new IllegalArgumentException("请至少申请一个权限"); } // 获取在配置文件中声明的权限 mReqPermissions = getConfigPermissions(mOrigin.getContext()); if (mReqPermissions.isEmpty()) { throw new IllegalStateException("请在配置文件中声明要申请的权限"); } for (String target : permissions) { if (!mReqPermissions.contains(target)) { // 没有在配置中声明要申请的权限,直接抛异常 throw new IllegalStateException(String.format("%1$s权限没有配置文件中声明", target)); } } }5、2 判断是否有权限
检测完权限是否在配置中声明后,就可以判断是否有权限了。这里就是通过上下文对象的verifySelfPermission方法来判断是否有权限,如果没有权限,可以弹窗告知用户申请的原因。
/** * 是否有权限 * * @param context * @param permissions * @return */ @Override public boolean hasPermission(Context context, List<String> permissions) { for (String permission : permissions) { int result = context.verifySelfPermission(permission); if (result == IBundleManager.PERMISSION_DENIED) { // 没有权限 return false; } } return true; }5、3 判断用户是否点击了不再提醒
通过上下文对象的canRequestPermission方法来判断用户是否点击了不再提醒。
/** * 用户是否点击了不在提醒 * * @param permission 权限 * @return */ @Override public boolean canRequestPermission(String permission) { return mContext.canRequestPermission(permission); }5、4 跳转到设置页面
如果用户点击了不再提醒,则可以跳转到设置页面让用户开启权限
/** * 跳转到设置页面 */ @Override public void gotoSetting() { try { Intent intent = new Intent(); intent.setAction(IntentConstants.ACTION_APPLICATION_DETAILS_SETTINGS); intent.setUri(Uri.parse("package:" + mOrigin.getContext().getBundleName())); mOrigin.startAbility(intent); } catch (Exception e) { e.printStackTrace(); } }5、5 启动透明的Ability申请权限
如果没有权限,用户页面没有点击不再提醒,那就可以申请权限了。为了不让调用者重写onRequestPermissionsFromUserResult方法,桃夭内部启动了一个Ability。如下代码。
/** * 开启一个透明的Ability来申请权限,这样外界就不需要重写onRequestPermissionsFromUserResult方法 */ public class PermissionAbility extends Ability { private static final int REQUEST_CODE = 0X10; public static final String KEY_PERMISSION = "key_permission"; public static final String KEY_TYPE = "key_type"; public static final String SENSITIVE_PERMISSION = "sensitive_permission"; @Override public void onStart(Intent intent) { super.onStart(intent); getWindow().setTransparent(true); super.setUIContent(ResourceTable.Layout_ability_permission); List<String> permissions = intent.getSerializableParam(KEY_PERMISSION); String permissionType = intent.getStringParam(KEY_TYPE); // 请求权限 requestPermissionsFromUser(permissions.toArray(new String[0]), REQUEST_CODE); } @Override public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults); // 权限的回调方法 Postman.send(permissions, grantResults); terminateAbility(); } @Override protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) { super.onAbilityResult(requestCode, resultCode, resultData); } }直接启动一个Ability会发生页面跳转,为了不让页面发生跳转,这里启动了一个透明的Ability。如何将Ability设置透明,如下代码。在abilities节点添加metaData,这里最关键的是Translucent,也就是透明。
"abilities": [ { "orientation": "unspecified", "name": "com.poetry.taoyao.ability.PermissionAbility", "icon": "$media:icon", "description": "$string:permissionability_description", "label": "$string:taoyao_PermissionAbility", "type": "page", "launchType": "standard", "metaData": { "customizeData": [ { "name": "hwc-theme", "value": "androidhwext:style/Theme.Emui.Translucent.NoTitleBar" } ] } }仅仅有上面的步骤好不够,需要在Ability或者AbilitySlice里面将窗口设置成透明。如下代码。
getWindow().setTransparent(true);经过上面两步,也就是将Ability的主题和窗口都设置成透明,这样就能将Ability变成透明的了,同时也不会发生页面跳转。
5、6 判断用户是否授予权限
判断用户是否授予权限,可以使用标准的方式来判断。也就是通过grantResult来判断用户是否授予权限。
@Override public boolean hasPermission(int[] grantResults, String... permissions) { if (grantResults == null || grantResults.length <= 0) { return false; } for (int grantResult : grantResults) { if (grantResult == IBundleManager.PERMISSION_DENIED) { return false; } } return true; }其实还有另外的方式来判断用户是否授予权限。也就是不管用户是否授权,直接访问相关业务。比如,申请录音权限,当系统回调onRequestPermissionsFromUserResult方法时,直接去录音,如果发生异常,捕获异常说明没有权限。如下代码:
/** * 通过直接录音的方式来判断是否有录音权限 * * @param context * @return * @throws Throwable */ @Override public boolean test(Context context) throws Throwable { AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder().encodingFormat( AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT) .channelMask(AudioStreamInfo.ChannelMask.CHANNEL_IN_STEREO) .sampleRate(AUDIO_SAMPLE_RATE) .build(); AudioCapturerInfo audioCapturerInfo = new AudioCapturerInfo.Builder().audioStreamInfo(audioStreamInfo).build(); try { AudioCapturer capturer = new AudioCapturer(audioCapturerInfo); // 录音 capturer.start(); new Timer().schedule(new TimerTask() { @Override public void run() { capturer.stop(); } }, AUDIO_RECORDING_TIME); // 没有发生异常,有权限 return true; } catch (Exception e) { // 发生异常,无权限 return false; } }桃夭在判断用户是否授权时,上面的两种方式都使用了。
想了解更多内容,请访问:
和华为官方合作共建的鸿蒙技术社区
https://harmonyos.51cto.com