zoukankan      html  css  js  c++  java
  • Android_动态权限管理的解决方式

    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()的回调方法,主要接收请求授权的返回值

    //版本号推断
    if (Build.VERSION.SDK_INT >= 23) {
        //降低是否拥有权限
        int checkCallPhonePermission = ContextCompat.checkSelfPermission(getApplicationContext(), permission);
        if (checkCallPhonePermission != PackageManager.PERMISSION_GRANTED) {
            //弹出对话框接收权限
            ActivityCompat.requestPermissions(BaseActivity.this, new String[]{permission}, id);
            return;
    }
    @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.封装

    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.this, new 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, null,
                    null, null);
            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();
        }
    }

    源代码下载地址>>

  • 相关阅读:
    Array中使用异步函数遍历元素,Array循环同步执行
    vscode设置快捷键"h"快速生成html模板
    IOS(苹果手机)使用video播放HLS流,实现在内部播放及全屏播放(即非全屏和全屏播放)。
    FTP服务器与客户端的安装与配置
    移动端页面顶部滑动实现菜单的弹出与隐藏
    JS十大经典排序排序算法
    【bug】table重新加载数据,页面滚动条下沉到底部,记录scrollTop后将其恢复scrollTop出现闪烁
    寄生组合式继承
    扁平对象,转为树形对象
    使用CSS禁止textarea调整大小功能的方法
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7217766.html
Copyright © 2011-2022 走看看