运行时权限之拨打电话
Posted panqiaoyan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了运行时权限之拨打电话相关的知识,希望对你有一定的参考价值。
记录一下《第一行代码》的学习过程:
android的权限系统一直是首要的安全概念,因为这些权限只在安装的时候被询问一次。一旦安装了,app可以在用户毫不知晓的情况下访问权限内的所有东西,而且一般用户安装的时候很少会去仔细看权限列表,更不会去深入了解这些权限可能带来的相关危害。所以在android 6.0 Marshmallow版本之后,系统不会在软件安装的时候就赋予该app所有其申请的权限,对于一些危险级别的权限,app需要在运行时一个一个询问用户授予权限。
这只是微信所申请的一半左右的权限,因为权限太多一屏截不下来。其中有一些权限我并不认 可,比如微信为什么要读取我手机的短信和彩信?但是我不认可又能怎样,难道我拒绝安装微信?没错,这种例子比比皆是,当一些软件已经让我们产生依赖的时候就会容易 “店大欺客”, 反正这个权限我就是要了,你自己看着办吧!
Android开发团队当然也意识到了这个问题,于是在6.0系统中加入了运行时权限功能。也就是 说,用户不需要在安装软件的时候一次性授权所有申请的权限,而是可以在软件的使用过程中 再对某一项权限申请进行授权。比如说一款相机应用在运行时申请了地理位置定位权限,就算 我拒绝了这个权限,但是我应该仍然可以使用这个应用的其他功能,而不是像之前那样直接无 法安装它。
一、普通权限与危险权限
Android现在将所有的权限归成了两类,一类是普通权限,一类是危险权限。普通权限指的是那些不会直接威胁到用户的安全和隐私的权限,对于这部分权限申请,系统会自动帮我们进行授权, 而不需要用户再去手动操作了,比如在BroadcastTest项目中申请的两个权限就是普通权限。危险 权限则表示那些可能会触及用户隐私或者对设备安全性造成影响的权限,如获取设备联系人信 息、定位设备的地理位置等,对于这部分权限申请,必须要由用户手动点击授权才可以,否则 程序就无法使用相应的功能。现在对于新版本的权限变更应该有了基本的认识,那么,是不是所有权限都需要去进行特殊处理呢?当然不是,只有那些危险级别的权限才需要,如列表所示:
每当要 使用一个权限时,可以先到这张表中来查一下,如果是属于这张表中的权限,那么就需要进行 运行时权限处理,如果不在这张表中,那么只需要在AndroidManifest.xml文件中添加一下权限声 明就可以了。
另外注意一下,表格中每个危险权限都属于一个权限组,我们在进行运行时权限处理时使用的是权限名,但是用户一旦同意授权了,那么该权限所对应的权限组中所有的其他权限也会同时 被授权。访问http://developer.android.google.cn/reference/android/Manifest.permission.html 可以查看Android 系统中完整的权限列表。
二、在程序运行时申请打电话的权限
CALL_PHONE 这个权限是编写拨打电话功能的时候需要声明的,因为拨打电话会涉及用户手机 的资费问题,因而被列为了危险权限。修改activity_main.xml布局文件,如下所示:
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent"> 5 6 <Button 7 android:id="@+id/button" 8 android:layout_width="match_parent" 9 android:layout_height="wrap_content" 10 android:text="拨打电话"/> 11 </LinearLayout>
布局文件只是定义了一个按钮,当点击按钮时触发拨打电话的事件,接着修改MainActivity.java
package com.example.runtimepermission; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.Toast; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button=(Button)findViewById(R.id.button) ; button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { /*ContextCompat.checkSelfPermission返回结果是PackageManager的两个常量:PERMISSION_GRANTED或PERMISSION_DENIED *PERMISSION_GRANTED或PERMISSION_DENIED表示已授权,PERMISSION_DENIED表示无授权 *若用户不授权,就调用ActivityCompat.requestPermissions()方法来向用户申请授权 *该方法第一个参数是Activity的实例,第二个参数是String数组,存放要申请的用户权限名 * 第三参数是请求码,只要唯一值即可,这里传入1 */ if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CALL_PHONE)!=PackageManager.PERMISSION_GRANTED){ ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.CALL_PHONE},1); }else{ //用户授权 call(); } } }); } private void call(){ try{ Intent intent=new Intent(Intent.ACTION_CALL);//指定Intent的action是Intent.ACTION_CALL,系统内置打电话的动作 intent.setData(Uri.parse("tel:10086")); startActivity(intent); }catch (SecurityException e){ e.printStackTrace(); } } /** * 当调用完requestPermissions()方法后,系统会弹出一个权限申请的对话框,用户可以选择拒绝或同意 * 我们的权限申请,无论哪种结果,都会调用onRequestPermissionsResult方法,结果封装在grantResults中 * @param requestCode 请求码 * @param permissions 申请的权限 * @param grantResults 用户运行申请的权限 */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); switch (requestCode){ //System.out.println(grantResults[0]); case 1: if(grantResults.length>0 & grantResults[0]==PackageManager.PERMISSION_GRANTED){ call(); }else{ Toast.makeText(this,"你拒绝申请权限的请求",Toast.LENGTH_SHORT).show(); } break; default: break; } } }
第一步就是要先判断用户是不是已经给过我们授权了,借助的是ContextCompat.checkSelfPermission() 方法。checkSelfPermission() 方法接 收两个参数,第一个参数是Context ,这个没什么好说的,第二个参数是具体的权限名,比如 打电话的权限名就是Manifest.permission.CALL_PHONE 。
第二步是使用checkSelfPermission()方法的返回值和 PackageManager.PERMISSION_GRANTED 做比较,相等就说明用户已经授权,不等就表示 用户没有授权。
ContextCompat.checkSelfPermission返回结果是PackageManager的两个常量:PERMISSION_GRANTED或PERMISSION_DENIED 。PERMISSION_GRANTED或PERMISSION_DENIED表示已授权,PERMISSION_DENIED表示无授权。
第三步,如果已经授权的话直接去执行拨打电话的逻辑操作就可以,这里我们把拨打电话 的逻辑封装到了call() 方法当中。如果没有授权的话,则需要调 用ActivityCompat.requestPermissions() 方法来向用户申请授 权,requestPermissions() 方法接收3个参数,第一个参数要求是Activity的实例,第二个 参数是一个String 数组,我们把要申请的权限名放在数组中即可,第三个参数是请求码,只 要是唯一值就可以了,这里传入了1。 调用完了requestPermissions() 方法之后,系统会弹出一个权限申请的对话框,然后用户 可以选择同意或拒绝我们的权限申请,不论是哪种结果,最终都会回调 到onRequestPermissionsResult() 方法中,而授权的结果则会封装在grantResults 参 数当中。这里我们只需要判断一下最后的授权结果,如果用户同意的话就调用call() 方法来 拨打电话,如果用户拒绝的话我们只能放弃操作,并且弹出一条失败提示。
那么接下来修改AndroidManifest.xml文件,在其中声明如下权限:(第三行)
1 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 2 package="com.example.runtimepermission"> 3 <uses-permission android:name="android.permission.CALL_PHONE"/> 4 <application 5 android:allowBackup="true" 6 android:icon="@mipmap/ic_launcher" 7 android:label="@string/app_name" 8 android:roundIcon="@mipmap/ic_launcher_round" 9 android:supportsRtl="true" 10 android:theme="@style/AppTheme"> 11 <activity android:name=".MainActivity"> 12 <intent-filter> 13 <action android:name="android.intent.action.MAIN" /> 14 15 <category android:name="android.intent.category.LAUNCHER" /> 16 </intent-filter> 17 </activity> 18 </application> 19 20 </manifest>
运行程序:
点击拒绝后
再次点击按钮,按允许后
以上是关于运行时权限之拨打电话的主要内容,如果未能解决你的问题,请参考以下文章