android源碼中有很多hide的接口,編碼時無法直接調用. 怎么辦呢? 首先明確一點:hide標記只影響編譯時,不影響運行時,只要編譯能通過,運行時就能正常訪問hide標記的接口,因此,只需要確保調用hide接口能編譯通過即可,通常有三種做法:
- 基于android源碼編譯
- 修改源碼,去除hide標記,并編譯成framework.jar導入項目中
- 反射
其中方法1,2操作比較復雜,通常很少使用
調用hide接口或者傳入hide類型的參數,都可通過上述方式完成。如果接口接受hide類的回調參數呢?例如:
PackageManager.installPackage(String packageName, android.pm.content.IPackageInstallObjsever observer, int flag)
這個方法中IPackageInstallObserver就是個hide接口,除了上述方法1,2外,沒法直接創建子類來實現回調方法. 要解決這個問題,除了還有以下通過如下方式:
copy接口到自己到項目下,且保持包名,類名不變
在自己項目里創建一個與回調接口類相同的包名+類名, 并且創建回調方法,這里不需要創建所有的方法,只需要自己感興趣的回調方法就行了, 如只需要在自己創建的IPackageInstallObserver類中添加方法packageInstalled(String pkgName, int errorCode)
這樣編譯的時候就能在編譯路徑中找到IPcakageInstallObsever類了,編譯成功。但是運行時就存在兩個相同的類了,不會產生沖突么?答案是不會,因為framework中的IPackageInstallObsever類的ClassLoader是SystemClassLoader,而自己代碼是在PathClassLoader中,PathClassLoader的parent是SystemClassLoader, 根據類加在雙親委派機制,查找類時先有parent ClassLoader決定是否能加在,如果parent加在類,child就不再加載,顯然,framework中的IPackageInstallObserver會由SystemClassLoader加載,自己創建的IPackageInstallObserver會被當作相同的類,不會再加載,因此,運行時的IPackageInstallObsever一定是來自framework,而不是自己創建的那個,這也是為什么不需要添加所有的回調方法,因為運行時壓根就不會理會自己創建的類,它的目的就是為了保證編譯通過,只需要包名,類名相同就行了。
使用這種方式需要特別注意一點就是:混淆時一定要keep住回調接口,因為它屬于項目私有空間,回調方法默認會被混淆掉,運行時就會出現找不到回調方法掉的異常了。