草庐IT

Android---动态权限申请

别偷我的猪_09 2023-05-03 原文

目录

权限分类

动态权限核心函数

简易实现案例

完整代码

 

 

Google 在 Android 6.0 开始引入了权限申请机制,将所有权限分成了正常权限危险权限。App 每次在使用危险权限时需要动态的申请并得到用户的授权才能使用。

权限分类

系统权限分为两类:正常权限危险权限。

正常权限:不会直接给用户隐私带来危险。如果你在其清单中列出了正常权限,系统将自动授予该权限。

危险权限:授予应用访问用户机密数据的权限。如果你在清单文件中列出了危险权限,则用户必须明确批准你的应用使用这些权限。那么危险权限有那些?日历(CALENDAR)相机(CAMERA) 通讯录(CONTACTS)位置(LOCATION)拨号(PHONE)短信(SMS)存储(STORAGE)等。

<!-- 权限组:CALENDAR == 日历读取的权限申请 -->
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<!-- 权限组:CAMERA == 相机打开的权限申请 -->
<uses-permission android:name="android.permission.CAMERA" />
<!-- 权限组:CONTACTS == 联系人通讯录信息获取/写入的权限申请 -->
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
<!-- 权限组:LOCATION == 位置相关的权限申请 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 权限组:PHONE == 拨号相关的权限申请 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 权限组:SMS == 短信相关的权限申请 -->
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<!-- 权限组:STORAGE == 读取存储相关的权限申请 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

申请以上权限时,除了要在清单文件中添加权限,还需要通过代码动态申请。

动态权限核心函数

1. 检测权限

checkSelfPermission(@NonNull String permission)

2. 申请权限

requestPermissions(@NonNull String[] permissions, int requestCode)

3. 处理结果回调

onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults)

4. 是否需要显示 UI 界面提示用户为什么需要这个权限

shouldShowRequestPermissionRationale(@NonNull String permission)

简易实现案例

步骤1:在 AndroidManifest.xml 添加要申请的权限。这里以存储权限为例

<!-- STORAGE == 读取存储相关权限-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

骤2:封装一个 requestPermission 方法来动态检测和申请权限

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

 requestPermission() 函数里会先检测存储权限,如果没开启则动态申请存储权限。

private void requestPermission() {
        // checkSelfPermission() 检测权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {
            //TODO 申请存储权限
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    PERMISSION_REQUEST_CODE);
        }
    }

注意:这个 demo 里只申请了一个权限,当我们需要申请多个权限时,可以往requestPermissions 里的第二个参数添加其它需要的权限,因为它本就是一个 String 数组,且也要在 AndroidManifest里添加。

new String[]{Manifest.permission.READ_EXTERNAL_STORAGE
                    ,Manifest.permission.CAMERA}

步骤3:处理用户选择的结果(“允许” / “拒绝”),重写 onRequestPermissionsResult()方法。

//TODO 处理权限结果回调
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSION_REQUEST_CODE) {
            //用户点击了“确定” == grantResults[0] == PackageManager.PERMISSION_GRANTED)
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.i("TAG", "onRequestPermissionsResult granted");
            } else {
                Log.i("TAG", "onRequestPermissionsResult denied");
                // TODO 用户拒绝权限申请,则弹出警示框
                showWaringDialog();
            }
        }
    }

步骤4:当用户拒绝权限,则弹出警示框,并在用户点击“确定”后直接退出页面。因为没有存储权限肯定不能使用该应用的。

/**
     * 用户拒绝权限的警示
     */
    private void showWaringDialog() {
        new AlertDialog.Builder(this)
                .setTitle("警告!")
                .setMessage("请前往设置->应用->权限管理->打开存储权限,否则无法正常使用!")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //TODO 一般情况下如果用户不授权的话,功能时无法运行的,则直接退出
                        finish();
                    }
                }).show();
    }

完整代码

MainActivity.java

package com.example.dynamicauthority;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private static final int PERMISSION_REQUEST_CODE = 999;

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

        requestPermission();
    }

    private void requestPermission() {
        // checkSelfPermission() 检测权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
        != PackageManager.PERMISSION_GRANTED) {
            //TODO 申请存储权限
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    PERMISSION_REQUEST_CODE);
        }
    }

    //TODO 处理权限结果回调
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == PERMISSION_REQUEST_CODE) {
            //用户点击了“确定” == grantResults[0] == PackageManager.PERMISSION_GRANTED)
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Log.i("TAG", "onRequestPermissionsResult granted");
            } else {
                Log.i("TAG", "onRequestPermissionsResult denied");
                // TODO 用户拒绝权限申请,则弹出警示框
                showWaringDialog();
            }
        }
    }

    /**
     * 用户拒绝权限的警示
     */
    private void showWaringDialog() {
        new AlertDialog.Builder(this)
                .setTitle("警告!")
                .setMessage("请前往设置->应用->权限管理->打开存储权限,否则无法正常使用!")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //TODO 一般情况下如果用户不授权的话,功能时无法运行的,则直接退出
                        finish();
                    }
                }).show();
    }
}

有关Android---动态权限申请的更多相关文章

  1. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  2. ruby - rbenv 安装权限被拒绝 - 2

    大家好,我正在尝试设置一个开发环境,并且我一直在关注以下教程:Linktotutorial我做得不是很好,除了最基本的版本控制内容外,我对终端命令没有任何实际经验。我点击了第一个链接并尝试运行source~/.bash_profile我得到了错误;mkdir:/usr/local/rbenv/shims:权限被拒绝mkdir:/usr/local/rbenv/versions:权限被拒绝现在每次我加载终端时都会出现错误。bash_profile的内容;exportPATH=/usr/local/rbenv/bin:$PATHexportRBENV_ROOT=/usr/local/rbe

  3. ruby - 在 Ruby 中动态创建数组 - 2

    有没有办法在Ruby中动态创建数组?例如,假设我想遍历用户输入的书籍数组:books=gets.chomp用户输入:"TheGreatGatsby,CrimeandPunishment,Dracula,Fahrenheit451,PrideandPrejudice,SenseandSensibility,Slaughterhouse-Five,TheAdventuresofHuckleberryFinn"我把它变成一个数组:books_array=books.split(",")现在,对于用户输入的每一本书,我想用Ruby创建一个数组。伪代码来做到这一点:x=0books_array.

  4. ruby - 是否可以将 IRB 提示配置为动态更改? - 2

    我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO

  5. ruby-on-rails - carrierwave:在序列化动态属性上安装 uploader - 2

    首先,我使用的是rails3.1.3和来自master的carrierwavegithub仓库的分支。我使用after_init钩子(Hook)来确定基于属性的字段页面模型实例并为这些字段定义属性访问器将值存储在序列化哈希中(希望它清楚我是什么谈论)。这是我正在做的事情的精简版:classPage省略mount_uploader命令让我可以访问我想要的属性。但是当我安装uploader时出现错误消息说“nil类的未定义新方法”我在源代码中读到有方法read_uploader和扩展模块中的write_uploader。我如何必须覆盖这些来制作mount_uploader命令使用我的“虚拟

  6. ruby - 在 Ruby 中动态生成多维数组 - 2

    我正在尝试动态构建一个多维数组。我想要的基本上是这样的(为简单起见写出来):b=0test=[[]]test[b]这给了我错误:NoMethodError:undefinedmethod`test=[[],[],[]]而且它工作正常,但在我的实际使用中,我不会事先知道需要多少个数组。有一个更好的方法吗?谢谢 最佳答案 不需要像您正在使用的索引变量。只需将每个数组附加到您的test数组:irb>test=[]=>[]irb>test[["a","b","c"]]irb>test[["a","b","c"],["d","e","f"]]

  7. ruby-on-rails - 使用 gmaps4rails 动态加载谷歌地图标记 - 2

    如何只加载map边界内的标记gmaps4rails?当然,在平移和/或缩放后加载新的。与此直接相关的是,如何获取map的当前边界和缩放级别? 最佳答案 我是这样做的,我只在用户完成平移或缩放后替换标记,如果您需要不同的行为,请使用不同的事件监听器:在你看来(index.html.erb):{"zoom"=>15,"auto_adjust"=>false,"detect_location"=>true,"center_on_user"=>true}},false,true)%>在View的底部添加:functiongmaps4rail

  8. ruby - 动态方法链? - 2

    如何在对象上调用方法名称的嵌套哈希?例如,给定以下哈希:hash={:a=>{:b=>{:c=>:d}}}我想创建一个方法,给定上面的散列,执行以下操作:object.send(:a).send(:b).send(:c).send(:d)我的想法是我需要从一个未知的关联中获取一个特定的属性(这个方法不知道,但程序员知道)。我希望能够指定一个方法链来以嵌套哈希的形式检索该属性。例如:hash={:manufacturer=>{:addresses=>{:first=>:postal_code}}}car.execute_method_hash(hash)=>90210

  9. ruby-on-rails - 为什么用户必须输入 7 位数的 Twitter PIN 才能授予我的应用程序访问权限? - 2

    我正在为我的用户实现一些ruby​​onrails代码推特内容。我正在创建正确的oauth链接...类似http://twitter.com/oauth/authorize?oauth_token=y2RkuftYAEkbEuIF7zKMuzWN30O2XxM8U9j0egtzKv但在我的测试帐户授予对twitter的访问权限后,它会弹出一个页面,上面写着“您已成功授予对.我不知道用户应该在哪里输入此PIN以及他们为什么必须这样做。我认为这不是必要的步骤。Twitter应该将用户重定向到我在应用程序设置中提供的回调URL。有谁知道为什么会这样?更新我找到了thisarticle声明我需

  10. ruby - 如何使用 method_missing 动态声明方法? - 2

    我有一个ruby​​程序,我想接受用户创建的方法,并使用该名称创建一个新方法。我试过这个:defmethod_missing(meth,*args,&block)name=meth.to_sclass我收到以下错误:`define_method':interningemptystring(ArgumentError)in'method_missing'有什么想法吗?谢谢。编辑:我以不同的方式让它工作,但我仍然很好奇如何以这种方式做到这一点。这是我的代码:defmethod_missing(meth,*args,&block)Adder.class_evaldodefine_method

随机推荐