混合开发:

是一种开发模式Hybrid App.

混合开发 = Native + Web.

另一篇博文:Kotlin与H5通信

场景应用:

例如:

微信公众号通过JSSDK连接Native端和Web端

微信小程序通过内置框架连接Native端和Web端

android 混合 调试 安卓 混合开发_android


混合开发的核心技术:

JSBridge桥接器

  • 实现Native端和Web端双向通信的一种机制。
  • 以JS引擎或WebView容器作为媒介。
  • 通过约定协议进行通信

混合开发主流技术框架:

  • Web渲染: Cordova (前身是PhoneGap)
  • 原生渲染: RN、Weex、Flutter
  • 混合渲染:微信小程序

JSBridge实现原理:

android 混合 调试 安卓 混合开发_Web_02

  • 将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>

android 混合 调试 安卓 混合开发_web端_03

2. Web端:这里为了方便就不用公网了,node起有个服务器模拟公网

android 混合 调试 安卓 混合开发_android_04

android 混合 调试 安卓 混合开发_android 混合 调试_05

android 混合 调试 安卓 混合开发_android_06

 

android 混合 调试 安卓 混合开发_android_07


JSBridge的2种实现方式:[web端调用原生端有2种,原生调用web端只有1种]

1.拦截WebView请求的URL Schema

  • URL Schema是类URL的一种请求格式
  • <protocol>://<domain>/<path>?<query>
  • 自定义JSBridge通信的URL Schema
  • jsbridge://<method>?<params>

android 混合 调试 安卓 混合开发_Web_08

1.1 native 调用web端:调起了web端的弹窗

android 混合 调试 安卓 混合开发_android 混合 调试_09

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);
    }
}

android 混合 调试 安卓 混合开发_web端_10

1.2 web调用native端:调起了native端的弹窗

android 混合 调试 安卓 混合开发_Web_11

android 混合 调试 安卓 混合开发_android_12

android 混合 调试 安卓 混合开发_android 混合 调试_13

android 混合 调试 安卓 混合开发_web端_14

 

 

2.向WebView注入JS API

android 混合 调试 安卓 混合开发_web端_15

2. native 端和web端双向绑定

android 混合 调试 安卓 混合开发_android 混合 调试_16

android 混合 调试 安卓 混合开发_android 混合 调试_17

这样就把bridge对象暴露到webview中的一个名叫


NativeBridge对象上,



android 混合 调试 安卓 混合开发_android 混合 调试_18

web端可以拿到这个对象直接去调用.

android 混合 调试 安卓 混合开发_Web_19

android 混合 调试 安卓 混合开发_web端_20

android 混合 调试 安卓 混合开发_android_21

 


支持回调的JSBridge:

 上述的2种方式其实无法将执行的结果返回对方。

经常需要对端操作后需要将结果返回。

  • 在对端执行操作并返回结果
  • 有输入、输出才是完整的调用。

场景:Web端获取Native端输入框的值,还需要native端把获取的值再传回给web端。

 

android 混合 调试 安卓 混合开发_android_22

1. web端调用native端 

android 混合 调试 安卓 混合开发_android_23

android 混合 调试 安卓 混合开发_web端_24

android 混合 调试 安卓 混合开发_android_25

 改正一下上方的alert(),上面拼写错了位置

android 混合 调试 安卓 混合开发_android 混合 调试_26

 

android 混合 调试 安卓 混合开发_web端_27

 

android 混合 调试 安卓 混合开发_Web_28

2. native端调用web端并返回结果给native端

原生端新加一个按钮:

android 混合 调试 安卓 混合开发_web端_29

然后是一个回调:

android 混合 调试 安卓 混合开发_Web_30

android 混合 调试 安卓 混合开发_android 混合 调试_31

android 混合 调试 安卓 混合开发_android 混合 调试_32

android 混合 调试 安卓 混合开发_web端_33

android 混合 调试 安卓 混合开发_web端_34


JSBridge开源实现:

  • JSBridge: 拦截URL Schema
  • DSBridge: 注入JS API

Github上可搜索DSBridge-Android项目