您的位置:首页 > 移动开发 > Android开发

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

2017-12-16 10:29 1306 查看

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

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

有这样的需求:通过扫描二维码获取
Wi-Fi
ssid
和密码,然后自动连接。我们先后出了两个版本,第一个版本,是通过网络搜索出来融合的初略版本,代码比较简陋,效果就是很多用户反馈联网的问题;第二个版本是我写的,基于充分了解联网逻辑的基础上,用
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. 实现接口
InvocationHandler
ActionListener
中的回调方法的代码逻辑也是在里边实现。

3. 创建代理,关联
ActionListener
InvocationHandler
。此时的代理可以认为是
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()
并调用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android kotlin