📚
handbook
  • Introduction
  • 1.前言
    • 前言
    • 鸣谢
  • 2.环境篇
    • 工具部署和使用
      • 团队协作工具
        • Confluence
      • 开发工具
        • Docker
          • 镜像导入导出
          • 安装
        • Docker Compose
      • 持续集成工具
        • Gerrit
        • Sonarqube
          • 分析参数设定
          • Prerequisite
          • 服务端设置
        • Ubuntu Ci Deploy
          • ubuntu使用docker部署jenkins+sonarqube
        • 持续集成部署
      • 文本编辑工具
        • Gitbook相关注意事项
        • Markdown快速入门
      • 版本控制
        • Git
          • 1.基础
            • Git基础(一)
            • Git基础(二)
            • Git基础(三)
            • Git基础(四)
            • Git基础(五)
          • 2.命令详解
            • 命令速查
          • 3.进阶技巧
            • git技巧
      • 自动化测试工具
        • Appium
          • capability参数配置
          • 安装
          • 简介
      • 项目管理工具
        • Jira
    • 开发环境配置
      • 通用
        • Homebrew安装与使用
        • Git服务器添加SSH Key
        • koroFileHeader使用
        • nodejs与npm的安装
        • npm更换国内源
        • pip使用相关
        • PostgreSQL安装与使用
        • proxychain安装与使用
        • shell配置环境变量
        • snapd安装与使用
        • terminal走代理
    • 快捷键速查
      • shell常用快捷键
  • 3.语言篇
    • C
      • 代码规范
      • 语言技巧
    • Cpp
      • 代码规范
      • 基础知识
        • 理解C++中的左值和右值
      • 语言技巧
        • 并发编程
          • 简单的线程池实现
    • Golang
      • 代码规范
        • 避免使用转义字符串
        • 避免参数语义不明确
        • 嵌套式结构体
        • 函数的分组与顺序
        • 函数命名
        • 声明一致性
        • 导入别名
        • 使用字段名初始化结构体
        • 本地变量声明
        • map初始化
        • nil用法
        • 包命名
        • 命名Printf样式的函数
        • 减少嵌套
        • 缩小变量作用域
        • struct引用初始化
        • 测试表声明
        • 顶层变量声明
        • 不必要的else
      • 环境配置
        • 代码检查格式化工具
          • Go Fmt
          • Goimports
          • Golint
          • Go Vet
        • go mod详解
        • golang安装
        • Golang开发环境
        • Troubleshooting
      • 语言技巧
        • 如何分包
    • Java
      • 代码规范
      • 语言技巧
        • 注解编程
        • 动态代理
    • Js
      • 语言技巧
        • Rollup
    • Kotlin
      • 基础知识
        • 写给开发者Kotlin指引(一)
        • 写给开发者Kotlin指引(二)
    • Python
      • 语言技巧
        • Best Practice Of Python S Project Structure
  • 4.规范篇
    • Git message规范
  • 5.技术篇
    • Android技术
      • Hook
        • EdXposed例子
        • Android 10 上安装Magisk和EdXposed
      • Tinker
        • 1.Tinker及其使用
      • 准备
        • ADB连接设备步骤及注意事项
        • adb连接设备
        • aosp编译
      • 基础
        • Binder接口调用的鉴权方法
        • Make 及 Android 编译系统介绍
        • 使用Content Provider为其他应用提供数据
      • 源码阅读
        • Framework源码分析 Looper Handler
        • Framework源码分析 启动流程 ServiceManager的初始化
        • Framework源码分析 启动流程 Zygote启动SystemServer
    • JS Bridge
      • JSBridge初探
    • Kernel技术
      • kallsyms子系统
    • Test技术
      • 软件测试
        • jnekin+sonar 部署 问题总结
        • 性能测试基础
        • 软件测试的背景
        • 测试基础
        • 测试人员的核心竞争力
    • 操作系统原理
      • 处理器如何实现原子操作
Powered by GitBook
On this page
  • 为何关注JSBridge
  • 小程序平台发展时间线
  • 小程序数量
  • JSBridge是什么
  • JSBridge的小例子
  • 下一步如何丰富这个例子
  • 参考项目

Was this helpful?

  1. 5.技术篇
  2. JS Bridge

JSBridge初探

PreviousJS BridgeNextKernel技术

Last updated 4 years ago

Was this helpful?

为何关注JSBridge

自从2017年1月9日,微信小程序上线后,小程序生态已经吸引了大批的开发者入驻,开发快捷,快速部署,跨平台是小程序几个优点。到如今各个大平台都会根据自身业务实现各自的小程序平台。小程序隐隐成为新的流量入口。应用生态慢慢再向泛应用生态转变。在这个泛应用生态上会不会有安全问题,我们的检测如何触达;另外小程序框架有没有可能在我们未来的SDK或者2C应用中进行使用?带着这些问题去研究了小程序框架中最重要的核心功能JSBridge。在看技术之前还是回顾一下小程序的历史和现在的状况。

小程序平台发展时间线

  • 2017年1月 微信小程序上线

  • 2018年3月 快应用发布

  • 2018年7月 百度智能小程序上线

  • 2018年9月 支付宝程序、淘宝轻店铺上线

  • 2018年10月 抖音小程序上线

  • 2018年11月 头条小程序上线

  • 2019年5月 QQ小程序上线

  • 2019年7月 360小程序上线

  • 2019年10月 美团小程序上线

小程序数量

据艾媒网统计,2020年小程序数量将达到1400w+

JSBridge是什么

JSBridge很早就出现在软件开发中,它提供一个JS和Native互相调用的功能。在移动开发中,Natvie层指的就是APP的Java层,使用了JSBridge的H5页面可以通过js调用原生系统的一些功能,如打开通讯录,打开相册选取照片等等功能。 微信早期为自己的应用已经提供基于JSBridge的功能,叫WeiXinJSBridge,后来发现这套机制可以抽象统一后对外提供,于是现在微信的JSBridge被封装成JSSDK,也就有了后来的小程序的兴起。

JSBridge的基本框架如上图所示 在Android中使用的是Google的Webkit框架,其中Webview是支持将Native方法注册到一个js函数上,用来处理js层的调用 同样Webview也有一个evaluateJavascript方法可以调用已经加载的js方法 JSBridge其实就是利用上述两个方法进行封装而成的JS和JAVA层相互通信的通道。

JSBridge的小例子

俗话说的好Talk is cheap. Show me the code。为了更深刻的理解js和native的交互过程,写了一个最简单的例子。

  1. 首先创建一个app工程,就用empty view就可以

  2. 修改layout的activity_main.xml, 创建Webview

     <?xml version="1.0" encoding="utf-8"?>
     <androidx.constraintlayout.widget.ConstraintLayout 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"
         tools:context=".MainActivity">
    
         <WebView
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:id="@+id/webView"
             />
    
     </androidx.constraintlayout.widget.ConstraintLayout>
  3. 在src/main路径下创建assets目录,并在assets目录下创建index.html文件,写入如下内容

     <!DOCTYPE html>
     <html>
     <head>
         <title>WebView与JS方法交互</title>
    
         <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
         <meta http-equiv="description" content="this is my page">
         <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    
         <!--<link rel="stylesheet" type="text/css" href="./styles.css">-->
    
     </head>
    
     <body>
     <input type="button" value="Say hello"
         onClick="showAndroidToast('Hello Android!')" />
    
     <script type="text/javascript">
             //调起本地的Java方法
             function showAndroidToast(toast) {
                 window.Android.showToast(toast);
             }
         </script>
     </body>
     </html>
  4. 修改MainActivity

     package com.wq.jsbridge;
    
     import androidx.appcompat.app.AppCompatActivity;
    
     import android.os.Bundle;
     import android.webkit.JavascriptInterface;
     import android.webkit.WebSettings;
     import android.webkit.WebView;
     import android.webkit.WebViewClient;
     import android.widget.Toast;
    
     public class MainActivity extends AppCompatActivity {
         private WebView mWebView;
    
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
             setContentView(R.layout.activity_main);
    
             initWebView();
         }
    
         private void initWebView() {
             WebView mWebView = (WebView) findViewById(R.id.webView);
    
             //启用支持javascript
             WebSettings settings = mWebView.getSettings();
             settings.setJavaScriptEnabled(true);
    
             mWebView.addJavascriptInterface(new JsBridgeJavaScriptInterface(), "Android");
    
             //WebView加载web资源
             mWebView.loadUrl("file:///android_asset/index.html");
             //覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为,使网页用WebView打开
             mWebView.setWebViewClient(new WebViewClient() {
                 @Override
                 public boolean shouldOverrideUrlLoading(WebView view, String url) {
                     // TODO Auto-generated method stub
                     //返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器
                     view.loadUrl(url);
                     return true;
                 }
             });
         }
    
         final class JsBridgeJavaScriptInterface {
             /** JS调用native方法显示一个Toast */
             @JavascriptInterface
             public void showToast(String toast) {
                 Toast.makeText(getApplicationContext(), toast, Toast.LENGTH_SHORT).show();
             }
         }
     }
  5. 之后编译运行时就可以看到Activity中出现了一个button,点击button就会调用到Native的Toast方法进行

下一步如何丰富这个例子

上面的例子展示了如何从js方法中调用native方法,并没有展示Java回调js的过程,并且也没有对接口进行统一封装 回调的实现可以有两种方式:

  1. 返回值通过Native方法的返回值给出,一般是string类型,这个返回值可以直接返回到js方法中,在js中添加对返回值的处理函数

  2. 在js层实现一个供native调用的统一入口,在native执行完成后,准备返回值和callback函数名,通过evaluateJavascript方法处理

封装的话主要是对js调用native的接口以及native调用js的接口进行统一约定,其中包含API 名,参数格式,返回值格式等等

参考项目

这个项目很好的展示了双向调用的过程,并且整个代码结构也很清晰,可以作为后续使用和优化的参考

ZJsBridge
小程序统计
JSBridge框架图
运行截图