Android 开发 - 数据共享(数据共享、内容提供者实现、动态权限申请)

发布于:2025-08-29 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、数据共享

1、内容提供者
  • 内容提供者 ContentProvider 为 APP 存取内部数据提供统一的外部接口,让不同的应用之间得以共享数据
2、流程理解
  • Client APP 将用户的输入内容通过 ContentProvider 跨进程通信传递给 Server APP
3、数据访问
  • 利用 ContentProvider 只实现服务端 APP 的数据封装,如果客户端 APP 想访问对方的内部数据,就要通过内容解析器 ContentResolver 来访问
4、URI
  • URI(统一资源标识符 Universal Resource ldentifer)代表数据操作的地址,每一个ContentProvider 都会有唯一的地址
content://【authority】/【data path】/【id】
字段 说明
content:// 通用前缀,表示该 URI 用于 ContentProvider 定位资源
authority 用来确定具体提供资源的 ContentProvider
一般 authority 都由类的小写全称组成,以保证唯一性
data_path 数据路径,用来确定请求的是哪个数据集
id 数据编号,用来请求单条数据,如果是多条则忽略此字段

二、内容提供者实现

1、项目创建
  • 创建两个 module,分别为 server 和 client
2、server
(1)数据库操作类
  • UserDBHelper 类
package com.my.server.database;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;


public class UserDBHelper extends SQLiteOpenHelper {

    private static final String DB_NAME = "user.db";
    private static final int DB_VERSION = 1;
    public static final String TABLE_NAME = "user_info";
    private static UserDBHelper userDBHelper;

    private UserDBHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
    }

    // 使用单例模式获取数据库帮助器的唯一实例
    public static UserDBHelper getInstance(Context context) {
        if (userDBHelper == null) {
            userDBHelper = new UserDBHelper(context);
        }
        return userDBHelper;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {

        // 创建数据库,执行建表语句
        String sql = "CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
                "user_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
                "user_name VARCHAR NOT NULL," +
                "user_age INTEGER NOT NULL" +
                ");";
        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}
(2)资源类
  • UserInfoContent 类
package com.my.server.content;

import android.net.Uri;

public class UserInfoContent {

    public static final String AUTHORITIES = "com.my.server.provider.UserInfoProvider";

    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITIES + "/user");

    public static final String USER_ID = "user_id";
    public static final String USER_NAME = "user_name";
    public static final String USER_AGE = "user_age";
}

(3)内容提供者
  1. 创建内容提供者,右击包名 -> 【Other】 -> 【Content Provider】 -> 填写相关信息 -> 【Finish】
  • UserInfoProvider 类,默认
package com.my.server.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;

public class UserInfoProvider extends ContentProvider {
    public UserInfoProvider() {
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // Implement this to handle requests to delete one or more rows.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public String getType(Uri uri) {
        // TODO: Implement this to handle requests for the MIME type of the data
        // at the given URI.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO: Implement this to handle requests to insert a new row.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public boolean onCreate() {
        // TODO: Implement this to initialize your content provider on startup.
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        // TODO: Implement this to handle query requests from clients.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        // TODO: Implement this to handle requests to update one or more rows.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}
  1. 在清单文件 AndroidManifest.xml 中配置 provider 组件
  • AndroidManifest.xml
<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.AndroidDevelop">

    <!-- 将 authorities 设置为内容提供者的全类名 -->
    <provider
        android:name=".provider.UserInfoProvider"
        android:authorities="com.my.server.provider.UserInfoProvider"
        android:enabled="true"
        android:exported="true">
    </provider>

    ...

</application>
  • UserInfoProvider 类
package com.my.server.provider;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.util.Log;

import com.my.server.content.UserInfoContent;
import com.my.server.database.UserDBHelper;

public class UserInfoProvider extends ContentProvider {

    private static final String TAG = UserInfoProvider.class.getSimpleName();

    private UserDBHelper userDBHelper;

    private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);

    private static final int USES = 1;

    static {
        URI_MATCHER.addURI(UserInfoContent.AUTHORITIES, "/user", USES);
    }

    @Override
    public boolean onCreate() {
        Log.i(TAG, "-------------------- onCreate");
        userDBHelper = UserDBHelper.getInstance(getContext());

        // 返回 true 代表 provider 实例化成功,返回 false 代表失败
        return true;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        Log.i(TAG, "-------------------- insert");
        if (URI_MATCHER.match(uri) == USES) {
            SQLiteDatabase wd = userDBHelper.getWritableDatabase();
            wd.insert(UserDBHelper.TABLE_NAME, null, values);
        }
        return uri;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        Log.i(TAG, "-------------------- query");
        Cursor cursor = null;
        if (URI_MATCHER.match(uri) == USES) {
            SQLiteDatabase rd = userDBHelper.getReadableDatabase();
            cursor = rd.query(userDBHelper.TABLE_NAME, null, selection, selectionArgs,
                    null, null, null);
        }
        return cursor;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int count = 0;
        if (URI_MATCHER.match(uri) == USES) {
            SQLiteDatabase wd = userDBHelper.getWritableDatabase();
            count = wd.delete(userDBHelper.TABLE_NAME, selection, selectionArgs);
            wd.close();
        }
        return count;
    }

    @Override
    public String getType(Uri uri) {
        // TODO: Implement this to handle requests for the MIME type of the data
        // at the given URI.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        // TODO: Implement this to handle requests to update one or more rows.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}
2、client
(1)清单文件
<!-- Android 11 要求实现声明需要访问的软件包 -->
<queries>
    <package android:name="com.my.server"></package>

    <!-- 也可以声明需要访问的 provider -->
    <!-- <provider android:authorities="com.my.server.provider.UserInfoProvider"></provider> -->
</queries>
(2)实体类
  • User 类
package com.my.client.entity;

public class User {
    public Integer id;
    public String name;
    public Integer age;

    public User() {}

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public User(Integer id, String name, Integer age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
(3)资源类
  • UserInfoContent
package com.my.client.content;

import android.net.Uri;

public class UserInfoContent {

    public static final String AUTHORITIES = "com.my.server.provider.UserInfoProvider";

    public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITIES + "/user");

    public static final String USER_ID = "user_id";
    public static final String USER_NAME = "user_name";
    public static final String USER_AGE = "user_age";
}
(4)XML 文件
  • activity_client_input.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:text="姓名:" />

        <EditText
            android:id="@+id/et_name"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20dp"
            android:text="年龄:" />

        <EditText
            android:id="@+id/et_age"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content" />
    </LinearLayout>

    <Button
        android:id="@+id/btn_insert"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="插入" />

    <Button
        android:id="@+id/btn_query_by_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="根据姓名查询" />

    <Button
        android:id="@+id/btn_delete_by_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:text="根据姓名删除" />
</LinearLayout>
(5)Java 代码
  • ClientInputActivity 类
package com.my.client;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import com.my.client.content.UserInfoContent;
import com.my.client.entity.User;

public class ClientInputActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String TAG = ClientInputActivity.class.getSimpleName();
    private EditText et_name;
    private EditText et_age;

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

        et_name = findViewById(R.id.et_name);
        et_age = findViewById(R.id.et_age);
        Button btn_insert = findViewById(R.id.btn_insert);
        Button btn_query_by_name = findViewById(R.id.btn_query_by_name);
        Button btn_delete_by_name = findViewById(R.id.btn_delete_by_name);

        btn_insert.setOnClickListener(this);
        btn_query_by_name.setOnClickListener(this);
        btn_delete_by_name.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_insert:
                ContentValues values = new ContentValues();
                values.put(UserInfoContent.USER_NAME, et_name.getText().toString());
                values.put(UserInfoContent.USER_AGE, Integer.parseInt(et_age.getText().toString()));

                getContentResolver().insert(UserInfoContent.CONTENT_URI, values);
                Toast.makeText(this, "插入完成", Toast.LENGTH_SHORT).show();
                break;
            case R.id.btn_query_by_name:
                Cursor cursor = getContentResolver().query(UserInfoContent.CONTENT_URI, null, "user_name=?",
                        new String[]{et_name.getText().toString()}, null);

                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        User user = new User();
                        @SuppressLint("Range") int id = cursor.getInt(cursor.getColumnIndex(UserInfoContent.USER_ID));
                        @SuppressLint("Range") String name = cursor.getString(cursor.getColumnIndex(UserInfoContent.USER_NAME));
                        @SuppressLint("Range") int age = cursor.getInt(cursor.getColumnIndex(UserInfoContent.USER_AGE));

                        user.id = id;
                        user.name = name;
                        user.age = age;

                        Log.i(TAG, "---------- " + user);
                    }
                    cursor.close();
                }
                break;
            case R.id.btn_delete_by_name:
                int count = getContentResolver().delete(UserInfoContent.CONTENT_URI,
                        "user_name=?", new String[]{et_name.getText().toString()});
                if (count > 0) {
                    Toast.makeText(this, "删除完成", Toast.LENGTH_SHORT).show();
                }
                break;
        }
    }
}

三、动态权限申请

1、基本介绍
  • Android 系统为了防止某些 APP 滥用权限,从 6.0 开始引入了运行时权限管理机制,允许 APP 在运行过程中动态检查是否拥有某项权限,一旦发现缺少某种必需的权限,则系统会自动弹出小窗提示用户去开启该权限
2、动态权限申请步骤
  1. 检查 APP 是否开启了指定权限
  • 调用 ContextCompat 的 checkSelfPermission 方法
  1. 请求系统弹窗,以便用户选择是否开启权限
  • 调用 ActivityCompat 的 requestPermissions 方法,即可命令系统自动弹出权限申请窗口
  1. 判断用户的权限选择结果
  • 重写活动页面的权限请求回调方法 onRequestPermissionsResult,在该方法内部处理用户的权限选择结果
3、Lazy 模式
(1)清单文件
  • AndroidManifest.xml
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />

<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
(2)工具类
  • PermissionUtil 类
package com.my.client.util;

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

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) {

        // Android 6.0 之后开始采用动态权限管理
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            // 有权限,PackageManager.PERMISSION_GRANTED
            // 无权限,PackageManager.PERMISSION_DENIED
            // 保存一份权限查看结果的标识
            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) {
        if (grantResults != null) {
            for (int grantResult : grantResults) {
                if (grantResult != PackageManager.PERMISSION_GRANTED) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }
}
  • ToastUtil 类
package com.my.client.util;

import android.app.Activity;
import android.widget.Toast;

public class ToastUtil {

    public static void show(Activity act, String str) {
        Toast.makeText(act, str, Toast.LENGTH_SHORT).show();
    }
}
(3)XML 文件
  • activity_permission_lazy.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp">

    <Button
        android:id="@+id/btn_contact"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:text="读取通讯录"
        android:textSize="15dp" />

    <Button
        android:id="@+id/btn_sms"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="收发短信"
        android:textSize="15dp" />
</LinearLayout>
(4)Java 代码
  • PermissionLazyActivity 类
package com.my.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.view.View;
import android.widget.Button;

import com.my.client.util.PermissionUtil;
import com.my.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.SEND_SMS,
            Manifest.permission.READ_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);

        Button btn_contact = findViewById(R.id.btn_contact);
        Button btn_sms = findViewById(R.id.btn_sms);

        btn_contact.setOnClickListener(this);
        btn_sms.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_contact:
                PermissionUtil.checkPermission(this, PERMISSIONS_CONTACTS, REQUEST_CODE_CONTACTS);
                break;
            case R.id.btn_sms:
                PermissionUtil.checkPermission(this, PERMISSIONS_SMS, REQUEST_CODE_SMS);
                break;
        }
    }

    @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)) {
                    ToastUtil.show(this, "通讯录权限获取成功");
                } else {
                    ToastUtil.show(this, "通讯录权限获取失败");
                    jumpToSetting();
                }
                break;
            case REQUEST_CODE_SMS:
                if (PermissionUtil.checkGrant(grantResults)) {
                    ToastUtil.show(this, "收发短信权限获取成功");
                } else {
                    ToastUtil.show(this, "收发短信权限获取失败");
                    jumpToSetting();
                }
                break;
        }
    }

    // 跳转到应用设置界面
    public void jumpToSetting() {
        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);
    }
}
4、Hungry 模式
(1)清单文件
  • 同 【三 - 3 - (1)】
(2)工具类
  • 同 【三 - 3 - (2)】
(3)XML 文件
  • activity_permission_hungry.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="5dp">

    <Button
        android:id="@+id/btn_contact"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:text="读取通讯录"
        android:textSize="15dp" />

    <Button
        android:id="@+id/btn_sms"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="收发短信"
        android:textSize="15dp" />
</LinearLayout>
(4)Java 代码
  • PermissionHungryActivity 类
package com.my.client;

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

import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.widget.Button;

import com.my.client.util.PermissionUtil;
import com.my.client.util.ToastUtil;

public class PermissionHungryActivity extends AppCompatActivity implements View.OnClickListener {

    private static final String[] PERMISSIONS_ALL = new String[]{
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.WRITE_CONTACTS,
            Manifest.permission.SEND_SMS,
            Manifest.permission.READ_SMS
    };

    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.SEND_SMS,
            Manifest.permission.READ_SMS
    };

    private static final int REQUEST_CODE_CONTACTS = 1;
    private static final int REQUEST_CODE_SMS = 2;
    private static final int REQUEST_ALL = 3;

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

        Button btn_contact = findViewById(R.id.btn_contact);
        Button btn_sms = findViewById(R.id.btn_sms);

        btn_contact.setOnClickListener(this);
        btn_sms.setOnClickListener(this);

        PermissionUtil.checkPermission(this, PERMISSIONS_ALL, REQUEST_ALL);
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_contact:
                PermissionUtil.checkPermission(this, PERMISSIONS_CONTACTS, REQUEST_CODE_CONTACTS);
                break;
            case R.id.btn_sms:
                PermissionUtil.checkPermission(this, PERMISSIONS_SMS, REQUEST_CODE_SMS);
                break;
        }
    }

    @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)) {
                    ToastUtil.show(this, "通讯录权限获取成功");
                } else {
                    ToastUtil.show(this, "通讯录权限获取失败");
                    jumpToSetting();
                }
                break;
            case REQUEST_CODE_SMS:
                if (PermissionUtil.checkGrant(grantResults)) {
                    ToastUtil.show(this, "收发短信权限获取成功");
                } else {
                    ToastUtil.show(this, "收发短信权限获取失败");
                    jumpToSetting();
                }
                break;
            case REQUEST_ALL:
                if (PermissionUtil.checkGrant(grantResults)) {
                    ToastUtil.show(this, "所有权限获取成功");
                } else {
                    ok: for (int i = 0; i < grantResults.length; i++) {
                        if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
                            switch (permissions[i]) {
                                case Manifest.permission.READ_CONTACTS:
                                case Manifest.permission.WRITE_CONTACTS:
                                    ToastUtil.show(this, "通讯录权限获取失败");
                                    jumpToSetting();
                                    break ok;
                                case Manifest.permission.SEND_SMS:
                                case Manifest.permission.READ_SMS:
                                    ToastUtil.show(this, "收发短信权限获取失败");
                                    jumpToSetting();
                                    break ok;
                            }
                        }
                    }
                }
                break;
        }
    }

    // 跳转到应用设置界面
    public void jumpToSetting() {
        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);
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到