以前也用过webview,不过基本都是展示一些静态的页面,就直接对着API怼就行,现在由于某一块功能太过于繁杂,用本地的方法去开发的话就会太过于麻烦,不是做不到而是没必要,所以也就是时候好好尝试下混合开发。
这过程中会涉及到和前端JS的交互,如果没接触过前端的至少应该也要先去了解下前端,其实我对前端也只是略懂略懂。
既然要同时开发Android原生代码和前端代码,那肯定要做些准备,android端就用android studio这是肯定的,我前端打算写vue项目(我也不会angular),我是用webstorm去开发,然后肯定也搭好了Vue的环境,前端这一块用什么写无所谓,思想和操作我觉得其实是大概相同的。
因为是开发的过程,我们不可能每次写完前端的代码都要部署一次,所以第一件要做的事就是在手机端能正常运行到前端的代码。
其实这个一般不用说的,鉴于我是第一次嘛,就顺便记录一下,那怎么做呢,那这用vue举例。
(1)首先要先让手机和电脑都同时连在一个局域网内
(2)配置vue内部的环境(这个我只懂配,不懂原理,其它框架肯定也一样)。把host和端口都配置下。
(3)查看本地电脑的当前ip
我是windows的,在命令行输ipconfig查看IPv4地址,这个没啥好解释的
能正常在手机展示前端网页后,可以对接下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属于多进程吗?
我找了很多资料都没有看到有人提到过这个问题,如果有大神知道请告诉我,如果是在别的浏览器打开肯定是不同进程,但是浏览在本地呢算不算不同进程。
首先这个开发我不知道是怎样的一个流程,是我调用loadUrl方法的时候就开始加载前端页面了吗?
带着这个疑问我打算先去探究一下本地代码和前端代码的执行顺序,我在vue页面的生命周期中打印100个数字的循环,在本地loadUrl方法之后也打印100个数字的循环
前端:
本地
那是不是说明,等webview显示出来之后才去加载前端的页面?
很可惜的是在AS里面看不了webview的源码,对此只能到网上去找资料。
我找到别人说webview是多由两个线程组成,他初始化顺序是
那说明我们之前答应的数字有顺序是因为webview的初始化时间太长了而不是在同个进程。
大概了解两边的执行顺序之后就好弄的,因为如果你不知道执行顺序的话,有可能你在本地执行一个js的方法,你不知道是在什么时候执行,而大概知道整个过程之后就很好把控了。
看看webview有哪些操作,webview有两个比较重要的类
WebChromeClient和WebViewClient
关于这两个类,如果设置的话很多文章都写的是匿名内部类,我建议最好是继承去实现,这样扩展性会比较好。
第一个类主要跟一些网页的弹框之类的有关,第二个类主要跟一些流程有关。
API19以上可以用这个方法
webview.evaluateJavascript("javascript:changename()", new ValueCallback() {
@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() {
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
Log.v("Native",value);
}
});
}
});
还有一点,如果使用框架的话,是没法直接调用框架里面写的方法的,我用vue就是这样,网上查了,说要把前端的方法给window,那我这里也贴下我前端的代码
我这里把方法给window,这样android端就能正常的调用vue里面的方法。
其实这说法按网上的文章的写法,并不是让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的使用后可以看看美团的这篇文章:
https://tech.meituan.com/WebViewPerf.html
还有一些其它的特殊功能没详细讲,比如说定位,传图片这些,因为我也没怎么开发过这些功能,不过我敢保证肯定会有坑,剩下的等碰到再写吧。