ActivityCompat.requestPermissions不显示对话框


76
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,并在没有ActivityCompat的情况下使用requestPermissions(),但仍然无法正常工作。

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 '16

Answers:


94

这是使用示例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);
}

17
如果requestPermissions无法正常工作,执行所有这些检查是没有用的吗?在我的代码中,我只是检查我是否具有权限,如果没有,则调用requestPermissions。后来我想这会改变。和我完全按照您所说的那样执行了requestPermissions语法,但对我不起作用。
Idan Ayzen '16

由于您没有发布实际的requestPermissions()代码,因此我发布了一个完整的工作示例。对我来说很好。
NightSkyDev

我刚刚发布了我的实际requestPermissions()代码。感谢您的帮助:)
Idan Ayzen '16

1
@Phil-将两者都添加到示例中。如您所见,直接调用requestPermission一样容易,并且如果要请求多个权限,则需要这样做,因为此方法只是调用一个权限的包装。
NightSkyDev

5
感谢您突出显示“首先在清单中定义权限(如您在帖子中所做的一样),否则,您的请求将自动被拒绝”。我的就是这样<uses-permission android:name =“ android.permission.GET_ACCOUNTS” android:maxSdkVersion =“ 22” tools:replace =“ maxSdkVersion” />我将“ 22”更改为“ 23”
Jimmy Ilenloa

49

我遇到了同样的问题,事实证明这是由于清单合并工具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在清单中指定a 。我将<uses-permission>清单更改为:

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

(工具名称空间在http://schemas.android.com/tools


4
你救了我的一天!谢谢
Khang .NT

1
@usman不必为所有人工作,可能是您的情况有所不同。请发布您的问题,肯定可以解决您的问题:)
Shaktisinh Jadeja

2
至少从现在开始,要查看实际的权限(合并)清单,您可以在没有其他任何工具的情况下查看它aapt。当您从Android Studio中看到AndroidManifest.xml时,请查看底部的标签,只需单击该Merged Manifest标签即可。
adadion '19

你是个巫师。你是个巫师!
blastervla

27

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

最终的罪魁祸首是HockeyApp。它使用清单合并来包括自己的许可,WRITE_EXTERNAL_STORAGE除非它对其应用了max 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


谢谢,这整天都是我的问题。
米格尔·奥雷拉纳

13

更换:

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
拉纳

4

我将目标SDK版本从22更新到了23,效果很好。


1
是的,但这不是偶然的运气。原因是23是Android开始解释<uses-permission>为将来的代码操作而不是安装需求时。
艾略特·吉伦

4

单行代码可能不是问题。

在某些设备上(我不记得它是否有现货),“权限”对话框包含一个标有“不再询问”的复选框。如果在选中复选框的情况下单击“拒绝”,则不会再次提示您该权限,该权限将自动被应用拒绝。要对此进行验证,您必须进入“设置”->“应用程序”->“权限”,然后重新为该应用程序启用该权限。然后将其关闭以再次拒绝。您可能需要先打开应用程序,然后才能将其关闭(不确定)。

我不知道您的Nexus是否具备。也许值得一试。


我有这种情况。我能想到的最好的解决方法是检PackageManager.PERMISSION_DENIEDonRequestPermissionsResult()并调整UI,以向用户解释必须手动设置和打开权限Settings.ACTION_APPLICATION_DETAILS_SETTINGS
罗伊·索尔伯格

1

对我来说,问题是错误地请求了一个组,而不是实际的权限。


1

我遇到了同样的问题,并通过将Manifest.permission.READ_PHONE_STATE替换为android.Manifest.permission.READ_PHONE_STATE来解决了这个问题。


1

这只是发生在我身上。原来,当我需要过滤所有危险权限时,我正在请求所有权限,然后突然开始工作。

fun requestPermissions() {
    val missingDangerPermissions = PERMISSIONS
            .filter { ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED }
            .filter { this.getPackageManager().getPermissionInfo(it, PackageManager.GET_META_DATA).protectionLevel == PermissionInfo.PROTECTION_DANGEROUS } // THIS FILTER HERE!

    if (missingDangerPermissions.isNotEmpty()) {
        Log.i(TAG, "Requesting dangerous permission to $missingDangerPermissions.")
        ActivityCompat.requestPermissions(this,
                missingDangerPermissions.toTypedArray(),
                REQUEST_CODE_REQUIRED_PERMISSIONS);
        return
    } else {
        Log.i(TAG, "We had all the permissions we needed (yay!)")
    }
}

您从哪里获得ContextCompat的变量?我试过但没有找到变量?
gumuruh

1

我在三星S8和N8中遇到了这个问题(在其他任何产品中都发现过)

所以问题出在清单文件uses-permission

<uses-permission android:name="android.permission.CAMERA"
android:requiredFeature="true" />

由于某种原因,该属性android:requiredFeature是罪魁祸首。而且我还没有找到原因的解释。

解决,只需删除它,

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

0

我也遇到了同样的问题。我更新到buildToolsVersion“ 23.0.3”突然之间起作用了。希望这对遇到此问题的人有所帮助。


0

对我来说,问题是我的请求代码无效。我选择0xDEADBEEF作为请求代码,但它无声地失败了(也许在内部某个地方转换为小于32位的东西了吗?)如果我选择255,那么一切都可以像上述的NightSkyDev正常工作。


文档指出requestCode,应该是≥0 0xDEADBEEF是<0
Fls'Zen

0

上面的信息很好,但是设置targetSdkVersion为23(或更高)对于Android解释清单中的标签为“我将在代码中要求”而不是“安装时要求”至关重要<uses-permission>。许多消息源告诉您,您需要<uses-permission>标记,但是没有人说为什么,如果您没有设置该值,那么您将连续数小时像我一样感到困惑。


0

对我来说,错误出在清单中:权限为大写。Android Studio建议我使用大写权限。我不在乎,花了两个小时解决了这个问题。

权限的正确语法为
<uses-permission android:name =“ android.permission.WRITE_EXTERNAL_STORAGE” />


0

它发生在我上,我在API 23上运行它,我不得不使用代码来请求权限,例如下面的代码将其放在create方法上。请注意,MY_PERMISSIONS_REQUEST_READ_LOCATION是一个等于1的整数示例int MY_PERMISSIONS_REQUEST_READ_LOCATION = 1:

如果(Build.VERSION.SDK_INT> = Build.VERSION_CODES.M){requestPermissions(new String [] {Manifest.permission.ACCESS_COARSE_LOCATION},MY_PERMISSIONS_REQUEST_READ_LOCATION); }


0

也许此解决方案可以帮助任何人,而不是:

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

采用 :

ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);

所以我们添加android.Manifest.permission.WRITE_EXTERNAL_STORAGE


0

对我来说,问题在于发出请求后,我的主要活动又发起了另一个活动。那取代了对话,所以它从未被看到。


0

不要忘记在清单中没有多余空格的情况下写权限。就我而言,我有:

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

但是,最后,还有一个额外的空间。用正确的方式写

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

现在正在工作


0

无论您做什么,请检查是否在清单文件中声明了所需的权限。


    <!--Declaring the required permissions-->
    <uses-permission
        android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission
        android:name="android.permission.CAMERA" />


然后转到下一步。


0

这是我想与大家分享的另一种经验。在实现以下代码以检查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;

我的意思是要区分在清单中已定义的FINE和COARSE位置权限请求。在检查ACCESS_COARSE_LOCATION权限时,“请求权限”对话框从不弹出,但onRequestPermissionsResult始终使用PERMISSION_DENIED调用(以防在应用程序设置中未启用权限的情况下)。因此,我删除了对BUILD.SDK的检查,仅检查ACCESS_FINE_LOCATION了缺少的对话框,并且显示出来。

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

做到了。

清单源包含:

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

但该APKandroid.permission.ACCESS_FINE_LOCATION仅包含。在构建期间的某个时间,COARSE_LOCATION已将其删除。

我希望这可以帮助遇到同样问题的人。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.