在 Xposed 模块下优雅的调用宿主——对象篇

在 Xposed 模块下优雅的调用宿主——对象篇

前言

通过之前 讨论 Xposed 模块的类和宿主中的类 中我们已经知道,Xposed 模块是无法直接在项目里添加Stub包,然后直接使用宿主的类对象。所以这篇文章的想法就是怎么在这么苛刻的环境下能直接使用Stub包下的类对象。

需求

宿主中存在代码(宿主代码一般通过反编译等手段获取,得到的一般是 Java 代码,因此实例直接用 Java 写了)

class Param {
    @NonNull
    @Override
    public String toString() {
        return "一些操作";
    }
}

public class Host {
    void api(Param param) {
        System.out.println(param.toString());
    }
}

需求是在 Xposed 代码中创建一个Param对象,然后将其放入api参数中。

传统方法

通过反射Param类获取构造方法,构造完了,反射执行api函数了

fun main() {
    // 在模块中我们只能拿到这些对象
    val host: Any = Host()
    val paramClass: Class<*> = Param::class.java
    val hostClass: Class<*> = Host::class.java

    // 下面是处理逻辑
    val constructor = paramClass.getDeclaredConstructor()
    constructor.isAccessible = true
    val param = constructor.newInstance()
    val method = hostClass.getDeclaredMethod("api", paramClass)
    method.isAccessible = true
    method.invoke(host, param)
}
缺点:
  1. 步骤繁多,代码可观性很低
  2. 拿到的始终是一个Object对象,完全不好管理

优化思路

  1. 让模块加载宿主的类对象
  2. 想个法子继承宿主类
  3. 全程通过反射进行代理

结果

思路1:让模块加载宿主的类对象

因为模块Classloader中的父亲(不是继承)并不是宿主Classloader。因此即使真的加载了宿主的类,两个类对象由于Classloader不同也不会相同,就不能直接赋值。

思路2:想个法子 继承宿主类

在插件的代码中的所有能直接引用的类都由模块Classloader加载

即使通过动态构建,继承了宿主类,也无法在代码直接引用,得到的还是一个 Object

思路3:全程通过反射进行代理

即编写一个代理类

class ParamProxy(private val param: Any?) {
    val instance get() = param
	
    // 下面可以通过反射调用 `instance` 里面的一些方法
    /// ...
}

param对象封装起来,需要用到的时候可以直接使用 ParamProxy.instance进行调用。而且我们可以直接封装起来

abstract class OpenProxy(private val param: Any?) {
    val instance get() = param
}

让任何有需要的代理类继承这个类

可以在写一个HostProxy

class ParamProxy(param: Any?) : OpenProxy(param) {

}

class HostProxy(param: Any?): OpenProxy(param) {
    fun api(paramProxy: ParamProxy) {
        val param = paramProxy.instance
        // 用反射进行执行方法
    }
}

abstract class OpenProxy(private val obj: Any?) {
    val instance get() = obj
}

优点是代码可观性提高很多,反射之类的活全部封装起来。如果使用动态代理+注解进行处理的话,代码量和Stub库多不了多少

fun main() {
    // 在模块中我们只能拿到这些对象
    val host: Any = Host()
    val paramClass: Class<*> = Param::class.java
    val hostClass: Class<*> = Host::class.java

    // 下面是处理逻辑
    val constructor = paramClass.getDeclaredConstructor()
    constructor.isAccessible = true
    val param = constructor.newInstance()
    val paramProxy = ParamProxy(param)
    val hostProxy = HostProxy(host)
    hostProxy.api(paramProxy)
}

缺点也很显然,事实上不好做构造函数的处理,而且内部如果不做缓存效率会慢上一点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值