运行时权限

    xiaoxiao2022-07-12  148

        一、代码示例:

    public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private static final int REQUEST_PERMISSION_CAMERA_CODE = 2001; private static final int REQUEST_CODE_OVERLAY = 2002; private static final int REQUEST_CODE_WRITE_SETTINGS=2003; ActivityMainBinding binding; RxPermissions rxPermissions ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); binding= DataBindingUtil.setContentView(this,R.layout.activity_main); initData(); initView(); } private void initData(){ rxPermissions = new RxPermissions(this); } private void initView(){ binding.activityMainTv1.setOnClickListener(this); binding.activityMainTv2.setOnClickListener(this); binding.activityMainTv3.setOnClickListener(this); binding.activityMainTv4.setOnClickListener(this); binding.activityMainTv5.setOnClickListener(this); binding.activityMainTv6.setOnClickListener(this); } @Override public void onClick(View view) { switch (view.getId()){ case R.id.activity_main_tv1: rxPermissions .request(Manifest.permission.CAMERA) .subscribe(new Consumer<Boolean>() { @Override public void accept(Boolean aBoolean) throws Exception { showToastAndLog("granted aBoolean:"+aBoolean); } }); break; case R.id.activity_main_tv2: rxPermissions .requestEach(Manifest.permission.CAMERA) .subscribe(new Consumer<Permission>() { @Override public void accept(Permission permission) throws Exception { if (permission.granted) { // 用户允许权限 showToastAndLog("granted"); } else if (permission.shouldShowRequestPermissionRationale) { // 用户拒绝了权限申请 showToastAndLog("shouldShowRequestPermissionRationale"); } else { // 用户拒绝,并且选择不再提示 // 可以引导用户进入权限设置界面开启权限 showToastAndLog("dis granted"); } } }); break; case R.id.activity_main_tv3: //判断当前系统是否高于或等于6.0 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { //当前系统大于等于6.0 if (ContextCompat.checkSelfPermission(this,Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) { //具有拍照权限,直接调用相机 //具体调用代码 showToastAndLog("has permission.CAMERA"); } else { //不具有拍照权限,需要进行权限申请 ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.CAMERA}, REQUEST_PERMISSION_CAMERA_CODE); showToastAndLog("has not permission.CAMERA"); } } else { //当前系统小于6.0,直接调用拍照 } break; case R.id.activity_main_tv4: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if(!shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)){ //如果用户勾选了不再提醒,则返回false //给予用户提醒,比如Toast或者对话框,让用户去系统设置-应用管理里把相关权限打开 showToastAndLog("用户勾选了不再提醒 shouldShowRequestPermissionRationale"); }else{ showToastAndLog("用户没有勾选了不再提醒 has permission.CAMERA"); } } break; case R.id.activity_main_tv5: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestAlertWindowPermission(); } break; case R.id.activity_main_tv6: if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestWriteSettings(); } break; } } private void showToastAndLog(String tip){ if(!TextUtils.isEmpty(tip)){ Log.e("system.out",tip); Toast.makeText(this, tip, Toast.LENGTH_SHORT).show(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if(REQUEST_PERMISSION_CAMERA_CODE==requestCode){ if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { showToastAndLog("相机权限已申请"); } else { //用户勾选了不再询问 //提示用户手动打开权限 if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) { showToastAndLog("相机权限已被禁止"); }else{ } } }else if(REQUEST_CODE_OVERLAY==requestCode){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.canDrawOverlays(this)) { showToastAndLog("onActivityResult granted"); } } }else if(REQUEST_CODE_WRITE_SETTINGS==requestCode){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Settings.System.canWrite(this)) { showToastAndLog( "onActivityResult write settings granted" ); } } } } private void requestAlertWindowPermission() { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, REQUEST_CODE_OVERLAY); } private void requestWriteSettings() { Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, REQUEST_CODE_WRITE_SETTINGS ); } }

     二、权限的分组

         Android中有很多权限,但并非所有的权限都是敏感权限,于是6.0系统就对权限进行了分类,一般为下述几类

    正常(Normal Protection)权限危险(Dangerous)权限特殊(Particular)权限其他权限

    正常权限

        正常权限具有如下的几个特点

    对用户隐私没有较大影响或者不会带来安全问题。安装后就赋予这些权限,不需要显示提醒用户,用户也不能取消这些权限。

         上述的权限基本设计的是关于网络,蓝牙,时区,快捷方式等方面,只要在AndroidManifest.xml指定了这些权限,就会被授予,并且不能撤销。

        注意:直接在AndroidManifest.xml文件中声明权限即可。

    特殊权限

         这里讲特殊权限提前讲一下,因为这个相对来说简单一些。

         特殊权限,顾名思义,就是一些特别敏感的权限,在Android系统中,主要由两个

    SYSTEM_ALERT_WINDOW(设置悬浮窗,进行一些黑科技)WRITE_SETTINGS (修改系统设置)

       关于上面两个特殊权限的授权,做法是使用startActivityForResult启动授权界面来完成。

       注意:关于这两个特殊权限,一般不建议应用申请。

       请求SYSTEM_ALERT_WINDOW

    private void requestAlertWindowPermission() { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, REQUEST_CODE_OVERLAY); }

       请求WRITE_SETTINGS

    private void requestWriteSettings() { Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS); intent.setData(Uri.parse("package:" + getPackageName())); startActivityForResult(intent, REQUEST_CODE_WRITE_SETTINGS ); }

    危险权限

    危险权限实际上才是运行时权限主要处理的对象,这些权限可能引起隐私问题或者影响其他程序运行。

    Android中的危险权限可以归为以下几个分组:

    权限组

    权限列表

    android.permission-group.CALENDAR

    android.permission.READ_CALENDAR

    (允许程序读取用户的日程信息)

    android.permission-group.CAMERA

    android.permission.CAMERA

    (允许访问摄像头进行拍照)

    android.permission-group.CONTACTS

    android.permission.READ_CONTACTS

    (允许应用访问联系人通讯录信息)

    android.permission.WRITE_CONTACTS

    (写入联系人,但不可读取)

    android.permission.GET_ACCOUNTS

    (访问GMail账户列表)

    android.permission-group.LOCATION

    android.permission.ACCESS_COARSE_LOCATION

    (通过WiFi或移动基站的方式获取用户错略的经纬度信息,定位精度大概误差在30~1500米)

    android.permission.ACCESS_FINE_LOCATION

    (通过GPS芯片接收卫星的定位信息,定位精度达10米以内)

    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

    (允许程序使用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

    (接收WAP PUSH信息)

    android.permission.RECEIVE_MMS

    (接收彩信)

    android.permission.READ_CELL_BROADCASTS

    ()

    android.permission-group.STORAGE

    android.permission.READ_EXTERNAL_STORAGE

    (允许程序读取外部存储,如SD卡读文件)

    android.permission.WRITE_EXTERNAL_STORAGE

    (允许程序写入外部存储,如SD卡上写文件)

     

    三、方法说明

     

       ContextCompat.checkSelfPermission()

    检查是否有权限。

       ActivityCompat.shouldShowRequestPermissionRationale()说明

    shouldShowRequestPermissionRationale() 默认返回 false。第一次请求权限时,如果用户拒绝了,再次请求时 shouldShowRequestPermissionRationale() 返回 true。多次请求权限(超过一次),用户如果选择了不再提醒并拒绝,shouldShowRequestPermissionRationale() 返回 false。设备的策略禁止当前应用获取这个权限的授权,shouldShowRequestPermissionRationale() 返回 false。

      ActivityCompat.requestPermissions()

    申请权限

      onRequestPermissionsResult()回调方法

    权限申请结果

    四、在设置中修改权限,返回应用崩溃

     在设置中,选择该应用,关闭某个权限,再返回该应用,点击back键,会出现闪退的情况。原因是在设置修改权限以后,程序进程变成了dead。

    解决方案,在一个Activity的基类的onCreate方法中,判断savedInstanceState是否为null,如果为null,说明是正常启动,如果有数据,就是设置被修改,异常关闭情况下,程序会保存一些数据,所以在有数据的情况下,重新打开启动页。

     

    参考资料

    Android6.0运行时权限(基于RxPermission开源库)

    android应用运行中,在设置中修改权限,返回应用崩溃

    Android在应用设置里关闭权限,返回生命周期处理

    最新回复(0)