Android 14下Byte Buddy Android抛出SecurityException问题求助
解决Android 10+中Byte Buddy的SecurityException问题及使用指南
问题根源
Android 10(API 29)及以上版本的安全政策禁止从应用可写私有目录加载DEX文件,你使用的AndroidClassLoadingStrategy.Wrapping策略会将生成的DEX写入app_generated这类可写目录,因此触发java.lang.SecurityException。
快速修复:改用内存加载策略
直接使用AndroidClassLoadingStrategy.InMemory策略,该策略在内存中生成并加载DEX,不落地文件,完美避开安全限制。修改后的代码如下:
private fun runBuddyTest(context: Context) { // 改用内存加载策略,无需指定目录 val strategy = AndroidClassLoadingStrategy.InMemory() // 创建动态类型(继承Object)并修改toString方法 val dynamicType = ByteBuddy() .subclass(Any::class.java) .method(ElementMatchers.named("toString")) .intercept(FixedValue.value("Hello World!")) .make() .load(this.javaClass.classLoader, strategy) .loaded // 实例化动态类并验证toString方法 val instance = dynamicType.getDeclaredConstructor().newInstance() assert(instance.toString() == "Hello World!") }
若需持久化动态类:使用代码缓存目录
如果必须将生成的DEX文件持久化,可以使用应用的codeCacheDir(专门存放可执行代码的目录,Android允许从这里加载DEX),并确保文件生成后设置为只读权限。示例代码:
private fun runBuddyTestWithPersistence(context: Context) { val codeCacheDir = context.codeCacheDir val strategy = AndroidClassLoadingStrategy.Wrapping(codeCacheDir) val dynamicType = ByteBuddy() .subclass(Any::class.java) .method(ElementMatchers.named("toString")) .intercept(FixedValue.value("Hello World!")) .make() .load(this.javaClass.classLoader, strategy) .loaded // 生成后修改文件权限为只读,符合安全政策要求 strategy.files.forEach { file -> file.setReadable(true, false) file.setWritable(false) file.setExecutable(false) } val instance = dynamicType.getDeclaredConstructor().newInstance() assert(instance.toString() == "Hello World!") }
Byte Buddy Android相关教程资源
- 官方核心文档:Byte Buddy官方文档包含Android模块专属章节,覆盖基础用法、类加载策略适配、方法拦截等核心场景,是最权威的学习资料。
- 官方示例代码:Byte Buddy仓库的Android模块包含多个可运行示例,展示动态代理、方法增强等场景的最佳实践。
- 基础API适配:先掌握Byte Buddy Java版核心API(如
subclass、method、intercept),再结合Android类加载机制调整策略,大部分Java场景用法可直接适配Android。
Gradle配置注意事项
确保依赖的byte-buddy-android为最新稳定版,避免版本兼容问题。若你的依赖管理未指定版本,可明确添加:
implementation 'net.bytebuddy:byte-buddy-android:2.14.11'
内容的提问来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

