有時在開發 Android app 時,可能會想使用非公開的 API (就是有註解為 @hide),這時候可以使用 Java 的 Reflection 機制來達成。本文並不討論此機制的原理,有興趣的網友可以自行 GOOGLE。
在 Android 要使用 Reflection 機制有兩項前提,分別是:
1. 必須要知道要使用的 API 其完整 class name 及 method name,class name 要包含 package name
2. 使用此 API 所需的 permission ( 加在 AndroidManifest 的)
其實上述這兩點只要看 source code 就可以知道了,而網路上都有 source code 可以看,所以應該不是什麼大問題… 底下是一個簡單的範例:
上面的程式碼用來開啟 WIFI AP,因為這些 method 是不公開的,所以要用這個 method 就要用 Reflection。我們可以看到,Class.forName 要帶的參數是要取得的 class name,一般情形可以用 class.getName() 來取得。假如整個 class 都是 hide 的話,就要從 source code 取得 class name。因此
可以改成以下型式:
Class 的 getMethod 就是用來取得想使用的 method。第一個參數代表 method name,之後的參數表示此 method 所傳入的參數型態
代表 setWifiApEnabled 這個 method 需要兩個參數,一個是 WifiConfiguration object,另一個是 boolean 值。不帶參數及帶參數的 method 取得分別如下:
最後就是 invoke method:
大概就是這樣吧...
P.S. 我個人覺得這跟 JNI 很像,懂其中一種應該另一種會學很快吧XD
參考資料
1. java.lang.Class
2. java.lang.reflect.Method
---
在 Android 要使用 Reflection 機制有兩項前提,分別是:
1. 必須要知道要使用的 API 其完整 class name 及 method name,class name 要包含 package name
2. 使用此 API 所需的 permission ( 加在 AndroidManifest 的)
其實上述這兩點只要看 source code 就可以知道了,而網路上都有 source code 可以看,所以應該不是什麼大問題… 底下是一個簡單的範例:
WifiManager wifiMgr = (WifiManager) getSystemService(Context.WIFI_SERVICE); WifiConfiguration wifiConfig = null; try { Class WifiMgrClz = Class.forName(WifiManager.class.getName()); Method getWifiApCOnfiguration = WifiMgrClz.getMethod("getWifiApConfiguration"); wifiConfig = (WifiConfiguration) getWifiApCOnfiguration.invoke(wifiMgr); Class[] paramOfClass = new Class[2]; paramOfClass[0] = WifiConfiguration.class; paramOfClass[1] = Boolean.TYPE; Method setWifiApEnabled = WifiMgrClz.getMethod("setWifiApEnabled", paramOfClass); Object[] paramOfObject = new Object[2]; paramOfObject[0] = wifiConfig; paramOfObject[1] = Boolean.valueOf(true); setWifiApEnabled.invoke(wifiMgr, paramOfObject); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }
上面的程式碼用來開啟 WIFI AP,因為這些 method 是不公開的,所以要用這個 method 就要用 Reflection。我們可以看到,Class.forName 要帶的參數是要取得的 class name,一般情形可以用 class.getName() 來取得。假如整個 class 都是 hide 的話,就要從 source code 取得 class name。因此
Class WifiMgrClz = Class.forName(WifiManager.class.getName());
可以改成以下型式:
Class WifiMgrClz = Class.forName(“android.net.wifi.WifiManager”);
Class 的 getMethod 就是用來取得想使用的 method。第一個參數代表 method name,之後的參數表示此 method 所傳入的參數型態
Class[] paramOfClass = new Class[2]; paramOfClass[0] = WifiConfiguration.class; paramOfClass[1] = Boolean.TYPE;
代表 setWifiApEnabled 這個 method 需要兩個參數,一個是 WifiConfiguration object,另一個是 boolean 值。不帶參數及帶參數的 method 取得分別如下:
Method getWifiApCOnfiguration = WifiMgrClz.getMethod("getWifiApConfiguration");
Method setWifiApEnabled = WifiMgrClz.getMethod("setWifiApEnabled", paramOfClass);再來就是 Method 的 invoke method,第一個參數表示要 invoke 此 method 的 class object,依上面的例子就是 WifiManager instance object,假如要呼叫的是 static method,則可以帶入 null 省略。第二個參數就是表示實際要傳入此 method 的參數:
Object[] paramOfObject = new Object[2]; paramOfObject[0] = wifiConfig; paramOfObject[1] = Boolean.valueOf(true);
最後就是 invoke method:
setWifiApEnabled.invoke(wifiMgr, paramOfObject);
大概就是這樣吧...
P.S. 我個人覺得這跟 JNI 很像,懂其中一種應該另一種會學很快吧XD
參考資料
1. java.lang.Class
2. java.lang.reflect.Method
---
留言
張貼留言