segmentfault.com/a/1190000002919135?
之前看到簡書Android客戶端使用的編輯器,甚是喜歡,它的優(yōu)雅以及高性能的特點讓我愛不釋手,很想自己也去做一個。
此前實現過一個在Android上的Markdown編輯器
但是界面以及所見即所得的效果非常不好看,所以一直耿耿于懷。
然后冒昧看了下簡書的布局系統(tǒng),看見了幾個奇怪的類,包括類似XWalkContentView,于是Google了下,就查到了CrossWalk這個hybrid框架了。第一眼并不覺得它有啥不一樣,以為是一個Cordova的輪子。后來細看,發(fā)現是自個兒編輯了整個Chrominum,屌屌屌!
運行個demo,wrapper了一個http://sf.gg發(fā)現體驗真的是不錯啊,webview性能到這個水平內心都寬慰了,但是為何安裝速度那么慢呢?一看apk大小,足足有40M+,感覺天都要塌了。SegmentFault for Android客戶端才3.03M,我要是包上這玩意,估計就沒多少人下了吧。。。然后又看看簡書,整個apk大小才8M,在啟動編輯器的時候,提示需要下載編輯器,下載了一會,然后再打開。頓時就明白了,看來它的庫是從外部載入的,記得以前看到過從外部加載動態(tài)鏈接庫想想很是簡單,于是入坑了。
好嘛,我把so文件先不放進apk中,讓apk裝好之后,放入/data/data//lib目錄下,啟動app,直接crash。
看日志入下:
DavlikDexClassLoader Unsatisfied Link library['/xxxx/xxx.apk', '/vendor/lib', '/system/lib']
一看這個路徑,淚奔了,原來library path只有三個路徑下去檢查,算了,我們不是有System.load和System.loadLibrary函數么,直接調用唄,于是我就先暫時把絕對路徑給寫了下來,直接調用System.load函數。
再次啟動,發(fā)現CrossWalk報Shared Library should use SharedXWalkView。但是使用SharedXWalkView有許多的限制,比如需要安裝一個CrossWalk Runtime的apk,奇怪了,它怎么知道我是用Shared Library的呢?而且簡書也沒有說要安裝apk啊。
于是我繼續(xù)研究,開始看CrossWalk的源碼,找到ReflectionHelper這個類里面有一行代碼shouldUseLibrary(),它會去調用System.loadLibrary()如果沒有報異常,則返回false,否則返回true。
我們知道System.loadLibrary這個函數,會去java.library.path這個環(huán)境變量的路徑下面尋找?guī)欤鳤ndroid是不允許我們更改這個環(huán)境變量的值的,就導致CrossWalk認為并沒有加載它的runtime而去開啟Shared模式。
OK,知道怎么解決就方便了,首先,我們要把so文件放入到/data/data//下的任意路徑,因為我們的apk有這個權限在這里放東西,然后使用System.load加載這個so庫,最后使用反射的方式欺騙CrossWalk框架,告訴它我們的類庫已經加載完畢。
我們仔細研究下它的源碼,發(fā)現有幾個標志位需要更改,具體代碼如下:
System.load(libPath);try{? ? LibraryLoader loader = LibraryLoader.get(1);? ? Class c = Class.forName("org.xwalk.core.internal.XWalkViewDelegate");? ? Field field = c.getDeclaredField("sLibraryLoaded");? ? field.setAccessible(true);? ? field.setBoolean(null,true);? ? field.setAccessible(false);? ? field = LibraryLoader.class.getDeclaredField("mLoaded");? ? field.setAccessible(true);? ? field.setBoolean(loader,true);? ? field.setAccessible(false);? ? PathUtils.setPrivateDataDirectorySuffix("xwalkcore");}catch(NoSuchFieldException e) {? ? e.printStackTrace();}catch(IllegalAccessException e) {? ? e.printStackTrace();}catch(ClassNotFoundException e) {? ? e.printStackTrace();}catch(ProcessInitException e) {? ? e.printStackTrace();}
只要把以上的類中的標志位更改掉,那么CrossWalk就認為庫已經加載成功了。