Physical Address:
ChongQing,China.
WebSite:
近期在将某个原生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。