Android 权限 checkSelfPermission 不起作用

Android permissions checkSelfPermission doesn't work

在我的应用程序的 AndroidManifest.xml 中,我指定了一个目标 API 到 26:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.javasrv"
android:minSdkVersion="23"
android:targetSdkVersion="26"
android:versionCode="6"
android:versionName="1.0.0">
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

但是当我 运行 Android x86 8.1 上的应用程序并通过系统菜单禁用存储访问权限时,它说 "This app was designed for an older version of Android. Denying permission may cause it to no longer function as intended."

怎么可能?

此外,我在运行时权限检查方面遇到问题:即使我在系统设置中禁用了它,它也始终认为已授予访问权限:

if (ContextCompat.checkSelfPermission(LoaderActivity.this, permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    Toast.makeText(LoaderActivity.this, "PERMISSION_DENIED", Toast.LENGTH_SHORT).show();
    Log.d("*** Loader::onCreate ***", "PERMISSION_DENIED");
    if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission.WRITE_EXTERNAL_STORAGE)) {
    } else {
    }
    ActivityCompat.requestPermissions(this, new String[]{permission.WRITE_EXTERNAL_STORAGE}, 0);
} else {
    Toast.makeText(LoaderActivity.this, "PERMISSION_GRANTED", Toast.LENGTH_SHORT).show();
    Log.d("*** Loader::onCreate ***", "PERMISSION_GRANTED");
}

再说一遍,不清楚怎么可能。有什么想法吗?

编辑: 我正在使用 android api v26 和 android 支持库 v23。

编译脚本:

file=javasrv.apk

# export CLASSPATH=/opt/android-sdk/platforms/android-26/android.jar:/opt/android-sdk/extras/android/support-library/23.2.1/android-support-v4.jar
#
rm -f com/javasrv/*.class
javac -cp $CLASSPATH -source 1.8 -target 1.8 com/javasrv/*.java
#dx --dex --output classes.dex com/javasrv/*.class
dx --dex --output classes.dex com/javasrv/*.class android/support/v4/app/*.class android/support/v4/content/*.class

#aapt package -f -m -F "$file" -M AndroidManifest.xml -S res -I "$CLASSPATH"
#aapt add "$file" classes.dex
rm -rf build && mkdir build
find ./res -type f  | grep -vE '\.sw.$' | xargs -I{} aapt2 compile -o build "{}" --no-crunch
aapt2 link -R build/* --manifest AndroidManifest.xml $(echo "$CLASSPATH" | tr -d '\n' | xargs -d':' -L1 -I{} echo " -I {} ") -o "$file" --auto-add-overlay
zip -uj "$file" classes.dex

zipalign -f 4 "$file" "$file.aligned"
mv -f "$file.aligned" "$file"
apksigner sign --ks-pass pass:pwd --ks javasrv.keystore "$file"

Edit2: 这是另一个可能与aapt2有关的问题。如果我在 AndroidManifest.xml 中指定 compileSdkVersion 它会抛出一个错误:

AndroidManifest.xml:2: error: attribute android:compileSdkVersion not found.
error: failed processing manifest.

我只是通过从清单中删除 compileSdkVersion 来忽略它。我现在想知道我是否应该...

Edit3:与该权限检查的 logcat 有关。我只能访问 /data/log.txt。但它应该足够了。没有?

08-16 19:24:39.236 18965 18965 E /system/bin/webview_zygote32: Failed to make and chown /acct/uid_99182: Permission denied
08-16 19:24:39.236 18965 18965 E Zygote  : createProcessGroup(99182, 0) failed: Permission denied
08-16 19:24:39.239  2219  2900 I am_proc_start: [0,18965,99182,com.android.chrome:sandboxed_process0,webview_service,com.javasrv/org.chromium.content.app.SandboxedProcessService0]
08-16 19:24:39.239  2219  2900 I ActivityManager: Start proc 18965:com.android.chrome:sandboxed_process0/u0i182 for webview_service com.javasrv/org.chromium.content.app.SandboxedProcessService0
08-16 19:24:39.255 18965 18965 W /system/bin/webview_zygote32: Unexpected CPU variant for X86 using defaults: x86_64
08-16 19:24:39.256 18931 18931 I auditd  : type=1400 audit(0.0:3392): avc: denied { read } for comm="com.javasrv" name="vmstat" dev="proc" ino=4026531858 scontext=u:r:untrusted_app_25:s0:c512,c768 tcontext=u:object_r:proc:s0 tclass=file permissive=1
08-16 19:24:39.256 18931 18931 I com.javasrv: type=1400 audit(0.0:3392): avc: denied { read } for name="vmstat" dev="proc" ino=4026531858 scontext=u:r:untrusted_app_25:s0:c512,c768 tcontext=u:object_r:proc:s0 tclass=file permissive=1
08-16 19:24:39.256 18931 18931 I auditd  : type=1400 audit(0.0:3393): avc: denied { open } for comm="com.javasrv" path="/proc/vmstat" dev="proc" ino=4026531858 scontext=u:r:untrusted_app_25:s0:c512,c768 tcontext=u:object_r:proc:s0 tclass=file permissive=1
08-16 19:24:39.256 18931 18931 I com.javasrv: type=1400 audit(0.0:3393): avc: denied { open } for path="/proc/vmstat" dev="proc" ino=4026531858 scontext=u:r:untrusted_app_25:s0:c512,c768 tcontext=u:object_r:proc:s0 tclass=file permissive=1
08-16 19:24:39.263 18959 18959 W zygote  : Unexpected CPU variant for X86 using defaults: x86_64
08-16 19:24:39.281  1022  1022 I auditd  : type=1400 audit(0.0:3395): avc: denied { read } for comm="loop0" path="/mnt/android-8.1-r2/system.img" dev="vda2" ino=1422631 scontext=u:r:kernel:s0 tcontext=u:object_r:unlabeled:s0 tclass=file permissive=1
08-16 19:24:39.281  1022  1022 I loop0   : type=1400 audit(0.0:3395): avc: denied { read } for path="/mnt/android-8.1-r2/system.img" dev="vda2" ino=1422631 scontext=u:r:kernel:s0 tcontext=u:object_r:unlabeled:s0 tclass=file permissive=1
08-16 19:24:39.289  2671  2691 D SubscriptionController: [getPhoneId] asked for default subId=-1
08-16 19:24:39.290  2671  2691 D SubscriptionController: [getSubId]- invalid slotIndex=-1
08-16 19:24:39.336 18931 18931 D *** Loader::onCreate ***: PERMISSION_GRANTED
08-16 19:24:39.336 18931 18931 D *** getListFiles ***: [W]/sdcard/Download/FDroid.apk
08-16 19:24:39.336 18931 18931 D *** getListFiles ***: [W]/sdcard/Download/javasrv.apk

编辑4: 这就是我请求权限的 activity 的启动方式:

Intent intent = new Intent(this, LoaderActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the activity to be cleared before the activity is started. That is, the activity becomes the new root of an otherwise empty task, and any old activities are finished. This can only be used in conjunction with FLAG_ACTIVITY_NEW_TASK.
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);

编辑 5: 天啊!我刚刚反编译了生成的 apk 并注意到我的 android:versionCodeandroid:versionName 变成了 platformbuildversioncodeplatformbuildversionname 分别。这太疯狂了!我想知道这到底是怎么发生的。 已添加: 哦哦。它与 aapt2 的版本有某种关系。我使用了 build-tools 28.0.3。将其更改为 26.0.2,它的行为没有那种疯狂。

编辑 6: 由于 aapt2 的错误,我恢复到 aapt。至少它不会把清单弄乱太多:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:minSdkVersion="23" android:targetSdkVersion="26" package="com.javasrv" platformBuildVersionCode="26" platformBuildVersionName="8.0.0">

出于某种原因,它删除了我的应用自定义版本号和版本代码。但至少这不应该影响应用程序的工作。 我仍在努力解决的问题是,由于在包 android[=105= 中未找到 compileSdkVersion 的相同错误,我无法指定 compileSdkVersion ].

编辑 7: 好的。这是我从最终 apk(我使用 aapt2 v26 构建)反编译的清单的头部:

<?xml version="1.0" encoding="utf-8" standalone="no"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" android:minSdkVersion="23" android:targetSdkVersion="26" package="com.javasrv">
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

所以唯一缺少的就是compileSdkVersion。我仍然无法弄清楚如何让 aapt2 将该值放入清单中。但是我测试了那个 apk 并且运行时权限的错误仍然存​​在。很奇怪。

编辑 8: 安装了最新的 aapt2 版本。来自这里:https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/3.6.0-alpha11-5720371/aapt2-3.6.0-alpha11-5720371-linux.jar 还是一样——它不会插入 compileSdkVersion.

编辑 9: 实际上很明显 compiledSdkVersion 不在我使用的命名空间中。我也无法在文档中的任何地方找到它:https://developer.android.com/guide/topics/manifest/uses-sdk-element 在我看来,我根本不应该使用它——实际上我看不出它有任何用途。如果我可以指定最低版本和目标版本,谁在乎我编译我的应用程序的版本?所以错误应该在其他地方。

编辑 10: Android 支持库更新至 24.1.1 版本。检查运行时权限仍然不走运。

编辑 11: 尝试调用 requestPermissions,即使它错误地将其检测为 GRANTED 并出现运行时错误:找不到类 android.support.v4.app.ActivityCompatApi23。有趣的... 嗯。显然我应该使用与我的 SDK 相同版本的 Android 支持库。但我不清楚如何获得最新版本支持库的 jar(参见 Install latest android support library CLI) 嗯是的。从 24.1.1 的 aar 中提取 jar 文件可能是个坏主意——显然它不是整个库,而只是一个补丁。所以我决定使用一些人编译的 jar 23.2.1:https://github.com/pbakondy/cordova-plugin-android-support-v4-jar

编辑 12: 随着 v23.2.1 android 支持库回到原位,我决定在使用 PERMISSION_GRANTED 消息调用 Log.d 后立即调用 requestPermissions。这是输出:

08-17 12:50:15.132 28837 28837 D *** Loader::onCreate ***: PERMISSION_GRANTED
08-17 12:50:15.136 28837 28891 I com.javasrv: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
08-17 12:50:15.139  2219  2600 I ActivityManager: START u0 {act=android.content.pm.action.REQUEST_PERMISSIONS pkg=com.google.android.packageinstaller cmp=com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity (has extras)} from uid 10081
08-17 12:50:15.141  2219  2600 I wm_task_moved: [179,1,6]
08-17 12:50:15.142  2219  2600 I am_create_activity: [0,28890900,179,com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,android.content.pm.action.REQUEST_PERMISSIONS,NULL,NULL,8388608]
08-17 12:50:15.147  2219  2600 I am_pause_activity: [0,43511476,com.javasrv/.LoaderActivity]
08-17 12:50:15.182  2446  2446 V StatusBar: setLightsOn(true)
08-17 12:50:15.183 28837 28837 I am_on_resume_called: [0,com.javasrv.LoaderActivity,LAUNCH_ACTIVITY]
08-17 12:50:15.254 28837 28873 W cr_media: Requires BLUETOOTH permission
08-17 12:50:15.273 28837 28837 I am_on_paused_called: [0,com.javasrv.LoaderActivity,handlePauseActivity]
08-17 12:50:15.284  2219  2259 I am_restart_activity: [0,28890900,179,com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity]
08-17 12:50:15.285  2219  2259 I am_set_resumed_activity: [0,com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,minimalResumeActivityLocked]
08-17 12:50:15.291  2219  2298 I sysui_count: [window_time_0,3]
08-17 12:50:15.291  2219  2298 I sysui_multi_action: [757,803,799,window_time_0,802,3]
08-17 12:50:15.297  2446  2446 V StatusBar: setLightsOn(true)
08-17 12:50:15.304  2219  5022 I am_finish_activity: [0,28890900,179,com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity,app-request]
08-17 12:50:15.305  2219  5022 I am_pause_activity: [0,28890900,com.google.android.packageinstaller/com.android.packageinstaller.permission.ui.GrantPermissionsActivity]
08-17 12:50:15.308  2219  2298 I sysui_count: [window_time_0,0]
08-17 12:50:15.308  2219  2298 I sysui_multi_action: [757,803,799,window_time_0,802,0]
08-17 12:50:15.439  2219  2259 I am_set_resumed_activity: [0,com.javasrv/.LoaderActivity,resumeTopActivityInnerLocked]
08-17 12:50:15.446  2219  2259 I am_resume_activity: [0,43511476,179,com.javasrv/.LoaderActivity]
08-17 12:50:15.457  2219  2298 I sysui_count: [window_time_0,0]
08-17 12:50:15.457  2219  2298 I sysui_multi_action: [757,803,799,window_time_0,802,0]
08-17 12:50:15.557  2446  2446 I chatty  : uid=10030(com.android.systemui) identical 5 lines
08-17 12:50:15.594  2446  2446 V StatusBar: setLightsOn(true)

没有出现对话框。看起来系统让应用程序认为权限已被授予。

我想知道为什么......清单肯定有问题,但是什么?

我将通过 apkanalyzer 输出整个清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:minSdkVersion="23"
    android:versionCode="6"
    android:versionName="1.0.0"
    android:targetSdkVersion="26"
    package="com.javasrv">

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

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

    <application
        android:label="@ref/0x7f060000"
        android:icon="@ref/0x7f020000">

        <activity
            android:theme="@ref/0x010300f0"
            android:label="@ref/0x7f060000"
            android:name="com.javasrv.MainActivity">

            <intent-filter>

                <action
                    android:name="android.intent.action.MAIN" />

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

        <activity
            android:theme="@ref/0x010300f0"
            android:label="@ref/0x7f060000"
            android:name="com.javasrv.LoaderActivity">

            <intent-filter>

                <action
                    android:name="android.intent.action.MAIN" />

                <category
                    android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

        <activity
            android:theme="@ref/0x01030011"
            android:label="@string/0xb"
            android:icon="@ref/0x7f010000"
            android:name="com.javasrv.TestActivity"
            android:screenOrientation="1">

            <intent-filter>

                <action
                    android:name="android.intent.action.MAIN" />

                <category
                    android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

        <service
            android:name=".MyTestService" />

        <service
            android:name=".MyJobService"
            android:permission="android.permission.BIND_JOB_SERVICE" />

        <receiver
            android:name="Boot">

            <intent-filter
                android:priority="100">

                <action
                    android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

有什么想法吗?

问题已解决

也许这对你有帮助。

只需在您的应用程序中设置 gradle 您的 compileSdkVersion 和 targetSdkVersion 为 26。

如果 checkpermission 不起作用,您可以尝试对话框权限

当您的应用从 checkSelfPermission() 收到 PERMISSION_DENIED 时,您需要提示用户获得该权限。 Android 提供了几种可用于请求权限的方法,例如 requestPermissions()。

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

然后覆盖方法

  @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case 1: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // permission was granted

            } else {
                // permission denied

                Toast.makeText(BiggerScreen.this, "Permission denied to write your External storage", Toast.LENGTH_SHORT).show();
            }
            return;
        }
        // other 'case' lines to check for other
        // permissions this app might request
    }
}

哇。一直以来,问题都出在 AndroidManifest.xml 上。我在错误的地方指定了 minSdkVersion。我应该在 uses-sdk xml 标签中做到这一点,而不是在 manifest 标签中,就像在 Android开发者网站是这样写的:https://developer.android.com/guide/topics/manifest/uses-sdk-element

我不知道我从哪里得到这些属性应该写在 manifest 标签中的想法。也许这就是 gradle 正在做的 - 它在编译 apk 时传输属性..

编辑: 此外,必须在授予 权限后重新启动应用程序。否则,checkSelfPermission 将通知已授予访问权限,但应用程序将无权访问文件: