引言:去年Android 6.0发布后,其新引入的(Requesting Permissions at Run Time)运行时权限就备受开发者关注,随着今年国内手机厂商对6.0系统的普及,觉得大家有必要了解下这个新特性,因为在TargetSDK23+进行开发不注意这些会造成APP运行在6.0+手机上崩溃,这篇博文将对这个新特性进行探索。

在之前的SDK开发中,如果需要用到一些权限例如打电话,发短信只在AndroidManifest中配置一下就可以了,但是SDK23+以上用到一些危险敏感(Dangerous Permissions)权限就不仅仅是在AndroidManifest配置一下就可以了,需要在操作发生前需要让用户进行授予权限才能进行下一步的操作,跟iOS的权限处理很像,如果没让用户授予权限或用户拒绝了此权限再进行操作例如打电话就会造成软件崩溃。

*如果你的app TargetSDK设置在了23以下那么在6.0+系统中运行是不会崩溃的,当然你也可以TargetSDK一直设置在23以下,那么这篇文章你就没必要继续看了:)

那么到底哪些权限需要进行在运行时进行授权呢?看下官方的说明

Dangerous permissions

以上这些权限不仅仅需要在AndroidManifest配置,还需要在运行时让用户进行授予权限才能使用这些功能。

可以看到打电话是需要进行运行时授权的,我们就做个点击按钮打电话的小demo,看看这个运行时权限到底怎么回事。

1:需要将APP的targetSdkVersion设置到23以上并且在Android6.0以上系统运行

2:在AndroidManifest中配置拨打电话的权限

1

1

3:在布局layout中我们就简简单单放个按钮,点击进行拨打电话(略)

4.1:如果不做运行时权限处理会怎么样呢?我们直接进行点击按钮拨打电话

1

2

3

4

5

6

1

2

3

4

5

6public void CallPhone(View v) {

Intent intent = new Intent(Intent.ACTION_CALL);

Uri data = Uri.parse("tel:" + "10010");

intent.setData(data);

startActivity(intent);

}

运行效果:

可以看到在android 6.0系统上运行会崩溃

4.2:我们加上运行时权限的处理再运行

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19private static final int REQUESTCODE = 8;

public void CallPhone(View v) {

//检查权限

if (ContextCompat.checkSelfPermission(this,

Manifest.permission.CALL_PHONE)

!= PackageManager.PERMISSION_GRANTED) {

//没有权限,申请权限

ActivityCompat.requestPermissions(this,

new String[]{Manifest.permission.CALL_PHONE},

REQUESTCODE);

} else {

//已经拥有权限进行拨打

call();

}

}

API:  REQUESTCODE的作用是为了进行回调处理,因为申请权限是有回调结果的后面会说到。

ContextCompat.checkSelfPermission 主要用于检测某个权限是否已经被授予,方法参数为(context,需要检测的权限)方法返回值为PackageManager.PERMISSION_DENIED或者PackageManager.PERMISSION_GRANTED,当返回PackageManager.PERMISSION_DENIED时需要调用API进行权限申请。

ActivityCompat.requestPermissions用于权限的申请,方法参数为(context,需要申请的权限数组,自定义的请求码),系统会弹出一个申请权限的对话框。

运行效果:

可以看到程序已经成功进行了电话的拨打。

4.3 但是如果用户拒绝了此权限并且设置了不再提醒怎么办呢?点击按钮就会没响应了,是非常不友好的,如下。

稍稍改下代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36public void CallPhone(View v) {

//检查权限

if (ContextCompat.checkSelfPermission(this,

Manifest.permission.CALL_PHONE)

!= PackageManager.PERMISSION_GRANTED) {

if (ActivityCompat.shouldShowRequestPermissionRationale(this,

Manifest.permission.CALL_PHONE)) {

new AlertDialog.Builder(MainActivity.this)

.setMessage("app需要开启权限才能使用此功能")

.setPositiveButton("设置", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialogInterface, int i) {

Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

intent.setData(Uri.parse("package:" + getPackageName()));

startActivity(intent);

}

})

.setNegativeButton("取消", null)

.create()

.show();

} else {

//申请权限

ActivityCompat.requestPermissions(this,

new String[]{Manifest.permission.CALL_PHONE},

REQUESTCODE);

}

} else {

//已经拥有权限进行拨打

call();

}

}

这里我们在申请权限前加了个判断ActivityCompat.shouldShowRequestPermissionRationale(this,  Manifest.permission.CALL_PHONE)方法参数为(context,需要检测的权限)如果返回true证明用户上次点击已经选了拒绝,所以我们进行一些友好的提示,这里做的是进行进行提示并让用户跳转到设置将权限打开。

运行效果:

5:OK 最后介绍下,申请权限的回调方法处理

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18@Override

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

switch (requestCode) {

case REQUESTCODE: {

if (grantResults.length > 0

&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {

//用户同意了授权

call();

} else {

//用户拒绝了授权

// Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();

}

return;

}

}

}

这个方法跟onActivityResult比较类似,先判断requestCode,之后在判断用户的授权状态,grantResults数组代表了权限的结果数组,有点绕口,哈哈,之前申请权限是支持数组的,所以 onRequestPermissionsResult的返回结果也放到了一个数组里面,数组grantResults[n] == PackageManager.PERMISSION_GRANTED代表这个权限已经被用户授权了。

final:最后我们看下完整的代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81/** * blog:www.lijizhou.com */

public class MainActivity extends AppCompatActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

private static final int REQUESTCODE = 8;

public void CallPhone(View v) {

//检查权限

if (ContextCompat.checkSelfPermission(this,

Manifest.permission.CALL_PHONE)

!= PackageManager.PERMISSION_GRANTED) {

if (ActivityCompat.shouldShowRequestPermissionRationale(this,

Manifest.permission.CALL_PHONE)) {

new AlertDialog.Builder(MainActivity.this)

.setMessage("app需要开启权限才能使用此功能")

.setPositiveButton("设置", new DialogInterface.OnClickListener() {

@Override

public void onClick(DialogInterface dialogInterface, int i) {

Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);

intent.setData(Uri.parse("package:" + getPackageName()));

startActivity(intent);

}

})

.setNegativeButton("取消", null)

.create()

.show();

} else {

//申请权限

ActivityCompat.requestPermissions(this,

new String[]{Manifest.permission.CALL_PHONE},

REQUESTCODE);

}

} else {

//已经拥有权限进行拨打

call();

}

}

private void call() {

Intent intent = new Intent(Intent.ACTION_CALL);

Uri data = Uri.parse("tel:" + "10010");

intent.setData(data);

startActivity(intent);

}

@Override

public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

switch (requestCode) {

case REQUESTCODE: {

if (grantResults.length > 0

&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {

//用户同意了授权

call();

} else {

//用户拒绝了授权

// Toast.makeText(MainActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();

}

return;

}

}

}

}

OK,一个利用android原始API进行的运行时权限处理就介绍完了,当然你也可以对此进行封装方便使用,欢迎大家在下方留言,本篇源码下载地址 http://download.csdn.net/detail/leejizhou/9532629

最后如果只是调起打电话功能,其实谷歌是推荐采用 intent.setAction(Intent.ACTION_DIAL);

intent.setData(Uri.parse("tel:"+ phone)); 这样将跳到电话拨打界面,而不是直接调起打电话。

Android打电话功能权限报错,从打电话权限报错看Android6.0权限变化相关推荐

  1. android 6.0 短信权限,Android6.0权限适配

    Code4Android .jpg 前言 现在谈论Android权限适配可能有点没必要,因为网上关于权限适配的文章很多,搜一下Android6.0权限适配关键词能搜到一堆文章,而且很多写的还很不错.不 ...

  2. android拍照所需的权限,eclipse --- Android拍照,相册选择图片以及Android6.0权限管理...

    [实例简介] eclipse --- Android拍照,相册选择图片以及Android6.0权限管理 [实例截图] [核心代码] camreainandroidm └── camreainandro ...

  3. Android6 0权限机制(一):介绍

    本篇文章已授权微信公众号 hongyangAndroid (鸿洋)独家发布 Android6.0权限机制(一):介绍 Android6.0权限机制(二):封装 Android6.0权限机制(三):6. ...

  4. Android6.0权限适配及兼容库的实现

    从6.0 MarshMallow开始,Android支持动态权限管理,即有些权限需要在使用到的时候动态申请,根据用户的选择需要有不同的处理,具体表现可以看下图: 本文并不关心权限适配的原理,原理可以参 ...

  5. Android6.0权限大全和权限分类

    自从出了Android6.0权限管理之后,再也不能像以前那样粘贴复制了,必须认识权限了,所以总结一下方便以后自己使用. 一.所有权限 访问登记属性 android.permission.ACCESS_ ...

  6. Android教程 -05 Android6.0权限的管理

    视频为本篇博客知识的讲解,建议采用超清模式观看, 欢迎点击订阅我的优酷 height="498" width="510" src="http://pl ...

  7. android关闭权限管理,Android6.0权限管理以及使用权限该注意的地方

    Android 6.0 Marshmallow首次增加了执行时权限管理,这对用户来说,能够更好的了解.控 制 app 涉及到的权限.然而对开发人员来说却是一件比較蛋疼的事情.须要兼容适配,并保证程序功 ...

  8. 【Android】app应用内版本更新升级(DownloadManager下载,适配Android6.0以上所有版本)

    目录 前言 一.实现思路 二.服务端接口 三.UI页面 三.工具类实现 1.检查版本号 2.下载apk 3.安装apk 4.实时更新下载进度 5.完整代码 三.外部使用 总结 前言 版本的升级和更新是 ...

  9. android6.0权限管理工具EasyPermissionUtil

    前言 android6.0開始,权限的申请发生了改变,申请变的动态化,也就是执行时权限,和iOS相仿,动态化的意思是指,在每次使用须要危急权限的方法的时候.须要检查程序是否获得了该权限的许可.动态化的 ...

最新文章

  1. 深度学习目标检测法进化史,看这一篇就够了
  2. python PyQt5 QLCDNumber类(用于显示数字或一些符号的容器)
  3. ubuntu下面pycharm设置pyspark的配置
  4. CSS3动画@keyframes中translate和scale混用出错问题
  5. 怎么上传文件到kk服务器,VS Code 关于SFTP上传文件到多服务器的配置
  6. mac系统升级 brew 是用不了_PostgreSQL数据库默默升级,导致数据库服务不可用
  7. 网络函数bind源码分析
  8. Python基础——min/max与np.argmin/np.argmax
  9. java语言是那年_Java语言是在()年正式推出的_学小易找答案
  10. Spring: Export - WAR file - 404 Not Found 问题
  11. 慕课软件工程(第二十章.ISO9000标准)
  12. win10中常用快捷键 (包括切换窗口、打开我的电脑等快捷键)
  13. html如何删除目录,无法删除文件夹 目录不是空的
  14. Fabric v2.3测试网络 - 创建通道 返回结果分析
  15. openstack出错The server is currently unavailable. Please try again at a later time.(HTTP 503)
  16. OSG 添加文字(显示中英文)
  17. 一级计算机上字处理题的替换题步骤,一级计算机练习题计算机一级计算机基础及+MS+OFFICE+应用(操作题)-试卷6...
  18. xxxxxlllllxl的专栏 链接,很多实际动手操作的东西
  19. C++第2次实验作业
  20. linux top内存 不一致,为什么TOP看不出真实的内存占用情况?

热门文章

  1. Visual Studio Code的用户设置相关
  2. SAP Data Intelligence API返回错误消息 - Fordidden cross-site request
  3. SAP Enterprise search test report ESH_TEST_SEARCH debug in Q2D
  4. 如何查询SAP Cloud for Customer系统升级和维护时间
  5. spark-submit的执行原理
  6. Angular:why click add button does not work for the second time
  7. WordPress设置页面的加载机制
  8. use putty to log on OS
  9. Batch request processing in backend
  10. ABAP system landscape和vue项目webpack构建的一种实践