react-native-gizwits-ios-agent
v1.0.0
Published
iOS H.264 packet assembly, video decoding and image analysis for React Native
Maintainers
Readme
react-native-gizwits-ios-agent
React Native 的 iOS 视频与图像原生插件:GK 视频分片重组、VideoToolbox H.264 解码、JPEG 帧事件、截图差异检测、指针定位,以及有限的 iOS 后台执行时间。
本包不包含设备连接、BLE 传输、Agent 规划、模型调用或 UI。宿主负责接收设备数据并调用 push()。Live Activity 由宿主 App 自行维护。
环境
- 仅支持 iOS;原生 Pod 最低 iOS 15.5,App 的最低版本还须满足 React Native 自身要求。
- 当前对接基线为 React Native 0.82.1 / React 19.1.1。peer dependency 暂限定 RN 0.82,其他版本需要单独验证后放宽。
- 使用
RCTEventEmitter桥接,在 RN 新架构下依赖 legacy native module interop;没有独立 TurboModule codegen。 - Expo 项目需要自行编译原生 App / development build,Expo Go 不包含本插件。
安装
发布 npm 后:
npm install react-native-gizwits-ios-agent
cd ios
pod install重新编译 iOS App。Pod 由 React Native 自动链接,无需添加手工 pod 'GizwitsIOSAgent'。
尚未发布时,可以在本仓库执行 npm pack,然后在宿主安装生成的 .tgz 文件。使用 Yarn 的宿主可执行 yarn add /absolute/path/to/react-native-gizwits-ios-agent-1.0.0.tgz。
使用
import * as IOSAgent from 'react-native-gizwits-ios-agent';
if (!IOSAgent.isAvailable()) {
throw new Error('请在已安装插件的 iOS App 中使用');
}
const session = `video-${Date.now()}`;
const subscriptions = [
IOSAgent.addListener('GizAgentFrame', frame => {
if (frame.session !== session) return;
const imageURI = `data:image/jpeg;base64,${frame.jpeg}`;
// 将 imageURI 交给 React Native Image 显示。
}),
IOSAgent.addListener('GizAgentError', error => {
if (error.session === session) console.warn(error.message);
}),
IOSAgent.addListener('GizAgentExpired', event => {
if (event.session === session) {
// iOS 授予的临时后台时间已到期,由宿主决定后续行为。
}
}),
];
try {
await IOSAgent.open(session);
} catch (error) {
subscriptions.forEach(subscription => subscription.remove());
IOSAgent.close(session);
throw error;
}
// 每次收到完整 GK 视频包时调用;参数是整包的 base64,不是裸 H.264。
const onVideoPacket = (packet: string) => IOSAgent.push(session, packet);
// 页面/设备会话退出时,先停止调用 onVideoPacket,再清理:
const dispose = () => {
subscriptions.forEach(subscription => subscription.remove());
IOSAgent.close(session);
};原生解码器一次仅维护一个会话。open() 会替换旧会话并重置解码状态;所有事件携带 session,调用方应过滤过期事件。close() 同时结束该会话的临时后台任务,但不会自动移除 JS 事件监听。
API
| 方法 | 返回值 | 说明 |
| --- | --- | --- |
| isAvailable() | boolean | 检查 iOS 平台和原生模块是否存在 |
| open(session) | Promise<boolean> | 初始化或替换解码会话 |
| push(session, packet) | void | 投递 GK 视频包;无效包或过期会话会被忽略 |
| close(session) | void | 关闭匹配的会话并结束其临时后台任务 |
| beginBackground(session) | Promise<boolean> | 申请有限后台时间;未获批准返回 false,其他会话占用时拒绝 |
| endBackground(session) | void | 结束匹配会话的临时后台任务 |
| analyze(options) | Promise<boolean \| Point \| null> | 图像差异检测或指针定位 |
| addListener(event, listener) | { remove(): void } | 订阅原生事件 |
除 isAvailable() 外,调用不支持的平台或未链接的模块会同步抛错。无需在导入模块前进行平台判断。
const changed = await IOSAgent.analyze({
before: beforeJPEGBase64,
after: afterJPEGBase64,
ignore: [[0.5, 0.5]],
});
const pointer = await IOSAgent.analyze({
mode: 'pointer',
before: beforeJPEGBase64,
after: afterJPEGBase64,
x: 0.5,
y: 0.5,
shift: 0.02,
wide: false,
});截图参数使用不带 data: 前缀的 base64,单张字符串最多 8,000,000 字符。坐标和 shift 按图片宽高归一化;无法确定指针时返回 null。差异检测的 ignore 仅作用于细粒度比较,粗粒度整图比较仍可能判定变化。
GizAgentFrame 包含 session、递增帧 id、jpeg、width、height、毫秒时间戳 receivedAt / capturedAt、decodeMs、snap、snapshotID 和 snapshotComplete。capturedAt 是由设备时间估算的时间;只有 snap && snapshotComplete && snapshotID > 0 才表示有请求关联的完整截图。
GizAgentError 包含 session / message;GizAgentExpired 包含 session。完整类型见 index.d.ts。
视频协议与后台行为
push() 接收 GK v1 video 包,头部为 47 4B 01 03,可带前置的 06。常规传输使用整包 base64,也兼容以 474b01 或 06474b01 开头的十六进制字符串。头部之后是小端序号 u16、flags u8 和载荷;START 分片的载荷先带设备时间 u32 LE,之后才是 Annex-B H.264 数据。flags 各位依次为 START、END、IDR、CONFIG、BENCH、SNAP、PREROLL、SNAPSHOT_LAST。完整 CONFIG + SNAP + SNAPSHOT_LAST 包中的设备时间被用作截图请求 ID,后续截图最终帧回传此 ID。
beginBackground() 使用 iOS 临时后台任务,不承诺无限后台运行。BLE 权限、连接、bluetooth-central 后台模式及其生命周期由宿主管理;安装此插件不会自动修改 Info.plist。
从本地 Pod 迁移
当前 gizwits-super-app 可继续使用原有本地 Pod,整理包结构不会改变桥接名称。正式切换时:
- 在宿主安装本包,更新 npm / Yarn 锁文件。
- 删除 Podfile 中
pod 'GizwitsIOSAgent', :path => '../modules/gizwits-ios-agent',避免与自动链接重复。 - 执行
pod install并提交生成的 Podfile.lock,确认来源改为node_modules/react-native-gizwits-ios-agent。 - 重新编译并验证视频、截图和后台会话后,再删除宿主旧
modules/gizwits-ios-agent目录。
原有模板通过 NativeModules.GizwitsIOSAgent / NativeEventEmitter 调用的方式继续兼容,无需将包代码再次打进动态模板。services/iosAgent.ts 中的设备会话、凭证和 BLE 管理仍属于宿主。
开发与发布
JS 入口直接发布,无构建步骤,也不在 npm 包内携带 React Native。仓库内的 JS 测试使用 Node 内建测试框架,无需安装依赖。
npm test
npm run test:native # macOS + Xcode 命令行工具 + ffmpeg(含 libx264)
npm pack --dry-run原生回归测试覆盖分片序号回绕、H.264 参考帧、实时预览、截图关联与最终帧一致性,不替代 iOS App / 真机集成测试。
仓库:https://github.com/kylewang4929/react-native-gizwits-ios-agent
发布前核对包名、版本及 npm 账号权限,并完成宿主集成验证,然后执行 npm publish。Podspec 从 package.json 读取版本和仓库,Git 标签使用 v<version>(例如 v1.0.0)。npm 发布不需要将 Pod 单独提交 CocoaPods Specs。
许可证
MIT。保留原有 LICENSE 中 Henry Yuan 的版权声明;原生视频与图像逻辑源于 esp32-iphone-agent/ios 的适配。
