Android 反射、代理调用系统隐藏API方法与接口类连接Wi-Fi

Android 反射、代理调用系统隐藏API方法与接口类连接Wi-Fi

本文转载自:http://www.xwdoor.net/android-reflection-proxy-call-system-hidden-api-method-and-interface-class-wi-fi-connection/

有这样的需求:通过扫描二维码获取Wi-Fissid和密码,然后自动连接。我们先后出了两个版本,第一个版本,是通过网络搜索出来融合的初略版本,代码比较简陋,效果就是很多用户反馈联网的问题;第二个版本是我写的,基于充分了解联网逻辑的基础上,用kotlin实现的,效果马马虎虎,不过时不时还是有用户反馈联网的问题,大概1%左右吧;这次痛定思痛,采用反射调用系统framework的隐藏方法来实现连接wifi的功能。

因为是反射调用隐藏的方法 connect,且用到了一个隐藏的回调接口类ActionListener,所以在调用connect()方法前,需要先实现该接口,这就用到了委托、代理的原理

Note: 本文所有代码均是基于kotlin语言实现

1.实现 ActionListener 接口类

系统提供的连接wifi的方法有两个,分别是:

public void connect(WifiConfiguration config, ActionListener listener)
public void connect(int networkId, ActionListener listener)

可以看到,两个重载方法都需要传递一个ActionListener接口参数,这个接口的源代码如下:

/**
 * Interface for callback invocation on an application action
 * @hide
 */
public interface ActionListener {
    /** The operation succeeded */
    public void onSuccess();
    /**
     * The operation failed
     * @param reason The reason for failure could be one of
     * {@link #ERROR}, {@link #IN_PROGRESS} or {@link #BUSY}
     */
    public void onFailure(int reason);
}

简单来讲,接口类ActionListener有两个回调方法,分别是成功回调onSuccess和失败回调onFailure,跟我们平时使用的网络访问回调很像,麻烦在于它是隐藏的。

第一步,使用反射和代理实现 ActionListener 接口类,代码如下:

//通过反射获取 ActionListener 类
val actionListener = Class.forName("android.net.wifi.WifiManager\$ActionListener")
//实现 InvocationHandler 接口,所有的我们需要的回调方法,都是通过这个代理回调来实现的
//通过第二个参数可以判断回调的是什么方法
val invocationHandler = InvocationHandler { proxy, method, args ->
    Log.i("test", "代理回调: ${args.joinToString()}")
    //通过方法的名称判断回调的是什么方法
    if (method.name == "onSuccess") {
        Log.i("test", "联网成功")
        //等待获取ip地址
        Log.i("test", "wait ip address available")
    } else {
        Log.i("test", "联网失败: $args")
    }
}
//创建接口代理类,可以理解这个就是接口实现类(实现了接口 ActionListener 的类)
val proxy = Proxy.newProxyInstance(app.classLoader, arrayOf(actionListener), invocationHandler)

Note: ActionListener中有两个回调方法,这个时候我们可以通过第二个参数的属性值method.name来判断回调的是哪个方法

总结一下,创建代理的步骤如下:
1. 获取接口类的类型。如果是公开的(public),就直接类::java.class就行,比如:ActionListener::class.java,如果是隐藏的,就通过反射获取。
2. 实现接口InvocationHandlerActionListener中的回调方法的代码逻辑也是在里边实现。
3. 创建代理,关联ActionListenerInvocationHandler。此时的代理可以认为是ActionListener的实现类

一语概之,先通过反射获取隐藏接口类 ActionListener,然后通过代理实现该接口

2.获取 connect 方法实现联网操作

接下来就简单了,获取隐藏方法connect()连接Wi-Fi,代码如下:

//通过反射获取隐藏方法`connect()`
val connectMethod = context.wifiManager.javaClass.getDeclaredMethod("connect", WifiConfiguration::class.java, actionListener)
//第二个参数需要自己创建,具体的可以参考网络
connectMethod.invoke(context.wifiManager, config, proxy)

通过反射获取其中一个连接Wi-Fi的方法:public void connect(WifiConfiguration config, ActionListener listener),然后调用。需要注意的是,该方法的第一个参数是WifiConfiguration类型的,所以需要各位自己去创建了,创建过程比较麻烦,可以参考网络,我有空的话再写一篇文章,哈哈。

3.总结

好了,具体实现方法已经记录完毕,剩下的估计就是一些参数的创建,和回调方法中的具体代码逻辑了,最后,再归纳一下步骤吧:
1. 获取接口类的类型,方法:反射获取或者类::java.class
2. 继承实现接口InvocationHandler
3. 创建代理Proxy,作用是关联第一步中的接口类和第二步中的InvocationHandler
4. 反射获取隐藏方法connect()并调用

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值