安卓基础之《(16)—内容提供者(2)使用内容组件获取通讯信息》

一、运行时动态申请权限

1、Android系统为了防止某些App滥用权限,从6.0开始引入了运行时权限管理机制,允许App在运行过程中动态检查是否拥有某些权限,一旦发现缺少某种必需的权限,则系统会自动弹出小窗提示用户去开启该权限

二、动态申请权限的步骤

1、检查App是否开启了指定权限

调用ContextCompat的checkSelfPermission方法

public static int checkSelfPermission(@NonNull Context context, @NonNull String permission)

说明:

(1)context:传所在的Activity

(2)permission:权限

2、请求系统弹窗,以便用户选择是否开启权限

调用ActivityCompat的requestPermissions方法,即可命令系统自动弹出权限申请窗口

public static void requestPermissions(final @NonNull Activity activity, final @NonNull String\[\] permissions, final @IntRange(from = 0) int requestCode)

说明:

(1)activity:传所在的Activity

(2)permissions:权限数组

(3)requestCode:标识符,表示请求的是什么类型的权限

3、判断用户的权限选择结果

重写Activity页面的权限请求回调方法onRequestPermissionsResult,在该方法内部处理用户的权限选择结果

public void onRequestPermissionsResult(requestCode, permissions, grantResults)

说明:

(1)requestCode:申请权限的时候,传递进去,回调方法使用这个来进行判断

(2)permissions:权限的数组列表(读、写)

(3)grantResults:用户操作后返回的授权结果

4、在清单文件里定义权限

老版本只要在清单文件里定义就好了,新版本不仅要在清单文件里定义,还需要动态去申请权限

<uses-permission android:name="android.permission.READ_CONTACTS"/>

<uses-permission android:name="android.permission.WRITE_CONTACTS"/>

<uses-permission android:name="android.permission.SEND_SMS"/>

<uses-permission android:name="android.permission.READ_SMS"/>

三、运行时动态申请权限-懒汉模式

1、懒汉模式,就是点击按钮时申请权限

2、例子

PermissionLazyActivity.java

java 复制代码
package com.example.chapter07_client;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.Manifest;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;

import com.example.chapter07_client.util.PermissionUtil;
import com.example.chapter07_client.util.ToastUtil;

/**
 * 懒汉式
 */
public class PermissionLazyActivity extends AppCompatActivity implements View.OnClickListener {

    // 读写通讯录权限
    private static final String[] PERMISSIONS_CONTACTS = new String[] {
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.WRITE_CONTACTS
    };

    // 读写短信的权限
    private static final String[] PERMISSIONS_SMS = new String[] {
            Manifest.permission.READ_SMS,
            Manifest.permission.SEND_SMS
    };

    // 标识符,表示请求的是什么类型的权限(通讯录、短信等)
    private static final int REQUEST_CODE_CONTACTS = 1;
    private static final int REQUEST_CODE_SMS = 2;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_permission_lazy);

        findViewById(R.id.btn_contact).setOnClickListener(this);
        findViewById(R.id.btn_sms).setOnClickListener(this);


    }

    @Override
    public void onClick(View view) {
        boolean result;
        if (view.getId() == R.id.btn_contact) {
            // 点击按钮后,首先检查有没有权限
            result = PermissionUtil.checkPermission(this, PERMISSIONS_CONTACTS, REQUEST_CODE_CONTACTS);
            if (result) {
                ToastUtil.show(this, "通讯录权限已获取");
            }
        } else if (view.getId() == R.id.btn_sms) {
            result = PermissionUtil.checkPermission(this, PERMISSIONS_SMS, REQUEST_CODE_SMS);
            if (result) {
                ToastUtil.show(this, "收发短信权限已获取");
            }
        }
    }

    /**
     *
     * @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) {
            case REQUEST_CODE_CONTACTS:
                // 在这里弹窗用户操作
                if (PermissionUtil.checkGrant(grantResults)) {
                    Log.d("sam", "通讯录权限获取成功");
                } else {
                    ToastUtil.show(this, "获取通讯录读写权限失败");
                    jumpToSettings();
                }
                break;
            case REQUEST_CODE_SMS:
                if (PermissionUtil.checkGrant(grantResults)) {
                    Log.d("sam", "收发短信权限获取成功");
                } else {
                    ToastUtil.show(this, "获取收发短信权限失败");
                    jumpToSettings();
                }
                break;
        }
    }

    /**
     * 拒绝多了,就不会弹窗了
     * 所以跳转到应用设置界面,让用户手工设置
     */
    private void jumpToSettings() {
        Intent intent = new Intent();
        intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        intent.setData(Uri.fromParts("package", getPackageName(), null));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}

工具类PermissionUtil.java

java 复制代码
package com.example.chapter07_client.util;

import android.app.Activity;
import android.content.pm.PackageManager;

import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class PermissionUtil {

    // 检查多个权限,返回true表示已完全启用权限,返回false表示未完全启用权限
    public static boolean checkPermission(Activity act, String[] permissions, int requestCode) {
        int check = PackageManager.PERMISSION_GRANTED; // 默认的是已经授权了
        for (String permission : permissions) {
            check = ContextCompat.checkSelfPermission(act, permission);
            if (check != PackageManager.PERMISSION_GRANTED) {
                break; // 如果权限组里只要有一个没有授权,退出循环
            }
        }

        // 未开启该权限,则请求系统弹窗,让用户选择是否立即开启权限
        if (check != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(act, permissions, requestCode);
            return false;
        }

        return true;
    }

    // 检查权限结果数组,返回true表示都已经获得授权,返回false表示至少有一个未获得授权
    public static boolean checkGrant(int[] grantResults) {
        // 遍历权限结果数组中的每条选择结果
        for (int grant : grantResults) {
            if (grant != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }
}

布局文件activity_permission_lazy.xml

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"
    tools:context=".PermissionLazyActivity">

    <Button
        android:id="@+id/btn_contact"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="读写通讯录"/>

    <Button
        android:id="@+id/btn_sms"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="收发短信"/>

</LinearLayout>

清单文件

XML 复制代码
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <queries>
        <package android:name="com.example.chapter07_server" />
    </queries>

    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.READ_SMS"/>

    <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/Theme.MyApplication">

        <activity
            android:name=".PermissionLazyActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

四、运行时动态权限申请-饿汉模式

1、饿汉模式,就是当我们打开Activity的时候,上来就申请通讯录读写权限、收发短信权限

2、

相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui