目录
写在前面
文章有点长,请注意保护您的眼睛,如若引起身体不适请自行关闭!
之前是定了个目标说是做到每周一更,很开心已经坚持了三周了,希望接下来能够再接再厉吧!今天抽空写个基础业务方面的——移动端混合开发基础。对于应用层来说,其实混合开发用的还是比较多的,相信你肯定也用过,很多为了快速开发快速迭代节省成本的业务,基本上都会采用这种方式去进行开发,今天就做个总结,整理一下这方面的基础知识点。
本篇代码地址:https://github.com/JArchie/JSBridgeDemo
一、混合开发介绍
1.1、什么是混合开发?
- 它是一种开发模式,并不是一种具体的技术,英文名称叫Hybrid APP
- 混合使用Native(Android、iOS)和Web(HTML、CSS、JavaScript)技术开发
这两类技术各自的特点通过混合开发可以把它们结合起来,比如对于原生开发Android一般使用的就是Java和Kotlin,iOS一般使用的就是Objective-C和Swift。原生开发的实际操作过程都是比较慢的,改动一行代码你就需要重新编译打包安装到硬件设备上面看效果,如果有问题又要重复这个过程,在你发布升级的时候,用户需要重新安装这个APP,所以推送升级也是个问题。而Web技术就可以克服这些缺点,比如你修改代码之后,刷新一下页面就可以立马看到修改后的结果,当它发布的时候,部署之后用户下次打开就可以看到最新的页面,所以它并不存在发包覆盖率的问题,把这两种技术结合起来,就可以各自做各自擅长的事情,这也是混合开发的意义所在,也因此来说混合开发只是一种模式。
1.2、混合开发优缺点
其实上面也提到了一部分,这里做个总结性的概括:
- 优点:开发快(介于原生和Web开发的速度之间)、易更新(原生开发作为容器,里面的内容采用Web技术部署静态页面,用户动态加载更新)、开发周期短(开发速度快加之具有即时发布更新的特点)
- 缺点:性能问题(相较于纯原生开发Web技术在切页和手势动画等方面没有原生流畅)、兼容性问题(原生承载Web网页相当于原生充当了浏览器的角色,浏览器不同的版本支持的Web特性是不一样的)
- Android 5.0+ 和 iOS 9.0+ 缺点不再明显(硬件设备自身性能和操作系统版本提升)
1.3、混合开发应用场景
①、微信公众号,通过JSSDK连接Native端和Web端
我们可以把微信看做是原生开发,微信公众号内部的网页则是Web开发,它们通过JSSDK连接起来,这样在做微信公众号的时候可以使用Web技术发布更新,同时可以利用JSSDK使用到微信提供的原生能力。
②、微信小程序,通过内置框架连接Native段和Web端
微信小程序相比较于微信公众号则更进一步,它相当于是将JSSDK和Web技术内置整合了一套框架,内部会将这些调用和渲染连接到Native端,使用它的框架编写程序,它自身会做桥接的工作。
1.4、了解混合开发的意义
①、更好的使用第三方平台
比如我们要开发微信小程序或者在某个Web平台上开发一些插件,我们就需要了解混合开发的原理和机制,这样在使用第三方平台提供的接口调用时若发生某些特定的行为,可以深刻的理解生命周期和调用的链路,从而能够更好的使用第三方平台。
②、更灵活的技术方案选型
比如领导让你开发一款新的移动应用时,如果你了解混合开发,那么你可以选择纯原生开发,也可以通过原生结合Web技术进行混合开发,技术选型更加灵活。
③、具备搭建平台和输出服务的能力
当你了解混合开发之后,你可以搭建一个类似微信公众号或微信小程序这样的平台,可以把原生APP提供各种接口能力并输出成JSSDK。
二、混合开发的核心技术
2.1、混合开发核心技术——JSBridge
- 实现Native端和Web端双向通信的一种机制
- 以JavaScript引擎或WebView容器为媒介
- 通过约定协议进行通信
2.2、混合开发主流技术框架
- Web渲染:Cordova(前身是PhoneGap)
- 原生渲染:React Native、Weex
- 混合渲染:微信小程序
2.3、JSBridge实现原理
由上图可以看出,上面是Web端,下面是Native端,JSBridge在中间起了一个桥梁作用,透过JSBridge,Web端可以直接调用Native端的Java接口,Native端也可以调用Web端提供的JavaScript接口,从而可以实现Web端和Native端之间的双向通信。可以把这种模式和客户端/服务器这种C/S模式作一个对比,把Web端比作客户端,Native端比作Server端,在Web端调用Native端接口时和客户端向Server端发出一个请求类似,其中JSBridge在这个过程充当的就是HTTP协议的角色。
- 类比Client/Server模式
- 将Native端原生接口封装成JavaScript接口
- 将Web端JavaScript接口封装成原生接口
- Web端和Native端之间双向通信
三、JSBridge的实现方式
3.1、创建Native和Web工程
在说JSBridge的几种实现方式之前,我们还得做一件事,先来创建两个Demo工程,一个是Android端,一个是Web端,然后在这个基础上通过实际的代码来介绍几种JSBridge的用法,这样看的也比较清晰明了!
OK,先来创建一个Web工程,这里我使用的是IDEA,然后在/Users/Jarchie/Desktop/AndroidProjects/Web/src 这个目录下创建一个index.html页面,内容也很简单,如下图所示:
这里我使用node安装一个http静态服务来跑这个web页面,打开终端进入到页面所在目录,使用npm i -g http-server 命令安装静态资源服务器,执行 http-server 它会在当前服务下启一个静态资源服务,这样可以拿到一个地址,如下所示:
然后可以直接通过这个地址在浏览器中访问这个静态页面,如下图:
然后再来创建一个Android工程,界面也比较简单,上面是Web页面,下面是Android页面,布局代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#eaeaea"
android:orientation="vertical">
<WebView
android:id="@+id/mWebview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">
<EditText
android:id="@+id/mEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入内容"
android:textSize="45sp" />
<TextView
android:id="@+id/mShowBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#BBB5B5"
android:text="显示Web弹窗"
android:textSize="45sp" />
<TextView
android:id="@+id/mRefreshWeb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:background="#BBB5B5"
android:text="刷新Web页面"
android:textSize="45sp" />
</LinearLayout>
</LinearLayout>
然后在Activity页面中进行数据初始化操作:
package com.jarchie.jsbridge;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.TextView;
import java.util.Date;
/**
* 作者: 乔布奇
* 日期: 2020-04-11 13:50
* 邮箱: [email protected]
* 描述: Native端页面展示层,上方为Web页面,下方为Android页面
*/
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private WebView mWebview;
private EditText mEditText;
private TextView mShowBtn,mRefreshWeb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initListener();
initData();
}
//初始化数据加载
private void initData() {
//为了每次获取的页面都是最新的,加了个时间戳,防止页面有缓存
mWebview.loadUrl("http://192.168.0.102:8080/?timestamp" + new Date().getTime());
}
//初始化事件监听
private void initListener() {
mShowBtn.setOnClickListener(this);
mRefreshWeb.setOnClickListener(this);
}
//初始化绑定控件
private void initView() {
mWebview = findViewById(R.id.mWebview);
mEditText = findViewById(R.id.mEditText);
mShowBtn = findViewById(R.id.mShowBtn);
mRefreshWeb = findViewById(R.id.mRefreshWeb);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.mShowBtn:
break;
case R.id.mRefreshWeb:
mWebview.loadUrl("http://192.168.0.102:8080/?timestamp" + new Date().getTime());
break;
}
}
}
接着把它运行一下,看下结果:
到了这里,准备工作就已经做完了,接下来就来说JSBridge的几种用法了!
Web端调用Native端的实现方式有两种:①、拦截WebView请求的URL Schema;②、向WebView注入JS API
原生端调用Web端的实现方式只有一种:直接执行js代码去调用web端代码
3.2、拦截URL Schema
3.2.1、原理及特点简介
- URL Schema是类URL的一种请求格式
- <protocol>://<domain>/<path>?<query> 比如:https://www.google.com/search?keyword=xxx
- 自定义JSBridge通信的URL Schema
- jsbridge://<method>?<params> 比如:jsbridge://showToast?name=jarchie&age=27
上面的这个例子中自定义的Schema是以jsbridge开头,后面的showToast是调用的原生方法名,问号后面是需要传给这个方法的参数对,那么它是怎么实现拦截来调用原生方法的呢?它的原理这里用一张图片来说明:
原生端的WebView加载Web网页之后,Web网页中发出的所有请求都会经过WebView组件,所以原生端可以去重写WebView组件里面的方法从而拦截Web网页中的请求,对请求的地址作出判断,如果它是符合自定义jsbridge的格式,就进行解析,解析之后拿到对应的方法名及相关参数,去调用对应的原生方法,如果不是自定义的URL Schema,比如它是一个http协议,在正常的拦截之后就进行转发请求真正的服务。这个过程Web端虽然没有真正的调用Native端的方法,但它间接实现了调用的过程,从逻辑上来看就是Web端调用了原生端的方法,这就是它的实现机制。
- 优点:兼容性好(Android4.4以下也是支持的)
- 缺点:不直观、URL长度有限制
3.2.2、代码实战
(一)、原生端调用Web端弹窗展示内容
在写代码之前先来理一下业务逻辑,我们需要实现的效果是:在原生端输入内容,然后点击按钮调用Web端弹窗展示。
OK,按照这个顺序一步一步来写,首先要给原生的Webview设置支持js脚本:
mWebview.getSettings().setJavaScriptEnabled(true);
接着封装一个方法,将原生端输入的内容传入,然后执行一段js代码,调用Web端弹窗展示这个内容:
//Native端调用Web端方法,只有一种方式,直接执行js代码
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
private void showWebDialog(String content){
String jsCode = String.format("window.showWebDialog('%s')",content);
mWebview.evaluateJavascript(jsCode,null);
}
添加点击事件,将输入框的内容传入该方法:
case R.id.mShowBtn://点击按钮获取输入框值,并传入对应的调用Web端的方法中
showWebDialog(mEditText.getText().toString().trim());
break;
在Web端的showWebDialog方法中调用window展示:
<script>
window.showWebDialog = content => window.alert(content);
</script>
这样我们就完成了,来看下效果,如下图所示:
(二)、Web端调用原生端弹窗展示内容
这次的业务逻辑是反向操作,在Web端输入内容,点击Web端按钮调用原生端的弹窗展示这个内容。
首先,在Web端给文档添加一个监听事件,在DOM加载完成之后获取对应的DOM元素,然后给按钮添加一个点击事件,拿到输入框的值,接着封装一个方法,将获取的输入框的值传入,在方法内部实现调用原生端的弹窗,这里就是通过自定义URL Schema的方式去实现,具体的代码如下:
<script>
document.addEventListener('DOMContentLoaded', e => {
const editText = document.querySelector('#editText');
const showBtn = document.querySelector('#showBtn');
showBtn.addEventListener('click', e => {
const inputValue = editText.value;
showNativeDialog(inputValue)
})
})
function showNativeDialog(content) {
window.alert('jsbridge://showNativeDialog?content=' + content);
}
</script>
然后我们在原生端自定义WebChromeClient拦截Alert方法,通过解析URL Schema获取Web端输入的值:
//自定义WebChromeClient拦截自定义的URL Schema
private class MyWebChromeClient extends WebChromeClient{
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
if (!message.startsWith("jsbridge://")){
return super.onJsAlert(view, url, message, result);
}
String content = message.substring(message.indexOf("=")+1);
showNativeDialog(content);
result.confirm();
return true;
}
}
然后再封装一个显示原生弹窗的方法showNativeDialog:
//Web端调用原生端方法
private void showNativeDialog(String content){
new AlertDialog.Builder(this)
.setTitle("Web端调用Native端")
.setMessage(content)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.create()
.show();
}
这样也就完成了,来看下效果:
3.3、注入JS API
3.3.1、原理及特点简介
这种方式相比较于自定义URL Schema的方式更加直观,从下图中也能够看出:
APP可以将原生的Java接口注入到WebView中,在WebView中暴露出一个JS对象,JS对象方法名跟原生的接口方法名是一一对应的,Web端就可以直接引用这个暴露的全局JS对象,通过这个对象调用到原生端的方法。
- 优点:简单直观
- 缺点:有兼容性问题(Android 4.2+,之前存在兼容性和安全漏洞,现在随着系统升级这些问题也都有对应的解决办法,实际应用中优先推荐这种方式)
3.3.2、代码实战
原生端调用Web端的代码和上面的一样不用做任何的改动,因为它就一种实现方式,直接执行js脚本。
重点来看Web端调用原生端的这块业务,这里使用JS注入API的方式来实现。首先来看下原生端如何修改?我们这里使用WebView的addJavaScriptInterface方法暴露全局的js对象,需要传入一个js对象和需要暴露的js对象的方法名,所以这里写一个内部类,就是需要暴露的js对象及相关的方法:
class NativeBridge {
private Context mContext;
NativeBridge(Context context) {
this.mContext = context;
}
//注意必须加这个注解
@JavascriptInterface
public void showNativeDialog(String content) {
new AlertDialog.Builder(mContext)
.setTitle("Web端调用Native端")
.setMessage(content)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.create()
.show();
}
}
mWebview.addJavascriptInterface(new NativeBridge(this), "NativeBridge");
然后看Web端,这里给文档添加事件监听,给按钮添加点击事件,获取输入框的值这一部分不用改动,需要改动的是我们封装的调用原生弹窗的方法:
<script>
window.showWebDialog = content => window.alert(content);
document.addEventListener('DOMContentLoaded', e => {
const editText = document.querySelector('#editText');
const showBtn = document.querySelector('#showBtn');
showBtn.addEventListener('click', e => {
const inputValue = editText.value;
showNativeDialog(inputValue)
})
})
function showNativeDialog(content) {
window.NativeBridge.showNativeDialog(content);
}
</script>
来看下运行的效果,如下图所示:
3.4、带回调的JSBridge
3.4.1、简介及原理说明
在实际应用场景中,我们经常需要在对端执行结果后需要把执行结果给返回,比如:Web端获取Native端输入框的值,那么这就需要支持回调的JSBridge了,什么是带回调的JSBridge?这里总结亮点:
- 在对端执行操作并返回结果
- 有输入有输出才是完整的调用
如何实现带回调的JSBridge?
从上图中可以看到,在WebView实现单向调用的时候,可以在参数中加一个特殊的标记callback id,Native端收到Web端的调用请求之后,会去检查参数中是否带有callback id,如果有,就立即执行一次调用,从Native端调用Web端接收消息的方法,将Native端执行的结果传回给Web端,Web端拿到结果之后,同时会检查callback id跟之前请求的callback id是否一致,这样就知道这个结果是哪一次调用所返回的,从而实现了支持带回调的JSBridge。
3.4.2、代码实战
(一)、Web端展示原生端输入框内容
首先在web端新加一个按钮获取Native端输入:
<div>
<button id="showBtn2">获取Native输入</button>
</div>
然后在js中保存这个按钮的引用,并给这个按钮添加一个点击事件,在点击事件内部获取web端的输入并用原生弹窗展示:
const showBtn2 = document.querySelector('#showBtn2');
showBtn2.addEventListener('click', e=> {
window.JSSDK.getNativeEdittextValue(value => window.alert('Native端输入值:'+value))
})
这里封装了一个JSSDK,这里创建创建一个回调id,并使用Map将其保存,每次请求都产生一个新的回调id,并切提供两个支持回调的方法:获取原生输入框的值、接收原生消息返回的值:
let id = 1
const callbackMap = {}
window.JSSDK = {
getNativeEdittextValue(callback){
const callbackId = id++
callbackMap[callbackId] = callback
NativeBridge.getNativeEdittextValue(callbackId)
},
receiveMessage(callbackId,value){
if (callbackMap[callbackId]){
callbackMap[callbackId](value)
}
}
}
然后在Native这边新增一个获取输入框值的方法,并调用web端方法,这里同样的就是构造js代码:
class NativeBridge {
private Context mContext;
NativeBridge(Context context) {
this.mContext = context;
}
@JavascriptInterface
public void getNativeEdittextValue(int callbackId){
final MainActivity mainActivity = (MainActivity) mContext;
String value = mainActivity.mEditText.getText().toString().trim();
final String jsCode = String.format("window.JSSDK.receiveMessage('%s','%s')",callbackId,value);
mainActivity.runOnUiThread(new Runnable() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void run() {
mainActivity.mWebview.evaluateJavascript(jsCode,null);
}
});
}
}
这样就写完了,来看下运行效果:
(二)、Native端展示Web端输入框内容
首先在原生端页面上添加一个按钮mShowBtn2,绑定控件并添加点击事件,代码都很简单就不贴了,后面大家自己看源码吧。
然后同样的封装一个NativeSDK,内部提供两个方法:获取Web端输入框的值并传入一个回调接口,接收Web消息回传的值:
interface Callback {
void invoke(String value);
}
class NativeSDK {
private Context mContext;
private int id = 1;
private Map<Integer, Callback> callbackMap = new HashMap();
NativeSDK(Context context) {
this.mContext = context;
}
void getWebEditTextValue(Callback callback) {
int callbackId = id++;
callbackMap.put(callbackId, callback);
final String jsCode = String.format("window.JSSDK.getWebEditTextValue(%s)", callbackId);
((MainActivity) mContext).runOnUiThread(new Runnable() {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
@Override
public void run() {
((MainActivity) mContext).mWebview.evaluateJavascript(jsCode, null);
}
});
}
void receiveMessage(int callbackId, String value) {
if (callbackMap.containsKey(callbackId)) {
callbackMap.get(callbackId).invoke(value);
}
}
}
然后在NativeBridge中添加一个接收web端回传值的方法:
@JavascriptInterface
public void receiveMessage(int callbackId, String value) {
((MainActivity) mContext).nativeSDK.receiveMessage(callbackId, value);
}
接着同样定义一个显示原生窗口的方法:
//获取Web端输入的值并展示
private void showNativeDialog2(String content) {
new AlertDialog.Builder(this)
.setTitle("获取Web端输入的值")
.setMessage(content)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
})
.create()
.show();
}
然后实例化我们之前定义的Native SDK,点击按钮通过sdk调用对应的方法,展示弹窗:
case R.id.mShowBtn2:
nativeSDK.getWebEditTextValue(new Callback() {
@Override
public void invoke(String value) {
showNativeDialog2("Web 输入值:" + value);
}
});
break;
最后修改web端,在JSSDK中定义getWebEditTextValue方法,将输入框的值通过NativeBridge的receiveMessage方法传回:
getWebEditTextValue(callbackId){
const editText = document.querySelector('#editText');
const value = editText.value
NativeBridge.receiveMessage(callbackId,value)
}
来看下运行结果:
3.5、JSBridge的开源实现
3.5.1、JSBridge开源库介绍
首先我们学习JSBridge应当掌握它的实现原理,具备造轮子的能力,但是我们应该避免重复造轮子,尽量复用开源社区已有的实现,并且这些开源库都是经过大量的实践验证目前已经很稳定了,对于JSBridge来说有哪些优秀的开元实现呢?
- JSBridge:基于拦截URL Schema
- DSBridge:基于注入JS API
掌握这两类实现方式基本上可以应对大部分的场景了,大家可以根据自己的需要去选择,这里我选择使用第二种方式来介绍它的用法,接下来我会使用DSBridge来重写我们上面的Demo,下面给大家看一下DSBridge的相关介绍:
3.5.2、DSBridge重写Demo
(一)、Web端展示Native端输入框内容
首先来看下Web端的实现:根据文档先要引入dsbridge.js,引入之后会在全局暴露一个dsBridge的全局变量,通过这个变量可以调用一些原生提供的方法,这里通过dsBridge.call方法去调用原生的getNativeEditTextValue方法,获取到输入框的值之后会得到一个回调,在回调内部通过Web弹窗将获取的值显示出来:
<script src="https://unpkg.com/[email protected]/dist/dsbridge.js"> </script>
<script>
document.addEventListener('DOMContentLoaded', e => {
const showBtn2 = document.querySelector('#showBtn2');
showBtn2.addEventListener('click', e => {
dsBridge.call('getNativeEditTextValue','',value => {
window.alert('Native端的输入值:' + value)
})
})
})
</script>
原生端的DWebView(DSBridge中提供的,我们需要使用这个WebView)中提供了一个注册原生接口的方法addJavascriptObject,然后提供一个自定义的JSAPI的类,类中统一管理提供给webview的方法:
mWebview.addJavascriptObject(new JSAPI(this),null);
class JSAPI{
private Context mContext;
public JSAPI(Context context){
this.mContext = context;
}
@JavascriptInterface
public void getNativeEditTextValue(Object msg, CompletionHandler<String> handler){
String content = ((MainActivity)mContext).mEditText.getText().toString().trim();
handler.complete(content);
}
}
来看下运行结果:
(二)、Native端展示Web端输入框内容
首先Native端在按钮的点击事件触发时,通过DWebView调用callHandler方法,这个方法有三个参数分别是:要调用的Web端的api名称、传递的参数、结果回调,这里定义web端方法名为getWebEditTextValue,在回调中调用显示原生弹窗的方法:
mWebview.callHandler("getWebEditTextValue", null, new OnReturnValue<String>() {
@Override
public void onValue(String retValue) {
showNativeDialog("Web端输入值:" + retValue);
}
});
然后Web端通过dsBridge调用register去注册一个web方法给原生端调用,并且可以将返回值返回给原生端:
dsBridge.register('getWebEditTextValue', () => {
const editText = document.querySelector('#editText')
return editText.value
})
来看下运行结果:
OK,写到这里关于JSBridge相关的知识点就写完了,从上面的实现过程相信大家也能看出,使用开源库来实现JSBridge代码还是相当简洁的,内部都是做了高度封装,我们只需要简单的调用几个API就可以实现我们开始一大堆代码才能完成的效果,所以实际开发中还是推荐大家使用开源库来实现。
四、实战案例——开发一个简单的混合APP
文章的最后一部分通过DSBridge这个开源框架来实现一个简单的Hybrid APP,关于DSBridge的相关用法上面也介绍过了,更加详细的用法请移步至官方文档:https://github.com/wendux/DSBridge-Android.
因为是一个综合案例,所以具体的代码我就不详细写了,因为用到的技术点上面也都说过了,这里就说一下具体的需求、实现思路以及实现效果,具体的源码我也已经放到github上面了,有需要的请自提!
功能需求:
- ①、Web端调用原生端发送HTTP请求,并将请求结果展示到Web端;
- ②、APP整体沉浸式换肤效果
实现思路:
需求①:首先在原生端通过addJavascriptObject注册一个原生接口,并提供一个JSAPI类,类的内部提供requestHttp()方法,同时将结果返回给Web端;在Web端添加所需的html元素,并给按钮添加点击事件,通过dsBridge.call调用原生端封装的发送http请求的方法比如就叫requestHttp(),拿到的返回值放到对应的html标签上展示即可。
需求②:首先在页面标题栏添加一个菜单栏就叫换肤,点击换肤调用换肤方法实现换肤效果。对于状态栏、标题栏、导航栏这些直接调用原生API设置颜色值改变对应的颜色,对于Web页面使用webview.callHandler传入web需要定义的方法名及参数,在web端通过dsBridge.register注册原生端需要的方法,在方法内部实现web页面背景色的更改。
实现效果:
如下图所示,左图是需求①的效果,右图是需求②的效果:
写到这里很是疲惫,总结的不好有点惭愧,没啥说的下期再会!