混合开发:
是一种开发模式Hybrid App.
混合开发 = Native + Web.
另一篇博文:Kotlin与H5通信
场景应用:
例如:
微信公众号通过JSSDK连接Native端和Web端
微信小程序通过内置框架连接Native端和Web端
混合开发的核心技术:
JSBridge桥接器
- 实现Native端和Web端双向通信的一种机制。
- 以JS引擎或WebView容器作为媒介。
- 通过约定协议进行通信
混合开发主流技术框架:
- Web渲染: Cordova (前身是PhoneGap)
- 原生渲染: RN、Weex、Flutter
- 混合渲染:微信小程序
JSBridge实现原理:
- 将Native端原生接口封装为JS接口
- 将Web端JS接口封装成原生接口
- Web、Native端的双向通信
案例准备:[全部源码见文末]
1.Native端UI:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
android:background="#eaeaea">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</WebView>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入内容"
android:textSize="45sp"/>
<Button
android:id="@+id/showBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示WebView界面"
android:textSize="45sp"/>
</LinearLayout>
</LinearLayout>
2. Web端:这里为了方便就不用公网了,node起有个服务器模拟公网
JSBridge的2种实现方式:[web端调用原生端有2种,原生调用web端只有1种]
1.拦截WebView请求的URL Schema
- URL Schema是类URL的一种请求格式
- <protocol>://<domain>/<path>?<query>
- 自定义JSBridge通信的URL Schema
- jsbridge://<method>?<params>
1.1 native 调用web端:调起了web端的弹窗
package com.yinlei.hybridapp;
import androidx.appcompat.app.AppCompatActivity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
import java.util.Date;
public class MainActivity extends AppCompatActivity {
private WebView webView;
private Button showBtn;
private Button refreshBtn;
private EditText editText;
private MainActivity self;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
self = this;
webView = findViewById(R.id.webView);
refreshBtn = findViewById(R.id.refreshBtn);
showBtn = findViewById(R.id.showBtn);
editText = findViewById(R.id.editText);
webView.loadUrl("http://192.168.56.1:5000/web?timestamp"+new Date().getTime());//记得加网络权限,注意网络明文适配,加时间是为了防止页面缓存
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebChromeClient(new WebChromeClient());
showBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String inputValue = editText.getText().toString();
self.showWebDialog(inputValue);
}
});
refreshBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {// 重新加载
webView.loadUrl("http://192.168.56.1:5000/web?timestamp"+new Date().getTime());//记得加网络权限,注意网络明文适配,加时间是为了防止页面缓存
}
});
}
private void showWebDialog(String text){//原生端调用web端
String jsCOde = String.format("window.showWebDialog('%s')",text);
webView.evaluateJavascript(jsCOde,null);
}
}
1.2 web调用native端:调起了native端的弹窗
2.向WebView注入JS API
2. native 端和web端双向绑定
这样就把bridge对象暴露到webview中的一个名叫
NativeBridge对象上,
即
web端可以拿到这个对象直接去调用.
支持回调的JSBridge:
上述的2种方式其实无法将执行的结果返回对方。
经常需要对端操作后需要将结果返回。
- 在对端执行操作并返回结果
- 有输入、输出才是完整的调用。
场景:Web端获取Native端输入框的值,还需要native端把获取的值再传回给web端。
1. web端调用native端
改正一下上方的alert(),上面拼写错了位置
2. native端调用web端并返回结果给native端
原生端新加一个按钮:
然后是一个回调:
JSBridge开源实现:
- JSBridge: 拦截URL Schema
- DSBridge: 注入JS API
Github上可搜索DSBridge-Android项目