当前位置: 首页 > news >正文

强大的鸿蒙HarmonyOS网络调试工具PageSpy 介绍及使用

PageSpy 是一款兼容 Web、小程序、React Native、鸿蒙 App 等平台项目的开源调试平台。通过封装原生 API,它能将调用原生方法时的参数进行过滤和转化,并整理成特定格式的消息,供调试端消费。调试端接收到这些消息后,会以类似本地控制台的功能界面呈现出来。

当遇到无法在本地使用控制台调试的情况时,PageSpy 就显得尤为强大和便捷。该开源神器支持Web、小程序和HarmonyOS等各种平台。相当于你可以远程查看设备的日志,即便设备选在千里之外,也可以抓取它的日志和查看报警报错信息,岂不美哉?

接下来,我将通过几个典型场景来具体了解 PageSpy 的优势。

PageSpy For HarmonyOS介绍

@huolala/page-spy-harmony 是由货拉拉开源项目 PageSpy 在鸿蒙端实现的 SDK。 PageSpy 用于本地开发调试、远程调试用户设备,支持调试 WEB / 小程序 / 鸿蒙等平台,更多细节内容介绍请参考 主仓库。

page-spy-harmony 三方库地址
https://ohpm.openharmony.cn/#/cn/detail/@huolala%2Fpage-spy-harmony

常见调试场景
  1. 本地调试 H5 与 Webview 应用:传统 H5 信息查看面板在移动端存在屏幕尺寸限制、操作不便、显示效果差、信息被截断等问题。PageSpy 则解决了这些问题,提供了更为直观和高效的方式。

  2. 远程办公与跨地域协作:传统沟通方式如邮件、电话或视频会议,不仅效率低下,且信息传递不完整,容易引发误解和误判。PageSpy 可以帮助开发者通过一个网页界面实时查看调试信息,提高了远程调试的效率。

  3. 用户终端出现白屏问题:面对用户终端异常问题,通常依赖数据监控和日志分析定位问题,耗时且需要深入了解业务和技术实现。PageSpy 的介入可以简化这一流程,帮助快速定位问题。

搭建后台服务环境

在引入 鸿蒙客户端SDK 前,需先部署 PageSpy 服务,因为该方案是需要在网页上查看调试信息的,需要部署个后台服务。PageSpy 后台服务提供多种部署方案,可以根据自身情况选择任意一种进行部署:

方式一: 使用 Node 部署:通过 yarn 或 npm 安装。

 yarn global add @huolala-tech/page-spy-api@latest  # 如果你使用 npmnpm install -g @huolala-tech/page-spy-api@latest

安装完成后,可以在命令行中执行 page-spy-api 启动服务。启动后,打开浏览器访问 http://localhost:6752 体验,测试完成后部署到服务器上。

方式二:使用 Docker 部署

    docker run -d --restart=always -v ./log:/app/log -v ./data:/app/data -p 6752:6752 --name="pageSpy" ghcr.io/huolalatech/page-spy-web:latest

启动完成后,打开浏览器访问 http://localhost:6752 体验,测试完成后部署到服务器上。推荐使用docker方式在服务端部署,简单快捷,一行命令搞定。

在这里插入图片描述

这里我选择了使用 docker进行部署。安装部署完成后服务自动启动,端口号是6752.浏览器打开 http://yourremoteip:6752 就可以体验了。

在这里插入图片描述
服务部署完成后,打开对应网页,点击web页面左上角的开始调试按钮。如果有客户端接入进来了,则能看到以下页面:
在这里插入图片描述

鸿蒙应用集成使用方法

鸿蒙应用的集成方法很简单,只需几行代码,无侵入的完成集成。

  1. 安装依赖:由于鸿蒙应用商店最低要求使用 API 12,建议使用 API 17。我们的应用最低也是在 API 17,可以使用基于 API 16 版本开发的 @huolala/page-spy-harmony@2.1.x 版本。

    ohpm install @huolala/page-spy-harmony
    

    这将安装 ^2.1.0 版本。

  2. 连接服务:首先创建一个 axios 的单例对象并导出,项目中所有网络请求均使用该对象。

    import axios from '@ohos/axios';
    const axiosInstance = axios.create({baseURL: 'https://api.github.com',timeout: 1000,
    });
    export {axiosInstance};
    

    然后在 EntryAbility 的 onWindowStageCreate 生命周期方法中创建 PageSpy 对象。

    import { PageSpy } from '@huolala/page-spy-harmony';
    onWindowStageCreate(windowStage: window.WindowStage): void {new PageSpy({context: this.context,api: "192.168.1.25:6752",enableSSL: false,axios: axiosInstance})windowStage.loadContent('pages/Index', (err) => {if (err.code) {hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));return;}hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');});
    }
    

注意事项:

1.如果是在自己的电脑上进行测试(服务端装在你自己的本地电脑上),需要手机和电脑连接同一个 Wi-Fi,api 就写电脑的 ip 地址 + 6752 端口号。本地部署没有 https 证书,所以 enableSSL 必须设置为 false。axios 为我们前面创建的 axios 单例对象。

2.如果服务是部署在云服务器上,则这里的ip需要填写你部署的PageSpy 的服务地址和端口。如果不是https 连接,则必须把enableSSL 设置为false.

3.当前PageSpy的HarmonyOS的sdk只支持axios客户端。如果嫌axios客户端的使用太繁琐,推荐坚果派的nutpi/axios三方库,该库极大简化了axios网络库的使用,且也是支持PageSpy。

nutpi/axios三方库地址: https://ohpm.openharmony.cn/#/cn/detail/@nutpi%2Faxios

测试连接:将应用运行到手机上,在 log 日志中看到下面两条日志:

 [PageSpy] [LOG] Device ID: f764[PageSpy] [LOG] Connect successful.

然后点击网页右上角的开始调试,选择在线实时即可开始调试。此时在新页面上可以看到我们的设备。

使用 PageSpy 调试

当环境搭建好后,可以通过点击调试按钮进入调试页面。可以看到左侧有输出、网络、存储、系统四个选项。

  • 输出:展示 console 打印的日志,不能展示 hilog 输出的日志。
  • 网络请求:PageSpy 将网络请求的详细信息保存下来,对远程协同办公和内部测试特别有用。
  • AppStorage 存储:PageSpy 可以实时查看 AppStorage 中保存的数据,无需手动刷新网页。
  • 系统:展示系统概览信息,如 Platform 和 User Agent。
生产环境部署

确认测试无误后,可以将 PageSpy 部署到生产环境中。PageSpy 服务端会自动读取当前运行目录下的 config.json 配置文件,支持配置运行端口、多实例部署、跨域配置、日志数据配置等。

版本兼容性
  • @huolala/page-spy-harmony@1.x:基于 API 9 版本开发。
  • @huolala/page-spy-harmony@2.0.x:基于 API 11 版本开发。
  • @huolala/page-spy-harmony@2.1.x:基于 API 16 版本开发。
能力概览
  • console 打印日志
  • 项目报错信息输出
  • 网络请求信息输出
  • 应用数据查看
开始正式使用

在引入 SDK 之前,请先部署 PageSpy 服务,部署方式参见上文或者可参考官方文档的部署教程。

部署成功后,在项目中引入 HAR SDK:

ohpm install @huolala/page-spy-harmony

然后在项目中引入 SDK 并实例化:

import { PageSpy } from '@huolala/page-spy-harmony';
import axiosInstance from 'path/to/your/axios';export default class EntryAbility extends UIAbility {onWindowStageCreate(windowStage: window.WindowStage) {const $pageSpy = new PageSpy({context: this.context,api: '<your-pagespy-server-host>',enableSSL: true,axios: axiosInstance,});}
}

PageSpy 默认会在 DevEcho Studio 的 Log 面板中输出调试的连接信息;也可以使用 $pageSpy.showPanel(); 方法手动弹窗查看。

如果使用的是坚果派的nutpi/axios的三方库,则使用方式如下:

import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import PreferencesUtils from '../utils/PreferencesUtils';
import { PageSpy } from '@huolala/page-spy-harmony';
import { axiosClient } from '../utils/axiosClient';export default class EntryAbility extends UIAbility {onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');}onDestroy(): void {hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');}onWindowStageCreate(windowStage: window.WindowStage): void {// Main window is created, set main page for this abilityhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');new PageSpy({context: this.context,api: "120.27.146.2xx:6752", //你的PageSpy后台服务地址enableSSL: false,axios: axiosClient.instance,})windowStage.loadContent('pages/StartPage', (err) => {if (err.code) {hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');return;}hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');});}
}

axiosClient从哪来?axiosClient是使用nutpi/axios三方库封装的一个网络请求工具类。

源码如下:

//axiosClient.ets
import {AxiosError,AxiosHeaders,AxiosHttpRequest,AxiosRequestHeaders,FileUploadConfig,HttpPromise,UploadFile
} from '@nutpi/axios';
import { Log } from './logutil';
import { promptAction, router } from '@kit.ArkUI';
import { AppAuthManager } from './AppAuthManager';function showToast(msg: string) {Log.debug(msg)promptAction.showToast({ message: msg })
}function showLoadingDialog(msg: string) {Log.debug(msg)// promptAction.showToast({ message: msg })
}function hideLoadingDialog() {}// 移除硬编码的token,改为动态获取
// AppStorage.SetOrCreate('Authorization', "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6Miwibmlja25hbWUiOm51bGwsImF2YXRhciI6bnVsbCwiaWF0IjoxNzU0NjY2ODk3LCJleHAiOjE3NTQ3NTMyOTd9.32Kp1pCt-HIqKglOpLrRhOMdSjyonutEDkifQRaoZCo");// 图片地址的前缀
export const IMAGE_BASE_URL = 'http://xxx.felin.xxxx.com'/*** axios请求客户端创建*/
const axiosClient = new AxiosHttpRequest({baseURL: "http://xxx.maotuai.com/api",timeout: 10 * 1000,checkResultCode: false,showLoading: true,headers: new AxiosHeaders({'Content-Type': 'application/json'}) as AxiosRequestHeaders,interceptorHooks: {requestInterceptor: async (config) => {// 在发送请求之前做一些处理,例如打印请求信息Log.debug('网络请求Request 请求方法:', `${config.method}`);Log.debug('网络请求Request 请求链接:', `${config.url}`);Log.debug('网络请求Request Params:', `\n${JSON.stringify(config.params)}`);Log.debug('网络请求Request Data:', `${JSON.stringify(config.data)}`);// 动态获取tokenconst token = AppAuthManager.getToken();if (token) {config.headers['Authorization'] = 'Bearer ' + token;}axiosClient.config.showLoading = config.showLoadingif (config.showLoading) {showLoadingDialog("加载中...")}if (config.checkLoginState) {// 检查登录状态if (!AppAuthManager.getToken()) {if (config.needJumpToLogin) {// 可以在这里跳转到登录页面// router.replaceUrl({ url: 'pages/LoginPage' });}throw new AxiosError("请登录")}}return config;},requestInterceptorCatch: (err) => {Log.error("网络请求RequestError", err.toString())if (axiosClient.config.showLoading) {hideLoadingDialog()}return err;},responseInterceptor: (response) => {//优先执行自己的请求响应拦截器,在执行通用请求request的if (axiosClient.config.showLoading) {hideLoadingDialog()}if (response.status === 200) {if (response.data.code != 0) {errorHandle(response)// 处理业务错误return Promise.reject(response)}return Promise.resolve(response);} else {return Promise.reject(response);}},responseInterceptorCatch: (error) => {if (axiosClient.config.showLoading) {hideLoadingDialog()}Log.error("网络请求响应异常", error.toString());errorHandler(error);return Promise.reject(error);},}
});// 处理业务错误
function errorHandle(response) {switch (response.data.code) {case 401:AppAuthManager.clearToken();router.replaceUrl({ url: 'pages/LoginPage' });break;// 403 token过期// 登录过期对用户进行提示// 清除本地token和清空vuex中token对象// 跳转登录页面case 403:showToast("登录过期,请重新登录")AppAuthManager.clearToken();router.replaceUrl({ url: 'pages/LoginPage' });break;// 404请求不存在case 404:showToast("网络请求不存在")break;default:showToast(response.data.message)break}
}function errorHandler(error: any) {if (error instanceof AxiosError) {//showToast(error.message)} else if (error != undefined && error.response != undefined && error.response.status) {switch (error.response.status) {// 401: 未登录// 未登录则跳转登录页面,并携带当前页面的路径// 在登录成功后返回当前页面,这一步需要在登录页操作。case 401:AppAuthManager.clearToken();router.replaceUrl({ url: 'pages/LoginPage' });break;// 403 token过期// 登录过期对用户进行提示// 清除本地token和清空vuex中token对象// 跳转登录页面case 403:showToast("登录过期,请重新登录")AppAuthManager.clearToken();router.replaceUrl({ url: 'pages/LoginPage' });break;// 404请求不存在case 404:showToast("网络请求不存在")break;// 其他错误,直接抛出错误提示default:if (error.response.data && error.response.data.message) {showToast(error.response.data.message)}}}
}// 导出AppAuthManager供其他模块使用
export { AppAuthManager as AppAuthManager, axiosClient, HttpPromise, UploadFile, FileUploadConfig };

有了上述封装后,写网络接口变得超级简单了,如以下使用方式,清晰明了:

/*** 照片管理相关api实现*/import { axiosClient, HttpPromise } from "../../../utils/axiosClient";
import { GetPhotoDetailResp } from "../bean/photo/getPhotoDetailResp";
import { GetPhotoListReq } from "../bean/photo/getPhotoListReq";
import { GetPhotoListResp } from "../bean/photo/getPhotoListResp";
import { PhotoAddReq } from "../bean/photo/photoAddReq";
import { PhotoAddResp } from "../bean/photo/photoAddResp";// 创建照片
export const photoAdd = (req:PhotoAddReq): HttpPromise<PhotoAddResp> => axiosClient.post({url:'/app/photo/add',data: req});// 获取照片列表
export const getPhotoList = (req:GetPhotoListReq): HttpPromise<GetPhotoListResp> => axiosClient.get({url:'/app/photo/',params: req});// 获取照片详情
export const getPhotoDetail = (photoId:string): HttpPromise<GetPhotoDetailResp> => axiosClient.get({url:'/app/photo/'+photoId});
PageSpy 后台界面调试

进入调试后,可以清晰看到后台的网络接口访问,请求的数据和响应的数据清晰明了。
在这里插入图片描述

在左侧的输出选项页面中,则可以看到应用console.log打印的日志:

在这里插入图片描述

在左侧的存储选项中,则可以查看应用的AppStorage中存放的数据。

在这里插入图片描述

总结

通过以上介绍,可以看出 PageSpy 是一款强大的调试工具,适用于多种开发场景,特别是对于移动端开发调试提供了极大的便利性。推荐大家尝试并体验下这一网络调试神器。


文章转载自:

http://uGEHDm2d.fpryg.cn
http://ZCLR1gMZ.fpryg.cn
http://Y99g2L8n.fpryg.cn
http://6wK3lMSN.fpryg.cn
http://dAwsj3TN.fpryg.cn
http://jodp1GSL.fpryg.cn
http://94GOiJKC.fpryg.cn
http://eqCk9WqX.fpryg.cn
http://Jj1Je5fa.fpryg.cn
http://mUrvTymn.fpryg.cn
http://KH3ak9xj.fpryg.cn
http://awK6YAYU.fpryg.cn
http://oytKVtom.fpryg.cn
http://nEgVLz9K.fpryg.cn
http://S94VC6Hq.fpryg.cn
http://udHTC75y.fpryg.cn
http://67atHHZr.fpryg.cn
http://6iml41kV.fpryg.cn
http://93ScP3wn.fpryg.cn
http://xY0rp6kF.fpryg.cn
http://ZZniaSxC.fpryg.cn
http://sbpGesJD.fpryg.cn
http://NsxTnzof.fpryg.cn
http://d2TJPGIr.fpryg.cn
http://6ZRxjSI2.fpryg.cn
http://oHrVb22G.fpryg.cn
http://85u9yvZK.fpryg.cn
http://6DiE5cjE.fpryg.cn
http://0hs0roX2.fpryg.cn
http://LPGg3OCf.fpryg.cn
http://www.dtcms.com/a/377909.html

相关文章:

  • C++/QT 1
  • 软件测试用例详解
  • 【ROS2】基础概念-进阶篇
  • 三甲地市级医院数据仓湖数智化建设路径与编程工具选型研究(上)
  • 利用Rancher平台搭建Swarm集群
  • BRepMesh_IncrementalMesh 重构生效问题
  • VRRP 多节点工作原理
  • 运行 Ux_Host_HUB_HID_MSC 通过 Hub 连接 U 盘读写不稳定问题分析 LAT1511
  • Oracle体系结构-控制文件(Control Files)
  • 0303 【软考高项】项目管理概述 - 组织系统(项目型组织、职能型组织、矩阵型组织)
  • Spark-SQL任务提交方式
  • 10、向量与矩阵基础 - 深度学习的数学语言
  • 开发避坑指南(45):Java Stream 求两个List的元素交集
  • React19 中的交互操作
  • 阿里云ECS vs 腾讯云CVM:2核4G服务器性能实测对比 (2025)
  • 网络编程;TCP多进程并发服务器;TCP多线程并发服务器;TCP网络聊天室和UDP网络聊天室;后面两个还没写出来;0911
  • STM32项目分享:基于stm32的室内环境监测装置设计与实现
  • 利用归并算法对链表进行排序
  • GPU 服务器压力测试核心工具全解析:gpu-burn、cpu-burn 与 CUDA Samples
  • Power Automate List Rows使用Fetchxml查询的一个bug
  • Zynq开发实践(FPGA之ddr sdram读写)
  • LeetCode 热题 160.相交链表(双指针)
  • 西门子 S7-200 SMART PLC 编程:转换 / 定时器 / 计数器指令详解 + 实战案例(案例篇)
  • SAM-Med3D:面向三维医疗体数据的通用分割模型(文献精读)
  • 考研复习-计算机网络-第五章-传输层
  • win11安装jdk8-u211-windows
  • 从传统到智能:3D 建模流程的演进与 AI 趋势 —— 以 Blender 为例
  • 开发避坑指南(46):Java Stream 对List的BigDecimal字段进行求和
  • 在OpenHarmony上适配图形显示【3】——添加显示接口类型
  • Node.js 模块化规范详解