zoukankan      html  css  js  c++  java
  • Android获取设备隐私 忽略6.0权限管理

    1.前言

    (1).由于MIUI等部分国产定制系统也有权限管理,没有相关api,故无法判断用户是否允许获取联系人等隐私。在Android 6.0之后,新增权限管理可以通过官方api判断用户的运行状态;

    (2).我们指定targetSdkVersion为23或者之后我们还需要在运行时请求这些所需的权限。这很重要,因为已经出现了很多开发者把targetSdkVersion飙到了最新,然后发现自己的app疯狂的崩溃,这是由于他们没有实现执行运行时权限请求的代码。当你已经把一个targeting API 为23或者之后的app发布到了Google Play上,这更是一个问题,你无法立即把那个apk的targeting API替换成更早的版本。

    2.权限分析

    从Android6.0开始,权限分为普通权限和许可权限。许可权限分类归组,一个权限授权之后,该组下的权限均可使用。

    (1)普通权限

    只需要在xml申请即可,使用方法和之前6.0以前的一样。在应用安装应用时,会默认获得许可。

    (2)许可权限

    可执行 $adb shell pm list permissions -d -g

    Permission GroupPermissions
    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

    同一组的任何一个权限被授权了,其他权限也自动被授权。例如,一旦WRITE_CONTACTS被授权了,app也有READ_CONTACTS和GET_ACCOUNTS了。
    源码中被用来检查和请求权限的方法分别是Activity的checkSelfPermission和requestPermissions,这些方法api23引入。

    3.相关方法

    (1).ContextCompat.checkSelfPermission()

    检查应用是否拥有该权限,被授权返回值为PERMISSION_GRANTED,否则返回PERMISSION_DENIED

    (2).ActivityCompat.requestPermissions()

    将弹出请求授权对话框,这个方法在M之前版本调用,OnRequestPermissionsResultCallback 直接被调用,带着正确的 PERMISSION_GRANTED或者 PERMISSION_DENIED 。

    (3).AppCompatActivity.onRequestPermissionsResult()

    该方法类似于Activity的OnActivityResult()的回调方法,主要接收请求授权的返回值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //版本判断
    if (Build.VERSION.SDK_INT >= 23) {
          //减少是否拥有权限
          int checkCallPhonePermission = ContextCompat.checkSelfPermission(getApplicationContext(), permission);
          if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
               //弹出对话框接收权限
               ActivityCompat.requestPermissions(BaseActivity.thisnew String[]{permission}, id);
               return;
          }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
         if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
              //TODO:已授权
         else {
              //TODO:用户拒绝
         }
    }

    4.封装

    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
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    public class BaseActivity extends AppCompatActivity {
         private Map<Integer, Runnable> allowablePermissionRunnables = new HashMap<>();
         private Map<Integer, Runnable> disallowablePermissionRunnables = new HashMap<>();
         @Override
         protected void onCreate(Bundle savedInstanceState) {
               super.onCreate(savedInstanceState);
         }
         /**
           * 请求权限
           * @param id 请求授权的id 唯一标识即可
           * @param permission 请求的权限
           * @param allowableRunnable 同意授权后的操作
           * @param disallowableRunnable 禁止权限后的操作
           */
         protected void requestPermission(int id, String permission, Runnable allowableRunnable, Runnable disallowableRunnable) {
              if (allowableRunnable == null) {
                     throw new IllegalArgumentException("allowableRunnable == null");
              }
              allowablePermissionRunnables.put(id, allowableRunnable);
              if (disallowableRunnable != null) {
                    disallowablePermissionRunnables.put(id, disallowableRunnable);
              }
              //版本判断
              if (Build.VERSION.SDK_INT >= 23) {
                   //减少是否拥有权限
                   int checkCallPhonePermission = ContextCompat.checkSelfPermission(getApplicationContext(), permission);
                   if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
                          //弹出对话框接收权限
                          ActivityCompat.requestPermissions(BaseActivity.thisnew String[]{permission}, id);
                          return;
                   else {
                          allowableRunnable.run();
                   }
              else {
                   allowableRunnable.run();
              }
        }
        @Override
        public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                   Runnable allowRun = allowablePermissionRunnables.get(requestCode);
                   allowRun.run();
            else {
                   Runnable disallowRun = disallowablePermissionRunnables.get(requestCode);
                   disallowRun.run();
            }
        }
    }
     
    public class MainActivity extends BaseActivity implements View.OnClickListener{
         private Button btCallPhone;
         private Button btContact;
         @Override
         protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
              btCallPhone = (Button) findViewById(R.id.call_phone);
              btContact = (Button) findViewById(R.id.contact);
              btCallPhone.setOnClickListener(this);
              btContact.setOnClickListener(this);
         }
         @Override
         public void onClick(View v) {
              if(v == btCallPhone){
                   //拨打电话
                   requestPermission(1, Manifest.permission.CALL_PHONE, new Runnable() {
                   @Override
                   public void run() {
                        callPhone();
                   }
              }, new Runnable() {
                   @Override
                   public void run() {
                        callPhoneDenied();
                   }
              });
         }else if(v == btContact){
              //读取联系人信息
              requestPermission(2, Manifest.permission.WRITE_CONTACTS, new Runnable() {
                    @Override
                    public void run() {
                         readContact();
                    }
              }, new Runnable() {
                    @Override
                    public void run() {
                         readContactDenied();
                    }
              });
          }
      }
      private void callPhone() {
           Toast.makeText(MainActivity.this"CALL_PHONE OK", Toast.LENGTH_SHORT).show();
      }
      private void callPhoneDenied() {
          Toast.makeText(MainActivity.this"CALL_PHONE Denied", Toast.LENGTH_SHORT).show();
      }
      private void readContact() {
           ContentResolver cr = getContentResolver();
           String str[] = {ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.PHOTO_ID};
           Cursor cur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, str, nullnullnull);
           int count = cur.getCount();
           cur.close();
           Toast.makeText(MainActivity.this, String.format("发现%s条", count), Toast.LENGTH_SHORT).show();
      }
      private void readContactDenied() {
          Toast.makeText(MainActivity.this"Contact Denied", Toast.LENGTH_SHORT).show();
      }
    }
     
  • 相关阅读:
    RedisCluster的rename机制失败报错,解决又是数据倾斜问题
    开发如何避免redis集群访问倾斜和数据倾斜
    Pika 连接 rabbitmq 集群
    RabbitMQ概念及环境搭建(三)RabbitMQ cluster
    Rabbitmq安装过程和踩过的坑( 二 集群搭建 )
    java中<<、>>、>>>
    用WordPress 插入广告的几种方法
    macOS Mojave 卡顿问题解决
    前端元编程——使用注解加速你的前端开发
    如何优雅安全地在深层数据结构中取值
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/5801113.html
Copyright © 2011-2022 走看看