Android SDK Hidden API使用

Android SDK Hidden API的使用方法
Views: 591
2 0
Read Time:1 Minute, 58 Second

近期在将某个原生APP从AOSP源码环境编译转变为Android Studio下Gradle编译,其中涉及到一个API接口registerReceiverForAllUsers,在编译时报错该方法不存在。

经查,该方法实现位于frameworks/base/core/java/android/content/Context.java文件内,代码如下:

/**
     * Same as {@link #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)}
     * but this receiver will receive broadcasts that are sent to all users. The receiver can
     * use {@link BroadcastReceiver#getSendingUser} to determine on which user the broadcast
     * was sent.
     *
     * @param receiver The BroadcastReceiver to handle the broadcast.
     * @param filter Selects the Intent broadcasts to be received.
     * @param broadcastPermission String naming a permissions that a
     *      broadcaster must hold in order to send an Intent to you. If {@code null},
     *      no permission is required.
     * @param scheduler Handler identifying the thread that will receive
     *      the Intent. If {@code null}, the main thread of the process will be used.
     *
     * @return The first sticky intent found that matches <var>filter</var>,
     *         or {@code null} if there are none.
     *
     * @see #registerReceiver(BroadcastReceiver, IntentFilter, String, Handler)
     * @see #sendBroadcast
     * @see #unregisterReceiver
     * @hide
     */
    @Nullable
    @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
    @SystemApi
    public Intent registerReceiverForAllUsers(@Nullable BroadcastReceiver receiver,
            @NonNull IntentFilter filter, @Nullable String broadcastPermission,
            @Nullable Handler scheduler) {
        throw new RuntimeException("Not implemented. Must override in a subclass.");
}

可以看到虽然该方法具有public属性,但是却通过@hide标识其会作为一个Hidden api而存在;从android 9开始(API级别属于28),为了帮助提升用户体验和开发者体验,为用户降低应用发生崩溃的风险,同时为开发者降低紧急发布的风险,Android对应用的非SDK接口做了限制,使用非SDK接口,或通过反射、JNI的方式来使用非SDK接口将不被允许,关于该限制的更多信息可以参考该Link

如何区分SDK接口和非SDK接口呢,SDK接口是在https://developer.android.com/reference/packages中公开可查询的稳定提供的接口,而非SDK接口通常是不稳定的,所以不会对外开放,关于这些非SDK接口的信息,可以参考该Link

在实际开发过程中,我们可能会用到这些Hidden API,以往我们可以通过反射的方式来调用这些API,但这种方法在新的安卓系统中已经不再适用,那么还有没有办法可以绕开该限制呢。这里以两种情形教大家如何去调用Hidden API。

情形一:AOSP源码环境下使用Android.bp配置编译环境

在AOSP源码环境下调用Hidden API,一般我们只需要进行两个步骤即可。一是在Android.bp中配置相关权限,二是在AndroidManifest.xml中对相关权限进行声明。针对registerReceiverForAllUsers接口,我们需要配置Android.bp如下:

android_app {
    name: "App_Name",

    owner: "google",

    srcs: ["src/**/*.java"],

    resource_dirs: ["res"],

    // registerReceiverForAllUsers() is a hidden api.need this setting
    platform_apis: true,

}

信息来源于谷歌官方Link

At build time, Make and Soong verify that Java modules in the product partition don't use hidden APIs by checking the platform_apis and sdk_version fields. The sdk_version of apps in the product partition must be filled with current, system_current, or numeric version of the API, and the platform_apis field must be empty

除了Android.bp中进行配置,我们还需要进行权限相关的声明:

<!-- for registerReceiverForAllUsers() -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />

具体需要的权限,请查看该接口实现的地方所作的定义。

情形二:Android Stuido环境下使用Gradle配置编译

当我们把源码放到Android Studio环境下进行编译时,同样需要在 AndroidManifest.xml中对相关权限进行声明,这一点同上。不过此时我们无法在Gradle配置中配置platform_apis属性了。

此时我们可以在AOSP环境下找到包含该SDK接口的android.jar,替换掉Android Studio下载的SDK中的${Android Sdk}/platforms/andorid-api/即可,在AOSP源码环境下有诸多android.jar,如何查看该android.jar是否包含该接口呢,这里我们使用jar命令进行查看,如下所示:

fanzkafkafka:$ jar xf android.jar | grep -nr registerReceiverForAllUsers
fanzkafkafka:$ Binary file android/content/ContextWrapper.class matches
fanzkafkafka:$ Binary file android/content/Context.class matches

如果你没有AOSP环境,我们可以通过一个GitHub项目来获取相应的Android.jar,具体可参考该项目

如此,我们就能正常使用Hidden API了。不过需要说明的是,Hidden API是官方明确不希望开发者使用的,可能会存在不稳定或者兼容性问题,我们应当尽可能避免使用这类API。

Happy
Happy
100 %
Sad
Sad
0 %
Excited
Excited
0 %
Sleepy
Sleepy
0 %
Angry
Angry
0 %
Surprise
Surprise
0 %
FranzKafka95
FranzKafka95

极客,文学爱好者。如果你也喜欢我,那你大可不必害羞。

Articles: 86

Leave a Reply

Your email address will not be published. Required fields are marked *

en_USEN