android源碼中有很多hide的接口料按,編碼時無法直接調(diào)用. 怎么辦呢? 首先明確一點:hide標(biāo)記只影響編譯時,不影響運行時卓箫,只要編譯能通過载矿,運行時就能正常訪問hide標(biāo)記的接口,因此,只需要確保調(diào)用hide接口能編譯通過即可烹卒,通常有三種做法:
- 基于android源碼編譯
- 修改源碼闷盔,去除hide標(biāo)記,并編譯成framework.jar導(dǎo)入項目中
- 反射
其中方法1旅急,2操作比較復(fù)雜逢勾,通常很少使用
調(diào)用hide接口或者傳入hide類型的參數(shù),都可通過上述方式完成藐吮。如果接口接受hide類的回調(diào)參數(shù)呢溺拱?例如:
PackageManager.installPackage(String packageName, android.pm.content.IPackageInstallObjsever observer, int flag)
這個方法中IPackageInstallObserver就是個hide接口,除了上述方法1,2外炎码,沒法直接創(chuàng)建子類來實現(xiàn)回調(diào)方法. 要解決這個問題盟迟,除了還有以下通過如下方式:
copy接口到自己到項目下秋泳,且保持包名,類名不變
在自己項目里創(chuàng)建一個與回調(diào)接口類相同的包名+類名, 并且創(chuàng)建回調(diào)方法潦闲,這里不需要創(chuàng)建所有的方法,只需要自己感興趣的回調(diào)方法就行了, 如只需要在自己創(chuàng)建的IPackageInstallObserver類中添加方法packageInstalled(String pkgName, int errorCode)
這樣編譯的時候就能在編譯路徑中找到IPcakageInstallObsever類了迫皱,編譯成功歉闰。但是運行時就存在兩個相同的類了辖众,不會產(chǎn)生沖突么?答案是不會和敬,因為framework中的IPackageInstallObsever類的ClassLoader是SystemClassLoader凹炸,而自己代碼是在PathClassLoader中,PathClassLoader的parent是SystemClassLoader, 根據(jù)類加在雙親委派機制昼弟,查找類時先有parent ClassLoader決定是否能加在啤它,如果parent加在類,child就不再加載舱痘,顯然变骡,framework中的IPackageInstallObserver會由SystemClassLoader加載,自己創(chuàng)建的IPackageInstallObserver會被當(dāng)作相同的類芭逝,不會再加載塌碌,因此,運行時的IPackageInstallObsever一定是來自framework,而不是自己創(chuàng)建的那個旬盯,這也是為什么不需要添加所有的回調(diào)方法台妆,因為運行時壓根就不會理會自己創(chuàng)建的類,它的目的就是為了保證編譯通過胖翰,只需要包名,類名相同就行了接剩。
使用這種方式需要特別注意一點就是:混淆時一定要keep住回調(diào)接口,因為它屬于項目私有空間萨咳,回調(diào)方法默認(rèn)會被混淆掉搂漠,運行時就會出現(xiàn)找不到回調(diào)方法掉的異常了。