以前也用過webview,不過基本都是展示一些靜态的頁面,就直接對着API怼就行,現在由于某一塊功能太過于繁雜,用本地的方法去開發的話就會太過于麻煩,不是做不到而是沒必要,是以也就是時候好好嘗試下混合開發。
這過程中會涉及到和前端JS的互動,如果沒接觸過前端的至少應該也要先去了解下前端,其實我對前端也隻是略懂略懂。
一.開發前的準備
既然要同時開發Android原生代碼和前端代碼,那肯定要做些準備,android端就用android studio這是肯定的,我前端打算寫vue項目(我也不會angular),我是用webstorm去開發,然後肯定也搭好了Vue的環境,前端這一塊用什麼寫無所謂,思想和操作我覺得其實是大概相同的。
1.手機浏覽本地網頁
因為是開發的過程,我們不可能每次寫完前端的代碼都要部署一次,是以第一件要做的事就是在手機端能正常運作到前端的代碼。
其實這個一般不用說的,鑒于我是第一次嘛,就順便記錄一下,那怎麼做呢,那這用vue舉例。
(1)首先要先讓手機和電腦都同時連在一個區域網路内
(2)配置vue内部的環境(這個我隻懂配,不懂原理,其它架構肯定也一樣)。把host和端口都配置下。

(3)檢視本地電腦的目前ip
我是windows的,在指令行輸ipconfig檢視IPv4位址,這個沒啥好解釋的
然後測試一下能不能在本地用ip來打開你寫的網頁
(4)手機輸入網址
電腦是能正常的打開了,然後試試在手機上能不能打開這個網址
看到這樣就說明手機能正常展示電腦上的我們寫的網頁,這樣就完成了第一步。
二.對接Android與前端
能正常在手機展示前端網頁後,可以對接下Android與前端,其實就是使用webview,webview就是一個内置的浏覽器
WebView webview = (WebView) findViewById(R.id.webview);
webview.getSettings().setJavaScriptEnabled(true);
webview.getSettings().setDomStorageEnabled(true);
webview.loadUrl("http://192.168.1.119:8090");
loadUrl就是展示網頁這個我想應該不用多解釋,把展示的位址設定成我們前端網頁的位址看看效果
嗯,能正常的展示出頁面,這樣我們就能在不部署前端代碼的情況下進行混合開發。
這裡說一下,這裡我用Vue是響應式的就很友善,我直接改前端的代碼,不用重新整理WebView裡面的頁面内容也會直接進行改變,這樣隻要我們不改Android原生的代碼的話就不用重新run APP,但是這基本是不可能的,既然是混合開發,一般對接的功能兩邊都要改。
三.WebView
能正常顯示後我們現在就應該把中心放到WebView上面,WebView現在就相當于兩個端的一個橋梁。
1.探究兩端代碼的執行順序
其實這裡我想問一個問題:
WebView屬于多程序嗎?
我找了很多資料都沒有看到有人提到過這個問題,如果有大神知道請告訴我,如果是在别的浏覽器打開肯定是不同程序,但是浏覽在本地呢算不算不同程序。
首先這個開發我不知道是怎樣的一個流程,是我調用loadUrl方法的時候就開始加載前端頁面了嗎?
帶着這個疑問我打算先去探究一下本地代碼和前端代碼的執行順序,我在vue頁面的生命周期中列印100個數字的循環,在本地loadUrl方法之後也列印100個數字的循環
前端:
本地
框中的方法是能列印前端的日記到androidstudio的logcat上。這樣做,是不是說明如果兩個數字交叉列印的話就證明至少它們的執行不在一個線程上,然後列印發現結果是先列印本地的0到99,再列印前端的0到99(數字太多我就不貼了),在onResume列印也是這個結果。
那是不是說明,等webview顯示出來之後才去加載前端的頁面?
很可惜的是在AS裡面看不了webview的源碼,對此隻能到網上去找資料。
我找到别人說webview是多由兩個線程組成,他初始化順序是
出自
https://tech.meituan.com/WebViewPerf.html那說明我們之前答應的數字有順序是因為webview的初始化時間太長了而不是在同個程序。
四.webview的操作
大概了解兩邊的執行順序之後就好弄的,因為如果你不知道執行順序的話,有可能你在本地執行一個js的方法,你不知道是在什麼時候執行,而大概知道整個過程之後就很好把控了。
看看webview有哪些操作,webview有兩個比較重要的類
WebChromeClient和WebViewClient
關于這兩個類,如果設定的話很多文章都寫的是匿名内部類,我建議最好是繼承去實作,這樣擴充性會比較好。
第一個類主要跟一些網頁的彈框之類的有關,第二個類主要跟一些流程有關。
1.Android調用js的方法
API19以上可以用這個方法
webview.evaluateJavascript("javascript:changename()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此處為 js 傳回的結果
Log.v("Native",value);
}
});
19以下可以用
webview.loadUrl("javascript:changename()");
關鍵你要知道在什麼地方調用js的方法,調用時你要保證頁面已經加載完成了,不然你調用也沒效果,那麼要如何确定頁面已經加載完成,這就需要上面說的WebViewClient
如果你想在加載頁面後馬上調用js的某個方法,你可以這樣寫
webview.setWebViewClient(new WebViewClient(){
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
// 開始加載頁面時
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
// 加載結束
webview.evaluateJavascript("javascript:changename()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此處為 js 傳回的結果
Log.v("Native",value);
}
});
}
});
還有一點,如果使用架構的話,是沒法直接調用架構裡面寫的方法的,我用vue就是這樣,網上查了,說要把前端的方法給window,那我這裡也貼下我前端的代碼
我這裡把方法給window,這樣android端就能正常的調用vue裡面的方法。
2.js調用Android方法
其實這說法按網上的文章的寫法,并不是讓js直接調用Android的方法,而是在Android定義一個對象,讓這個對象映射到js裡面的一個對象,再讓這個對象去調用方法。
(1)android端
先定義一個要映射給js的對象,要讓js調用的方法要加上 @JavascriptInterface
public class WebTest {
private Context context;
public WebTest(Context context){
this.context = context;
}
@JavascriptInterface
public void show(String s) {
Toast.makeText(context,s,Toast.LENGTH_SHORT).show();
}
}
然後設定給前端,将WebTest對象映射到前端的mandroid對象
webview.addJavascriptInterface(new WebTest(this),"mandroid");
(2)前端
我先寫個點選事件
在這個事件中調用android的方法
show(){
mandroid.show("js調用了android中的方法");
}
這樣就能在js中調用android的代碼。
五.總結
先講這麼多吧,主要是說說怎麼在本地共同開發android和前端,WebChromeClient的onConsoleMessage可以列印前端的日記,這樣的話調試的時候也基本沒啥問題。
第二個就是簡單的講了Android端和Js的調用,其實隻要能通信的話就很友善了,就像我之前寫的程序間的通信,也是拿到代理對象後通信,這裡差不多的。
我并沒用詳細去寫太多關于webview的内容,因為如果有人想看API這些總結的話别人寫得比我好,我就沒必要再寫了:
https://mp.weixin.qq.com/s/Rn7s31nxxY3vWnFRyjyjiA這裡有很多webview的相關方法。
然後就是如果你會了這些其實還是沒法做好混合開發,因為體驗的效果其實并不是很好,等熟悉webview的使用後可以看看美團的這篇文章:
還有一些其它的特殊功能沒詳細講,比如說定位,傳圖檔這些,因為我也沒怎麼開發過這些功能,不過我敢保證肯定會有坑,剩下的等碰到再寫吧。