android 学习笔记之六 动态获取权限

更多内容,请查看

https://inthecheesefactory.com/blog/things-you-need-to-know-about-android-m-permission-developer-edition/en

除了下面的之外,在工作中发现

        Intent intentPermissions = new Intent(activity, PermissionCheckActivity.class);
        上面的intent不能传输权限

Intent intentPermissions=new Intent(activity.getIntent());
        intentPermissions.setClass(activity, PermissionCheckActivity.class);

这个intent 才能够很好的传输权限

众所周知,Android 6.0 相比之前的Android版本有一个很大的不同点,就是动态获取权限。今天自己在做拨号功能时,正巧遇到这个问题, 顺手记录下在Android 6.0 上如何动态获取权限。

下面从自己一开始的问题入手

实现拨号功能

说到拨号,一个 Intent 就搞定,代码如下,

1
2
3
4
5
6
    private void callDirectly(String mobile){
         Intent intent =  new  Intent();
         intent.setAction( "android.intent.action.CALL" );
         intent.setData(Uri.parse( "tel:"  + mobile));
         mContext.startActivity(intent);
     }

当然 你可别忘了在 Manifest 文件中去声明拨号的权限

1
<uses-permission android:name= "android.permission.CALL_PHONE"  />

问题

如果在Android6.0以前的设备上,上面的代码都是没有问题的,但是如果是在Android6.0设备上, 你就会发现,拨号键盘是不能正常吊起的,因为 Android M 的权限是在运行时动态赋给用户的。关于动态分配权限,一些同学可能不是很清楚。 这里稍稍提一下 Android6.0 的权限动态分配。如果你只对最终的解决方案感兴趣,可以跳过下面这节,直接去看解决方案

权限动态分配

在 Android6.0 之前,下载好一个应用程序,点击安装我们看到的大都是像这样的界面。

permission

上图分别是Nexus6和小米手机在安装软件时的界面。

在安装时你会发现,手机操作系统会提示,这个软件会索要了你手机的那些权限,并且给用一个列表进行展示,但是这些提示只是在安装是提示,只要你点击接受或者安装, 表示你允许这个应用在可以获取它申明的所有权限。一般很少有人在安装时,会因为看到某个应用因为申请了某一个敏感权限而放弃安装应用。因为这个权限虽然敏感, 但是对于当前的用户是不可感知的,因为他现在并没有立即去查看你的最近通话、短信记录…

说到这里,我们自然而然的会想到,其实最好的方式是,当这个应用在用户使用过程中,正准备使用某个权限时,比如说读取短信列表,系统能及时的弹出一个提示框,说这个应用要读取您的短信内容, 您是否允许。然后用户结合当前应用的执行动作,依据当前条件判断,是不是应该授予应用读取短信记录的权限。这绝对的最完美的。 因为在具体的使用过程中,用户可以结合当前应用的使用场景,去思考、判断是不是应该给这个应用相应的权限。不给能怎样,给了会怎样, 这样对用户而言,完全是主动的,相比安装时那种选择,这样的做法无疑是对用户莫大的尊重,同时这也保证了用户的个人隐私。

说到这里,不得不插一句,其实 MIUI 早就实现了这个系统特性,在这一点上 MIUI 确实走到了 Android团队的前面,恩,给 MIUI 点个赞。

然而直到 Android 6.0 这个版本开始,上面的假设终于得到了谷歌的实践,除了在应用安装时,操作系统会提示应用会获取那些权限,在运行过程中,当应用去真的获取一些敏感 权限时,系统还会弹出一个提示框,询问用户是不是授予应用相应的权限。如下图所示。

这就是 Android 6.0 的运行时权限检查机制。下面是Google官方对此的解释,只截取介绍部分

Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. This approach streamlines the app install process, since the user does not need to grant permissions when they install or update the app. It also gives the user more control over the app's functionality; for example, a user could choose to give a camera app access to the camera but not to the device location. The user can revoke the permissions at any time, by going to the app's Settings screen.

解决方案

对Android版本做判断,然后对Android 6.0 做特殊处理,代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
final public static int REQUEST_CODE_ASK_CALL_PHONE = 123;
 
  public void onCall(String mobile){
         this .mMobile = mobile;
         if  (Build.VERSION.SDK_INT >= 23) {
             int checkCallPhonePermission = ContextCompat.checkSelfPermission(mContext,Manifest.permission.CALL_PHONE);
             if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED){
                 ActivityCompat.requestPermissions(mContext, new  String[]{Manifest.permission.CALL_PHONE},REQUEST_CODE_ASK_CALL_PHONE);
                 return ;
             } else {
                 //上面已经写好的拨号方法
                 callDirectly(mobile);
             }
         else  {
             //上面已经写好的拨号方法
             callDirectly(mobile);
         }
     }

此时,如果一个Android6.0的用户触发拨号动作,执行上面的代码,那么他将会看到一个很好看的MaterialDialog,如下图所示。

permission

那么用户点击拒绝或者允许,我们怎么才能拿到回调呢,如果能拿到回调,我们就可以根据用户的选择来执行不同的操作了。

这里应该会看到在 ActivityCompat 的 requestPermissions 方法中,最后一个参数是一个requestCode,看到它自然而然想到了经常用到的onActivityResult, 这里当执行 ActivityCompat 的 requestPermissions 方法后有一个回调机制,需要我们在当前 Activity 中实现 onRequestPermissionsResult 这个方法,具体如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
     @Override
     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
         switch  (requestCode) {
             case  REQUEST_CODE_ASK_CALL_PHONE:
                 if  (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                     // Permission Granted
                     callDirectly(mobile);
                 else  {
                     // Permission Denied
                     Toast.makeText(MainActivity. this "CALL_PHONE Denied" , Toast.LENGTH_SHORT)
                             .show();
                 }
                 break ;
             default :
                 super .onRequestPermissionsResult(requestCode, permissions, grantResults);
         }
     }

这里会对提供了一个对用户点击做判断的入口,开发者可以根据 grantResults[0] 的类型,来判断用户点击的是允许还是拒绝,接着就可以执行相应的逻辑了。

动态申请权限列表


多个权限的申请,实例

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
final private int REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS = 124 ;
 
private void insertDummyContactWrapper() {
     List<String> permissionsNeeded = new ArrayList<String>();
 
     final List<String> permissionsList = new ArrayList<String>();
     if (!addPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
         permissionsNeeded.add( "GPS" );
     if (!addPermission(permissionsList, Manifest.permission.READ_CONTACTS))
         permissionsNeeded.add( "Read Contacts" );
     if (!addPermission(permissionsList, Manifest.permission.WRITE_CONTACTS))
         permissionsNeeded.add( "Write Contacts" );
 
     if (permissionsList.size() > 0 ) {
         if (permissionsNeeded.size() > 0 ) {
             // Need Rationale
             String message = "You need to grant access to " + permissionsNeeded.get( 0 );
             for ( int i = 1 ; i < permissionsNeeded.size(); i++)
                 message = message + ", " + permissionsNeeded.get(i);
             showMessageOKCancel(message,
                     new DialogInterface.OnClickListener() {
                         @Override
                         public void onClick(DialogInterface dialog, int which) {
                             requestPermissions(permissionsList.toArray( new String[permissionsList.size()]),
                                     REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
                         }
                     });
             return ;
         }
         requestPermissions(permissionsList.toArray( new String[permissionsList.size()]),
                 REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS);
         return ;
     }
 
     insertDummyContact();
}
 
private boolean addPermission(List<String> permissionsList, String permission) {
     if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
         permissionsList.add(permission);
         // Check for Rationale Option
         if (!shouldShowRequestPermissionRationale(permission))
             return false ;
     }
     return true ;
}



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
@Override
public void onRequestPermissionsResult( int requestCode, String[] permissions, int [] grantResults) {
     switch (requestCode) {
         case REQUEST_CODE_ASK_MULTIPLE_PERMISSIONS:
             {
             Map<String, Integer> perms = new HashMap<String, Integer>();
             // Initial
             perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
             perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
             perms.put(Manifest.permission.WRITE_CONTACTS, PackageManager.PERMISSION_GRANTED);
             // Fill with results
             for ( int i = 0 ; i < permissions.length; i++)
                 perms.put(permissions[i], grantResults[i]);
             // Check for ACCESS_FINE_LOCATION
             if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                     && perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED
                     && perms.get(Manifest.permission.WRITE_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
                 // All Permissions Granted
                 insertDummyContact();
             } else {
                 // Permission Denied
                 Toast.makeText(MainActivity. this , "Some Permission is Denied" , Toast.LENGTH_SHORT)
                         .show();
             }
             }
             break ;
         default :
             super .onRequestPermissionsResult(requestCode, permissions, grantResults);
     }
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值