文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

在鸿蒙系统上实现权限请求框架—桃夭权限请求框架

2024-12-02 17:39

关注

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

本文正在参与优质创作者激励

一、简介

桃夭是鸿蒙系统上的一款权限请求框架,对请求权限的代码进行高度封装,极大的简化了申请权限的代码逻辑,同时支持在Ability、FractionAbility、AbilitySlice、Fractiion里面申请权限。

二、源码

源码

建议大家把源码下载下来看看。

三、申请权限的一般步骤

每次申请权限的时候,都需要经过以上几个步骤,当申请的权限越来越多,大量的重复代码就出现了。为了减少重复代码,我封装了一个权限请求框架,权限请求框架取名为桃夭。

四、桃夭的使用方式

如下代码,先添加依赖,然后你只需要告知权限请求框架你需要什么权限,权限请求框架就会告知你权限申请成功还是失败。你不需要手动判断是否有权限,不需要弹窗告知用户申请权限的原因,不需要判断用户是否点击了不再提醒,不需要跳转设置页面让用户开启权限,不需要重写onRequestPermissionsFromUserResult方法。框架把这些代码逻辑都给做了,你只需要关注权限申请成功还是失败。

申请权限变得如此之简单。

添加依赖

  1. api 'io.gitee.zhongte:taoyao:1.0.1' 

 申请权限

  1. // 申请多设备协同权限 
  2. EasyPermission.requestPermission(this, EasyPermission.DISTRIBUTED_DATASYNC, new PermissionAction() { 
  3.             @Override 
  4.             public void onGranted(List permissions) { 
  5.                 // 权限申请成功 
  6.                  
  7.             } 
  8.  
  9.             @Override 
  10.             public void onDenied(List permissions) { 
  11.                 // 权限申请失败 
  12.             } 
  13.         }, SystemPermission.DISTRIBUTED_DATASYNC); 

 申请权限的时候可能会涉及到两个弹窗,一个弹窗是用来告知用户申请权限的原因,另一个弹窗是用来告知用户去设置页面开启权限,这两个弹窗在不同的应用里面可能长得不一样,所以这两个弹窗并没有被封装到桃夭框架里面,而是需要使用者根据你的弹窗样式对桃夭进行二次封装,我在源码里面对桃夭框架进行了二次封装,大家可以把源码下载下来,参考下我是如何对桃夭框架进行二次封装的。二次封装完成后,就可以愉快的使用上面的代码申请权限了。

五、实现原理

1 检测申请的权限是否在配置文件中声明

申请的权限必须在配置文件中声明,否则桃夭会直接抛异常。如何检测申请的权限是否在配置文件中声明。

如下代码,获取bundleManager对象,通过bundleManager对象获取应用信息,之后就可以获取应用在配置文件中声明的权限了。

  1.  
  2. private List getConfigPermissions(Context context) { 
  3.     // 获取bundleManager对象 
  4.     IBundleManager bundleManager = context.getBundleManager(); 
  5.     String bundleName = context.getBundleName(); 
  6.     try { 
  7.         // 获取应用信息 
  8.         BundleInfo bundleInfo = bundleManager.getBundleInfo(bundleName, IBundleManager.GET_BUNDLE_WITH_REQUESTED_PERMISSION); 
  9.         // 获取应用在配置文件中声明的权限 
  10.         List reqPermissionDetails = bundleInfo.reqPermissions; 
  11.         if (reqPermissionDetails == null || reqPermissionDetails.isEmpty()) { 
  12.             throw new IllegalStateException("请在配置文件中声明要申请的权限"); 
  13.         } 
  14.         return reqPermissionDetails; 
  15.     } catch (RemoteException e) { 
  16.         e.printStackTrace(); 
  17.     } 
  18.     return new ArrayList<>(); 

获取到在配置文件中声明的权限后,就可以判断申请的权限是否在配置文件中了

  1.  
  2.     private void checkPermissions(String... permissions) { 
  3.         if (permissions == null || permissions.length == 0) { 
  4.             throw new IllegalArgumentException("请至少申请一个权限"); 
  5.         } 
  6.         // 获取在配置文件中声明的权限 
  7.         mReqPermissions = getConfigPermissions(mOrigin.getContext()); 
  8.         if (mReqPermissions.isEmpty()) { 
  9.             throw new IllegalStateException("请在配置文件中声明要申请的权限"); 
  10.         } 
  11.         for (String target : permissions) { 
  12.             if (!mReqPermissions.contains(target)) { 
  13.                 // 没有在配置中声明要申请的权限,直接抛异常 
  14.                 throw new IllegalStateException(String.format("%1$s权限没有配置文件中声明", target)); 
  15.             } 
  16.         } 
  17.     } 

2 判断是否有权限

检测完权限是否在配置中声明后,就可以判断是否有权限了。这里就是通过上下文对象的verifySelfPermission方法来判断是否有权限,如果没有权限,可以弹窗告知用户申请的原因。

  1.  
  2.    @Override 
  3.    public boolean hasPermission(Context context, List permissions) { 
  4.        for (String permission : permissions) { 
  5.            int result = context.verifySelfPermission(permission); 
  6.            if (result == IBundleManager.PERMISSION_DENIED) { 
  7.                // 没有权限 
  8.                return false
  9.            } 
  10.        } 
  11.        return true
  12.    } 

3 判断用户是否点击了不再提醒

通过上下文对象的canRequestPermission方法来判断用户是否点击了不再提醒。

  1.  
  2.   @Override 
  3.   public boolean canRequestPermission(String permission) { 
  4.       return mContext.canRequestPermission(permission); 
  5.   } 

4 跳转到设置页面

如果用户点击了不再提醒,则可以跳转到设置页面让用户开启权限

  1.  
  2.     @Override 
  3.     public void gotoSetting() { 
  4.         try { 
  5.             Intent intent = new Intent(); 
  6.             intent.setAction(IntentConstants.ACTION_APPLICATION_DETAILS_SETTINGS); 
  7.             intent.setUri(Uri.parse("package:" + mOrigin.getContext().getBundleName())); 
  8.             mOrigin.startAbility(intent); 
  9.         } catch (Exception e) { 
  10.             e.printStackTrace(); 
  11.         } 
  12.     } 

5 启动透明的Ability申请权限

如果没有权限,用户页面没有点击不再提醒,那就可以申请权限了。为了不让调用者重写onRequestPermissionsFromUserResult方法,桃夭内部启动了一个Ability。如下代码。

  1.  
  2. public class PermissionAbility extends Ability { 
  3.  
  4.     private static final int REQUEST_CODE = 0X10; 
  5.     public static final String KEY_PERMISSION = "key_permission"
  6.     public static final String KEY_TYPE = "key_type"
  7.     public static final String SENSITIVE_PERMISSION = "sensitive_permission"
  8.  
  9.     @Override 
  10.     public void onStart(Intent intent) { 
  11.         super.onStart(intent); 
  12.         getWindow().setTransparent(true); 
  13.         super.setUIContent(ResourceTable.Layout_ability_permission); 
  14.         List permissions = intent.getSerializableParam(KEY_PERMISSION); 
  15.         String permissionType = intent.getStringParam(KEY_TYPE); 
  16.         // 请求权限 
  17.         requestPermissionsFromUser(permissions.toArray(new String[0]), REQUEST_CODE); 
  18.     } 
  19.  
  20.     @Override 
  21.     public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) { 
  22.         super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults); 
  23.         // 权限的回调方法 
  24.         Postman.send(permissions, grantResults); 
  25.         terminateAbility(); 
  26.     } 
  27.  
  28.     @Override 
  29.     protected void onAbilityResult(int requestCode, int resultCode, Intent resultData) { 
  30.         super.onAbilityResult(requestCode, resultCode, resultData); 
  31.     } 

直接启动一个Ability会发生页面跳转,为了不让页面发生跳转,这里启动了一个透明的Ability。如何将Ability设置透明,如下代码。在abilities节点添加metaData,这里最关键的是Translucent,也就是透明。

  1. "abilities": [ 
  2.       { 
  3.         "orientation""unspecified"
  4.         "name""com.poetry.taoyao.ability.PermissionAbility"
  5.         "icon""$media:icon"
  6.         "description""$string:permissionability_description"
  7.         "label""$string:taoyao_PermissionAbility"
  8.         "type""page"
  9.         "launchType""standard"
  10.         "metaData": { 
  11.           "customizeData": [ 
  12.             { 
  13.               "name""hwc-theme"
  14.               "value""androidhwext:style/Theme.Emui.Translucent.NoTitleBar" 
  15.             } 
  16.           ] 
  17.         } 
  18.       } 

仅仅有上面的步骤好不够,需要在Ability或者AbilitySlice里面将窗口设置成透明。如下代码。

  1. getWindow().setTransparent(true); 

 经过上面两步,也就是将Ability的主题和窗口都设置成透明,这样就能将Ability变成透明的了,同时也不会发生页面跳转。

6 判断用户是否授予权限

判断用户是否授予权限,可以使用标准的方式来判断。也就是通过grantResult来判断用户是否授予权限。

  1. @Override 
  2.  public boolean hasPermission(int[] grantResults, String... permissions) { 
  3.      if (grantResults == null || grantResults.length <= 0) { 
  4.          return false
  5.      } 
  6.      for (int grantResult : grantResults) { 
  7.          if (grantResult == IBundleManager.PERMISSION_DENIED) { 
  8.              return false
  9.          } 
  10.      } 
  11.      return true
  12.  } 

其实还有另外的方式来判断用户是否授予权限。也就是不管用户是否授权,直接访问相关业务。比如,申请录音权限,当系统回调onRequestPermissionsFromUserResult方法时,直接去录音,如果发生异常,捕获异常说明没有权限。如下代码:

  1.  
  2.    @Override 
  3.    public boolean test(Context context) throws Throwable { 
  4.        AudioStreamInfo audioStreamInfo = new AudioStreamInfo.Builder().encodingFormat( 
  5.                AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT) 
  6.                .channelMask(AudioStreamInfo.ChannelMask.CHANNEL_IN_STEREO) 
  7.                .sampleRate(AUDIO_SAMPLE_RATE) 
  8.                .build(); 
  9.        AudioCapturerInfo audioCapturerInfo = new AudioCapturerInfo.Builder().audioStreamInfo(audioStreamInfo).build(); 
  10.        try { 
  11.            AudioCapturer capturer = new AudioCapturer(audioCapturerInfo); 
  12.            // 录音 
  13.            capturer.start(); 
  14.            new Timer().schedule(new TimerTask() { 
  15.                @Override 
  16.                public void run() { 
  17.                    capturer.stop(); 
  18.                } 
  19.            }, AUDIO_RECORDING_TIME); 
  20.            // 没有发生异常,有权限 
  21.            return true
  22.        } catch (Exception e) { 
  23.            // 发生异常,无权限 
  24.            return false
  25.        } 
  26.    } 

桃夭在判断用户是否授权时,上面的两种方式都使用了。

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

来源:鸿蒙社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯