4
最佳

Program type already present: com.hyphenate.EMCallBack 环信_Android

beyond 回复了问题 • 4 人关注 • 4770 次浏览 • 2019-02-27 13:53 • 来自相关话题

5
最佳

android studio 1.5导入EaseUI时 出现Unable to find sources for subproject:hyphenatechatsdk 环信_Android

beyond 回复了问题 • 6 人关注 • 6346 次浏览 • 2019-02-27 13:53 • 来自相关话题

2
最佳

通知栏点击跳转问题 环信_Android

beyond 回复了问题 • 3 人关注 • 2048 次浏览 • 2019-02-27 13:52 • 来自相关话题

2
回复

java.lang.IllegalArgumentException: either category or name must be provided. 和集成的SDK冲突闪退 Android sdk

beyond 回复了问题 • 2 人关注 • 1795 次浏览 • 2019-02-27 13:52 • 来自相关话题

2
回复

为什么不能播放,官方也不修复一下呢?????? 环信 Android

beyond 回复了问题 • 2 人关注 • 1286 次浏览 • 2019-02-27 13:49 • 来自相关话题

2
最佳

如何获取好友昵称 环信_WebIM

beyond 回复了问题 • 2 人关注 • 1692 次浏览 • 2019-02-27 13:49 • 来自相关话题

1
回复

集成easeui报错 集成EaseUI 有问题

beyond 回复了问题 • 2 人关注 • 1478 次浏览 • 2019-02-27 13:48 • 来自相关话题

5
最佳

聊天室和群组 群组 聊天室 环信技术支持

beyond 回复了问题 • 5 人关注 • 11282 次浏览 • 2019-02-27 13:47 • 来自相关话题

1
回复

php 如何 集成环信 laravel当中 感谢 环信 laravel PHP 集成

beyond 回复了问题 • 2 人关注 • 1254 次浏览 • 2019-02-27 13:47 • 来自相关话题

2
最佳

Android新注册用户登录时报错用户已登录 环信_Android

beyond 回复了问题 • 2 人关注 • 987 次浏览 • 2019-02-27 13:46 • 来自相关话题

1
回复

现在环信获取聊天记录只剩下这一个接口能获取了吗? 有专职工程师值守

beyond 回复了问题 • 2 人关注 • 864 次浏览 • 2019-02-27 13:46 • 来自相关话题

0
评论

.net快速开发平台,learun敏捷开发框架 .net快速开发平台

涵涵有小虎牙 发表了文章 • 475 次浏览 • 2019-02-26 17:49 • 来自相关话题

前言:

快速开发的趋势

 在十年前,没有人会想到互联网会发展成今天这个样子,同样,也没有人料到软件开发行业也会经历如此大的巨变,在开发这一行业,停下学习就等于死亡并不是危言耸听,不关注行业未来发展趋势的人可能错过了第一个十年,如果不学习,恐怕第二个也要错过了。

快速开发目前风头正盛,但是十分完善的快速开发平台目前并不多,用过的可能都知道,虽然宣称可以覆盖各种功能,但实际使用起来bug也少不到哪里去,之所以越来越受到人们的关注,是因为它能提供便捷化、个性化的软件开发服务。
所谓快速开发其实是针对标准开发而言,通俗的讲,快速开发平台其实是一套软件半成品加一套功能3D打印机,相当于一座建好的毛坯房,主体框架已经建好,样板已经做好,各类装修材料也已经准备齐全,业务功能可以通过3D打印机生成,用户可以在这个框架以不写代码或少些代码的方式进行业务系统的开发工作。

快速开发平台在中国的发展历程不算长,但是却很迅速,而在西方国家,这一开发模式已经在各种企业中广泛应用,占据了近一半的市场份额。这一模式的好处是软件可变性强,业务延展性好,对供需双方来说付出的成本都要小很多。

而我国,在近些年,经济才开始突飞猛进,由于特殊的社会与经济环境,这种半定制的软件平台还是一种新生事物,没有被大多数人充分理解。但是实际上,每一个企业由于自身所处的行业不同,历史背景及业务状况不同,对软件系统会有不同的特殊要求,尤其是现在的一些互联网企业往往提供的都是一些个性化的服务,其对软件的实际需求可能五花八门,显然市场上的通用软件不可能全部兼顾的到,这就会对公司的实际运作造成影响,同时,对通用标准软件的口碑也造成一定的影响。

快速开发平台的出现就是为了解决软件在企业中水土不服的情况,虽然目前国内已经有多家公司在此领域进行布局,但时至今日,依然没有一家领军企业的出现,这涉及到多方面原因,开发公司自身来说,规模与技术实力有限;社会因素来说是企业自身管理需求。比如,早些年的劳动密集型产业,软件个性化需求不够迫切,类excel服务器平台基本上就解决了问题,不需要太高的灵活性。但是随着

中国劳动力成本优势的丧失、国民素质的提升、个性化互联网公司的井喷,快速开发平台将在中国迎来一个高速发展期。
Learun快速开发平台简介

Learun快速开发平台是一套基于智能化可扩展组件式的软件系统项目,使用了当前主流的应用开发技术,框架内置工作流、向导式智能开发组件、即时通讯组件、APP开发组件、微信组件、通用权限等一系列组件,以及可扩展的系统机制,开发人员通过一系列简单配置就可以快速构建高质量的信息系统。

UI:至美至简,多风格可选
经典版
炫动版
飞扬版
风尚版

 

站在技术前沿,learun能解决什么

 一、提高开发效率

整体框架都已经搭建好了,开发者只需要实现业务功能。并且框架内已经集成了大量业务模板,大量的公共组件,开发人员只需要根据开发向导进行设置就可快速完成开发工作。比起传统的开发至少要节约90%的工作量,能够大大地提升开发效率。

二、提升软件质量

规范的编码,专业的架构,稳定高效的底层。这是软件质量的先天优势。基于learun敏捷开发框架做开发,可以使软件质量大幅提升。

三、降低成本

本身在提高效率的同时就是在降低成本。现在软件工程师的工资一般都比较高,特别是架构师级别的动不动就数十万年薪,使得软件开发的成本变得非常之高。在使用learun敏捷开发框架的条件下,初级程序员甚至只要思路清晰的人就可以进行功能开发。开发周期变短,对开发人员的要求变低,也使得开发成本大幅下降。

四、提高客户满意度

Learun为开发人员提供了美观简洁的UI,美观大方、操作便捷,用户体验友好度高。

五、稳定高效的技术支持团队

维护期内learun开发团队原班人马为会提供优质贴心的技术支持,不管是架构还是编码都能全方位的贴心服务,不用担心开发过程中遇到的阻力,免去了因员工流失而给软件项目带来的各种损失。

六、提供框架源代码,提供完整的授权

框架提供全部源代码,毫不保留。二次开发出售无需授权,毫无后顾之忧。

 

Learun能开发什么

一、业务管理软件

ERP、MIS、CRM、WMS、MES、TMS、物流快递管理等这类企业管理系统已经被几家大的软件公司产品化,但是每个行业都有不同的业务需求,每家企业都会有自己不同的业务需求。

标准品无法做到面面俱到的所以我们很难采购到自己想要的产品。独立从头到尾开发一套系统需要大量的人力物力,到头来成本可能比采购软件成品还高,力软敏捷开发框架已经为开发都搭好框架预置了各类基础模块可以直接使用,另外系统根据各类系统的特点建立了多套开发模板,开发者可以按照开发向导快速开发出各种业务系统。

二、协同办公软件

Learun敏捷开发框架已经内置了工作流引擎、自定义表单引擎、即时通讯模块再配合框架完善的权限管理模块,可以轻松地定制协同办公软件,OA、HRM、KM等系统的开发将变得非常简单甚至不需要编写一行代码。

三、电商平台后台

Learun敏捷开发框架强大的后台管理功能及微信模块、短信平台模块开发电商平台后台也非常方便。

四、商业智能(BI)软件

Learun框架集成了大量图表插件,并且提供了智能图表功能,开发者只需要按照向导操作就能生成图形报表。所以此框架也非常适合开发BI软件。




learun功能分布详情

Learun以“让开发变得简单”为宗旨,部署有完善的基础功能

一、系统管理


二、单位组织





三、表单中心




四、工作流程




五、报表中心







 

六、公共信息




七、常用示例




字典分类表




可视化开发


内置代码生成器,只需点击下一步,所有部署自动完成



插件及拓展

框架搭配众多的插件及拓展功能,均支持当前主流浏览器,基本可以满足任何需求



 版本更迭

learun快速开发平台是一款不断成长的敏捷开发框架,经过不断的版本更迭,目前已经更新至7.0版本,需要体验或升级的客户,请至官网www.learun.cn操作。

目前网络上存在的一些盗版软件,均非力软官方发布,不能享受力软持续的技术指导,使用有风险,请谨慎辨别,支持正版。






力软敏捷开发框架7.0 版本发布

2018年08月01日



1.多语言功能;

2.代码生成器模版;

a.可编辑列表代码生成器(Excel风格)模版;

b.报表现实代码生成器模版;

3.树形代码生成功能;

4.动态配置首页功能;

5.外部邮件收发功能;

6.办公类型文件在线预览功能;

7.表单页面的弹出框;

a.左边树;

b.中间选择;

c.右边显示已选择;



1.表格控件子表格展开显示异常问题;

2.日期控件偶尔出现格式错乱问题;

3.分页控件页面再次加载页数错误问题;



1.代码生成器优化成拖拽式设计;

2.支持数据库多架构设计;

3.表格组件支持;

a.下拉框;

b.单选框;

c.复选框;

d.弹窗等功能;

4.工作流支持动态选择下一审批人;

5.IM组件重构;

6.文件上传效率;

7.工作流审核方式;

8.重新美化四套皮肤;




力软敏捷开发框架6.1.6.2 版本发布

2018年04月03日



1.手机流程

a.我的流程- 可查看流程进度和表单内容;

b.待办任务- 可查看流程进度和表单内容,审核;

c.已办任务- 可查看流程进度和表单内容;

d.自定义表单流程发起审核;

2.自定义表单可以发布到手机端;

3.数据权限-增加上下级数据权限管理;

4.新增在线建表功能;

5.一套APP开发实例;



1.pc端流程-修复传阅节点bug;

2.数据库事务中查询异常bug;

3.文件上传控件兼容性bug;

4.Oracle数据库流程流转中bug;

5.Oracle数据库自定义表单显示中的bug;



1.手机端用户密码修改功能;

2.pc端优化了经典版皮肤;

3.pc端流程;

a.增加流程时间轴;

b.下一节点若多人可审核,审核时可具体指定某一人;

4.手机端支持从vs2017进行开发、打包;

5.数据库连接性能优化;

6.前端基础数据加载优化;



相信,随着敏捷思想的不断深入,力软敏捷开发框架会得到越来越多人的认同,毕竟,价值才是第一驱动力。

一路走来数个年头,感谢力软敏捷开发框架框的支持者与使用者,大家可以通过下面的地址了解详情。

力软敏捷开发框架官方网站:www.learun.cn

力软敏捷开发框架官方免费体验网站:http://www.learun.cn/Home/VerificationForm

力软敏捷开发框架由专业团队长期打造、一直在更新、一直在升级,请放心使用! 查看全部



前言:

快速开发的趋势

 在十年前,没有人会想到互联网会发展成今天这个样子,同样,也没有人料到软件开发行业也会经历如此大的巨变,在开发这一行业,停下学习就等于死亡并不是危言耸听,不关注行业未来发展趋势的人可能错过了第一个十年,如果不学习,恐怕第二个也要错过了。

快速开发目前风头正盛,但是十分完善的快速开发平台目前并不多,用过的可能都知道,虽然宣称可以覆盖各种功能,但实际使用起来bug也少不到哪里去,之所以越来越受到人们的关注,是因为它能提供便捷化、个性化的软件开发服务。
所谓快速开发其实是针对标准开发而言,通俗的讲,快速开发平台其实是一套软件半成品加一套功能3D打印机,相当于一座建好的毛坯房,主体框架已经建好,样板已经做好,各类装修材料也已经准备齐全,业务功能可以通过3D打印机生成,用户可以在这个框架以不写代码或少些代码的方式进行业务系统的开发工作。

快速开发平台在中国的发展历程不算长,但是却很迅速,而在西方国家,这一开发模式已经在各种企业中广泛应用,占据了近一半的市场份额。这一模式的好处是软件可变性强,业务延展性好,对供需双方来说付出的成本都要小很多。

而我国,在近些年,经济才开始突飞猛进,由于特殊的社会与经济环境,这种半定制的软件平台还是一种新生事物,没有被大多数人充分理解。但是实际上,每一个企业由于自身所处的行业不同,历史背景及业务状况不同,对软件系统会有不同的特殊要求,尤其是现在的一些互联网企业往往提供的都是一些个性化的服务,其对软件的实际需求可能五花八门,显然市场上的通用软件不可能全部兼顾的到,这就会对公司的实际运作造成影响,同时,对通用标准软件的口碑也造成一定的影响。

快速开发平台的出现就是为了解决软件在企业中水土不服的情况,虽然目前国内已经有多家公司在此领域进行布局,但时至今日,依然没有一家领军企业的出现,这涉及到多方面原因,开发公司自身来说,规模与技术实力有限;社会因素来说是企业自身管理需求。比如,早些年的劳动密集型产业,软件个性化需求不够迫切,类excel服务器平台基本上就解决了问题,不需要太高的灵活性。但是随着

中国劳动力成本优势的丧失、国民素质的提升、个性化互联网公司的井喷,快速开发平台将在中国迎来一个高速发展期。
Learun快速开发平台简介

Learun快速开发平台是一套基于智能化可扩展组件式的软件系统项目,使用了当前主流的应用开发技术,框架内置工作流、向导式智能开发组件、即时通讯组件、APP开发组件、微信组件、通用权限等一系列组件,以及可扩展的系统机制,开发人员通过一系列简单配置就可以快速构建高质量的信息系统。

UI:至美至简,多风格可选
经典版
炫动版
飞扬版
风尚版

 

站在技术前沿,learun能解决什么

 一、提高开发效率

整体框架都已经搭建好了,开发者只需要实现业务功能。并且框架内已经集成了大量业务模板,大量的公共组件,开发人员只需要根据开发向导进行设置就可快速完成开发工作。比起传统的开发至少要节约90%的工作量,能够大大地提升开发效率。

二、提升软件质量

规范的编码,专业的架构,稳定高效的底层。这是软件质量的先天优势。基于learun敏捷开发框架做开发,可以使软件质量大幅提升。

三、降低成本

本身在提高效率的同时就是在降低成本。现在软件工程师的工资一般都比较高,特别是架构师级别的动不动就数十万年薪,使得软件开发的成本变得非常之高。在使用learun敏捷开发框架的条件下,初级程序员甚至只要思路清晰的人就可以进行功能开发。开发周期变短,对开发人员的要求变低,也使得开发成本大幅下降。

四、提高客户满意度

Learun为开发人员提供了美观简洁的UI,美观大方、操作便捷,用户体验友好度高。

五、稳定高效的技术支持团队

维护期内learun开发团队原班人马为会提供优质贴心的技术支持,不管是架构还是编码都能全方位的贴心服务,不用担心开发过程中遇到的阻力,免去了因员工流失而给软件项目带来的各种损失。

六、提供框架源代码,提供完整的授权

框架提供全部源代码,毫不保留。二次开发出售无需授权,毫无后顾之忧。

 

Learun能开发什么

一、业务管理软件

ERP、MIS、CRM、WMS、MES、TMS、物流快递管理等这类企业管理系统已经被几家大的软件公司产品化,但是每个行业都有不同的业务需求,每家企业都会有自己不同的业务需求。

标准品无法做到面面俱到的所以我们很难采购到自己想要的产品。独立从头到尾开发一套系统需要大量的人力物力,到头来成本可能比采购软件成品还高,力软敏捷开发框架已经为开发都搭好框架预置了各类基础模块可以直接使用,另外系统根据各类系统的特点建立了多套开发模板,开发者可以按照开发向导快速开发出各种业务系统。

二、协同办公软件

Learun敏捷开发框架已经内置了工作流引擎、自定义表单引擎、即时通讯模块再配合框架完善的权限管理模块,可以轻松地定制协同办公软件,OA、HRM、KM等系统的开发将变得非常简单甚至不需要编写一行代码。

三、电商平台后台

Learun敏捷开发框架强大的后台管理功能及微信模块、短信平台模块开发电商平台后台也非常方便。

四、商业智能(BI)软件

Learun框架集成了大量图表插件,并且提供了智能图表功能,开发者只需要按照向导操作就能生成图形报表。所以此框架也非常适合开发BI软件。




learun功能分布详情

Learun以“让开发变得简单”为宗旨,部署有完善的基础功能

一、系统管理


二、单位组织





三、表单中心




四、工作流程




五、报表中心







 

六、公共信息




七、常用示例




字典分类表




可视化开发


内置代码生成器,只需点击下一步,所有部署自动完成



插件及拓展

框架搭配众多的插件及拓展功能,均支持当前主流浏览器,基本可以满足任何需求



 版本更迭

learun快速开发平台是一款不断成长的敏捷开发框架,经过不断的版本更迭,目前已经更新至7.0版本,需要体验或升级的客户,请至官网www.learun.cn操作。

目前网络上存在的一些盗版软件,均非力软官方发布,不能享受力软持续的技术指导,使用有风险,请谨慎辨别,支持正版。






力软敏捷开发框架7.0 版本发布

2018年08月01日



1.多语言功能;

2.代码生成器模版;

a.可编辑列表代码生成器(Excel风格)模版;

b.报表现实代码生成器模版;

3.树形代码生成功能;

4.动态配置首页功能;

5.外部邮件收发功能;

6.办公类型文件在线预览功能;

7.表单页面的弹出框;

a.左边树;

b.中间选择;

c.右边显示已选择;



1.表格控件子表格展开显示异常问题;

2.日期控件偶尔出现格式错乱问题;

3.分页控件页面再次加载页数错误问题;



1.代码生成器优化成拖拽式设计;

2.支持数据库多架构设计;

3.表格组件支持;

a.下拉框;

b.单选框;

c.复选框;

d.弹窗等功能;

4.工作流支持动态选择下一审批人;

5.IM组件重构;

6.文件上传效率;

7.工作流审核方式;

8.重新美化四套皮肤;




力软敏捷开发框架6.1.6.2 版本发布

2018年04月03日



1.手机流程

a.我的流程- 可查看流程进度和表单内容;

b.待办任务- 可查看流程进度和表单内容,审核;

c.已办任务- 可查看流程进度和表单内容;

d.自定义表单流程发起审核;

2.自定义表单可以发布到手机端;

3.数据权限-增加上下级数据权限管理;

4.新增在线建表功能;

5.一套APP开发实例;



1.pc端流程-修复传阅节点bug;

2.数据库事务中查询异常bug;

3.文件上传控件兼容性bug;

4.Oracle数据库流程流转中bug;

5.Oracle数据库自定义表单显示中的bug;



1.手机端用户密码修改功能;

2.pc端优化了经典版皮肤;

3.pc端流程;

a.增加流程时间轴;

b.下一节点若多人可审核,审核时可具体指定某一人;

4.手机端支持从vs2017进行开发、打包;

5.数据库连接性能优化;

6.前端基础数据加载优化;



相信,随着敏捷思想的不断深入,力软敏捷开发框架会得到越来越多人的认同,毕竟,价值才是第一驱动力。

一路走来数个年头,感谢力软敏捷开发框架框的支持者与使用者,大家可以通过下面的地址了解详情。

力软敏捷开发框架官方网站:www.learun.cn

力软敏捷开发框架官方免费体验网站:http://www.learun.cn/Home/VerificationForm

力软敏捷开发框架由专业团队长期打造、一直在更新、一直在升级,请放心使用!
1
回复

环信3.5.3发起视频会议提示未登录 环信_Android

null123456 回复了问题 • 2 人关注 • 1425 次浏览 • 2019-02-26 17:17 • 来自相关话题

2
评论

老司机带你一文读懂Android运行时权限 Android

serge 发表了文章 • 537 次浏览 • 2019-02-25 17:50 • 来自相关话题

 
老司机发车了,未到终点请勿下车. 嘟嘟嘟~~~
 运行时权限从Android 6.0版本开始的,如果你的项目中 targetSdkVersion/compileSdkVersion 大于等于23,那么你就必须要考虑动态权限了。

权限又分为普通权限和危险权限。
普通权限如下:
android.permission.ACCESS LOCATIONEXTRA_COMMANDS
android.permission.ACCESS NETWORKSTATE
android.permission.ACCESS NOTIFICATIONPOLICY
android.permission.ACCESS WIFISTATE
android.permission.ACCESS WIMAXSTATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE NETWORKSTATE
android.permission.CHANGE WIFIMULTICAST_STATE
android.permission.CHANGE WIFISTATE
android.permission.CHANGE WIMAXSTATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND STATUSBAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET PACKAGESIZE
android.permission.INTERNET
android.permission.KILL BACKGROUNDPROCESSES
android.permission.MODIFY AUDIOSETTINGS
android.permission.NFC
android.permission.READ SYNCSETTINGS
android.permission.READ SYNCSTATS
android.permission.RECEIVE BOOTCOMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST INSTALLPACKAGES
android.permission.SET TIMEZONE
android.permission.SET_WALLPAPER
android.permission.SET WALLPAPERHINTS
android.permission.SUBSCRIBED FEEDSREAD
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE SYNCSETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT
普通权限是当需要用到时,只需要在清单文件中声明就可。危险权限除了需要在清单文件中声明外,还需在代码中动态进行判断申请。

危险权限如下:
android.permission-group.CALENDAR
android.permission.READ_CALENDAR
android.permission.WRITE_CALENDAR

android.permission-group.CAMERA
android.permission.CAMERA

android.permission-group.CONTACTS
android.permission.READ_CONTACTS
android.permission.WRITE_CONTACTS
android.permission.GET_ACCOUNTS

android.permission-group.LOCATION
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION

android.permission-group.MICROPHONE
android.permission.RECORD_AUDIO

android.permission-group.PHONE
android.permission.READ_PHONE_STATE
android.permission.CALL_PHONE
android.permission.READ_CALL_LOG
android.permission.WRITE_CALL_LOG
com.android.voicemail.permission.ADD_VOICEMAIL
android.permission.USE_SIP
android.permission.PROCESS_OUTGOING_CALLS

android.permission-group.SENSORS
android.permission.BODY_SENSORS

android.permission-group.SMS
android.permission.SEND_SMS
android.permission.RECEIVE_SMS
android.permission.READ_SMS
android.permission.RECEIVE_WAP_PUSH
android.permission.RECEIVE_MMS
android.permission.READ_CELL_BROADCASTS

android.permission-group.STORAGE
android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGE
危险权限是按组划分的,每一组中当某一个权限被允许或者拒绝后,同一组的其他权限也相应的自动允许或者拒绝。

当targetSdkVersion/compileSdkVersion大于等于23时,我们用到危险权限时,应按照这样的逻辑去处理。先判断当前应用是否具有权限,如果没有就去申请,当用户允许或者拒绝后,会回调相应的方法,我们在回调中处理自己的逻辑。


申请单个权限

在Activity/Fragment中,判断是否具有权限的方法是 checkSelfPermission(),申请权限的方法是requestPermissions(),然后用户允许或者拒绝后会回调方法onRequestPermissionsResult()。
虽然Activity/Fragment提供了这些方法,如果我们用这些的话,要判断安卓版本是否大于等于23,代码如下: 
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
//动态请求权限

}else{
//直接去调用代码
}
 
谷歌工程师当然考虑到了这些,于是给开发者提供了兼容包,在Activity/Fragment中用ContextCompat.checkSelfPermission()判断是否具有权限;
在Activity中用 ActivityCompat.requestPermissions()请求权限;
在Fragment中直接用 requestPermissions()请求权限,不要在前面加上ActivityCompat,否则会回调Fragment所在Activity的回调方法;
在Activity/Fragment中用户允许或者拒绝权限后会回调onRequestPermissionsResult()方法。

下面看一个平常的调用系统相机拍照功能的代码:
private void takePhoto() {
Intent photoIn = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(photoIn, TAKE_PHOTO_REQUEST);
}
 
如果我们项目targetSdkVersion/compileSdkVersion大于等于23,那么就需要动态申请权限了:
if (ContextCompat.checkSelfPermission(MySetupActivity.this, Manifest.permission.CAMERA)!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MySetupActivity.this,new String[]{Manifest.permission.CAMERA}, 100);
} else {
takePhoto();
}
 
先判断是否具有权限,如果有直接去执行相关代码,没有则去申请权限。
当用户点击允许或者拒绝权限时,会回调onRequestPermissionsResult方法,我们在此方法中进行处理:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

if (requestCode == 100) {//相机
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
takePhoto();
} else {
// Permission Denied
AlertDialog mDialog = new AlertDialog.Builder(MySetupActivity.this)
.setTitle("友好提醒")
.setMessage("您已拒绝权限,请开启权限!")
.setPositiveButton("开启", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
ShowAppSetDetails.showInstalledAppDetails(MySetupActivity.this, "user.zhuku.com");
LogPrint.logILsj(TAG, "开启权限设置");
}
})
.setCancelable(true)
.create();
mDialog.show();
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
当用户允许权限后我们直接执行相关代码,若拒绝则提示用户,弹窗提示是否需要开启权限。其中的
ShowAppSetDetails.showInstalledAppDetails(MySetupActivity.this, "user.zhuku.com");
是开启当前app信息设置界面的代码。

具体代码如下:
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
public class ShowAppSetDetails {
private static final String SCHEME = "package";
/**
* 调用系统InstalledAppDetails界面所需的Extra名称(用于Android 2.1及之前版本)
*/
private static final String APP_PKG_NAME_21 = "com.android.settings.ApplicationPkgName";
/**
* 调用系统InstalledAppDetails界面所需的Extra名称(用于Android 2.2)
*/
private static final String APP_PKG_NAME_22 = "pkg";
/**
* InstalledAppDetails所在包名
*/
private static final String APP_DETAILS_PACKAGE_NAME = "com.android.settings";
/**
* InstalledAppDetails类名
*/
private static final String APP_DETAILS_CLASS_NAME = "com.android.settings.InstalledAppDetails";

/**
* 调用系统InstalledAppDetails界面显示已安装应用程序的详细信息。 对于Android 2.3(Api Level
* 9)以上,使用SDK提供的接口; 2.3以下,使用非公开的接口(查看InstalledAppDetails源码)。
*
* @param context
* @param packageName 应用程序的包名
*/
public static void showInstalledAppDetails(Context context, String packageName) {
Intent intent = new Intent();
final int apiLevel = Build.VERSION.SDK_INT;
if (apiLevel >= 9) { // 2.3(ApiLevel 9)以上,使用SDK提供的接口
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts(SCHEME, packageName, null);
intent.setData(uri);
} else { // 2.3以下,使用非公开的接口(查看InstalledAppDetails源码)
// 2.2和2.1中,InstalledAppDetails使用的APP_PKG_NAME不同。
final String appPkgName = (apiLevel == 8 ? APP_PKG_NAME_22
: APP_PKG_NAME_21);
intent.setAction(Intent.ACTION_VIEW);
intent.setClassName(APP_DETAILS_PACKAGE_NAME,
APP_DETAILS_CLASS_NAME);
intent.putExtra(appPkgName, packageName);
}
context.startActivity(intent);
}
}
当app申请权限时,如果用户点击了“不再提醒”,则会直接回调拒绝权限,为此谷歌工程师提供了shouldShowRequestPermissionRationale()方法。兼容包中方法是ActivityCompat.shouldShowRequestPermissionRationale(),如果是在Fragment中使用请直接用shouldShowRequestPermissionRationale()。

ActivityCompat.shouldShowRequestPermissionRationale()方法返回值是boolean类型,当第一次申请权限时,此方法会返回false,如果用户点击“不再提醒”,则此方法会返回true。
 
详细代码如下:
if (ContextCompat.checkSelfPermission(MySetupActivity.this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MySetupActivity.this, Manifest.permission.CAMERA)) {
//已经禁止提示了
mDialog = new AlertDialog.Builder(MySetupActivity.this)
.setTitle("友好提醒")
.setMessage("您已拒绝相机权限,此功能需要开启,是否开启?")
.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
ActivityCompat.requestPermissions(MySetupActivity.this,
new String[]{Manifest.permission.CAMERA},
100);
}
})
.setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setCancelable(true)
.create();
mDialog.show();
} else {
ActivityCompat.requestPermissions(MySetupActivity.this,
new String[]{Manifest.permission.CAMERA},
100);
}

} else {
takePhoto();
}
 
如果是在Fragment中,则代码如下:
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
//已经禁止提示了
mDialog = new AlertDialog.Builder(getContext())
.setTitle("友好提醒")
.setMessage("您已拒绝相机权限,此功能需要开启,是否开启?")
.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
requestPermissions(new String[]{Manifest.permission.CAMERA},
PERMISSIONS_CAMERA);
}
})
.setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setCancelable(true)
.create();
mDialog.show();
} else {
requestPermissions(new String[]{Manifest.permission.CAMERA},
PERMISSIONS_CAMERA);
}

} else {
selectPicFromCamera();
}
特别要注意的是,如果在Fragment中请求权限,若在Activity中也重写了onRequestPermissionsResult(),则onRequestPermissionsResult()方法中一定要写
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
这句代码,若不写,则Activity不会分发执行Fragment中的权限回调方法。

因为Fragment中requestPermissions()源码如下:
public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mHost.onRequestPermissionsFromFragment(this, permissions, requestCode);
}
其实在Fragment请求权限也是在它Activity中请求,只是把回调结果传递给了Fragment。


一次申请多个权限

例如需要申请的权限如下:
/**
* 需要进行检测的权限数组
*/
protected String[] permissionList = {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
};
 
我们要先判断每一个权限是否已经允许或者拒绝,当有某一个权限未被允许时,则申请未被允许的权限。
protected void onStart() {
super.onStart();

if (PermissionUtils.checkSelfPermission(SplashActivity.this, permissionList)) {
PermissionUtils.checkPermissions(this, 0, permissionList);
} else {
//处理业务逻辑
}

}
其中PermissionUtils类的代码如下:
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;

import java.util.ArrayList;
import java.util.List;

public class PermissionUtils {
/**
* 检查权限
*/
public static void checkPermissions(Activity activity, int permissRequestCode, String... permissions) {
List<String> needRequestPermissonList = findDeniedPermissions(activity, permissions);
if (null != needRequestPermissonList
&& needRequestPermissonList.size() > 0) {
ActivityCompat.requestPermissions(activity,
needRequestPermissonList.toArray(
new String[needRequestPermissonList.size()]),
permissRequestCode);
}
}

/**
* 获取权限中需要申请权限的列表
*/
public static List<String> findDeniedPermissions(Activity activity, String[] permissions) {
List<String> needRequestPermissonList = new ArrayList<String>();
for (String perm : permissions) {
if (ContextCompat.checkSelfPermission(activity,
perm) != PackageManager.PERMISSION_GRANTED) {
needRequestPermissonList.add(perm);
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(
activity, perm)) {
needRequestPermissonList.add(perm);
}
}
}
return needRequestPermissonList;
}

public static boolean checkSelfPermission(Context context, String[] permissions) {
for (String perm : permissions) {
if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED) {
return true;
}
}
return false;
}

public static boolean checkSelfResult(int[] grantResults) {
for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
}
 
onRequestPermissionsResult回调方法中则这样处理:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);

if (requestCode == 0) {
if (PermissionUtils.checkSelfResult(grantResults)) {
// Permission Granted
//处理业务逻辑
} else {
// Permission Denied

if (null == mDialog)
mDialog = new AlertDialog.Builder(SplashActivity.this)
.setTitle("友好提醒")
.setMessage("没有权限将不能更好的使用,请开启权限!")
.setPositiveButton("开启", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
ShowAppSetDetails.showInstalledAppDetails(SplashActivity.this, "user.zhuku.com");
LogPrint.logILsj(TAG, "开启权限设置");
}
})
.setCancelable(false)
.create();

if (!mDialog.isShowing()) {
mDialog.show();
}
}
}
}
 
如果项目需要在页面可见时进行权限申请,请放在onStart()方法中,不要写在onResume()中。
可以想象一下,如果写在onResume()中,当用户同意了权限,则无碍,若是点击拒绝,则会回调权限拒绝的方法,这时系统申请权限的对话框消失不见,会再次调用onResume()请求权限显示对话框,若是还拒绝,则会再次调用onResume()方法,一直处于死循环。
因为系统请求权限的对话框其实一个开启了一个Activity。部分源码如下:  
 
public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
if (mHasCurrentPermissionsRequest) {
Log.w(TAG, "Can reqeust only one set of permissions at a time");
// Dispatch the callback with empty arrays which means a cancellation.
onRequestPermissionsResult(requestCode, new String[0], new int[0]);
return;
}
Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
mHasCurrentPermissionsRequest = true;
}
至此,老司机本次发车已到终点,这一程体验,你还不会封装自己的运行时权限库吗?
 
 





微信公众号:IT大前端
关注可了解更多的大前端领域技术 查看全部
 
老司机发车了,未到终点请勿下车. 嘟嘟嘟~~~
 运行时权限从Android 6.0版本开始的,如果你的项目中 targetSdkVersion/compileSdkVersion 大于等于23,那么你就必须要考虑动态权限了。

权限又分为普通权限和危险权限。
普通权限如下:
android.permission.ACCESS LOCATIONEXTRA_COMMANDS 
android.permission.ACCESS NETWORKSTATE
android.permission.ACCESS NOTIFICATIONPOLICY
android.permission.ACCESS WIFISTATE
android.permission.ACCESS WIMAXSTATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE NETWORKSTATE
android.permission.CHANGE WIFIMULTICAST_STATE
android.permission.CHANGE WIFISTATE
android.permission.CHANGE WIMAXSTATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND STATUSBAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET PACKAGESIZE
android.permission.INTERNET
android.permission.KILL BACKGROUNDPROCESSES
android.permission.MODIFY AUDIOSETTINGS
android.permission.NFC
android.permission.READ SYNCSETTINGS
android.permission.READ SYNCSTATS
android.permission.RECEIVE BOOTCOMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST INSTALLPACKAGES
android.permission.SET TIMEZONE
android.permission.SET_WALLPAPER
android.permission.SET WALLPAPERHINTS
android.permission.SUBSCRIBED FEEDSREAD
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE SYNCSETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT

普通权限是当需要用到时,只需要在清单文件中声明就可。危险权限除了需要在清单文件中声明外,还需在代码中动态进行判断申请。

危险权限如下:
android.permission-group.CALENDAR   
android.permission.READ_CALENDAR
android.permission.WRITE_CALENDAR

android.permission-group.CAMERA
android.permission.CAMERA

android.permission-group.CONTACTS
android.permission.READ_CONTACTS
android.permission.WRITE_CONTACTS
android.permission.GET_ACCOUNTS

android.permission-group.LOCATION
android.permission.ACCESS_FINE_LOCATION
android.permission.ACCESS_COARSE_LOCATION

android.permission-group.MICROPHONE
android.permission.RECORD_AUDIO

android.permission-group.PHONE
android.permission.READ_PHONE_STATE
android.permission.CALL_PHONE
android.permission.READ_CALL_LOG
android.permission.WRITE_CALL_LOG
com.android.voicemail.permission.ADD_VOICEMAIL
android.permission.USE_SIP
android.permission.PROCESS_OUTGOING_CALLS

android.permission-group.SENSORS
android.permission.BODY_SENSORS

android.permission-group.SMS
android.permission.SEND_SMS
android.permission.RECEIVE_SMS
android.permission.READ_SMS
android.permission.RECEIVE_WAP_PUSH
android.permission.RECEIVE_MMS
android.permission.READ_CELL_BROADCASTS

android.permission-group.STORAGE
android.permission.READ_EXTERNAL_STORAGE
android.permission.WRITE_EXTERNAL_STORAGE

危险权限是按组划分的,每一组中当某一个权限被允许或者拒绝后,同一组的其他权限也相应的自动允许或者拒绝。

当targetSdkVersion/compileSdkVersion大于等于23时,我们用到危险权限时,应按照这样的逻辑去处理。先判断当前应用是否具有权限,如果没有就去申请,当用户允许或者拒绝后,会回调相应的方法,我们在回调中处理自己的逻辑。


申请单个权限

在Activity/Fragment中,判断是否具有权限的方法是 checkSelfPermission(),申请权限的方法是requestPermissions(),然后用户允许或者拒绝后会回调方法onRequestPermissionsResult()。
虽然Activity/Fragment提供了这些方法,如果我们用这些的话,要判断安卓版本是否大于等于23,代码如下: 
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
//动态请求权限

}else{
//直接去调用代码
}

 
谷歌工程师当然考虑到了这些,于是给开发者提供了兼容包,在Activity/Fragment中用ContextCompat.checkSelfPermission()判断是否具有权限;
在Activity中用 ActivityCompat.requestPermissions()请求权限;
在Fragment中直接用 requestPermissions()请求权限,不要在前面加上ActivityCompat,否则会回调Fragment所在Activity的回调方法;
在Activity/Fragment中用户允许或者拒绝权限后会回调onRequestPermissionsResult()方法。

下面看一个平常的调用系统相机拍照功能的代码:
private void takePhoto() {
Intent photoIn = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(photoIn, TAKE_PHOTO_REQUEST);
}

 
如果我们项目targetSdkVersion/compileSdkVersion大于等于23,那么就需要动态申请权限了:
if (ContextCompat.checkSelfPermission(MySetupActivity.this,  Manifest.permission.CAMERA)!=  PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MySetupActivity.this,new String[]{Manifest.permission.CAMERA}, 100);
} else {
takePhoto();
}

 
先判断是否具有权限,如果有直接去执行相关代码,没有则去申请权限。
当用户点击允许或者拒绝权限时,会回调onRequestPermissionsResult方法,我们在此方法中进行处理:
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

if (requestCode == 100) {//相机
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
takePhoto();
} else {
// Permission Denied
AlertDialog mDialog = new AlertDialog.Builder(MySetupActivity.this)
.setTitle("友好提醒")
.setMessage("您已拒绝权限,请开启权限!")
.setPositiveButton("开启", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
ShowAppSetDetails.showInstalledAppDetails(MySetupActivity.this, "user.zhuku.com");
LogPrint.logILsj(TAG, "开启权限设置");
}
})
.setCancelable(true)
.create();
mDialog.show();
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

当用户允许权限后我们直接执行相关代码,若拒绝则提示用户,弹窗提示是否需要开启权限。其中的
ShowAppSetDetails.showInstalledAppDetails(MySetupActivity.this, "user.zhuku.com");

是开启当前app信息设置界面的代码。

具体代码如下:
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
public class ShowAppSetDetails {
private static final String SCHEME = "package";
/**
* 调用系统InstalledAppDetails界面所需的Extra名称(用于Android 2.1及之前版本)
*/
private static final String APP_PKG_NAME_21 = "com.android.settings.ApplicationPkgName";
/**
* 调用系统InstalledAppDetails界面所需的Extra名称(用于Android 2.2)
*/
private static final String APP_PKG_NAME_22 = "pkg";
/**
* InstalledAppDetails所在包名
*/
private static final String APP_DETAILS_PACKAGE_NAME = "com.android.settings";
/**
* InstalledAppDetails类名
*/
private static final String APP_DETAILS_CLASS_NAME = "com.android.settings.InstalledAppDetails";

/**
* 调用系统InstalledAppDetails界面显示已安装应用程序的详细信息。 对于Android 2.3(Api Level
* 9)以上,使用SDK提供的接口; 2.3以下,使用非公开的接口(查看InstalledAppDetails源码)。
*
* @param context
* @param packageName 应用程序的包名
*/
public static void showInstalledAppDetails(Context context, String packageName) {
Intent intent = new Intent();
final int apiLevel = Build.VERSION.SDK_INT;
if (apiLevel >= 9) { // 2.3(ApiLevel 9)以上,使用SDK提供的接口
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts(SCHEME, packageName, null);
intent.setData(uri);
} else { // 2.3以下,使用非公开的接口(查看InstalledAppDetails源码)
// 2.2和2.1中,InstalledAppDetails使用的APP_PKG_NAME不同。
final String appPkgName = (apiLevel == 8 ? APP_PKG_NAME_22
: APP_PKG_NAME_21);
intent.setAction(Intent.ACTION_VIEW);
intent.setClassName(APP_DETAILS_PACKAGE_NAME,
APP_DETAILS_CLASS_NAME);
intent.putExtra(appPkgName, packageName);
}
context.startActivity(intent);
}
}

当app申请权限时,如果用户点击了“不再提醒”,则会直接回调拒绝权限,为此谷歌工程师提供了shouldShowRequestPermissionRationale()方法。兼容包中方法是ActivityCompat.shouldShowRequestPermissionRationale(),如果是在Fragment中使用请直接用shouldShowRequestPermissionRationale()。

ActivityCompat.shouldShowRequestPermissionRationale()方法返回值是boolean类型,当第一次申请权限时,此方法会返回false,如果用户点击“不再提醒”,则此方法会返回true。
 
详细代码如下:
if (ContextCompat.checkSelfPermission(MySetupActivity.this, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(MySetupActivity.this, Manifest.permission.CAMERA)) {
//已经禁止提示了
mDialog = new AlertDialog.Builder(MySetupActivity.this)
.setTitle("友好提醒")
.setMessage("您已拒绝相机权限,此功能需要开启,是否开启?")
.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
ActivityCompat.requestPermissions(MySetupActivity.this,
new String[]{Manifest.permission.CAMERA},
100);
}
})
.setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setCancelable(true)
.create();
mDialog.show();
} else {
ActivityCompat.requestPermissions(MySetupActivity.this,
new String[]{Manifest.permission.CAMERA},
100);
}

} else {
takePhoto();
}

 
如果是在Fragment中,则代码如下:
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
//已经禁止提示了
mDialog = new AlertDialog.Builder(getContext())
.setTitle("友好提醒")
.setMessage("您已拒绝相机权限,此功能需要开启,是否开启?")
.setPositiveButton("是", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
requestPermissions(new String[]{Manifest.permission.CAMERA},
PERMISSIONS_CAMERA);
}
})
.setNegativeButton("否", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setCancelable(true)
.create();
mDialog.show();
} else {
requestPermissions(new String[]{Manifest.permission.CAMERA},
PERMISSIONS_CAMERA);
}

} else {
selectPicFromCamera();
}

特别要注意的是,如果在Fragment中请求权限,若在Activity中也重写了onRequestPermissionsResult(),则onRequestPermissionsResult()方法中一定要写
  super.onRequestPermissionsResult(requestCode, permissions, grantResults);

这句代码,若不写,则Activity不会分发执行Fragment中的权限回调方法。

因为Fragment中requestPermissions()源码如下:
public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mHost.onRequestPermissionsFromFragment(this, permissions, requestCode);
}

其实在Fragment请求权限也是在它Activity中请求,只是把回调结果传递给了Fragment。


一次申请多个权限

例如需要申请的权限如下:
    /**
* 需要进行检测的权限数组
*/
protected String[] permissionList = {
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.CAMERA,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
};

 
我们要先判断每一个权限是否已经允许或者拒绝,当有某一个权限未被允许时,则申请未被允许的权限。
protected void onStart() {
super.onStart();

if (PermissionUtils.checkSelfPermission(SplashActivity.this, permissionList)) {
PermissionUtils.checkPermissions(this, 0, permissionList);
} else {
//处理业务逻辑
}

}

其中PermissionUtils类的代码如下:
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;

import java.util.ArrayList;
import java.util.List;

public class PermissionUtils {
/**
* 检查权限
*/
public static void checkPermissions(Activity activity, int permissRequestCode, String... permissions) {
List<String> needRequestPermissonList = findDeniedPermissions(activity, permissions);
if (null != needRequestPermissonList
&& needRequestPermissonList.size() > 0) {
ActivityCompat.requestPermissions(activity,
needRequestPermissonList.toArray(
new String[needRequestPermissonList.size()]),
permissRequestCode);
}
}

/**
* 获取权限中需要申请权限的列表
*/
public static List<String> findDeniedPermissions(Activity activity, String[] permissions) {
List<String> needRequestPermissonList = new ArrayList<String>();
for (String perm : permissions) {
if (ContextCompat.checkSelfPermission(activity,
perm) != PackageManager.PERMISSION_GRANTED) {
needRequestPermissonList.add(perm);
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(
activity, perm)) {
needRequestPermissonList.add(perm);
}
}
}
return needRequestPermissonList;
}

public static boolean checkSelfPermission(Context context, String[] permissions) {
for (String perm : permissions) {
if (ContextCompat.checkSelfPermission(context, perm) != PackageManager.PERMISSION_GRANTED) {
return true;
}
}
return false;
}

public static boolean checkSelfResult(int[] grantResults) {
for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
}

 
onRequestPermissionsResult回调方法中则这样处理:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);

if (requestCode == 0) {
if (PermissionUtils.checkSelfResult(grantResults)) {
// Permission Granted
//处理业务逻辑
} else {
// Permission Denied

if (null == mDialog)
mDialog = new AlertDialog.Builder(SplashActivity.this)
.setTitle("友好提醒")
.setMessage("没有权限将不能更好的使用,请开启权限!")
.setPositiveButton("开启", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
ShowAppSetDetails.showInstalledAppDetails(SplashActivity.this, "user.zhuku.com");
LogPrint.logILsj(TAG, "开启权限设置");
}
})
.setCancelable(false)
.create();

if (!mDialog.isShowing()) {
mDialog.show();
}
}
}
}

 
如果项目需要在页面可见时进行权限申请,请放在onStart()方法中,不要写在onResume()中。
可以想象一下,如果写在onResume()中,当用户同意了权限,则无碍,若是点击拒绝,则会回调权限拒绝的方法,这时系统申请权限的对话框消失不见,会再次调用onResume()请求权限显示对话框,若是还拒绝,则会再次调用onResume()方法,一直处于死循环。
因为系统请求权限的对话框其实一个开启了一个Activity。部分源码如下:  
 
 public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
if (mHasCurrentPermissionsRequest) {
Log.w(TAG, "Can reqeust only one set of permissions at a time");
// Dispatch the callback with empty arrays which means a cancellation.
onRequestPermissionsResult(requestCode, new String[0], new int[0]);
return;
}
Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
mHasCurrentPermissionsRequest = true;
}

至此,老司机本次发车已到终点,这一程体验,你还不会封装自己的运行时权限库吗?
 
 

qrcode_for_gh_08bfa7313fb2_258.jpg

微信公众号:IT大前端
关注可了解更多的大前端领域技术
1
回复

com.hyphenate.exceptions.HyphenateException: Unknown server error 环信_RestAPI 环信_管理后台 环信_Android 环信_iOS

geri_yang 回复了问题 • 3 人关注 • 3208 次浏览 • 2019-02-25 16:43 • 来自相关话题

1
回复

登录环信 回调结果提示 User dosn't exist 。自己在环信后台创建的就没问题 ,这是后台注册的原因吗 环信_iOS

beyond 回复了问题 • 2 人关注 • 1022 次浏览 • 2019-02-20 16:19 • 来自相关话题

1
回复

web IM 聊天记录怎么获取?就前端能行吗?还是需要后台配合? 环信_WebIM

beyond 回复了问题 • 2 人关注 • 1644 次浏览 • 2019-02-18 15:08 • 来自相关话题

0
回复

iOS SDK v2.x 在Xcode10上编译失败,libstdc++6.0.9.tbd没了 环信_iOS

回复

天行和九妹 发起了问题 • 1 人关注 • 1077 次浏览 • 2019-02-15 14:23 • 来自相关话题

0
评论

2018,环信是如何C位出道的!(分享你和环信的故事赢千元奖励) 有奖调查 环信即时通讯云 2018 环信

beyond 发表了文章 • 703 次浏览 • 2019-02-01 15:25 • 来自相关话题

六年,筚路蓝缕,环信走过了一段从无至有的征程;

六年,栉风沐雨,见证了中国SaaS从0到1到1++的幸运;

六年,砥砺前行,从IM云1.0到IM云4.0,从移动客服到全媒体客服再到智能客服;

六年,峥嵘岁月,又一个全新的起点等待环信人去超越,从“心”出发;

六载春秋,陪伴是最长情的告白!感恩有你!!!



















































分享你和环信的故事赢千元奖励

欢迎在评论区分享你和环信的故事,评论区点赞前3名各送200元京东卡一张,第4-10名各送100元京东卡一张。(春节后第一个工作日2月11日公布获奖名单)

评论地址:https://mp.weixin.qq.com/s/Tij4kpquSUSeB04lkcepXQ 查看全部
六年,筚路蓝缕,环信走过了一段从无至有的征程;

六年,栉风沐雨,见证了中国SaaS从0到1到1++的幸运;

六年,砥砺前行,从IM云1.0到IM云4.0,从移动客服到全媒体客服再到智能客服;

六年,峥嵘岁月,又一个全新的起点等待环信人去超越,从“心”出发;

六载春秋,陪伴是最长情的告白!感恩有你!!!


新年广告_01.jpg


新年广告_02.jpg


新年广告_03.jpg


新年广告_05.jpg


新年广告_06.jpg


新年广告_07.jpg


新年广告_08.jpg


新年广告_09.jpg


新年广告_10.jpg


新年广告_11.jpg

分享你和环信的故事赢千元奖励

欢迎在评论区分享你和环信的故事,评论区点赞前3名各送200元京东卡一张,第4-10名各送100元京东卡一张。(春节后第一个工作日2月11日公布获奖名单)

评论地址:https://mp.weixin.qq.com/s/Tij4kpquSUSeB04lkcepXQ
6
最佳

android使用easeui3.0以上版本,怎么实现未读语音自动播放 环信_Android

kulong 回复了问题 • 4 人关注 • 4927 次浏览 • 2019-01-31 17:08 • 来自相关话题

0
回复

环信客服云iOS端如何收发视频消息 环信_iOS 视频消息

回复

一包僵尸粉 发起了问题 • 1 人关注 • 1195 次浏览 • 2019-01-31 16:26 • 来自相关话题

2
回复

web im 怎样调用conn.open? 调用conn.open

童年的回忆 回复了问题 • 3 人关注 • 2489 次浏览 • 2019-01-29 11:56 • 来自相关话题

1
回复

关于IOS设置群需要验证入群的问题。、 环信_iOS

回复

LI.N 、 回复了问题 • 1 人关注 • 1234 次浏览 • 2019-01-25 10:38 • 来自相关话题

0
回复

Android 视频电话问题 环信_Android

回复

CrystalIFDE 发起了问题 • 1 人关注 • 1318 次浏览 • 2019-01-25 10:14 • 来自相关话题

2
回复

关于IOS设置群免打扰功能得问题 环信_iOS

LI.N 、 回复了问题 • 2 人关注 • 1166 次浏览 • 2019-01-25 08:44 • 来自相关话题