HarmonyOS鸿蒙Next中往web传json map问题
HarmonyOS鸿蒙Next中往web传json map问题 网页内嵌了一个web组件,需要点击ArkUI按钮将json数据传输到webview内,应该如何实现呢?
- ArkTS 侧实现 (发送方)
**核心思路:**将 JSON 对象序列化为字符串,通过 runJavaScript 调用网页中预定义的全局函数。
import { webview } from '@kit.ArkWeb';
import { promptAction } from '@kit.ArkUI';
@Entry
@Component
struct WebDataTransferPage {
// 1. 创建控制器实例
private controller: webview.WebviewController = new webview.WebviewController();
// 模拟要发送的 JSON 数据
@State jsonData: object = {
userId: "10086",
userName: "VoyahUser",
timestamp: Date.now()
};
build() {
Column() {
// 2. ArkUI 按钮
Button('发送 JSON 到 WebView')
.width('80%')
.height(50)
.margin(20)
.onClick(() => {
this.sendDataToWeb();
})
// 3. Web 组件
Web({ src: $rawfile('index.html'), controller: this.controller })
.javaScriptAccess(true) // 【关键】必须开启 JavaScript 支持
.onPageEnd(() => {
console.info('页面加载完成,可以开始通信');
})
.onConsole((event) => {
// 监听网页打印的日志,方便调试
console.info(`[Web Console]: ${event.message.getMessage()}`);
return true;
})
}
.width('100%')
.height('100%')
}
/**
* 核心方法:发送数据
*/
private sendDataToWeb() {
// 1. 将 JSON 对象转换为字符串
const jsonString = JSON.stringify(this.jsonData);
// 2. 构造要在网页中执行的 JS 代码
// 假设网页中有一个名为 receiveDataFromArk 的全局函数
const jsCode = `if (typeof receiveDataFromArk === 'function') {
receiveDataFromArk('${jsonString}');
} else {
console.log('网页未定义 receiveDataFromArk 函数');
}`;
// 3. 执行 JS
try {
this.controller.runJavaScript(jsCode).then(() => {
console.info('JSON 数据发送成功');
}).catch((err: Error) => {
console.error('发送失败:', err.message);
});
} catch (error) {
console.error('runJavaScript 异常:', error);
}
}
}
- Web 侧实现 (接收方)
在你的 $rawfile/index.html 或远程网页中,需要定义一个全局函数来接收并解析数据。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>HarmonyOS Web Demo</title>
</head>
<body>
<h1>等待 ArkUI 发送数据...</h1>
<div id="result" style="padding: 20px; background: #f0f0f0;">暂无数据</div>
<script>
/**
* 定义全局函数供 ArkTS 调用
* @param {string} jsonStr - ArkTS 传来的 JSON 字符串
*/
function receiveDataFromArk(jsonStr) {
console.log("收到 ArkTS 数据:", jsonStr);
try {
// 1. 解析 JSON 字符串
const data = JSON.parse(jsonStr);
// 2. 更新页面 UI
document.getElementById('result').innerHTML =
`用户ID: ${data.userId}<br>用户名: ${data.userName}`;
// 3. 可以在这里执行其他业务逻辑
alert("数据接收成功!");
} catch (e) {
console.error("JSON 解析失败:", e);
}
}
</script>
</body>
</html>
总结建议
- 简单推送:使用 runJavaScript 调用网页全局函数,这是最直接的方式。
- 安全性:务必在 Web 组件中开启 .javaScriptAccess(true)。
- 调试:利用 .onConsole() 回调,你可以在 DevEco Studio 的 HiLog 中直接看到网页 console.log 的输出,这对排查 JSON 格式问题非常有帮助。
更多关于HarmonyOS鸿蒙Next中往web传json map问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
APP应用侧可以通过runJavaScript()和runJavaScriptExt()方法调用前端页面的JavaScript相关函数。
runJavaScript()和runJavaScriptExt()在参数类型上有以下差异:runJavaScriptExt()支持string和ArrayBuffer类型参数,而runJavaScript()仅支持string类型参数。
在下面的示例中,点击应用侧的“runJavaScript”按钮时,触发前端页面的htmlTest()方法。
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<button type="button" onclick="callArkTS()">Click Me!</button>
<h1 id="text">这是一个测试信息,默认字体为黑色,调用runJavaScript方法后字体为黄色、调用runJavaScriptParam方法后字体为绿色、调用runJavaScriptCodePassed方法后字体为红色</h1>
<script>
// 有参函数。
var param = "param: JavaScript Hello World!";
function htmlTestParam(param) {
document.getElementById('text').style.color = 'green';
console.info(param);
}
// 无参函数。
function htmlTest() {
document.getElementById('text').style.color = 'yellow';
}
// 点击“Click Me!”按钮,触发前端页面callArkTS()函数执行JavaScript传递的代码。
function callArkTS() {
changeColor();
}
</script>
</body>
</html>
import { webview } from '@kit.ArkWeb';
@Entry
@Component
struct WebComponent {
webviewController: webview.WebviewController = new webview.WebviewController();
aboutToAppear() {
// 配置Web开启调试模式
webview.WebviewController.setWebDebuggingAccess(true);
}
build() {
Column() {
Button('runJavaScriptParam')
.onClick(() => {
// 调用前端页面有参函数。
this.webviewController.runJavaScript('htmlTestParam(param)');
})
Button('runJavaScript')
.onClick(() => {
// 调用前端页面无参函数。
this.webviewController.runJavaScript('htmlTest()');
})
Button('runJavaScriptCodePassed')
.onClick(() => {
// 传递runJavaScript侧代码方法。
this.webviewController.runJavaScript(
`function changeColor(){document.getElementById('text').style.color = 'red'}`);
})
Web({ src: $rawfile('index.html'), controller: this.webviewController })
}
}
}
核心原理
无论使用哪种框架,核心逻辑都是:
- 原生侧(ArkUI): 拦截按钮点击事件,调用 Web 组件提供的 JavaScript 注入接口。
- 数据转换: 将原生侧的 Map/Object 转换为 JSON 字符串。
- Web 侧(JS): 编写一个全局函数来接收这个字符串,并解析回 JSON 对象使用。
方案一:HarmonyOS ArkUI (ArkTS)
如果你是在开发鸿蒙应用,使用的是 @ohos.web.webview 组件。
ArkUI 侧 (ArkTS)
你需要使用 runJavaScript 方法来执行一段 JS 代码,将数据传进去。
import web_webview from '@ohos.web.webview';
@Entry
@Component
struct WebPage {
// 创建一个 WebController 来控制 Web 组件
controller: web_webview.WebviewController = new web_webview.WebviewController();
// 模拟要传输的 JSON Map
private myData: Record<string, any> = { "name": "张三", "age": 18, "city": "Shanghai" };
build() {
Column() {
// 按钮
Button('发送数据到Web')
.onClick(() => {
// 1. 将 Map 转换为 JSON 字符串
let jsonStr = JSON.stringify(this.myData);
// 2. 构造要执行的 JS 代码
// 假设 Web 页面里有一个叫 receiveDataFromNative 的函数
let jsCommand = `receiveDataFromNative('${jsonStr}')`;
// 3. 调用 runJavaScript 注入代码
this.controller.runJavaScript(jsCommand);
})
// Web 组件
Web({ src: 'www.example.com/index.html', controller: this.controller })
}
}
}
Web 侧 (HTML/JS)
在网页中定义对应的接收函数:
// 定义全局函数供原生调用
function receiveDataFromNative(jsonStr) {
console.log("收到原生数据:", jsonStr);
try {
var data = JSON.parse(jsonStr);
// 更新 UI 或处理逻辑
document.getElementById("content").innerText = "姓名: " + data.name;
} catch (e) {
console.error("解析 JSON 失败", e);
}
}
方案二:Flutter (Webview)
如果你使用的是 Flutter 的 webview_flutter 插件。
Flutter 侧 (Dart)
使用 runJavascript 方法。
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class MyWebView extends StatefulWidget {
@override
_MyWebViewState createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
late final WebViewController _controller;
// 模拟 JSON Map
final Map<String, dynamic> myData = {"name": "李四", "score": 95};
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.send),
onPressed: () async {
// 1. 转换为 JSON 字符串
String jsonStr = jsonEncode(myData);
// 2. 转义单引号(防止 JSON 里的双引号破坏 JS 语法,虽然通常 encode 处理好了,但稳妥起见)
// 注意:这里最好用单引号包裹参数,因为 JSON 内部全是双引号
String js = "receiveDataFromNative($jsonStr)";
// 3. 执行 JS
_controller.runJavaScript(js);
},
)
],
),
body: WebView(
initialUrl: 'assets/index.html',
javascriptMode: JavascriptMode.unrestricted, // 必须开启 JS
onWebViewCreated: (WebViewController webViewController) {
_controller = webViewController;
},
),
);
}
}
Web 侧
同上,定义 receiveDataFromNative 函数。
方案三:Android 原生 (WebView)
如果你是在写 Android 原生 ArkUI 组件或 Activity。
Android 侧 (Kotlin/Java)
使用 evaluateJavascript。
val data = mapOf("id" to 101, "status" to "active")
val jsonStr = JSONObject(data).toString()
// 注意转义,Kotlin 中可以使用 raw string """...""" 来简化
val jsCode = "javascript:receiveDataFromNative('$jsonStr')"
webView.evaluateJavascript(jsCode, null)
关键注意事项
-
JS 注入时机:
- 确保 Web 页面已经加载完成(例如监听了
onPageFinished或WebLifecycle的 Ready 状态)之后再发送数据,否则 JS 函数还没定义,调用会失败。 - 如果按钮点击时页面还没好,建议先把数据缓存起来,等页面加载完再发。
- 确保 Web 页面已经加载完成(例如监听了
-
字符转义(非常重要):
- JSON 字符串通常包含双引号
"。 - 如果 JS 函数调用写成
func(" + jsonStr + "),容易因为 JSON 里的双引号导致 JS 语法错误。 - 推荐做法: 在拼接 JS 字符串时,尽量利用 JSON 本身是双引号的特性,或者做好转义。
- 最佳实践: 很多框架(如 Flutter)的
runJavaScript其实可以直接接受对象(取决于版本),或者你需要手动确保生成的字符串是合法的 JS 代码。
- JSON 字符串通常包含双引号
-
安全性:
- 不要传输敏感信息(如密码、Token),因为 JS 代码在客户端是可见的。
总结
实现路径就是:ArkUI 按钮点击 -> JSON.stringify(Map) -> Web组件.runJavaScript(“回调函数(数据)”) -> Web页面对象接收并处理。
找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17
简单的一次性传值用 WebviewController.runJavaScript() 就可以,但要注意 JSON 字符串注入问题,别直接手拼。建议先 JSON.stringify(data),再作为 JS 函数参数传入:this.controller.runJavaScript(window.receiveFromArkTS(${JSON.stringify(data)}))。Web 侧定义 window.receiveFromArkTS = (data) => { … },这里拿到的就是对象。若数据量较大或需要 ArrayBuffer,可以看 runJavaScriptExt();若后续要双向通信、多个方法调用、回调结果,建议用 javaScriptProxy 建一层通信桥,而不是每个按钮都拼 JS 字符串。
这个还是很简单的,鸿蒙里 ArkUI ↔ Web 通信就用官方的:
webviewController.runJavaScript()
你要传 JSON / Map,直接转成字符串丢进去就行,网页那边自动解析成对象。
@Entry
@Component
struct WebToArkTSDemo {
// Web 控制器
webController: WebViewController = new WebViewController();
// 你要发送的 JSON / Map 数据
sendDataToWeb() {
// 1. 定义 JSON 对象(支持嵌套、数组、任意结构)
const data = {
name: "鸿蒙设备",
deviceId: "123456",
status: true,
list: [1, 2, 3],
info: {
temperature: 25,
humidity: 60
}
};
// 2. 转成 JSON 字符串(关键)
const jsonStr = JSON.stringify(data);
// 3. 调用网页的 JS 方法,把 JSON 传过去
this.webController.runJavaScript(`receiveDataFromHarmony(${jsonStr})`);
}
build() {
Column() {
// Web 组件
Web({
src: $rawfile("index.html"), // 本地网页
controller: this.webController
})
.width("100%")
.height(500)
// 按钮:发送数据
Button("点击发送JSON给Web")
.onClick(() => {
this.sendDataToWeb();
})
.margin(10)
}
}
}
可以使用双端通信 ArkWeb渲染框架适配-ArkWeb-应用框架 - 华为HarmonyOS开发者 详细看这个文档

通信层:对上层屏蔽具体的通信机制,主要负责Web侧和ArkTS侧数据的传递,但不解析数据的业务含义,不关注传递的数据内容。数据可以序列化为字符串进行传递或者以object对象进行传递。使用javaScriptProxy代理机制实现的通信层
通道层(Channel):允许注册多种方法层通道。该层的JS侧实现负责把方法层的API信息对象(包含名称、参数、返回值类型等信息)打包成通信层识别的信息数据,交给通信层传递到ArkTS侧。ArkTS侧的实现包含两个主要功能,一个是把信息数据解包出API的信息,并交给ArkTS侧的方法层调用具体的API;另外一个功能就是执行jsCall,ArkTS侧通过WebviewController .runJavaScript()方法在执行JS侧的回调函数
在HarmonyOS Next中,向Web组件传递JSON格式的Map数据,需先将Map转换为普通对象再序列化为JSON字符串。使用JSON.stringify(Object.fromEntries(map))生成字符串,然后通过WebviewController的runJavaScript或evaluateJavaScript方法注入到Web端。Web端需定义接收函数的全局方法。注意避免直接传递Map对象。
在HarmonyOS Next中,向Web组件传递JSON数据常用两种方式:
-
调用
runJavaScript直接执行JS
将JSON对象转为字符串,拼接成JS调用。// ArkUI侧 let jsonStr = JSON.stringify({key: "value"}); this.webController.runJavaScript(`window.receiveData(${jsonStr})`);Web侧需预先定义接收函数:
window.receiveData = (data) => { console.log(data); }; -
通过JavaScriptProxy注入对象(更规范)
先注册代理对象,然后从ArkUI侧调用代理方法传参。// ArkUI注册 this.webController.javaScriptProxy.register({ sendData: (jsonStr: string) => { this.webController.runJavaScript(`window.receiveData(${jsonStr})`); } }, 'nativeProxy', ['sendData']);按钮事件中调用:
this.webController.javaScriptProxy.call('nativeProxy', 'sendData', [JSON.stringify(mapData)]);两种方式都需要Web侧提前定义好接收函数。建议数据量小时用
runJavaScript,接口较多时用javaScriptProxy。


