> ## Content Index
> Fetch the complete content index at: https://sgpublic.xyz/llms.txt
> Use this file to discover other available public pages before exploring further.

# Android 反射调用 SDK 隐藏方法抛错 NoSuchMethodError
- URL: https://sgpublic.xyz/p/2024/01/6aac9cb1810a4800015335f6/
- Published: 2024-01-04T07:00:36.000Z
- Updated: 2024-01-04T07:00:36.000Z
- Author: Haven Madray
- Tags: 软件开发, Android, #wp-post

> 参考文章：[针对非 SDK 接口的限制 | Android 开发者 | Android Developers](https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces?ref=sgpublic.xyz)

最近在写 Android 系统应用的时候，因为某些特殊原因无法接触到 AOSP 开发环境，只能通过第三方应用 + 系统签名的方式调试。

其中一个功能是要通过 EthernetManager 获取到 configuration，于是乎首先用先前在 Android 8.0 上的经验，用反射的方式调用方法：

```
EthernetManager.getMethod("getConfiguration", String::class.java)
    .invoke(getSystemService("ethernet"), target) ?: IpConfiguration.newInstance()

```

但是这段代码抛错 `NoSuchMethodError`，直接列举所有方法也只有屈指可数的少数几个方法：

```
12:29:38.203 ReflectTest D  android.net.EthernetManager declaredMethods: enableEthernet(arg0: boolean): void
12:29:38.203 ReflectTest D  android.net.EthernetManager declaredMethods: getDns(arg0: java.lang.String): java.lang.String
12:29:38.203 ReflectTest D  android.net.EthernetManager declaredMethods: getGateway(arg0: java.lang.String): java.lang.String
12:29:38.203 ReflectTest D  android.net.EthernetManager declaredMethods: getIpAddress(arg0: java.lang.String): java.lang.String
12:29:38.203 ReflectTest D  android.net.EthernetManager declaredMethods: getNetmask(arg0: java.lang.String): java.lang.String
12:29:38.203 ReflectTest D  android.net.EthernetManager declaredMethods: getState(): int
12:29:38.204 ReflectTest D  android.net.EthernetManager declaredMethods: requestTetheredInterface(arg0: java.util.concurrent.Executor, arg1: android.net.EthernetManager.TetheredInterfaceCallback): android.net.EthernetManager.TetheredInterfaceRequest
12:29:38.204 ReflectTest D  android.net.EthernetManager methods: enableEthernet(arg0: boolean): void
12:29:38.204 ReflectTest D  android.net.EthernetManager methods: equals(arg0: java.lang.Object): boolean
12:29:38.204 ReflectTest D  android.net.EthernetManager methods: getClass(): java.lang.Class
12:29:38.204 ReflectTest D  android.net.EthernetManager methods: getDns(arg0: java.lang.String): java.lang.String
12:29:38.204 ReflectTest D  android.net.EthernetManager methods: getGateway(arg0: java.lang.String): java.lang.String
12:29:38.204 ReflectTest D  android.net.EthernetManager methods: getIpAddress(arg0: java.lang.String): java.lang.String
12:29:38.204 ReflectTest D  android.net.EthernetManager methods: getNetmask(arg0: java.lang.String): java.lang.String
12:29:38.204 ReflectTest D  android.net.EthernetManager methods: getState(): int
12:29:38.205 ReflectTest D  android.net.EthernetManager methods: hashCode(): int
12:29:38.205 ReflectTest D  android.net.EthernetManager methods: notify(): void
12:29:38.205 ReflectTest D  android.net.EthernetManager methods: notifyAll(): void
12:29:38.205 ReflectTest D  android.net.EthernetManager methods: requestTetheredInterface(arg0: java.util.concurrent.Executor, arg1: android.net.EthernetManager.TetheredInterfaceCallback): android.net.EthernetManager.TetheredInterfaceRequest
12:29:38.205 ReflectTest D  android.net.EthernetManager methods: toString(): java.lang.String
12:29:38.205 ReflectTest D  android.net.EthernetManager methods: wait(): void
12:29:38.205 ReflectTest D  android.net.EthernetManager methods: wait(arg0: long): void
12:29:38.205 ReflectTest D  android.net.EthernetManager methods: wait(arg0: long, arg1: int): void

```

代码跑在 Android 12 上，于是乎考虑是否是新增了什么特性限制了反射。查阅文档，发现是在 Android 9 开始新增了 [针对非 SDK 接口的限制](https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces?ref=sgpublic.xyz)，我遇到的情况正好符合 [访问受限的非 SDK 接口时可能会出现的预期行为](https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces?hl=zh-cn&ref=sgpublic.xyz#results-of-keeping-non-sdk)。

仔细查阅日志确实有这么一段：

```
14:01:42.489 ttingspppoetes                  W  Accessing hidden method Landroid/net/EthernetManager;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration; (max-target-r, reflection, denied)

```

由于我这里的目的仅仅是本地调试，本地能调用到就行了，调试完成后再尝试修改代码并入开发环境，因此我们可以按照 [如何允许访问非 SDK 接口？](https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces?hl=zh-cn&ref=sgpublic.xyz#how%5Fcan%5Fi%5Fenable%5Faccess%5Fto%5Fnon-sdk%5Finterfaces) 中介绍的方法：

Android 10 及以上使用：

```
adb shell settings put global hidden_api_policy 1

```

Android 9 及以下使用：

```
adb shell settings put global hidden_api_policy_pre_p_apps  1
adb shell settings put global hidden_api_policy_p_apps 1

```

设置完成后再次运行代码，反射就能正常使用了，查阅日志变为了：

```
14:01:42.489 ReflectTest W  Accessing hidden method Landroid/net/EthernetManager;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration; (max-target-r, reflection, allowed)

```