授予权限规则失败,无法授予权限。

19

我正在编写一个测试类,尝试使用规则 GrantPermissionRule 授予权限:

@Rule
public GrantPermissionRule permissionsRule = GrantPermissionRule.grant(
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE);

但是在测试执行开始时,我收到了以下错误:

junit.framework.AssertionFailedError: Failed to grant permissions, see logcat for details
    at junit.framework.Assert.fail(Assert.java:50)
    at android.support.test.runner.permission.PermissionRequester.requestPermissions(PermissionRequester.java:110)
    at android.support.test.rule.GrantPermissionRule$RequestPermissionStatement.evaluate(GrantPermissionRule.java:128)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at android.support.test.runner.AndroidJUnit4.run(AndroidJUnit4.java:101)
    at org.junit.runners.Suite.runChild(Suite.java:128)
    at org.junit.runners.Suite.runChild(Suite.java:27)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
    at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
    at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)
    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1886)

这是logcat输出(仅显示错误):

12-23 13:03:21.196 13242-13242/? E/dex2oat: Failed to create oat file: /data/dalvik-cache/arm/data@data@com.google.android.gms@app_chimera@m@00000088@DynamiteLoader.apk@classes.dex: Permission denied
12-23 13:03:21.721 13306-13306/? E/dex2oat: Failed to create oat file: /data/dalvik-cache/arm/data@data@com.google.android.gms@app_chimera@m@0000008a@DynamiteModulesC.apk@classes.dex: Permission denied
12-23 13:03:22.361 13328-13328/? E/dex2oat: Failed to create oat file: /data/dalvik-cache/arm/data@data@com.google.android.gms@app_chimera@m@00000086@AdsDynamite.apk@classes.dex: Permission denied
12-23 13:03:26.303 13436-13467/my.app.package E/GrantPermissionCallable: Permission: android.permission.READ_EXTERNAL_STORAGE cannot be granted!

但这似乎只在我的搭载Android 6.0.1的红米4手机上发生。但在三星Galaxy Tab S搭载6.0.1时,它也可以正常工作,在一些模拟器中也可以。

我错过了什么?


1
一开始看起来似乎是该设备的一个错误。尝试使用adb shell授予权限,看看是否有效。据我所知,这就是GetPermissionRule正在使用的全部内容。 - CommonsWare
8个回答

13

找到了解决方法。我必须在开发者选项菜单中授予权限:

usb_debugging_security_settings


6
很遗憾,我的开发者设置中没有这样的选项。还有其他解决方案吗?我在两个设备和模拟器中都遇到了同样的问题。顺便说一句:这似乎与 WRITE_EXTERNAL_STORAGE 权限有关。如果我只请求 READ_EXTERNAL_STORAGE 或 ACCESS_FINE_LOCATION 权限,则不会出现问题。 - user2808624
3
不要认为它与特定权限有关,可能与一组权限相关。对我来说,在尝试授予“ACCESS_BACKGROUND_LOCATION”时发生了这种情况,但对“ACCESS_FINE_LOCATION”正常工作。我在开发者选项中也没有看到“安全设置”。 - Marino
1
@Marino 如果你的设备版本低于AndroidQ,就会出现这种情况。你不需要的权限是无法授权给你的。只有在引入后台限制的>=AndroidQ中才能起作用。 - Otieno Rowland

10

我OPPO设备上没有上述选项。

但是有一个名为“禁用权限监控”的选项,可以实现相同的功能。

要解决此问题,请在开发者选项下打开“禁用权限功能”选项。


为了解决这个问题,在开发者选项下打开“禁用权限监控”选项。 - chinaanihchen

4
当我尝试在Android版本低于13的设备上授予POST_NOTIFICATIONS权限时,遇到了这个错误。因此,请检查您授予的权限是否与设备的API级别足够高或低。

1
在我的情况下,自 API 级别 32 起,READ_EXTERNAL_STORAGE 权限不再被授予。更换到一个 API 级别为 31 或更低的模拟器/设备可以解决这个问题。

0

就我而言:我只是忘记在应用程序清单中指定权限了。


0
以下代码解决了我的问题,现在我的测试在所有支持的应用版本中都通过了。
Kotlin,提供的示例还需要相机,如果您不需要它,可以将其删除。
// Android 13 requires more specific permission to read media
// https://dev59.com/HVQJ5IYBdhLWcg3wbFMW
private val requiredMediaPermissions = if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {

    Manifest.permission.READ_MEDIA_IMAGES
} else {

    Manifest.permission.READ_EXTERNAL_STORAGE
}

0
在我的情况下,我没有在清单中声明WRITE_EXTERNAL_STORAGE,而是从某个库中提供的,但在该库的新版本中,他们设置了maxSdkVersion 所以我只需将该权限添加到我的清单中,并忽略maxSdkVersion
<uses-permission
        android:name="android.permission.WRITE_EXTERNAL_STORAGE"
        tools:remove="android:maxSdkVersion"
        tools:ignore="ScopedStorage" />

0
我遇到了同样的问题:
  1. 在模拟器上运行时,使用 API>32 -> 出现了关于 WRITE_EXTERNAL_STORAGE 的异常
  2. 如果在 API<33 上运行 -> 出现了关于 POST_NOTIFICATIONS 的异常
对于第一个问题,Deni 的答案有所帮助,但第二个问题无法以同样的方式解决。
所以我根据原始的GrantPermissionRule创建了一个新的TestRule类:
/**
 * Custom realization of [GrantPermissionRule] with ability to skip grant check.
 *
 * [isActualPermission] - pass here your api check. If FALSE - permission check will be skipped.
 */
@SuppressLint("RestrictedApi")
@ExperimentalTestApi
class GrantPermissionApiRule(
    private val isActualPermission: Boolean,
    private val permissionGranter : PermissionGranter,
    vararg permissions: String
) : TestRule {

    init {
        val permissionSet = satisfyPermissionDependencies(*permissions)
        permissionGranter.addPermissions(*permissionSet.toTypedArray())
    }

    @VisibleForTesting
    private fun satisfyPermissionDependencies(vararg permissions: String): Set<String> {
        val permissionList: MutableSet<String> = LinkedHashSet(listOf(*permissions))
        /**
         * Explicitly grant READ_EXTERNAL_STORAGE permission when WRITE_EXTERNAL_STORAGE was
         * requested.
         */
        if (permissionList.contains(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE)
        }
        return permissionList
    }

    override fun apply(base: Statement, description: Description): Statement {
        return RequestPermissionStatement(base, isActualPermission, permissionGranter)
    }

    private class RequestPermissionStatement(
        private val base: Statement,
        private val isActualPermission: Boolean,
        private val permissionGranter: PermissionGranter
    ) : Statement() {

        @Throws(Throwable::class)
        override fun evaluate() {
            if (isActualPermission) {
                permissionGranter.requestPermissions()
            }
            base.evaluate()
        }
    }

    companion object {
        fun grant(
            isActualPermission: Boolean,
            vararg permissions: String
        ): GrantPermissionApiRule {
            val granter = ServiceLoaderWrapper.loadSingleService(PermissionGranter::class.java) {
                PermissionRequester()
            }
            return GrantPermissionApiRule(isActualPermission, granter, *permissions)
        }
    }
}

如果没有调用函数permissionGranter.requestPermissions(),你将不会收到关于错误API的异常。
你只需要做的就是检查当前的API版本,并在这个TestRule中传递isActualPermission。
像这样:
/**
 * If current device api >= TIRAMISU (33) - permission rule will be skipped.
 */
@get:Rule
val writeExternalGrantRule: GrantPermissionApiRule = GrantPermissionApiRule.grant(
    Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU, 
    Manifest.permission.WRITE_EXTERNAL_STORAGE
)

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