更多内容请访问:与华为官方共建的鸿蒙技术社区https://harmonyos.51cto.com本文参与优质创作作者激励1.简介淘药是鸿蒙系统上的一个权限请求框架。对申请权限的代码进行了高度封装,大大简化了申请权限的代码逻辑。同时支持在Ability、FractionAbility、AbilitySlice、Fractiion中的应用。权威。2.源码建议大家下载源码看看。3.申请权限的一般步骤判断是否有权限,有权限直接进入下一步。如果没有权限,可以弹窗告知用户为什么要申请权限。弹窗通知用户后,如果用户同意申请权限,则判断用户是否点击停止提醒。如果用户没有点击不再提醒,开始申请权限。如果用户点击不提醒,会弹窗提示用户去设置页面启用权限。用户点击弹窗后,会跳转到设置页面。重写onRequestPermissionsFromUserResult方法判断用户是否授权。每次申请权限,都需要经过以上步骤。当申请的权限越来越多时,就会出现大量的重复代码。为了减少重复代码,我封装了一个权限请求框架,名字叫Taoyao。4、淘药的使用方法如下:先添加依赖,然后你只需要告诉权限请求框架你需要什么权限,权限请求框架就会告诉你权限申请成功还是失败。不需要手动判断是否有权限,不需要弹窗告知用户申请权限的原因,不需要判断用户是否点击停止提醒,不需要跳转到设置页面让用户开启权限,也不需要重写onRequestPermissionsFromUserResult方法。框架已经把这些代码逻辑都做好了,你只需要关注权限申请是成功还是失败即可。申请许可从未如此简单。添加依赖api'io.gitee.zhongte:taoyao:1.0.1'申请权限//申请多机协同权限EasyPermission.requestPermission(this,EasyPermission.DISTRIBUTED_DATASYNC,newPermissionAction(){@OverridepublicvoidonGranted(Listpermissions){//权限申请成功}@OverridepublicvoidonDenied(Listpermissions){//权限申请失败}},SystemPermission.DISTRIBUTED_DATASYNC);申请权限时可能会有两个弹窗,一个弹窗用于告知用户申请权限的原因是另一个弹窗用于告知用户设置页面打开允许。这两个弹窗在不同的应用中可能看起来不一样,所以这两个弹窗并没有封装在淘药框架中,但是用户需要根据你的弹窗样式重新封装淘宝。我在源码中重新封装了淘药框架。大家可以下载源码,参考我是如何打包淘药框架的。用于二次包装。二次打包完成后,就可以愉快的使用上面的代码申请权限了。5、实现原理5.1检测请求的权限是否在配置文件中声明请求的权限必须在配置文件中声明,否则淘药会直接抛出异常。如何检测请求的权限是否在配置文件中声明。以下代码获取bundleManager对象,通过bundleManager对象获取应用信息,进而获取应用在配置文件中声明的权限。/***获取配置文件中声明的权限**@paramcontextcontext*@return配置文件中声明的权限*/privateListgetConfigPermissions(Contextcontext){//获取bundleManager对象IBundleManagerbundleManager=context.getBundleManager();StringbundleName=context.getBundleName();try{//获取应用信息BundleInfobundleInfo=bundleManager.getBundleInfo(bundleName,IBundleManager.GET_BUNDLE_WITH_REQUESTED_PERMISSION);//获取应用在配置文件中声明的权限ListreqPermissionDetails=bundleInfosion.reqPermisif(reqPermissionDetails==null||reqPermissionDetails.isEmpty()){thrownewIllegalStateException("请在配置文件中声明申请权限");}reqPermissionDetails;}catch(RemoteExceptione){e.printStackTrace();}returnnewArrayList<>();}获取到配置文件中声明的权限后,可以判断请求的权限是否在配置中file/***检查请求的权限是否在配置文件中声明**@parampermissions要申请的权限*/privatevoidcheckPermissions(String...permissions){if(permissions==null||permissions.length==0){thrownewIllegalArgumentException("请至少申请一个权限");}//获取配置文件中声明的权限mReqPermissions=getConfigPermissions(mOrigin.getContext());if(mReqPermissions.isEmpty()){thrownewIllegalStateException("请在配置文件中声明申请的权限");}for(Stringtarget:permissions){if(!mReqPermissions.contains(target)){//如果要申请的权限没有在配置中声明,则直接抛出异常thrownewIllegalStateException(String.format("%1$s权限没有在配置文件中声明",target));}}}5.2判断是否有权限查看在配置中声明了权限之后,就可以判断自己是否有权限了。这里可以通过context对象的verifySelfPermission方法判断自己是否有权限。如果没有权限,可以弹窗告知用户申请原因。/***你有没有权限**@paramcontext*@parampermissions*@return*/@OverridepublicbooleanhasPermission(Contextcontext,Listpermissions){for(Stringpermission:permissions){intresult=context.verifySelfPermission(permission);if(result==IBundleManager.PERMISSION_DENIED){//无权限returnfalse;}}returntrue;}5.3判断用户是否点击不再提醒使用context对象的canRequestPermission方法判断用户是否点击不再提醒。/***用户是否点击了不存在的提醒**@parampermissionpermission*@return*/@OverridepublicbooleancanRequestPermission(Stringpermission){returnmContext.canRequestPermission(permission);}5,4跳转到设置页面如果用户不再点击提醒,然后可以跳转到设置页面让用户开启权限/***跳转到设置页面*/@OverridepublicvoidgotoSetting(){try{Intentintent=newIntent();intent.setAction(IntentConstants.ACTION_APPLICATION_DETAILS_SETTINGS);intent.setUri(Uri.parse("package:"+mOrigin.getContext().getBundleName()));mOrigin.startAbility(intent);}catch(Exceptione){e.printStackTrace();}}5,5开始transparent可以申请权限如果没有权限,并且用户页面没有被点击停止提醒,那么可以申请权限。为了防止调用者重写onRequestPermissionsFromUserResult方法,淘药内部启动了一个Ability。代码如下。/***开启一个透明的Ability来申请权限,这样外界就不需要重写onRequestPermissionsFromUserResult方法*/publicclassPermissionAbilityextendsAbility{privatestaticfinalintREQUEST_CODE=0X10;publicstaticfinalStringKEY_PERMISSION="key_permission";publicstaticfinalStringKEY_TYPE="key_type";publicstaticfinalStringSENSITIVE_PERMISSION="sensitive_permission";@OverridepublicvoidonStart(Intentintent){super.onStart(intent);getWindow().setTransparent(true);super.setUIContent(ResourceTable.Layout_ability_permission);Listpermissions=intent.getSerializableParam(KEY_PERMISSION);StringpermissionType=intent.getStringParam(KEY_TYPE);//请求权限requestPermissionsFromUser(permissions.toArray(newString[0]),REQUEST_CODE);}@OverridepublicvoidonRequestPermissionsFromUserResult(intrequestCode,String[]permissions,int[]grantResults){super.onRequestPermissionsFromUserResult(requestCode,permissions),grant/grantResult权限回调方法Postman.send(permissions,grantResults);terminateAbility();}@OverrideprotectedvoidonAbilityResult(intrequestCode,intresultCode,IntentresultData){super.onAbilityResult(requestCode,resultCode,resultData);}}直接启动一个Ability会导致页面跳转。为了防止页面跳转,一个TransparentAbility如何设置Ability透明,如下代码所示。将元数据添加到能力节点。这里的关键是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用于判断用户是否授予权限。@OverridepublicbooleanhasPermission(int[]grantResults,String...permissions){if(grantResults==null||grantResults.length<=0){returnfalse;}for(intgrantResult:grantResults){if(grantResult==IBundleManager.PERMISSION_DENIED){returnfalse;}}returntrue;}其实还有其他方法可以判断用户是否授予权限。即不管用户是否被授权,直接访问相关服务。比如申请录音权限,当系统回调onRequestPermissionsFromUserResult方法时,会直接录音。如果出现异常,捕获异常说明没有权限。以下代码:/***判断是否有直接录音权限**@paramcontext*@return*@throwsThrowable*/@Overridepublicbooleantest(Contextcontext)throwsThrowable{AudioStreamInfoaudioStreamInfo=newAudioStreamInfo.Builder().encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT).channelMask(AudioStreamInfo.ChannelMask.CHANNEL_IN_STEREO).sampleRate(AUDIO_SAMPLE_RATE).build();AudioCapturerInfoaudioCapturerInfo=newAudioCapturerInfo.Builder().audioStreamInfo(audioStreamInfo).build();try{AudioCapturercapturer=newAudioCapturer/录音机信息(音频);capturer.start();newTimer().schedule(newTimerTask(){@Overridepublicvoidrun(){capturer.stop();}},AUDIO_RECORDING_TIME);//没有异常发生,有权限returntrue;}catch(Exceptione){//发生异常,无权限returnfalse;}}淘宝在判断用户是否被授权时使用了以上两种方式。更多信息请访问:Harmonyos.51cto.com,与华为官方合作打造的鸿蒙技术社区