利用Java Reflection來呼叫被隱藏{@hide}的API

如果您有研究過Android Source Code,應該會發現其中有許多函式都被標註了@hide。也就是這些函式在SDK中是被隱藏的,一般情形下無法被呼叫使用。但有時我們又想使用這些功能該怎麼辦呢? 在不更動Android System的前提下,我們可以透過Java的反射機制(Java Reflection)來達成。

範例:
我們在Android Source Code中的PackageManager類別裡發現了一個函式getPackageSizeInfo,可以用來取得應用程式的磁碟空間使用量,但在SDK內卻找不到此函式。

我們先試著用getMethods列出PackageManager中所有的函式
PackageManager pm = getPackageManager();
Method[] methods = pm.getClass().getMethods();
for (int i = 0; i < methods.length; i++)
{
    Log.d(TAG, methods[i].getName());
}

看一下結果,沒錯,裡面確實有getPackageSizeInfo這個函式


調用方式:
Method getPackageSizeInfo = pm.getClass().getMethod(
    "getPackageSizeInfo", String.class, IPackageStatsObserver.class);

getPackageSizeInfo.invoke(pm, "xxx.xxx.xxx", new IPackageStatsObserver.Stub() {
        @Override
        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
            throws RemoteException {
            Log.d(TAG, "codeSize: " + pStats.codeSize + " dataSize: " + pStats.dataSize + " cacheSize: " + pStats.cacheSize);
        }
    });

首先用getMethod透過名稱"getPackageSizeInfo"來取得函式,後面的String.class與IPackageStatsObserver.class是getPackageSizeInfo的參數型態(由Android Source Code得知)。
接著用invoke來實際調用,"xxx.xxx.xxx"是你想取得磁碟空間資料的應用程式package name,IPackageStatsObserver裡面則有一個onGetStatsCompleted的Callback會返回PackageStats資料。

過程中你會發現編譯器並不認識IPackageStatsObserver與PackageStats,
此時我們需要在專案中建立android.content.pm這個package,
並將Android Source Code\frameworks\base\core\java\android\content\pm目錄中的IPackageDataObserver.aidl與PackageStats.aidl複製到其中,剩下的ADT會自動處理。


另外,要使用getPackageSizeInfo必須於AndroidManifest.xml設定下面這個權限:
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />

執行,再看一次結果,確實取得了磁碟使用空間的資料。


總結:
使用Java的反射機制確實可以讓我們做到更多事情,但同時也要自負風險,畢竟官方將某些函式隱藏也許有他的理由。
另外,有些函式雖然可以被反射到,但裡面可能做了其他的防護(如限制Permission或檢查PID之類的),所以也不見得100%能被使用。

補充:
若是Class本身被隱藏的話,也可以用下面的方式透過名稱取出。
Class hideClass = Class.forName("android.xxx.xxx");

參考資料:
http://www-jo.se/f.pfleger/android-package-size
http://www.blogjava.net/zh-weir/archive/2011/03/26/347063.html

這個網誌中的熱門文章

Android Studio 如何調整字型大小

App在Google Play被停權與恢復的經驗分享

Android Studio 無法在實機上 Run/Debug 程式?