Appearance
HqManager (股票行情管理器)
管理股票实时行情数据的获取与订阅,自动根据 App 版本选择协议:
- 期货通 iOS < 037.08.389:使用
getHQ原生接口 - 其他平台/版本:使用
UnifiedRequestBridge
类型声明
typescript
type CodeWithMarket = string; // 格式: "股票代码_市场代码",如 "300033_33"
type StockHqInfo = {
code: string; // 股票代码(字段 4)
market: string; // 市场代码(字段 34338)
price: string; // 最新价(字段 10)
priceChangeRatio: string; // 涨跌幅(字段 34818)
name?: string; // 股票名称(字段 55)
high?: string; // 最高价(字段 233)
low?: string; // 最低价(字段 9)
time?: string; // 时间(字段 1)
pre: string; // 昨收价(字段 6)
priceChange: string; // 涨跌额(字段 34821)
[key: string]: string | undefined;
};
type AllStockHqInfo = Record<CodeWithMarket, StockHqInfo>;
type HqRequestParams = {
protocolId: string;
pageId: string;
onlineId: string;
requestDic: string;
actionType?: 'unSubscribe'; // 取消订阅时追加
_stocks?: CodeWithMarket[]; // getHQ 协议内部使用
_columOrder?: string[]; // getHQ 协议内部使用
};
class HqManager {
debug: boolean;
invoked: boolean;
connecting: boolean;
connectDelay: number;
visible: boolean;
error: any;
onlineId: string;
protocolId: number;
pageId: number;
columOrder: string[];
logTableFields: string[];
callback: (res: AllStockHqInfo) => void;
readonly codeWithMarkets: CodeWithMarket[];
constructor(config: {
onlineId: string;
debug?: boolean;
connectDelay?: number;
protocolId?: number;
pageId?: number;
columOrder?: string[];
callback: (res: AllStockHqInfo) => void;
});
registerStocks(stocks: Array<CodeWithMarket>): void;
unregisterStocks(stocks: Array<CodeWithMarket>): void;
clearStocks(): void;
connect(): Promise<void>;
disconnect(): void;
destroy(): void;
handleHqData(rawData: Record<string, string[]>): void;
log(...args: any[]): void;
}构造参数
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
onlineId | string | 是 | — | 订阅唯一标识,用于区分多个 HqManager 实例、取消订阅和返回数据分发 |
callback | function | 是 | — | 行情数据推送回调,接收 AllStockHqInfo |
debug | boolean | 否 | false | 开启调试日志 |
connectDelay | number | 否 | 100 | 重连延迟(毫秒),首次连接不延迟 |
protocolId | number | 否 | 1264 | 协议 ID(getHQ 模式下不生效) |
pageId | number | 否 | 9001 | 页面 ID(getHQ 模式下不生效) |
columOrder | string[] | 否 | ['4', '34338', '10', '34818', '55'] | 请求字段顺序 |
实例属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
codeWithMarkets | CodeWithMarket[] | [] | 只读,当前已注册的股票列表(去重后) |
error | any | null | 最近一次请求或解析错误,无错误时为 null |
visible | boolean | true | 当前页面可见状态,由 onShow/onHide 自动管理 |
invoked | boolean | false | 是否已完成首次连接(首次连接不延迟) |
connecting | boolean | false | 是否正在延迟重连中 |
方法
registerStocks(stocks)
注册股票并建立连接。使用引用计数机制:同一股票多次注册会增加计数,只有在股票为新加入时才触发重连。
stocks: Array<CodeWithMarket>— 股票代码数组,格式为"代码_市场"
unregisterStocks(stocks)
取消注册股票。使用引用计数:只有当计数减至 0 时才从列表移除,移除后触发重连。
stocks: Array<CodeWithMarket>— 要取消的股票代码数组
clearStocks()
清空所有已注册股票,发送空订阅请求断开数据推送。
connect()
手动触发连接/重连。首次连接立即执行,后续每次重连会等待 connectDelay 毫秒防抖。内部使用版本号机制防止并发重连导致的脏请求。
disconnect()
断开当前连接,清理 native 端的订阅回调。
destroy()
销毁实例:
- 清空所有股票引用
- 断开连接
- 移除 native 端的 handler 注册
- 清除
window.hqIns/window.hqIns_${onlineId}引用(debug 模式下) - 标记实例为已销毁,后续生命周期回调不再执行
handleHqData(rawData)
处理原始行情数据,将列式数据转换为按股票组织的 AllStockHqInfo 对象后回调 callback。
rawData: Record<string, string[]>— 原始数据,key 为字段编号(或映射后的字段名),value 为按股票索引排列的值数组
log(...args)
调试日志输出,仅在 debug: true 时输出到控制台,格式为 [HqManager:${onlineId}:${时间}]。
示例
typescript
import { HqManager } from '@fu/matrix';
// 创建实例
const hqManager = new HqManager({
onlineId: 'my-app',
debug: true,
callback: res => {
console.log('行情数据:', res);
// {
// "300033_33": { "code": "300033", "market": "33", "price": "100.01", "priceChangeRatio": "0%",
// "name": "同花顺", "pre": "99.50", "priceChange": "0.51" },
// "000099_33": { "code": "000099", "market": "33", "price": "15.16", "priceChangeRatio": "-1.24%",
// "name": "中信信息", "pre": "15.35", "priceChange": "-0.19" }
// }
}
});
// 注册股票(新股票会触发重连,已有股票不会重复)
hqManager.registerStocks(['300033_33', '000099_33']);
hqManager.registerStocks(['600519_11']); // 新增一只,触发重连
// 取消部分股票(同一股票需要 unregister 同等次数才能移除)
hqManager.unregisterStocks(['000099_33']);
// 查看当前订阅的股票
console.log(hqManager.codeWithMarkets); // ["300033_33", "600519_11"]
// 清空全部订阅
hqManager.clearStocks();
// 断开连接(保留注册列表)
hqManager.disconnect();
// 销毁实例(完全清理)
hqManager.destroy();工作原理
- 注册股票 —
registerStocks使用引用计数(_stockRefsMap),同一股票多次注册会累加计数,只有新加入的股票才会触发重连;unregisterStocks递减计数,计数归零时才真正移除并重连;clearStocks清空全部并发送空请求断开推送 - 建立连接 — 首次
connect立即执行,后续每次重连会等待connectDelay防抖。内部使用connectVersion版本号机制,延迟结束后若版本号已变更则放弃本次请求 - 数据推送 — 统一注册
UnifiedRequestBridge(或getHQ)回调,根据返回头部的onlineId分发到对应实例 - 数据转换 —
handleHqData将原始列式数据(每个字段对应一个数组)通过mapFields映射字段名后,按股票索引重组为AllStockHqInfo对象 - 生命周期管理 — 自动监听页面显示/隐藏(
onShow/onHide),切后台时断开连接并递增版本号,回前台时自动重连。destroy后不再响应生命周期事件
环境行为
| 环境 | 桥接模式 | 订阅 | 取消订阅 |
|---|---|---|---|
| Android | Android 模式 | WebViewJavascriptBridge.callOnlineHandler('UnifiedRequestBridge', onlineId, params) | WebViewJavascriptBridge.clearOnlineHandler([onlineId]) |
| iOS(>= 037.08.389) | iOS 模式 | callNativeHandler('UnifiedRequestBridge', params) | 在原请求参数上追加 actionType: 'unSubscribe' |
| 期货通 iOS(< 037.08.389) | getHQ 模式 | callNativeHandler('getHQ', {stocklist, marketlist, columnorder}) | callNativeHandler('getHQ', {method:'disconnect'}) |
| 期货通鸿蒙 | Android 模式 | 同 Android | 同 Android |
| 手炒/iFind 鸿蒙 | iOS 模式 | 同 iOS | 同 iOS |
协议选择由 bridge 层通过 isHigherInnerVersion 自动检测,调用方无需关心。
协议差异
| UnifiedRequestBridge | getHQ | |
|---|---|---|
| 适用平台 | iOS / Android / 鸿蒙 | 仅期货通 iOS(< 037.08.389) |
| 多实例隔离 | 支持,按 onlineId 路由 | 部分支持,所有实例的 stocks 合并发送 |
protocolId / pageId | 支持自定义 | 不支持,原生接口无此参数 |
| 请求格式 | {protocolId, pageId, onlineId, requestDic} | {stocklist, marketlist, columnorder} |
| 取消订阅 | actionType: 'unSubscribe' | {method: 'disconnect'} 清空全部 |
| 适用场景 | 复杂订阅,多页面并行 | 简单取数,单页面使用 |
注意:getHQ 模式存在兼容性限制,无法指定
protocolId和pageId,构造函数中相关配置项在该模式下不生效。该模式仅用于旧版期货通 iOS 的行情兼容,不建议在新业务中依赖。getHQ 模式下多个实例的股票列表会合并后统一发送给 native。
调试
开启 debug: true 后:
- 实例暴露到
window.hqIns和window.hqIns_${onlineId} - 连接参数和行情数据输出到控制台
- 使用
console.table按logTableFields字段格式化输出行情数据
注意事项
- 股票代码格式为
代码_市场,如300033_33(300033 是股票代码,33 是市场代码) onlineId必填,多实例时请使用不同的onlineId来隔离,重复 ID 会打印警告destroy()会同时清理window.hqIns/window.hqIns_${onlineId}引用并移除 native handlerregisterStocks使用引用计数,同一股票注册 N 次需要unregisterStocksN 次才能移除;新股票加入才会触发重连clearStocks()会发送空订阅请求断开推送,而disconnect()只断开连接不清空列表- getHQ 模式下
protocolId/pageId配置不生效,无法指定特定协议 visible属性由生命周期自动管理,页面隐藏时断开连接,显示时自动重连