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)- 1
- 2
可以看到,兩個重載方法都需要傳遞一個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); }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
簡單來講,接口類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)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
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)- 1
- 2
- 3
- 4
通過反射獲取其中一個連接Wi-Fi的方法:public void connect(WifiConfiguration config, ActionListener listener),然后調用。需要注意的是,該方法的第一個參數是WifiConfiguration類型的,所以需要各位自己去創建了,創建過程比較麻煩,可以參考網絡,我有空的話再寫一篇文章,哈哈。
3.總結
好了,具體實現方法已經記錄完畢,剩下的估計就是一些參數的創建,和回調方法中的具體代碼邏輯了,最后,再歸納一下步驟吧:
1. 獲取接口類的類型,方法:反射獲取或者類::java.class
2. 繼承實現接口InvocationHandler
3. 創建代理Proxy,作用是關聯第一步中的接口類和第二步中的InvocationHandler
4. 反射獲取隱藏方法connect()并調用
總結
以上是生活随笔為你收集整理的Android 反射、代理调用系统隐藏API方法与接口类连接Wi-Fi的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android开源框架源码鉴赏:Fres
- 下一篇: [Android]你不知道的Androi