!!!出现问题:当普通应用通过SDK调用接口时遇见AndroidRuntime: java.lang.NoSuchMethodError: No virtual method
得知:Android 中接口访问控制规则说明
在 Android 系统开发中,不同包名下的接口默认访问权限是不一样的。以下是详细的说明。
1. frameworks/base/core/java/android.*
包下新增的接口
- 默认访问权限:公开(public)
- 是否可被普通应用直接访问:✅ 是
- 说明 :
- 这些接口属于系统公开 API。
- 普通应用可以直接调用这些类和方法。
- 系统应用可以直接调用这些类和方法。
示例:
java
package android.app;
public class MyManager {
public void doSomething() { ... }
}
该方法 doSomething()
可以被任意普通 App 调用。
2. 其他包下新增的接口(如 frameworks/base/core/java/com/android/server
, frameworks/base/core/java/com/android/internal
,只要不是 frameworks/base/core/java/android.*
都是默认隐藏的接口)
- 默认访问权限:隐藏(hidden)
- 是否可被普通应用直接访问:❌ 否
- 是否可被系统应用直接访问:✅ 是
- 说明 :
- Android 从 10 开始加强了对隐藏 API 的限制(Hidden API Policy)。
- 即使你在 SDK 中能看到这些类或方法,运行时也会被限制访问。
- 只有系统应用能正常访问
3. 如何开放隐藏接口给普通应用?
使用注解:
java
@UnsupportedAppUsage
作用:
- 标记该方法为"被系统使用",并允许通过反射等方式被普通应用访问。
- 在构建时,该注解会保留到
public-api.xml
或system-api.xml
中,避免被标记为 hidden。
示例:
java
package com.android.server.myfeature;
import android.annotation.UnsupportedAppUsage;
public class MyInternalService {
@UnsupportedAppUsage
public void exposeToApp() {
// 可以被普通 App 调用
}
}
添加此注解后,普通应用可以通过以下方式调用:
- 反射调用;
- 在调试模式下(开启
--runtime-flags allow-incompatible-changes
)直接调用。
⚠️ 注意事项
项目 | 说明 |
---|---|
注解用途 | 用于兼容性过渡,不建议长期依赖 |
兼容性风险 | 使用隐藏 API 有版本升级不兼容的风险 |
官方推荐 | 如果需要开放接口,应申请加入 SDK Public API |
Android 版本限制 | Android 10 及以上加强了 hidden API 控制,需特别注意 |
🧩 延伸建议
如果你是在系统框架层修改代码,并希望某个接口能被第三方 App 调用,请确保:
- 接口所在的类/包不是
@hide
; - 方法上加上
@UnsupportedAppUsage
; - 构建时确认其出现在
public-api.xml
中; - App 编译时能找到对应的类和方法(可通过反射或定制 framework.jar)。