Android 将权限归为两类,一类是普通权限,一类是危险权限。
普通权限:不会直接威胁到用户的安全和隐私权限,系统会自动帮用户进行授权。
危险权限:可能会触及用户隐私,对设备安全性造成影响的权限,需要用户手动进行授权。
危险权限一 共 9 组 24 个,除了危险权限其余就是普通权限了。
下表列出了Android 所有的危险权限,可以看到我们此次需要的拨打电话权限 CALL_PHONE 属于危险权限
Android 危险权限 权限组名权限名CALENDARREAD_CALENDARWRITE_CALENDARCAMERACAMERACONTACTSREAD_CONTACTSWRITE_CONTACTSGET_ACCOUNTSLOCATIONACCESS_FINE_LOCATIONACCESS_COARSE_LOCATIONMICROPHONERECORD_AUDIOPHONEREAD_PHONE_STATECALL_PHONEREAD_CALL_LOGWRITE_CALL_LOGADD_VOICEMAILUSE_SIPPROCESS_OUTGOING_CALLSSENSORSBODY_SENSORSSMSSEND_SMSRECEIVE_SMSREAD_SMSRECEIVE_WAP_PUSHRECEIVE_MMSSTORAGEREAD_EXTERNAL_STORAGEWIRTE_EXTERNAL_STORAGE 解决方案首先修改 activity_main.xml 布局文件,如下所示:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="100dp" tools:context=".MainActivity"> <Button android:id="@+id/bt_call" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:text="拨打电话"/> </LinearLayout>我们在布局文件中添加了一个按钮,当点击按钮时就会触发拨打电话的逻辑。接着修改 AndroidManifest.xml 文件,在其中声明如下权限:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ww.call"> <!--添加拨打电话权限声明--> <uses-permission android:name="android.permission.CALL_PHONE"/> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>最后修改 MainActivity 中的代码,如下所示:
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.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 bt_call = findViewById(R.id.bt_call); bt_call.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { /* 判断用户是否已经授权,调用ContextCompat.checkSelfPermission() 比较方法的返回值和 PackageManager.PERMISSION_GRANTED, 不等时表示用户没有授权,否则,即已经授权 */ if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest. permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) { // 调用ActivityCompat.requestPermissions() 方法,向用户申请授权 ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission.CALL_PHONE}, 1); } else { // 已经授权,直接执行 call() 方法 call(); } } }); } private void call() { // 为了防止程序崩溃我们将所有操作放在了异常捕获代码块当中 try { // 构建一个隐式 intent ,intent 的 action 为 ACTION_CALL // ACTION_CALL 是系统内置的一个打电话的动作 Intent intent = new Intent(Intent.ACTION_CALL); // 指定协议为 tel ,号码为 10086 intent.setData(Uri.parse("tel:10086")); startActivity(intent); } catch (SecurityException e) { e.printStackTrace(); } } /* 调用完requestPermission() 方法之后,无论是哪一种结果,最终都回调到 onRequestPermissionsResult() 方法中 然后对授权结果 grantResults 进行判断 */ @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case 1: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { call(); } else { Toast.makeText(this, "你禁止了拨打电话的权限", Toast.LENGTH_SHORT).show(); } break; default: } } }由于 CALL_PHONE 属于危险权限,所以需要用户手动进行授权,因此在按钮的点击事件中我们需要先判断用户是否已经对应用进行授权了,这里我们借助调用 ContextCompat.checkSelfPermission() 方法,利用方法的返回值与PackageManager.PERMISSION_GRANTED 进行比较,从而判断用户是否已经授权。如果已经授权,我们就直接执行 call() 方法;否则,我们需要调用 ActivityCompat.requestPermissions() 方法向用户申请授权。
调用完 ActivityCompat.requestPermissions() 方法后,无论用户是否同意,最终系统还是会回调到onRequestPermissionsResult() 方法中。由于授权结果封装在了 grantResults 当中,所以我们需要对结果进行判断,并对相应的结果做出相应的处理。