Hybird开发,webview和H5交互

H5调用原生功能

封装一个统一的接口,供H5页面调用原生的功能,比如获取设备信息、打开相机、分享内容等。这样,H5页面只需调用这个接口,而无需关心具体的原生实现细节。

//定义一个类,用@JavascriptInterface注解来注释一个方法,这个方法就可以被H5直接调用
public class NativeAPI {@JavascriptInterfacepublic void getDeviceInfo() {// 假设获取设备信息的原生方法String deviceInfo = "Device: Android, Version: 11";// 将结果回调给H5页面String javascriptCode = "javascript:onDeviceInfoReceived('" + deviceInfo + "')";webView.loadUrl(javascriptCode);}
}// 添加 JavaScript 接口到 WebView 中webView.addJavascriptInterface(new NativeBridge(), "NativeBridge");

H5端调用:

function getDeviceInfo() {// 调用原生获取设备信息NativeAPI.getDeviceInfo();
}

原生调用H5

直接调用API:

String javascriptCode = "javascript:xxxx')";
webView.loadUrl(javascriptCode);
webView.evaluateJavascript("XXX")

原生回调H5

为了实现在 H5 页面中传递回调函数给原生代码,我们可以通过另外一种方式:使用随机生成的标识符来标记回调函数,并在原生代码中回调这个标识符对应的函数。

以下是修改后的示例代码,演示了在 H5 页面中调用复杂类型的 JavaScript 函数并传递回调函数标识符,然后在原生代码中通过标识符找到对应的回调函数并调用:

在 H5 页面中(例如 index.html):

<!DOCTYPE html>
<html>
<head><title>Complex Function Callback Example</title>
</head>
<body><h1>Complex Function Callback Example</h1><script>// 用于保存回调函数var callbacks = {};// 定义复杂的 JavaScript 函数,返回一个包含多个属性的对象function getComplexData() {var complexData = {name: "John Doe",age: 30,address: {city: "New York",country: "USA"},interests: ["Reading", "Traveling", "Coding"]};return complexData;}// 示例:调用一个复杂的 JavaScript 函数,并传递回调函数function triggerComplexFunctionWithCallback() {var complexData = getComplexData();// 生成一个随机标识符作为回调函数的标识var callbackId = "cb_" + new Date().getTime();// 将回调函数保存到 callbacks 对象中,用于在原生代码中调用callbacks[callbackId] = function(result) {// 在回调函数中处理原生传递回来的复杂类型数据console.log("Received complex data from Native: ", result);};// 调用原生方法,并传递回调函数标识符window.NativeBridge.onComplexFunctionWithCallbackResult(complexData, callbackId);}</script>
</body>
</html>

在 Android 原生代码中:

import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import androidx.appcompat.app.AppCompatActivity;
import org.json.JSONException;
import org.json.JSONObject;public class MainActivity extends AppCompatActivity {private WebView webView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);webView = findViewById(R.id.webView);WebSettings webSettings = webView.getSettings();webSettings.setJavaScriptEnabled(true);// 添加 JavaScript 接口到 WebView 中webView.addJavascriptInterface(new NativeBridge(), "NativeBridge");webView.setWebChromeClient(new WebChromeClient());webView.loadUrl("file:///android_asset/index.html");}// 定义一个 JavaScript 接口类,供 H5 页面调用private class NativeBridge {@JavascriptInterfacepublic void onComplexFunctionWithCallbackResult(String jsonString, String callbackId) {// 在主线程中解析 JSON 字符串为复杂类型数据runOnUiThread(new Runnable() {@Overridepublic void run() {try {JSONObject json = new JSONObject(jsonString);String name = json.getString("name");int age = json.getInt("age");JSONObject address = json.getJSONObject("address");String city = address.getString("city");String country = address.getString("country");// 处理复杂类型数据// ...// 构造一个复杂类型数据的 JSON 字符串作为回调给 H5 页面String result = "{ \"message\": \"Received complex data from Native\" }";// 获取 H5 页面传递过来的回调函数标识符对应的回调函数String callbackJs = "callbacks['" + callbackId + "']";// 使用字符串拼接的方式将回调结果传递给 H5 页面的回调函数webView.evaluateJavascript(callbackJs + "(" + result + ")", null);} catch (JSONException e) {e.printStackTrace();}}});}}
}

在上述示例中,我们在 H5 页面中定义了一个 JavaScript 对象 callbacks 来保存回调函数,并使用一个随机标识符来作为回调函数的键。在 triggerComplexFunctionWithCallback() 方法中,我们将回调函数保存到 callbacks 对象中,并传递回调函数的标识符给原生代码。

在原生代码中的 NativeBridge.onComplexFunctionWithCallbackResult(String jsonString, String callbackId) 方法中,我们获取到回调函数标识符,并通过字符串拼接的方式构造出相应的回调函数调用语句,从而正确地执行了 H5 页面传递过来的回调函数。

事件派发

封装一个事件派发机制,让原生和H5页面可以通过发送和监听事件来实现双向通信。这样可以在不直接调用对方方法的情况下,进行通信和数据交换。

在 Hybrid 开发中,事件派发是指从原生代码向 H5 页面发送消息或通知,让 H5 页面可以感知到某个事件的发生,从而执行相应的处理逻辑。事件派发是一种在原生和 H5 之间进行双向通信的手段之一。

以下是一种简单的实现方式,演示了如何在原生代码中派发一个事件给 H5 页面:

在 H5 页面中(例如 index.html):

<!DOCTYPE html>
<html>
<head><title>Event Dispatch Example</title>
</head>
<body><h1>Event Dispatch Example</h1><script>// 监听自定义事件window.addEventListener("customEvent", function(event) {console.log("Received custom event:", event.detail);// 在这里可以执行相应的处理逻辑// ...});</script>
</body>
</html>

在 Android 原生代码中:

import android.os.Bundle;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import androidx.appcompat.app.AppCompatActivity;public class MainActivity extends AppCompatActivity {private WebView webView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);webView = findViewById(R.id.webView);WebSettings webSettings = webView.getSettings();webSettings.setJavaScriptEnabled(true);webView.setWebChromeClient(new WebChromeClient());webView.loadUrl("file:///android_asset/index.html");// 派发事件到 H5 页面dispatchCustomEvent("Hello from Native!");}// 派发自定义事件到 H5 页面private void dispatchCustomEvent(String eventData) {// 使用 evaluateJavascript 方法调用 H5 页面中的 JavaScript 函数String script = "var event = new CustomEvent('customEvent', { detail: '" + eventData + "' });" +"window.dispatchEvent(event);";webView.evaluateJavascript(script, null);}
}

我们在 H5 页面中使用 window.addEventListener 方法来监听名为 “customEvent” 的自定义事件。然后,在原生代码中的 dispatchCustomEvent 方法中,我们使用 webView.evaluateJavascript 方法执行 JavaScript 代码,从而派发一个名为 “customEvent” 的自定义事件,并传递事件数据给 H5 页面。

当原生代码执行 dispatchCustomEvent(“Hello from Native!”) 后,H5 页面中的监听器会捕获到该事件,并执行相应的处理逻辑。

需要注意的是,事件派发时,我们可以自定义事件的类型和传递的数据,并通过 JavaScript 的 CustomEvent 构造函数来创建自定义事件对象。在这个例子中,我们通过 CustomEvent(‘customEvent’, { detail: eventData }) 创建了一个自定义事件,其中 eventData 就是我们要传递给 H5 页面的事件数据。在原生代码中,我们将 eventData 作为字符串传递给 H5 页面,但你也可以将更复杂的数据结构转换为 JSON 字符串,然后传递给 H5 页面进行处理。

错误处理

设计统一的错误处理机制,让原生和H5页面能够更好地处理错误情况,并向对方传递错误信息。例如,当某个功能不支持时,通过错误回调通知H5页面。

在 Hybrid 开发中,为了解决回调函数的问题,我们可以使用一种约定的方式,让原生代码返回一个标识符给 H5 端,表示回调函数的唯一标识。然后,H5 端将这个标识符保存起来,并在需要的时候调用原生代码提供的另一个方法,传递这个标识符和需要回调的数据。原生代码根据标识符找到对应的回调函数,并执行回调处理。

以下是一个重新设计的例子,演示了如何在 Hybrid 开发中实现回调函数的传递和调用:

在 H5 页面中(例如 index.html):

<!DOCTYPE html>
<html>
<head><title>Error Handling Example</title>
</head>
<body><h1>Error Handling Example</h1><script>// 保存回调函数的对象var callbacks = {};// 定义一个处理错误的回调函数function onError(errorMessage) {console.error("Received error message from Native:", errorMessage);// 在这里可以执行相应的错误处理逻辑// ...}// 定义一个注册回调函数的方法,返回一个唯一的标识符function registerCallback(callback) {var callbackId = "cb_" + new Date().getTime();callbacks[callbackId] = callback;return callbackId;}// 示例:调用原生方法,处理可能出现的错误function callNativeMethod() {// 注册回调函数,获取回调函数的标识符var callbackId = registerCallback(function(result) {// 检查 result 是否包含 error 字段if (result.error) {// 如果 result 包含 error 字段,则触发错误处理回调onError(result.error);} else {// 否则,继续处理正常的结果console.log("Received result from Native:", result);// 在这里可以执行正常的处理逻辑// ...}});// 调用原生方法,并传递回调函数的标识符window.NativeBridge.someFunction(callbackId);}</script>
</body>
</html>

在 Android 原生代码中:

import android.os.Bundle;
import android.webkit.JavascriptInterface;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import androidx.appcompat.app.AppCompatActivity;
import org.json.JSONException;
import org.json.JSONObject;public class MainActivity extends AppCompatActivity {private WebView webView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);webView = findViewById(R.id.webView);WebSettings webSettings = webView.getSettings();webSettings.setJavaScriptEnabled(true);// 添加 JavaScript 接口到 WebView 中webView.addJavascriptInterface(new NativeBridge(), "NativeBridge");webView.setWebChromeClient(new WebChromeClient());webView.loadUrl("file:///android_asset/index.html");}// 定义一个 JavaScript 接口类,供 H5 页面调用private class NativeBridge {@JavascriptInterfacepublic void someFunction(String callbackId) {try {// 假设这里出现了一个错误,我们模拟一个包含错误信息的 JSON 对象JSONObject errorObject = new JSONObject();errorObject.put("error", "Something went wrong!");// 获取回调函数的标识符对应的回调函数String callbackJs = "callbacks['" + callbackId + "']";// 使用字符串拼接的方式将错误信息传递给 H5 页面的回调函数webView.evaluateJavascript(callbackJs + "(" + errorObject.toString() + ")", null);} catch (JSONException e) {e.printStackTrace();}}}
}

桥接封装

将原生代码和H5交互的桥接代码进行封装,使其更易用、更健壮,避免直接在业务逻辑中直接操作桥接代码,从而降低耦合性。

对于桥接代码,可以封装一个BridgeHelper类,用于处理原生和H5交互的细节,使得在业务逻辑中不直接操作桥接代码。

public class BridgeHelper {private WebView webView;public BridgeHelper(WebView webView) {this.webView = webView;}// 封装调用原生功能的方法public void callNativeFunction(String functionName) {// 构建JavaScript代码String javascriptCode = "javascript:" + functionName + "()";// 调用原生方法webView.loadUrl(javascriptCode);}
}
//其他地方调用
BridgeHelper bridgeHelper = new BridgeHelper(webView);
bridgeHelper.callNativeFunction("someNativeFunction");

安全处理

考虑安全性问题,确保对于原生和H5之间的通信,只暴露必要的接口,并对传递的数据进行验证和过滤,以防止潜在的安全风险。

在封装的API中,对于接收的参数进行验证,确保数据的有效性和安全性。

H5代码:

function sendDataToNative(data) {// 对数据进行验证,确保不为空且符合要求if (data !== null && typeof data === 'object') {// 调用原生方法并传递数据NativeAPI.sendData(data);} else {console.error("Invalid data format!");}
}

版本兼容

针对不同的原生和H5版本,可以进行一些兼容性处理,确保在不同平台和环境下都能正常运行。

调试日志

在桥接代码中添加调试日志,以便在开发和测试过程中更容易发现问题,对于某些复杂的交互,可以在日志中打印交互数据,方便排查问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/3853.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构与算法——什么是线性表(线性存储结构)

我们知道&#xff0c;具有“一对一”逻辑关系的数据&#xff0c;最佳的存储方式是使用线性表。那么&#xff0c;什么是线性表呢&#xff1f; 线性表&#xff0c;全名为线性存储结构。使用线性表存储数据的方式可以这样理解&#xff0c;即“把所有数据用一根线儿串起来&#xf…

J2EEJSP标签02Foreach标签select

目录 一.foreach标签 编写助手类 编写tld 测试数据辅助类 在页面上使用标签 二.select 编写助手类 编写tld 在页面上使用标签 一.foreach标签 编写助手类 public class ForeachTag extends BodyTagSupport {//存放数据源private List<?> items;//每次循环获取的…

餐饮业油烟在线监测系统的具体应用 安科瑞 许敏

摘要&#xff1a;本文利用物联网技术&#xff0c;构建了一套餐饮企业智能油烟在线监测系统&#xff0c;该系统前台由厨房端和管道端组成&#xff0c;通过网关接入云平台管理系统&#xff0c;实时监控烟道阀门的启闭、变频风机的启停与风速及功率调节、油烟浓度数据等。结合动态…

随手笔记——如何手写高斯牛顿法

随手笔记——如何手写高斯牛顿法 说明源代码 说明 将演示如何手写高斯牛顿法 源代码 #include <iostream> #include <chrono> #include <opencv2/opencv.hpp> #include <Eigen/Core> #include <Eigen/Dense>using namespace std; using names…

HBase

一 HBase简介与环境部署 1.1 HBase简介&在Hadoop生态中的地位 1.1.1 什么是HBase HBase是一个分布式的、面向列的开源数据库HBase是Google BigTable的开源实现HBase不同于一般的关系数据库, 适合非结构化数据存储 1.1.2 BigTable BigTable是Google设计的分布式数据存储…

React总结-01

要点 create app use npx and lanchfolder File structure and main entry point in reactwhat is jsxuseState npx create-react-app my-app cd my-app npm start开始你的第一个react程序 删除除了index.js其他文件 import React from react; import ReactDOM from react-d…

【Linux工具】编译器、调式器、项目自动化构建工具以及git的使用3(GDB调试器的基础使用)

【Linux工具】编译器、调式器、项目自动化构建工具以及git的使用3&#xff08;GDB调试器的基础使用&#xff09; 目录 【Linux工具】编译器、调式器、项目自动化构建工具以及git的使用3&#xff08;GDB调试器的基础使用&#xff09;背景gdb的一些指令gdb实际运用显示代码运行程…

【NLP】transformers的位置编码

一、背景 本文是“实现的变压器”系列的第二篇。它从头开始引入位置编码。然后,它

Day4 网络流与二分图

之前那篇博客是在入门网络流时写的&#xff0c;现在对网络流重新有了一定的理解。 1. 最大流 FF 增广思想 Ford–Fulkerson 增广&#xff0c;核心即不断找增广路并增广。 dfs 实现 // FF brute #include <bits/stdc.h> #define int long longusing namespace std;in…

OkHttp原理和机制讲解

OkHttp原理和机制讲解 本文链接&#xff1a;https://blog.csdn.net/feather_wch/article/details/131767285 1、OkHttp的原理和机制包括哪些部分&#xff1f; 设计模式的运用&#xff1a;建造者模式、外观模式、责任链模式整体流程分发器(调度机制)TCP链接复用(复用机制)拦截…

2023米哈游图像算法暑期实习面经

来源&#xff1a;投稿 作者&#xff1a;LSC 编辑&#xff1a;学姐 本文不可转载 违者必究 1.自我介绍 2.能实习多久&#xff1f;公司在心目中的地位排序等 3.是否了解公司&#xff0c;用他们的产品吗&#xff1f;(比如原神) &#xff0c;喜欢游戏吗&#xff1f; 我只知道公司…

划片机的作用将晶圆分割成独立的芯片

划片机是将晶圆分割成独立芯片的关键设备之一。在半导体制造过程中&#xff0c;晶圆划片机用于将整个晶圆切割成单个的芯片&#xff0c;这个过程被称为“晶圆分割”或“晶圆切割”。 晶圆划片机通常采用精密的机械传动系统、高精度的切割刀具和先进的控制系统&#xff0c;以确保…

web-其他注入

堆叠注入 mysqli_query()只能执行一条SQL语句&#xff0c;mysqli_multi_query()可以执行多条语句 堆叠注入与联合查询的区别&#xff1a;union 执行的语句类型是有限的&#xff0c;只能执行 select &#xff0c;堆叠注入可以执行任意语句。但使用堆叠注入&#xff0c;需要后端…

恢复idea删除的git本地文件

idea中删除git本地文件无法远程拉取pull已删除文件的问题 当前本地库处于另一个分支中&#xff0c;需将本分支Head重置&#xff0c;git 强行pull并覆盖本地文件 解决方式一&#xff1a; git fetch --all git reset --hard origin/master git pull解决方式二&#xff1a; git…

Oracle密码文件

Oracle密码文件 Oracle密码文件用于用户远程管理数据库验证 我们可以通过将普通用户加入到密码文件中&#xff0c;使他们可以使用sysdba或sysoper的权限来管理数据库 使用ORAPWD命令创建 语法如下: ORAPWD FILEfilename [ENTRIESnumusers] [FORCE{Y|N}] [IGNORECASE{Y|N}] …

ylb-项目简介

1、各模块服务功能 注&#xff1a;其部分实体类、接口、mapper文件由MyBatis逆向工程生成。 2、Maven管理&#xff08;多模块&#xff0c;继承和聚合&#xff09; 2.1 parent模块 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"…

DevOps系列文章之 Dockerfile 使用流程

制作项目应用镜像 主要步骤&#xff1a; Step1、准备项目应用程序包 Step2、编写Dockerfile及启动脚本 Step3、docker build 构建镜像 Step4、docker run 启动容器 Step5、docker exec 进入容器进行验证 Step6、镜像的导入导出 Step7、提交容器生成新镜像 Step1、准备项目应…

如何缩短 js 解析时间,如何优化首屏(延迟加载)

缩短js解析时间 代码优化 避免全局查找&#xff08;沿着作用域链找需要时间&#xff09;&#xff0c;避免闭包&#xff0c;用数据结构等 减小js的大小&#xff1a;压缩和混淆 压缩 剔除没用到的代码&#xff0c;把长表达式转换成同含义的短表达式等 语法转换和优化&#…

c++ 无锁队列的简单实现

无锁队列的基本介绍 一个关于无锁队列的多线程读写代码示例。在这里&#xff0c;我提供一个简单的示例来说明这个问题。 在使用无锁队列时&#xff0c;需要注意以下几点&#xff1a; 使用原子操作来实现对队列的读写操作&#xff0c;以避免多线程同时访问同一数据导致的竞争条…

在SPringBoot生成验证码

1.引入依赖,这个依赖中包含了生成验证码的工具类 <!--引入hutool --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.9</version></dependency> 2.编写配置类 import cn.hu…