ActivityCompat.requestPermissions不显示对话框框。

113
if (ContextCompat.checkSelfPermission(RegisterActivity.this,      Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_DENIED){
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_PHONE_STATE}, REQUEST_READ_PHONE_STATE_PERMISSION);

我正在尝试在Nexus 5上的API 23上使用此函数,但它并没有像它应该做的那样显示对话框,什么也没发生。 可能是什么原因导致这个问题?(此代码在Java活动中) 我尝试将我的最小API更改为23,并使用requestPermissions()而不是ActivityCompat,但仍然无法解决。

apply plugin: 'com.android.application'

android {
compileSdkVersion 23
buildToolsVersion "23.0.2"

defaultConfig {
    applicationId "com.example.idanayzen.photomap"
    minSdkVersion 23
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
}
buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
}
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.google.android.gms:play-services:8.4.0'
compile 'com.android.support:design:23.1.1'
}

并且清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.idanayzen.photomap">

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

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">


    <meta-data
        android:name="com.google.android.geo.API_KEY"
        android:value="@string/google_maps_key" />

    <activity
        android:name=".MapsActivity"
        android:label="@string/title_activity_maps" />
    <activity android:name=".RegisterActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

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

</manifest>

顺便说一下,我已经尝试将字符串更改为“android.permission.READ_PHONE_STATE”,但仍然相同。 - Idan Ayzen
权限被阻止了吗? - K.Sopheak
24个回答

112

下面是使用requestPermissions()的示例:

首先,在清单文件中定义权限(就像您在帖子中所做的那样),否则,您的请求将自动被拒绝:

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

接下来,在onRequestPermissionsResult()方法中定义一个值以处理权限回调:

private final int REQUEST_PERMISSION_PHONE_STATE=1;

这是调用requestPermissions()函数的代码:

private void showPhoneStatePermission() {
    int permissionCheck = ContextCompat.checkSelfPermission(
            this, Manifest.permission.READ_PHONE_STATE);
    if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.READ_PHONE_STATE)) {
            showExplanation("Permission Needed", "Rationale", Manifest.permission.READ_PHONE_STATE, REQUEST_PERMISSION_PHONE_STATE);
        } else {
            requestPermission(Manifest.permission.READ_PHONE_STATE, REQUEST_PERMISSION_PHONE_STATE);
        }
    } else {
        Toast.makeText(MainActivity.this, "Permission (already) Granted!", Toast.LENGTH_SHORT).show();
    }
}

首先,您需要检查是否已获得权限(请记住,即使在被授予权限后,用户还可以在应用程序设置中撤销权限)。

最后,以下是您检查是否已获得权限的方法:

@Override
public void onRequestPermissionsResult(
        int requestCode,
        String permissions[],
        int[] grantResults) {
    switch (requestCode) {
        case REQUEST_PERMISSION_PHONE_STATE:
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Toast.makeText(MainActivity.this, "Permission Granted!", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "Permission Denied!", Toast.LENGTH_SHORT).show();
            }
    }
}

private void showExplanation(String title,
                             String message,
                             final String permission,
                             final int permissionRequestCode) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(title)
            .setMessage(message)
            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    requestPermission(permission, permissionRequestCode);
                }
            });
    builder.create().show();
}

private void requestPermission(String permissionName, int permissionRequestCode) {
    ActivityCompat.requestPermissions(this,
            new String[]{permissionName}, permissionRequestCode);
}

31
如果requestPermissions不起作用,那么进行所有这些检查不是徒劳无功吗?在我的代码中,我只是检查是否有权限,如果没有,我调用requestPermissions。稍后我想我会更改它。 而且,我已经按照你说的完全使用了requestPermissions语法,但对我来说它不起作用。 - Idan Ayzen
@NightSkyDev - 你示例中的requestPermission和showExplanation方法是什么? - Phil
1
@Phil - 已将两者都添加到示例中。正如您所看到的,直接调用requestPermission也同样容易,如果您正在请求多个权限,则需要这样做,因为此方法只是调用一个权限的包装器。 - RickBoyerDev
5
感谢您强调“首先,在清单文件中定义权限(就像您在帖子中所做的那样),否则,您的请求将自动被拒绝”。我的代码如下:<uses-permission android:name="android.permission.GET_ACCOUNTS" android:maxSdkVersion="23" tools:replace="maxSdkVersion" />我把“22”改成了“23”。 - Jimmy Ilenloa
@NightSkyDev 很好的答案。谢谢,解决了我的问题。 - André Luiz
显示剩余6条评论

60

我曾经也遇到同样的问题,后来发现是因为 manifest merger tool 从一个依赖中引入了 android:maxSdkVersion 属性。

要查看你在 APK 中请求的实际权限,可以使用 aapt 工具,像这样:

/path/to/android-sdk/build-tools/version/aapt d permissions /path/to/your-apk.apk

在我的情况下,它打印了:

uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE' maxSdkVersion='18'

即使我在清单文件中没有指定maxSdkVersion,我通过将清单文件中的<uses-permission>更改为以下内容来解决这个问题:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:remove="android:maxSdkVersion"/>

(其中工具命名空间为http://schemas.android.com/tools)


1
@usman,不一定适用于所有情况,也许你的情况不同。请发表您的问题,有人一定会解决您的问题 :) - Shaktisinh Jadeja
3
目前至少可以在不使用其他工具(如aapt)的情况下查看实际权限(合并)清单。当您在Android Studio中查看您的AndroidManifest.xml时,请查看底部选项卡,只需单击“合并清单”选项卡即可。 - adadion

31

我需要请求WRITE_EXTERNAL_STORAGE权限,但尽管尝试了所有不同的建议,仍然没有弹出窗口。

最后的罪魁祸首是HockeyApp。它使用清单合并来包含自己对WRITE_EXTERNAL_STORAGE的权限,但会将一个最大SDK版本应用到其中。

解决此问题的方法是在您的清单文件中包含它,并使用替换覆盖HockeyApp的版本,这样就可以成功了!

4.7.2其他请求外部存储权限的依赖项(SDK版本5.0.0及更高版本)。为了准备Android O,HockeySDK-Android 5.0.0及更高版本限制了WRITE_EXTERNAL_STORAGE 权限,具有maxSdkVersion过滤器。在某些用例中,例如应用程序包含需要此权限的依赖项的情况下,maxSdkVersion使得这些依赖项无法授予或请求权限。这些情况的解决方案如下:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" tools:node="replace"/>

这将导致低优先级清单中的其他属性被替换而不是合并。

https://support.hockeyapp.net/kb/client-integration-android/hockeyapp-for-android-sdk#permissions-advanced


谢谢,这一整天都是我的问题。 - Miguel Orellana
这解决了我的问题。非常感谢! - Burak

16

你的代码可能不止出现了一行问题。

在某些设备上(我记不清是不是在原生Android中),权限对话框包括一个名为“不再询问”的复选框。如果你勾选该复选框并点击拒绝,那么该应用程序将自动被拒绝请求该权限,以后也不会再提示你了。如果要恢复该权限,你需要进入“设置”→“应用程序”→“权限”,然后重新启用该应用程序的该权限。然后再关闭以再次拒绝。你可能需要在再次关闭之前打开该应用程序,但我不确定。

我不知道你的Nexus是否有这个功能,不过值得一试。


2
我曾经遇到过这种情况。我能想到的最好的解决方法是在onRequestPermissionsResult()中检查PackageManager.PERMISSION_DENIED,并调整UI以向用户解释必须手动设置权限并打开Settings.ACTION_APPLICATION_DETAILS_SETTINGS - Roy Solberg

15

更换:

ActivityCompat.requestPermissions(this, new String[]{"Manifest.permission.READ_PHONE_STATE"}, 225);

随着:

ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE}, 225);

该权限的实际字符串不是"Manifest.permission.READ_PHONE_STATE"。请使用符号Manifest.permission.READ_PHONE_STATE


1
不适用于我。我的应用程序配置为在16到23 SDK版本上运行。 - ciro
你应该使用android.Manifest.permission.READ_PHONE_STATE。 - rana

5
在我的情况下,将目标sdk从33降低到32就可以解决这个问题。

不要直接提供答案,尝试写一个详细的注释来解释解决方案,只要解释不太冗长。 - DSDmark
这对我也起作用了。不确定为什么,但至少我知道它与目标SDK相关,并且可以进一步调查。 - user401183
我同意 @DSDmark。我会从现在开始努力增加。 - undefined

4

我想和大家分享另一个经验。这个问题在我实现以下检查BLE访问权限的代码后出现:

final String requiredPermission = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && targetSdkVersion >= Build.VERSION_CODES.Q) ?
            android.Manifest.permission.ACCESS_FINE_LOCATION :
            android.Manifest.permission.ACCESS_COARSE_LOCATION;

我想区分细节和粗略定位权限请求,这两种权限都已在清单文件中定义。当检查ACCESS_COARSE_LOCATION权限时,“请求权限”对话框从未弹出,但如果应用程序设置中没有启用权限,则始终会调用 onRequstPermissionsResult,并返回PERMISSION_DENIED。因此,我删除了对BUILD.SDK的检查,仅检查ACCESS_FINE_LOCATION,然后缺失的对话框出现了。

final String requiredPermission = android.Manifest.permission.ACCESS_FINE_LOCATION;

解决了问题。

Manifest源代码包含:

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

但是apk只包含了android.permission.ACCESS_FINE_LOCATION。在构建过程中,COARSE_LOCATION已被删除。
我希望这可以帮助到有同样问题的人。

3

我将目标SDK版本从22升级到23,结果完美无误。


1
是的,但那不是随机运气。原因在于23是Android开始将<uses-permission>解释为未来代码操作而不是安装需求的时候。 - Eliot Gillum

3

别忘了在清单文件中写权限时不要有额外的空格。在我的情况下,我有:

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

但是看,最后有一个额外的空格。只需正确书写:

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

现在它正在运行。


3

对我而言,这与他们在33中更加细化权限相关,涉及请求read_external_storage有关。

以下是我正在使用的Kotlin代码,在2023年1月检查和请求访问权限。

private fun checkPermissions():Boolean{
        // version 33 gets more granular
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES)
                != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(
                    this, arrayOf(
                        Manifest.permission.READ_MEDIA_IMAGES,
                        Manifest.permission.READ_MEDIA_VIDEO // why isn't this plural too
                    ),
                    1
                )
                return false
            }
        }else{
            if (checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(
                    this, arrayOf(
                        Manifest.permission.READ_EXTERNAL_STORAGE
                    ),
                    1
                )
                return false
            }
        }
        return true
    }

我还需要将这三个添加到我的清单文件中,以支持31-33的API。
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"  />    
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"  />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"  />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接