HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

鸿蒙化适配 react-native-torch:模拟器无闪光灯,依赖硬件的三方库该怎么验证

本文记录把 react-native-torch(手电筒 / 相机闪光灯控制)适配到 HarmonyOS 的完整过程,涵盖版本对齐、原生实现走查、接入宿主、构建运行,以及依赖硬件的库在模拟器上究竟该怎么验证。

react-native-torch 的 API 只有两个,却是个典型例子:它控制的是一块模拟器上根本不存在的硬件。这类库的适配难点不在代码量,而在“什么算验证通过”。

一、先说结论

项 | 结果 |

上游最新版 | 1.2.0 |

是否带原生实现 | 是(ArkTS TurboModule,不是纯 JS) |

是否依赖硬件 | 是,依赖相机闪光灯 |

公开 API | switchState(enabled)、requestCameraPermission(title?, message?),都返回 Promise |

是否需要声明权限 | 不需要(连 ohos.permission.CAMERA 都用不上) |

原生实现体量 | ArkTS 侧 19 行,HAR 包 2,875 字节 |

编译是否通过 | ✅ assembleHap 成功,HAP 从 80,714,316 增至 80,867,227 字节(+152,911 ≈ 149 KB) |

原生是否注册 | ✅ 日志 TM created: RCTTorch |

软件层断言 | ✅ 13 / 13 通过(契约 6 + 参数守卫 7) |

硬件层结论 | ⚠️ 本机没有闪光灯,四次调用全部以 ERR_TORCH_UNAVAILABLE 拒绝——没有返回 true 假装成功 |

一句话结论:这个库不需要权限、实现只有 19 行、接入后正常注册;但它要控制的闪光灯在这台设备上并不存在,所以“灯亮不亮”无法在本轮验证——本轮真正验证到的,是它在硬件不支持时会明确报错,而不是假装成功。这两件事必须分开说。

二、判定过程

适配前先回答三个问题。

2.1 这个库需要鸿蒙化吗

看源码就知道必须:

// src/NativeTorch.ts  
import type {TurboModule} from 'react-native';  
import {TurboModuleRegistry} from 'react-native';  

export interface Spec extends TurboModule {  
  switchState(enabled: boolean): Promise<boolean>;  
  requestCameraPermission(title?: string, message?: string): Promise<boolean>;  
}  

export default TurboModuleRegistry.getEnforcing<Spec>('RCTTorch');

getEnforcing 意味着取不到原生模块就直接抛错,没有 JS 兜底实现。而 react-native-torch 上游只提供 Android 与 iOS 原生代码,鸿蒙上没有 RCTTorch 这个名字的模块——所以必须补一个鸿蒙原生实现。

这里和纯 JS 库的分界线很清楚:纯 JS 库只要能跑通就直接可用,而这类库不补原生实现就必然报错。

2.2 上游版本核对

npm view react-native-torch version   # 1.2.0

拿到鸿蒙适配包后对比到上游基线,版本一致,没有落后。

2.3 交付包里该有的信息都在

spec.json 里有 upstream 仓库地址,也有 upstreamCommit 基线 commit——两样都记了,意味着后续上游改动时能确定该合到哪个点,这次适配的可追溯性是完整的。

validation 里还明确写了能力边界,其中一条很关键:

返回 true 不表示设备一定有闪光灯。

交付包自己先把这件事说清楚了,这一点很重要——它没有让调用方误以为“switchState 返回 true = 灯亮了”。

三、适配实现:先查支持性,再下发命令

原生实现全文:

// harmony/torch/src/main/ets/RCTTorchTurboModule.ts  
import camera from '@ohos.multimedia.camera';  
import { UITurboModule } from '@rnoh/react-native-openharmony/ts';  

export class RCTTorchTurboModule extends UITurboModule {  
  async switchState(enabled: boolean): Promise<boolean> {  
    const manager = camera.getCameraManager(this.ctx.uiAbilityContext);  
    const mode = enabled ? camera.TorchMode.ON : camera.TorchMode.OFF;  
    if (!manager.isTorchSupported() || !manager.isTorchModeSupported(mode)) {  
      throw new Error('ERR_TORCH_UNAVAILABLE: flashlight mode is not supported');  
    }  
    manager.setTorchMode(mode);  
    return true;  
  }  

  async requestCameraPermission(): Promise<boolean> {  
    // HarmonyOS CameraManager torch APIs do not require CAMERA permission  
    // or open a camera input.  
    return true;  
  }  
}

三个设计点值得展开。

3.1 支持性检查必须在下发命令之前

if (!manager.isTorchSupported() || !manager.isTorchModeSupported(mode)) {  
  throw new Error('ERR_TORCH_UNAVAILABLE: ...');  
}  
manager.setTorchMode(mode);

这里做了两层检查:

  • isTorchSupported() —— 这台设备有没有闪光灯;
  • isTorchModeSupported(mode) —— 这个模式(ON / OFF)支不支持。

两层检查是必要的,因为有些设备的闪光灯只支持常亮、不支持闪烁(或反过来),“有闪光灯”并不等于“这个模式可用”。

检查失败时抛出的是带前缀的明确错误(ERR_TORCH_UNAVAILABLE),调用方能靠字符串识别并走降级逻辑。这一点比“静默返回 false”好得多——静默失败会让调用方以为操作成功了。

3.2 它不打开相机、不采集图像

实现里出现的相机 API 只有四个:

getCameraManager / isTorchSupported / isTorchModeSupported / setTorchMode

没有 createCameraInput、没有 createCaptureSession、没有预览流。这是静态就能查清的事实,也是理解“为什么不需要 CAMERA 权限”的钥匙——它只借用 CameraManager 的手电接口,不碰相机采集链路。

3.3 JS 侧的参数守卫是"被拒绝的 Promise"

上游 JS 层保留了类型校验:

async function switchState(enabled: boolean): Promise<boolean> {  
  if (typeof enabled !== 'boolean') {  
    throw new TypeError('Torch.switchState expects a boolean');  
  }  
  return NativeTorch.switchState(enabled);  
}

注意它在 async 函数里,所以抛出的是一个被拒绝的 Promise,而不是同步异常。这意味着:

// ❌ 抓不到  
try { Torch.switchState(1); } catch (e) {}  

// ✅ 这样才抓得到  
await Torch.switchState(1).catch(e => console.log(e.message));

这个细节在本轮验证中被实际确认过——参数守卫组的断言必须用 await 才能捕获到 TypeError。调用方如果按同步异常来写 try/catch,会漏掉所有参数错误。

四、requestCameraPermission() 为什么直接返回 true

这个方法最容易引起误解。它在 Android 上的语义是弹出系统相机授权框,所以返回值表示“用户授权了没有”。到了鸿蒙,实现直接写成:

async requestCameraPermission(): Promise<boolean> {  
  return true;  
}

为什么可以这样写?

因为鸿蒙的手电筒 API 走的是 CameraManager,既不要求声明 ohos.permission.CAMERA,也不打开相机输入。既然没有权限可申请,也就没有授权框可弹——直接返回 true 表示"没有权限障碍,你继续调 switchState 就行"。

这个 true 的含义要读准:

它表示 | 它不表示 |

不存在权限障碍 | 设备一定有闪光灯 |

可以继续调用 switchState | 闪光灯能被点亮 |

保留了上游接口的兼容性 | Android 上的授权弹窗行为也一致 |

交付包 README 专门写了这个限定,这一点做得很诚实。如果调用方把 requestCameraPermission() === true 当成"硬件可用"的判据,就会在无闪光灯设备上做出错误决策——正确的判据是 switchState 是否成功,而不是权限方法是否返回 true。

五、接入宿主

宿主工程是一个已经运行起来的 RNOH 示例应用。接入这个库要改四处:

文件 | 改动 |

package.json | 加 "react-native-torch": "file:../react-native-torch" |

metro.config.js | watchFolders 增加该库的绝对路径 |

index.js | import 测试页并注册 |

harmony/entry/oh-package.json5 | 手工加 HAR 依赖 |

第四处是唯一需要留神的:

"@react-native-ohos/react-native-torch": "file:../../node_modules/react-native-torch/harmony/torch.har"

自动链接工具不会写这一处。它会把 package.json 的依赖关系和 Metro 的模块解析处理好,日志里也会报 linked 9 libraries,但模块级的 oh-package.json5 依赖需要手工补——漏了这一步,编译期就会在 CMake / ohpm 阶段报找不到包。

这一点交付包的 README 里也专门提醒了,写成了一句很实在的话:

若宿主 CMake 的 OH_MODULES_DIR 指向 entry/oh_modules,还需在 harmony/entry/oh-package.json5 添加 HAR 依赖……不能据 link 成功省略这一步。

这类“工具链不会代劳的一步”是接入环节最容易踩的坑:link-harmony 成功不代表接线完成,得认准编译产物里到底有没有这个包。

另一个刻意的选择:没有改 harmony/entry/src/main/module.json5。宿主的 requestPermissions 里只有:

"requestPermissions": [  
  { "name": "ohos.permission.INTERNET" },  
  { "name": "ohos.permission.VIBRATE" }  
]

没有 ohos.permission.CAMERA——保持原样,因为本库不需要。这一点后来还成了一个有用的旁证,见第七节。

关于换测试页

宿主用一个启动参数(rnAppKey)决定加载哪个测试页。这个参数只在冷启动时生效,所以换页必须:

hdc shell aa force-stop com.rnoh084.demo  
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey TorchTestApp

force-stop 不能省。少了它,应用还活着,新参数不会重新读取,你会一直在看旧页面——而且页面长得没错,很容易误判。

六、构建与运行

# 1. 装依赖  
npm install  

# 2. 自动链接  
node_modules\.bin\react-native link-harmony        # linked 9 libraries  

# 3. 装 HAR(在 harmony/ 目录)  
ohpm install --all  

# 4. 出 bundle  
npm run dev  

# 5. 打 HAP  
hvigorw --mode module -p product=default -p module=entry@default assembleHap --no-daemon

编译结果:

项 | 数值 |

首次 assembleHap 耗时 | 6 分 39 秒 |

HAP 变化 | 80,714,316 → 80,867,227 字节(+152,911 ≈ 149 KB) |

原生注册日志 | #RNOH_ARK ... TM created: RCTTorch |

二次重编(改了一条断言) | 6 分 27 秒,HAP 80,867,224 字节 |

两个数量级上的观察:

  • 149 KB vs 2,875 字节的 HAR:HAR 本身极小,但会连带拉起相机相关的能力声明与依赖,所以最终产物增量比 HAR 大两个数量级。别拿 HAR 体积估增量。
  • 编译耗时基本由 ABI / CMake 阶段决定,跟这个库没关系:加 19 行 ArkTS 不会让编译从 2 分钟变成 6 分钟,这 6 分钟是 RNOH 工程本身的量级,做集成排期时要按这个数留时间。

日志里的 #RNOH_ARK 标签说明这是 ArkTS 侧 TurboModule(不是纯 C++ TurboModule,也不是 JSI)。这个区别在排查时有用:ArkTS 模块的问题看 ArkTS 日志,纯 C++ 模块才有 #RNOH_CPP 的 TurboModuleFactory.cpp 记录。

七、验证设计:依赖硬件的库在模拟器上怎么验

这是本文最重要的一节。

7.1 问题:灯亮不亮,模拟器答不了

模拟器(Pura X View,ohos-x64)没有闪光灯硬件。这意味着一件事:

switchState(true) 之后“灯是否真的亮了”,在模拟器上永远无法验证。

如果验证方案写成“调用 switchState(true),断言返回 true”,那么在这个环境下必然失败——但这个失败不是库的问题。反过来,如果为了让测试通过而放宽断言,又会遮盖真正该测的东西。

所以验证设计的关键是换一个落点。

7.2 换落点:从"硬件是否动作"换到"行为是否正确"

既然“能不能亮”验不了,那就验能验的、而且同样重要的:

硬件不支持时,它是明确失败,还是返回 true 假装成功?

这个问题在模拟器上完全可以验证,而且它比“灯能不能亮”更接近库的真实质量——因为调用方写降级逻辑时,依赖的正是“失败能被感知到”这件事。一个在无硬件时静默返回 true 的库,会让调用方以为灯亮了,这比报错糟糕得多。

于是把验证分成三层:

层 | 能验吗 | 内容 |

A. 契约与类型 | ✅ 完全可验 | 两个方法存在、返回 Promise、权限方法解析为 true |

B. JS 侧参数守卫 | ✅ 完全可验 | 非布尔参数必须以 TypeError 拒绝(6 种取值) |

C. 硬件相关行为 | ⚠️ 只记录,不断言“应当成功” | 实测结局,重点看是明确失败还是假装成功 |

A、B 两层进通过率,C 层如实记录。这样通过率是有意义的(13 / 13),同时不掩盖硬件未验证的事实。

7.3 A 组:契约与类型(6 项,全通过)

断言 | 结果 |

switchState 是 function | ✅ |

requestCameraPermission 是 function | ✅ |

requestCameraPermission() 返回 Promise | ✅ |

requestCameraPermission() 解析为 true | ✅ |

switchState(true) 返回 Promise | ✅ |

switchState(false) 返回 Promise | ✅ |

这里有个细节让这组在无硬件时依然成立:switchState 是 async 函数,无论内部成功还是抛错,返回的一定是 Promise。 因此,“返回 Promise”这条断言与硬件无关,可以放心验证。

7.4 B 组:参数守卫(7 项,全通过)

非布尔参数必须以 TypeError 拒绝:

传入值 | 结果 |

undefined | ✅ TypeError |

null | ✅ TypeError |

0 | ✅ TypeError |

1 | ✅ TypeError |

"true" | ✅ TypeError |

{} | ✅ TypeError |

非法参数之后,合法调用不再被参数守卫拦住 | ✅ |

最后一条值得单独说,因为它让我改过一次断言。

初版我把它写成"非法参数之后调用应当成功"。结果在本机失败——因为无闪光灯时,合法调用会以 ERR_TORCH_UNAVAILABLE 拒绝。那是正确的硬件行为,不是参数问题,但我的断言把两件事混在了一起。

改判据后:只检查结果里不再出现 TypeError,不管它最终是成功还是因硬件拒绝——这样断言只依赖"参数守卫"这一个契约,与环境能力无关。

教训:测试断言不能隐含"环境具备某能力"这个前提。

断言应该只依赖被测代码的契约,不依赖环境能力。如果确实要断言环境,就把它单独成组并如实记录,而不是混进通过率里——否则通过率会随设备变化,失去意义。

7.5 C 组:硬件相关行为(如实记录)

四次调用的实测结果:

硬件|switchState(true)        拒绝:ERR_TORCH_UNAVAILABLE: flashlight mode is not supported  
硬件|switchState(false)       拒绝:ERR_TORCH_UNAVAILABLE: flashlight mode is not supported  
硬件|switchState(true) 第二次   拒绝:ERR_TORCH_UNAVAILABLE: flashlight mode is not supported  
硬件|switchState(false) 第二次  拒绝:ERR_TORCH_UNAVAILABLE: flashlight mode is not supported  
硬件|两轮结果是否一致:是  
硬件|四次调用是否都以 ERR_TORCH_UNAVAILABLE 拒绝:是  
硬件|硬件不支持时是否返回 true 假装成功:否(明确失败)

后两条是页面从实测结果动态推导出来的,不是写死的文案——这样它们才是断言,而不是修饰。

两个结论:

  • 本机确实没有闪光灯 —— 四次调用全部走到"不支持"分支,两轮一致;
  • 库的行为是对的 —— 硬件不支持时明确拒绝,没有返回 true 假装成功。

第 2 条才是本轮真正验证到的东西,而它恰好是模拟器能验证、也最应该验证的那一条。

7.6 两个独立旁证

断言之外还找了两个不依赖测试页的旁证,用来交叉验证“确实没碰硬件”。

旁证一:相机服务侧没有任何日志。

在两次调用前后抓取 hilog,没有相机服务的任何记录。这和代码路径完全一致:isTorchSupported() 检查失败就抛错了,从未执行到 setTorchMode,所以系统侧没有动作可记录。

如果代码是“先下发命令再检查结果”,就会看到系统侧有响应——日志的有无,正好反证了检查发生在命令之前。

旁证二:没有 CAMERA 权限,错误类型却是“硬件不支持”。

宿主 module.json5 里没有声明 ohos.permission.CAMERA,而 switchState 返回的是:

ERR_TORCH_UNAVAILABLE: flashlight mode is not supported

是“不支持”,不是“无权限”。如果是权限问题,报错应该是权限拒绝;既然系统先给出了硬件不支持的判断,就说明这条调用路径根本没走到权限校验——独立印证了“鸿蒙手电 API 不需要相机权限”这个结论。

这两个旁证的价值在于:它们不来自我的测试代码。一个来自系统日志,一个来自工程配置,都是外部事实。

7.7 关于测试页本身

测试页沿用了一个统一的断言夹具:每条断言用 record(组名, 描述, 期望, 实际) 记录,最后按组汇总“通过 / 失败”。硬件行为单独成组,不计入通过率。页面根节点包在 SafeAreaView 里避免被状态栏遮挡,日志统一带 [torch-test] 前缀方便过滤。

另外,C 组的两个推导结论是运行时算出来的:

四次调用是否都以 ERR_TORCH_UNAVAILABLE 拒绝:是  
硬件不支持时是否返回 true 假装成功:否(明确失败)

这样做的好处是——换一台有闪光灯的设备跑,这两行会自动变成“否”和“不适用”,而不会继续打印“是”。写死的文案会骗人,动态推导不会。

八、真机验证:哪些验过了,哪些没验

这一节必须写清楚,因为这是本轮最容易被含糊过去的地方。

8.1 已验证

项 | 证据 |

两个方法的契约与类型 | A 组 6 条断言全通过 |

JS 侧参数守卫(6 种非布尔值) | B 组 7 条断言全通过 |

原生模块成功注册 | hilog 中 TM created: RCTTorch |

模块是 ArkTS 实现 | 日志标签为 #RNOH_ARK |

硬件不支持时的失败模式 | C 组:四次调用全部以 ERR_TORCH_UNAVAILABLE 明确拒绝,未返回 true 假装成功,两轮一致 |

失败发生命令下发之前 | 相机服务侧无任何 hilog 记录 |

手电 API 不需要 CAMERA 权限 | 宿主无该权限声明,错误类型仍是“硬件不支持”而非“无权限” |

编译与产物 | assembleHap 成功,HAP +149 KB |

8.2 未验证(本轮无法验证)

项 | 为什么没验 |

闪光灯是否真的会亮 | 本机没有闪光灯硬件,无法验证 |

开启 / 关闭的实际硬件状态 | 需要真机,并需要查看系统侧的手电状态事件 |

相机被其他应用占用时的失败路径 | 需要真实硬件与占用场景 |

其他 ROM / 平板 / 无闪光灯真机的差异 | 只有一台模拟器 |

亮灯时的功耗与发热 | 无硬件 |

8.3 为什么要分开写

因为这两类事的可信度完全不同。

  • 把"已验证"说成"适配成功、功能正常"是过度声明——灯到底亮不亮,我没验过;
  • 把"未验证"含糊成"应该没问题",会让下一位使用者踩坑;
  • 反过来,把"硬件不支持时正确报错"也归入未验证,又低估了本轮的实际成果。

准确的表述是:软件层全通过,硬件动作未验证,但硬件不支持时的失败模式已确认为正确。

九、已知限制

  • 模拟器没有闪光灯,"点亮"无法验证。这是本轮最大的空白,需要真机补充。
  • requestCameraPermission() 恒返回 true,是兼容桩而非硬件探测。它的返回值不能当作"硬件可用"的判据。调用方应改用 switchState 是否成功来判断。
  • 无权限声明的结论只在本轮环境成立。本轮验证了"不声明 CAMERA 权限也能走到硬件检查",但没有验证其他 ROM 上是否同样如此。
  • 未做跨平台对照。本轮只验证鸿蒙,没有对比 Android / iOS 上同一接口的行为差异(特别是 requestCameraPermission 的弹窗语义)。
  • ERR_TORCH_UNAVAILABLE 是字符串前缀,不是错误码。调用方靠自己匹配字符串来识别,匹配时要考虑前缀而非全等,否则错误文案微调就会破坏降级逻辑。
  • 单设备、单次运行。只在一台模拟器上跑过,没有压力测试、没有并发调用场景、没有反复快速切换。
  • 未改动库代码,也未发现缺陷。本轮唯一一次失败是我自己测试页的断言写错了(隐含了"硬件存在"的前提),修正后通过。

十、常见问题

Q1:调用 switchState(true) 报 ERR_TORCH_UNAVAILABLE,是适配坏了吗?

不一定。先确认设备有没有闪光灯——模拟器上、平板上、很多无闪光灯设备上,这个错误是正确行为。这个库的设计就是"没有闪光灯就明确报错",而不是静默成功。

Q2:requestCameraPermission() 返回 true 了,为什么 switchState 还是失败?

因为这两件事无关。true 表示"不存在权限障碍",不表示设备有闪光灯。在鸿蒙上手电 API 根本不需要相机权限,所以这个方法只是个兼容桩。

Q3:需要声明 ohos.permission.CAMERA 吗?

本库不需要,本轮实测没有声明也能正常走到硬件检查。但如果你的应用自己还要做拍照、录像,那当然要声明——那是另一条采集链路的事。

Q4:为什么 try { Torch.switchState(1) } catch {} 抓不到参数错误?

因为 JS 守卫在 async 函数里,抛出的是被拒绝的 Promise。必须 await 或 .catch():

await Torch.switchState(1).catch(e => console.log(e.message));

Q5:link-harmony 报链接成功,编译还是找不到包?

检查 harmony/entry/oh-package.json5 有没有手工加上 HAR 依赖。自动链接工具不写模块级的这一处,漏了就报找不到包——这不是链接失败,是链接没覆盖到这里。

Q6:换了测试页代码,界面还是旧的?

rnAppKey 这类启动参数只在冷启动生效。先 aa force-stop 再 aa start,否则一直在看旧页面。

Q7:怎么在自己设备上确认闪光灯到底能不能用?

别信权限方法,直接试:

try {  
  await Torch.switchState(true);  
  console.log('下发成功');        // 注意:命令被接受,不代表灯一定亮了  
} catch (e) {  
  console.log('不可用:', e.message);  
}

注意日志里的措辞——即使返回成功,也只表示"命令被系统接受";要确认灯真的亮了,得看设备本身。这个区分在交付包的 README 里也写明了。

Q8:编译要 6 分多钟,是不是这个库太重?

不是。这 6 分钟是 RNOH 工程本身 ABI / CMake 阶段的量级,跟 19 行 ArkTS 无关。HAR 只有 2,875 字节,但最终 HAP 增了 149 KB——别拿 HAR 体积估算集成增量。

小结

react-native-torch 是个小库:两个 API、19 行原生实现、不需要任何权限。但它在方法论上给了一个很典型的题目——当库依赖的硬件在你手上不存在时,验证该怎么做?

这次的做法是:

  • 把验证分层。 契约与参数守卫(A、B)完全可验,计入通过率;硬件行为(C)只记录、不断言“应当成功”。
  • 换验证落点。 既然“灯亮不亮”验不了,就验**“硬件不支持时是否明确失败,而不是返回 true 假装成功”**——这一条模拟器能验,而且比“能不能亮”更接近库的质量。
  • 找不依赖测试代码的旁证。 相机服务无日志(证明检查发生在命令下发之前)、无 CAMERA 权限却报“硬件不支持”(证明这条路径不需要相机权限)——两个都来自系统日志和工程配置,不是我自己的断言。
  • 把“已验证”和“未验证”分开写。 软件层全通过是真的,硬件动作没验也是真的,不能混成一句“适配成功”。

另外两条从实践中得来的经验:

  • 断言不能隐含“环境具备某能力”。 我初版把“非法参数之后调用应当成功”写成断言,在有闪光灯的机器上会过,在这台机器上必然失败。断言只该依赖被测代码的契约,否则通过率会随设备漂移,失去意义。
  • requestCameraPermission() 返回 true 不是硬件探针。 它是权限语义上的“没有障碍”,把两者混为一谈,就会在无硬件设备上做出错误决策。

还有一点关于交付包:它自己在 README 里就写清了“返回 true 不表示设备一定有闪光灯”,并且诚实声明了哪些场景是 mock 验证、哪些没做真机覆盖。 一个交付包能主动划出自己的能力边界,比它多写几个 API 有用得多——因为使用者正是靠这句话避免误判的。

本篇用到的库

项 | 内容 |

三方库 | react-native-torch(上游 1.2.0 的鸿蒙适配版) |

适配仓库 | https://atomgit.com/oh-react-native/react-native-torch |

适配 TAG | 1.2.0-ohos-1.0.0 |

ohpm 包名 | @react-native-ohos/react-native-torch |

HAR | harmony/torch.har(2,875 字节) |

原生模块名 | RCTTorch(ArkTS TurboModule,日志标签 #RNOH_ARK) |

是否需要权限 | 不需要 |

上游仓库 | https://github.com/ludo/react-native-torch(基线 commit 957db6330a0afd09455e42ce6537e0ca69518e3c,MIT) |

宿主工程 | RNOH084Demo(测试页 rnAppKey = TorchTestApp) |

接入方式:

// harmony/entry/oh-package.json5(需手工添加)  
"@react-native-ohos/react-native-torch": "file:../../node_modules/react-native-torch/harmony/torch.har"
import Torch from 'react-native-torch';  

await Torch.requestCameraPermission();   // 鸿蒙上恒为 true,仅表"无权限障碍"  
try {  
  await Torch.switchState(true);         // 成功只代表命令被系统接受  
} catch (e) {  
  // 无闪光灯设备会抛 ERR_TORCH_UNAVAILABLE  
  console.log(String(e));  
}  
await Torch.switchState(false);
# 换页启动测试页(force-stop 不能省,换页参数只在冷启动生效)  
hdc shell aa force-stop com.rnoh084.demo  
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey TorchTestApp

验证环境

项 | 版本 |

React Native | 0.84.1 |

React | 19.2.3 |

RNOH(npm / ohpm) | @react-native-oh/react-native-harmony / @rnoh/react-native-openharmony 0.84.3 |

Node.js | v24.14.0 |

DevEco Studio | 26.0.0.621 |

HarmonyOS SDK | API 26(26.0.0.32) |

设备 | HarmonyOS 7.0.0(26.0.0) Beta2 模拟器 Pura X View(ohos-x64)——无闪光灯硬件 |

宿主 HAP 产物 | entry-default-signed.hap(80.87 MB) |

本次增量构建 | assembleHap 6 分 39 秒,HAP +149 KB |

验证规模 | 设备侧软件层 13 项断言全部通过;硬件行为组 4 次调用如实记录(全部 ERR_TORCH_UNAVAILABLE) |

欢迎加入 CPF-RN 鸿蒙社区:https://atomgit.com/CPF-RN

React Native for OpenHarmony 组织:https://atomgit.com/oh-react-native

RN 三方库鸿蒙适配清单:https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview

继续阅读 »

本文记录把 react-native-torch(手电筒 / 相机闪光灯控制)适配到 HarmonyOS 的完整过程,涵盖版本对齐、原生实现走查、接入宿主、构建运行,以及依赖硬件的库在模拟器上究竟该怎么验证。

react-native-torch 的 API 只有两个,却是个典型例子:它控制的是一块模拟器上根本不存在的硬件。这类库的适配难点不在代码量,而在“什么算验证通过”。

一、先说结论

项 | 结果 |

上游最新版 | 1.2.0 |

是否带原生实现 | 是(ArkTS TurboModule,不是纯 JS) |

是否依赖硬件 | 是,依赖相机闪光灯 |

公开 API | switchState(enabled)、requestCameraPermission(title?, message?),都返回 Promise |

是否需要声明权限 | 不需要(连 ohos.permission.CAMERA 都用不上) |

原生实现体量 | ArkTS 侧 19 行,HAR 包 2,875 字节 |

编译是否通过 | ✅ assembleHap 成功,HAP 从 80,714,316 增至 80,867,227 字节(+152,911 ≈ 149 KB) |

原生是否注册 | ✅ 日志 TM created: RCTTorch |

软件层断言 | ✅ 13 / 13 通过(契约 6 + 参数守卫 7) |

硬件层结论 | ⚠️ 本机没有闪光灯,四次调用全部以 ERR_TORCH_UNAVAILABLE 拒绝——没有返回 true 假装成功 |

一句话结论:这个库不需要权限、实现只有 19 行、接入后正常注册;但它要控制的闪光灯在这台设备上并不存在,所以“灯亮不亮”无法在本轮验证——本轮真正验证到的,是它在硬件不支持时会明确报错,而不是假装成功。这两件事必须分开说。

二、判定过程

适配前先回答三个问题。

2.1 这个库需要鸿蒙化吗

看源码就知道必须:

// src/NativeTorch.ts  
import type {TurboModule} from 'react-native';  
import {TurboModuleRegistry} from 'react-native';  

export interface Spec extends TurboModule {  
  switchState(enabled: boolean): Promise<boolean>;  
  requestCameraPermission(title?: string, message?: string): Promise<boolean>;  
}  

export default TurboModuleRegistry.getEnforcing<Spec>('RCTTorch');

getEnforcing 意味着取不到原生模块就直接抛错,没有 JS 兜底实现。而 react-native-torch 上游只提供 Android 与 iOS 原生代码,鸿蒙上没有 RCTTorch 这个名字的模块——所以必须补一个鸿蒙原生实现。

这里和纯 JS 库的分界线很清楚:纯 JS 库只要能跑通就直接可用,而这类库不补原生实现就必然报错。

2.2 上游版本核对

npm view react-native-torch version   # 1.2.0

拿到鸿蒙适配包后对比到上游基线,版本一致,没有落后。

2.3 交付包里该有的信息都在

spec.json 里有 upstream 仓库地址,也有 upstreamCommit 基线 commit——两样都记了,意味着后续上游改动时能确定该合到哪个点,这次适配的可追溯性是完整的。

validation 里还明确写了能力边界,其中一条很关键:

返回 true 不表示设备一定有闪光灯。

交付包自己先把这件事说清楚了,这一点很重要——它没有让调用方误以为“switchState 返回 true = 灯亮了”。

三、适配实现:先查支持性,再下发命令

原生实现全文:

// harmony/torch/src/main/ets/RCTTorchTurboModule.ts  
import camera from '@ohos.multimedia.camera';  
import { UITurboModule } from '@rnoh/react-native-openharmony/ts';  

export class RCTTorchTurboModule extends UITurboModule {  
  async switchState(enabled: boolean): Promise<boolean> {  
    const manager = camera.getCameraManager(this.ctx.uiAbilityContext);  
    const mode = enabled ? camera.TorchMode.ON : camera.TorchMode.OFF;  
    if (!manager.isTorchSupported() || !manager.isTorchModeSupported(mode)) {  
      throw new Error('ERR_TORCH_UNAVAILABLE: flashlight mode is not supported');  
    }  
    manager.setTorchMode(mode);  
    return true;  
  }  

  async requestCameraPermission(): Promise<boolean> {  
    // HarmonyOS CameraManager torch APIs do not require CAMERA permission  
    // or open a camera input.  
    return true;  
  }  
}

三个设计点值得展开。

3.1 支持性检查必须在下发命令之前

if (!manager.isTorchSupported() || !manager.isTorchModeSupported(mode)) {  
  throw new Error('ERR_TORCH_UNAVAILABLE: ...');  
}  
manager.setTorchMode(mode);

这里做了两层检查:

  • isTorchSupported() —— 这台设备有没有闪光灯;
  • isTorchModeSupported(mode) —— 这个模式(ON / OFF)支不支持。

两层检查是必要的,因为有些设备的闪光灯只支持常亮、不支持闪烁(或反过来),“有闪光灯”并不等于“这个模式可用”。

检查失败时抛出的是带前缀的明确错误(ERR_TORCH_UNAVAILABLE),调用方能靠字符串识别并走降级逻辑。这一点比“静默返回 false”好得多——静默失败会让调用方以为操作成功了。

3.2 它不打开相机、不采集图像

实现里出现的相机 API 只有四个:

getCameraManager / isTorchSupported / isTorchModeSupported / setTorchMode

没有 createCameraInput、没有 createCaptureSession、没有预览流。这是静态就能查清的事实,也是理解“为什么不需要 CAMERA 权限”的钥匙——它只借用 CameraManager 的手电接口,不碰相机采集链路。

3.3 JS 侧的参数守卫是"被拒绝的 Promise"

上游 JS 层保留了类型校验:

async function switchState(enabled: boolean): Promise<boolean> {  
  if (typeof enabled !== 'boolean') {  
    throw new TypeError('Torch.switchState expects a boolean');  
  }  
  return NativeTorch.switchState(enabled);  
}

注意它在 async 函数里,所以抛出的是一个被拒绝的 Promise,而不是同步异常。这意味着:

// ❌ 抓不到  
try { Torch.switchState(1); } catch (e) {}  

// ✅ 这样才抓得到  
await Torch.switchState(1).catch(e => console.log(e.message));

这个细节在本轮验证中被实际确认过——参数守卫组的断言必须用 await 才能捕获到 TypeError。调用方如果按同步异常来写 try/catch,会漏掉所有参数错误。

四、requestCameraPermission() 为什么直接返回 true

这个方法最容易引起误解。它在 Android 上的语义是弹出系统相机授权框,所以返回值表示“用户授权了没有”。到了鸿蒙,实现直接写成:

async requestCameraPermission(): Promise<boolean> {  
  return true;  
}

为什么可以这样写?

因为鸿蒙的手电筒 API 走的是 CameraManager,既不要求声明 ohos.permission.CAMERA,也不打开相机输入。既然没有权限可申请,也就没有授权框可弹——直接返回 true 表示"没有权限障碍,你继续调 switchState 就行"。

这个 true 的含义要读准:

它表示 | 它不表示 |

不存在权限障碍 | 设备一定有闪光灯 |

可以继续调用 switchState | 闪光灯能被点亮 |

保留了上游接口的兼容性 | Android 上的授权弹窗行为也一致 |

交付包 README 专门写了这个限定,这一点做得很诚实。如果调用方把 requestCameraPermission() === true 当成"硬件可用"的判据,就会在无闪光灯设备上做出错误决策——正确的判据是 switchState 是否成功,而不是权限方法是否返回 true。

五、接入宿主

宿主工程是一个已经运行起来的 RNOH 示例应用。接入这个库要改四处:

文件 | 改动 |

package.json | 加 "react-native-torch": "file:../react-native-torch" |

metro.config.js | watchFolders 增加该库的绝对路径 |

index.js | import 测试页并注册 |

harmony/entry/oh-package.json5 | 手工加 HAR 依赖 |

第四处是唯一需要留神的:

"@react-native-ohos/react-native-torch": "file:../../node_modules/react-native-torch/harmony/torch.har"

自动链接工具不会写这一处。它会把 package.json 的依赖关系和 Metro 的模块解析处理好,日志里也会报 linked 9 libraries,但模块级的 oh-package.json5 依赖需要手工补——漏了这一步,编译期就会在 CMake / ohpm 阶段报找不到包。

这一点交付包的 README 里也专门提醒了,写成了一句很实在的话:

若宿主 CMake 的 OH_MODULES_DIR 指向 entry/oh_modules,还需在 harmony/entry/oh-package.json5 添加 HAR 依赖……不能据 link 成功省略这一步。

这类“工具链不会代劳的一步”是接入环节最容易踩的坑:link-harmony 成功不代表接线完成,得认准编译产物里到底有没有这个包。

另一个刻意的选择:没有改 harmony/entry/src/main/module.json5。宿主的 requestPermissions 里只有:

"requestPermissions": [  
  { "name": "ohos.permission.INTERNET" },  
  { "name": "ohos.permission.VIBRATE" }  
]

没有 ohos.permission.CAMERA——保持原样,因为本库不需要。这一点后来还成了一个有用的旁证,见第七节。

关于换测试页

宿主用一个启动参数(rnAppKey)决定加载哪个测试页。这个参数只在冷启动时生效,所以换页必须:

hdc shell aa force-stop com.rnoh084.demo  
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey TorchTestApp

force-stop 不能省。少了它,应用还活着,新参数不会重新读取,你会一直在看旧页面——而且页面长得没错,很容易误判。

六、构建与运行

# 1. 装依赖  
npm install  

# 2. 自动链接  
node_modules\.bin\react-native link-harmony        # linked 9 libraries  

# 3. 装 HAR(在 harmony/ 目录)  
ohpm install --all  

# 4. 出 bundle  
npm run dev  

# 5. 打 HAP  
hvigorw --mode module -p product=default -p module=entry@default assembleHap --no-daemon

编译结果:

项 | 数值 |

首次 assembleHap 耗时 | 6 分 39 秒 |

HAP 变化 | 80,714,316 → 80,867,227 字节(+152,911 ≈ 149 KB) |

原生注册日志 | #RNOH_ARK ... TM created: RCTTorch |

二次重编(改了一条断言) | 6 分 27 秒,HAP 80,867,224 字节 |

两个数量级上的观察:

  • 149 KB vs 2,875 字节的 HAR:HAR 本身极小,但会连带拉起相机相关的能力声明与依赖,所以最终产物增量比 HAR 大两个数量级。别拿 HAR 体积估增量。
  • 编译耗时基本由 ABI / CMake 阶段决定,跟这个库没关系:加 19 行 ArkTS 不会让编译从 2 分钟变成 6 分钟,这 6 分钟是 RNOH 工程本身的量级,做集成排期时要按这个数留时间。

日志里的 #RNOH_ARK 标签说明这是 ArkTS 侧 TurboModule(不是纯 C++ TurboModule,也不是 JSI)。这个区别在排查时有用:ArkTS 模块的问题看 ArkTS 日志,纯 C++ 模块才有 #RNOH_CPP 的 TurboModuleFactory.cpp 记录。

七、验证设计:依赖硬件的库在模拟器上怎么验

这是本文最重要的一节。

7.1 问题:灯亮不亮,模拟器答不了

模拟器(Pura X View,ohos-x64)没有闪光灯硬件。这意味着一件事:

switchState(true) 之后“灯是否真的亮了”,在模拟器上永远无法验证。

如果验证方案写成“调用 switchState(true),断言返回 true”,那么在这个环境下必然失败——但这个失败不是库的问题。反过来,如果为了让测试通过而放宽断言,又会遮盖真正该测的东西。

所以验证设计的关键是换一个落点。

7.2 换落点:从"硬件是否动作"换到"行为是否正确"

既然“能不能亮”验不了,那就验能验的、而且同样重要的:

硬件不支持时,它是明确失败,还是返回 true 假装成功?

这个问题在模拟器上完全可以验证,而且它比“灯能不能亮”更接近库的真实质量——因为调用方写降级逻辑时,依赖的正是“失败能被感知到”这件事。一个在无硬件时静默返回 true 的库,会让调用方以为灯亮了,这比报错糟糕得多。

于是把验证分成三层:

层 | 能验吗 | 内容 |

A. 契约与类型 | ✅ 完全可验 | 两个方法存在、返回 Promise、权限方法解析为 true |

B. JS 侧参数守卫 | ✅ 完全可验 | 非布尔参数必须以 TypeError 拒绝(6 种取值) |

C. 硬件相关行为 | ⚠️ 只记录,不断言“应当成功” | 实测结局,重点看是明确失败还是假装成功 |

A、B 两层进通过率,C 层如实记录。这样通过率是有意义的(13 / 13),同时不掩盖硬件未验证的事实。

7.3 A 组:契约与类型(6 项,全通过)

断言 | 结果 |

switchState 是 function | ✅ |

requestCameraPermission 是 function | ✅ |

requestCameraPermission() 返回 Promise | ✅ |

requestCameraPermission() 解析为 true | ✅ |

switchState(true) 返回 Promise | ✅ |

switchState(false) 返回 Promise | ✅ |

这里有个细节让这组在无硬件时依然成立:switchState 是 async 函数,无论内部成功还是抛错,返回的一定是 Promise。 因此,“返回 Promise”这条断言与硬件无关,可以放心验证。

7.4 B 组:参数守卫(7 项,全通过)

非布尔参数必须以 TypeError 拒绝:

传入值 | 结果 |

undefined | ✅ TypeError |

null | ✅ TypeError |

0 | ✅ TypeError |

1 | ✅ TypeError |

"true" | ✅ TypeError |

{} | ✅ TypeError |

非法参数之后,合法调用不再被参数守卫拦住 | ✅ |

最后一条值得单独说,因为它让我改过一次断言。

初版我把它写成"非法参数之后调用应当成功"。结果在本机失败——因为无闪光灯时,合法调用会以 ERR_TORCH_UNAVAILABLE 拒绝。那是正确的硬件行为,不是参数问题,但我的断言把两件事混在了一起。

改判据后:只检查结果里不再出现 TypeError,不管它最终是成功还是因硬件拒绝——这样断言只依赖"参数守卫"这一个契约,与环境能力无关。

教训:测试断言不能隐含"环境具备某能力"这个前提。

断言应该只依赖被测代码的契约,不依赖环境能力。如果确实要断言环境,就把它单独成组并如实记录,而不是混进通过率里——否则通过率会随设备变化,失去意义。

7.5 C 组:硬件相关行为(如实记录)

四次调用的实测结果:

硬件|switchState(true)        拒绝:ERR_TORCH_UNAVAILABLE: flashlight mode is not supported  
硬件|switchState(false)       拒绝:ERR_TORCH_UNAVAILABLE: flashlight mode is not supported  
硬件|switchState(true) 第二次   拒绝:ERR_TORCH_UNAVAILABLE: flashlight mode is not supported  
硬件|switchState(false) 第二次  拒绝:ERR_TORCH_UNAVAILABLE: flashlight mode is not supported  
硬件|两轮结果是否一致:是  
硬件|四次调用是否都以 ERR_TORCH_UNAVAILABLE 拒绝:是  
硬件|硬件不支持时是否返回 true 假装成功:否(明确失败)

后两条是页面从实测结果动态推导出来的,不是写死的文案——这样它们才是断言,而不是修饰。

两个结论:

  • 本机确实没有闪光灯 —— 四次调用全部走到"不支持"分支,两轮一致;
  • 库的行为是对的 —— 硬件不支持时明确拒绝,没有返回 true 假装成功。

第 2 条才是本轮真正验证到的东西,而它恰好是模拟器能验证、也最应该验证的那一条。

7.6 两个独立旁证

断言之外还找了两个不依赖测试页的旁证,用来交叉验证“确实没碰硬件”。

旁证一:相机服务侧没有任何日志。

在两次调用前后抓取 hilog,没有相机服务的任何记录。这和代码路径完全一致:isTorchSupported() 检查失败就抛错了,从未执行到 setTorchMode,所以系统侧没有动作可记录。

如果代码是“先下发命令再检查结果”,就会看到系统侧有响应——日志的有无,正好反证了检查发生在命令之前。

旁证二:没有 CAMERA 权限,错误类型却是“硬件不支持”。

宿主 module.json5 里没有声明 ohos.permission.CAMERA,而 switchState 返回的是:

ERR_TORCH_UNAVAILABLE: flashlight mode is not supported

是“不支持”,不是“无权限”。如果是权限问题,报错应该是权限拒绝;既然系统先给出了硬件不支持的判断,就说明这条调用路径根本没走到权限校验——独立印证了“鸿蒙手电 API 不需要相机权限”这个结论。

这两个旁证的价值在于:它们不来自我的测试代码。一个来自系统日志,一个来自工程配置,都是外部事实。

7.7 关于测试页本身

测试页沿用了一个统一的断言夹具:每条断言用 record(组名, 描述, 期望, 实际) 记录,最后按组汇总“通过 / 失败”。硬件行为单独成组,不计入通过率。页面根节点包在 SafeAreaView 里避免被状态栏遮挡,日志统一带 [torch-test] 前缀方便过滤。

另外,C 组的两个推导结论是运行时算出来的:

四次调用是否都以 ERR_TORCH_UNAVAILABLE 拒绝:是  
硬件不支持时是否返回 true 假装成功:否(明确失败)

这样做的好处是——换一台有闪光灯的设备跑,这两行会自动变成“否”和“不适用”,而不会继续打印“是”。写死的文案会骗人,动态推导不会。

八、真机验证:哪些验过了,哪些没验

这一节必须写清楚,因为这是本轮最容易被含糊过去的地方。

8.1 已验证

项 | 证据 |

两个方法的契约与类型 | A 组 6 条断言全通过 |

JS 侧参数守卫(6 种非布尔值) | B 组 7 条断言全通过 |

原生模块成功注册 | hilog 中 TM created: RCTTorch |

模块是 ArkTS 实现 | 日志标签为 #RNOH_ARK |

硬件不支持时的失败模式 | C 组:四次调用全部以 ERR_TORCH_UNAVAILABLE 明确拒绝,未返回 true 假装成功,两轮一致 |

失败发生命令下发之前 | 相机服务侧无任何 hilog 记录 |

手电 API 不需要 CAMERA 权限 | 宿主无该权限声明,错误类型仍是“硬件不支持”而非“无权限” |

编译与产物 | assembleHap 成功,HAP +149 KB |

8.2 未验证(本轮无法验证)

项 | 为什么没验 |

闪光灯是否真的会亮 | 本机没有闪光灯硬件,无法验证 |

开启 / 关闭的实际硬件状态 | 需要真机,并需要查看系统侧的手电状态事件 |

相机被其他应用占用时的失败路径 | 需要真实硬件与占用场景 |

其他 ROM / 平板 / 无闪光灯真机的差异 | 只有一台模拟器 |

亮灯时的功耗与发热 | 无硬件 |

8.3 为什么要分开写

因为这两类事的可信度完全不同。

  • 把"已验证"说成"适配成功、功能正常"是过度声明——灯到底亮不亮,我没验过;
  • 把"未验证"含糊成"应该没问题",会让下一位使用者踩坑;
  • 反过来,把"硬件不支持时正确报错"也归入未验证,又低估了本轮的实际成果。

准确的表述是:软件层全通过,硬件动作未验证,但硬件不支持时的失败模式已确认为正确。

九、已知限制

  • 模拟器没有闪光灯,"点亮"无法验证。这是本轮最大的空白,需要真机补充。
  • requestCameraPermission() 恒返回 true,是兼容桩而非硬件探测。它的返回值不能当作"硬件可用"的判据。调用方应改用 switchState 是否成功来判断。
  • 无权限声明的结论只在本轮环境成立。本轮验证了"不声明 CAMERA 权限也能走到硬件检查",但没有验证其他 ROM 上是否同样如此。
  • 未做跨平台对照。本轮只验证鸿蒙,没有对比 Android / iOS 上同一接口的行为差异(特别是 requestCameraPermission 的弹窗语义)。
  • ERR_TORCH_UNAVAILABLE 是字符串前缀,不是错误码。调用方靠自己匹配字符串来识别,匹配时要考虑前缀而非全等,否则错误文案微调就会破坏降级逻辑。
  • 单设备、单次运行。只在一台模拟器上跑过,没有压力测试、没有并发调用场景、没有反复快速切换。
  • 未改动库代码,也未发现缺陷。本轮唯一一次失败是我自己测试页的断言写错了(隐含了"硬件存在"的前提),修正后通过。

十、常见问题

Q1:调用 switchState(true) 报 ERR_TORCH_UNAVAILABLE,是适配坏了吗?

不一定。先确认设备有没有闪光灯——模拟器上、平板上、很多无闪光灯设备上,这个错误是正确行为。这个库的设计就是"没有闪光灯就明确报错",而不是静默成功。

Q2:requestCameraPermission() 返回 true 了,为什么 switchState 还是失败?

因为这两件事无关。true 表示"不存在权限障碍",不表示设备有闪光灯。在鸿蒙上手电 API 根本不需要相机权限,所以这个方法只是个兼容桩。

Q3:需要声明 ohos.permission.CAMERA 吗?

本库不需要,本轮实测没有声明也能正常走到硬件检查。但如果你的应用自己还要做拍照、录像,那当然要声明——那是另一条采集链路的事。

Q4:为什么 try { Torch.switchState(1) } catch {} 抓不到参数错误?

因为 JS 守卫在 async 函数里,抛出的是被拒绝的 Promise。必须 await 或 .catch():

await Torch.switchState(1).catch(e => console.log(e.message));

Q5:link-harmony 报链接成功,编译还是找不到包?

检查 harmony/entry/oh-package.json5 有没有手工加上 HAR 依赖。自动链接工具不写模块级的这一处,漏了就报找不到包——这不是链接失败,是链接没覆盖到这里。

Q6:换了测试页代码,界面还是旧的?

rnAppKey 这类启动参数只在冷启动生效。先 aa force-stop 再 aa start,否则一直在看旧页面。

Q7:怎么在自己设备上确认闪光灯到底能不能用?

别信权限方法,直接试:

try {  
  await Torch.switchState(true);  
  console.log('下发成功');        // 注意:命令被接受,不代表灯一定亮了  
} catch (e) {  
  console.log('不可用:', e.message);  
}

注意日志里的措辞——即使返回成功,也只表示"命令被系统接受";要确认灯真的亮了,得看设备本身。这个区分在交付包的 README 里也写明了。

Q8:编译要 6 分多钟,是不是这个库太重?

不是。这 6 分钟是 RNOH 工程本身 ABI / CMake 阶段的量级,跟 19 行 ArkTS 无关。HAR 只有 2,875 字节,但最终 HAP 增了 149 KB——别拿 HAR 体积估算集成增量。

小结

react-native-torch 是个小库:两个 API、19 行原生实现、不需要任何权限。但它在方法论上给了一个很典型的题目——当库依赖的硬件在你手上不存在时,验证该怎么做?

这次的做法是:

  • 把验证分层。 契约与参数守卫(A、B)完全可验,计入通过率;硬件行为(C)只记录、不断言“应当成功”。
  • 换验证落点。 既然“灯亮不亮”验不了,就验**“硬件不支持时是否明确失败,而不是返回 true 假装成功”**——这一条模拟器能验,而且比“能不能亮”更接近库的质量。
  • 找不依赖测试代码的旁证。 相机服务无日志(证明检查发生在命令下发之前)、无 CAMERA 权限却报“硬件不支持”(证明这条路径不需要相机权限)——两个都来自系统日志和工程配置,不是我自己的断言。
  • 把“已验证”和“未验证”分开写。 软件层全通过是真的,硬件动作没验也是真的,不能混成一句“适配成功”。

另外两条从实践中得来的经验:

  • 断言不能隐含“环境具备某能力”。 我初版把“非法参数之后调用应当成功”写成断言,在有闪光灯的机器上会过,在这台机器上必然失败。断言只该依赖被测代码的契约,否则通过率会随设备漂移,失去意义。
  • requestCameraPermission() 返回 true 不是硬件探针。 它是权限语义上的“没有障碍”,把两者混为一谈,就会在无硬件设备上做出错误决策。

还有一点关于交付包:它自己在 README 里就写清了“返回 true 不表示设备一定有闪光灯”,并且诚实声明了哪些场景是 mock 验证、哪些没做真机覆盖。 一个交付包能主动划出自己的能力边界,比它多写几个 API 有用得多——因为使用者正是靠这句话避免误判的。

本篇用到的库

项 | 内容 |

三方库 | react-native-torch(上游 1.2.0 的鸿蒙适配版) |

适配仓库 | https://atomgit.com/oh-react-native/react-native-torch |

适配 TAG | 1.2.0-ohos-1.0.0 |

ohpm 包名 | @react-native-ohos/react-native-torch |

HAR | harmony/torch.har(2,875 字节) |

原生模块名 | RCTTorch(ArkTS TurboModule,日志标签 #RNOH_ARK) |

是否需要权限 | 不需要 |

上游仓库 | https://github.com/ludo/react-native-torch(基线 commit 957db6330a0afd09455e42ce6537e0ca69518e3c,MIT) |

宿主工程 | RNOH084Demo(测试页 rnAppKey = TorchTestApp) |

接入方式:

// harmony/entry/oh-package.json5(需手工添加)  
"@react-native-ohos/react-native-torch": "file:../../node_modules/react-native-torch/harmony/torch.har"
import Torch from 'react-native-torch';  

await Torch.requestCameraPermission();   // 鸿蒙上恒为 true,仅表"无权限障碍"  
try {  
  await Torch.switchState(true);         // 成功只代表命令被系统接受  
} catch (e) {  
  // 无闪光灯设备会抛 ERR_TORCH_UNAVAILABLE  
  console.log(String(e));  
}  
await Torch.switchState(false);
# 换页启动测试页(force-stop 不能省,换页参数只在冷启动生效)  
hdc shell aa force-stop com.rnoh084.demo  
hdc shell aa start -b com.rnoh084.demo -a EntryAbility --ps rnAppKey TorchTestApp

验证环境

项 | 版本 |

React Native | 0.84.1 |

React | 19.2.3 |

RNOH(npm / ohpm) | @react-native-oh/react-native-harmony / @rnoh/react-native-openharmony 0.84.3 |

Node.js | v24.14.0 |

DevEco Studio | 26.0.0.621 |

HarmonyOS SDK | API 26(26.0.0.32) |

设备 | HarmonyOS 7.0.0(26.0.0) Beta2 模拟器 Pura X View(ohos-x64)——无闪光灯硬件 |

宿主 HAP 产物 | entry-default-signed.hap(80.87 MB) |

本次增量构建 | assembleHap 6 分 39 秒,HAP +149 KB |

验证规模 | 设备侧软件层 13 项断言全部通过;硬件行为组 4 次调用如实记录(全部 ERR_TORCH_UNAVAILABLE) |

欢迎加入 CPF-RN 鸿蒙社区:https://atomgit.com/CPF-RN

React Native for OpenHarmony 组织:https://atomgit.com/oh-react-native

RN 三方库鸿蒙适配清单:https://atomgit.com/oh-react-native/rn-ohos-adaptation-overview

收起阅读 »

DCloud 发文前,先检查这三个环节

DCloud

先核对登录账户和发布分类

这是一篇用于验证码友推广 DCloud 发布功能的测试文章。正式发布前,应核对当前登录账户,选择与正文相关的分类,并检查标题、正文、话题与配图。

按正文需要整理配图

配图上传后使用平台返回的附件编号插入正文,避免把本机路径提交到社区。发布前确认图片位置与预览一致,代码示例及列表应保留原来的结构。

const message = "ready";  
console.log(message);

网络异常时先核对结果

如果提交超时,应先到我的文章列表核对结果。已经提交成功或结果尚未确认的文章不应再次提交,以免产生重复内容。本文仅用于功能验证,不包含推广链接或产品效果承诺。

继续阅读 »

先核对登录账户和发布分类

这是一篇用于验证码友推广 DCloud 发布功能的测试文章。正式发布前,应核对当前登录账户,选择与正文相关的分类,并检查标题、正文、话题与配图。

按正文需要整理配图

配图上传后使用平台返回的附件编号插入正文,避免把本机路径提交到社区。发布前确认图片位置与预览一致,代码示例及列表应保留原来的结构。

const message = "ready";  
console.log(message);

网络异常时先核对结果

如果提交超时,应先到我的文章列表核对结果。已经提交成功或结果尚未确认的文章不应再次提交,以免产生重复内容。本文仅用于功能验证,不包含推广链接或产品效果承诺。

收起阅读 »

HBuilderX 5.26 鸿蒙生成本地安装包以后,打包成APP白屏问题

目前问题已解决,因为 /Applications/HBuilderX.app/Contents/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-app-vite/dist/plugins/template.js 这份文件中在打包的时候copy[uni-app-view.umd.js ]这份js没加判断,导致鸿蒙的包里面copy进去的也是安卓/iOS里面300+kb的,而不是鸿蒙里面800+kb的。我在template.js 中增加了判断```javascript outputDir = process.env.UNI_OUTPUT_DIR; if (renderer !== 'native') { // 鸿蒙用 uni-app-harmony 的 view 运行时(约 800KB+), // 安卓/iOS 仍用 uni-app-plus(约 300KB+) const viewPkg = process.env.UNI_PLATFORM === 'app-harmony' ? '@dcloudio/uni-app-harmony/dist/uni-app-view.umd.js' '@dcloudio/uni-app-plus/dist/uni-app-view.umd.js'; fs_extra_1.default.copySync((0, uni_cli_shared_1.resolveBuiltIn)(viewPkg), path_1.default.resolve(outputDir, 'uni-app-view.umd.js'), {
overwrite: true,
});
} ```
继续阅读 »
目前问题已解决,因为 /Applications/HBuilderX.app/Contents/HBuilderX/plugins/uniapp-cli-vite/node_modules/@dcloudio/uni-app-vite/dist/plugins/template.js 这份文件中在打包的时候copy[uni-app-view.umd.js ]这份js没加判断,导致鸿蒙的包里面copy进去的也是安卓/iOS里面300+kb的,而不是鸿蒙里面800+kb的。我在template.js 中增加了判断```javascript outputDir = process.env.UNI_OUTPUT_DIR; if (renderer !== 'native') { // 鸿蒙用 uni-app-harmony 的 view 运行时(约 800KB+), // 安卓/iOS 仍用 uni-app-plus(约 300KB+) const viewPkg = process.env.UNI_PLATFORM === 'app-harmony' ? '@dcloudio/uni-app-harmony/dist/uni-app-view.umd.js' '@dcloudio/uni-app-plus/dist/uni-app-view.umd.js'; fs_extra_1.default.copySync((0, uni_cli_shared_1.resolveBuiltIn)(viewPkg), path_1.default.resolve(outputDir, 'uni-app-view.umd.js'), {
overwrite: true,
});
} ``` 收起阅读 »

原创vue3+vite8+tauri2.12跨平台聊天实战

vite vue3

最新原创基于Tauri 2.12、Rust、Vite 8.3、Vue 3、Pinia 4及ElementPlus构建的跨平台仿微信桌面聊天程序。本次升级更新了全部依赖、重写封装Tauri多窗口管理、修复窗口重复创建问题及提升新窗口响应性能。

项目实现技术

  • 跨平台框架:Tauri2.12.0
  • 前端技术框架:vite^8.3.4+vue^3.5.43+vue-router^5.4.0
  • 状态管理:pinia^4.0.3
  • 本地存储:pinia-plugin-persistedstate^4.7.1
  • 组件库:element-plus^2.14.7
  • 样式管理:sass^1.105.0
  • 短视频滑动组件:swiper^14.3.0

项目目录结构

使用最新跨平台框架tauri2.12结合vite8+vue3创建项目模板。

tauri-wechat客户端聊天项目已经正式的发布到我的原创小店,欢迎下载使用哈~
Tauri2.12+Vite8+ElementPlus桌面聊天Exe程序

作者:xiaoyan2017
链接:https://www.cnblogs.com/xiaoyan2017/p/23249495
来源:博客园
本文原创发布于博客园 ,转载请注明出处,谢谢合作

继续阅读 »

最新原创基于Tauri 2.12、Rust、Vite 8.3、Vue 3、Pinia 4及ElementPlus构建的跨平台仿微信桌面聊天程序。本次升级更新了全部依赖、重写封装Tauri多窗口管理、修复窗口重复创建问题及提升新窗口响应性能。

项目实现技术

  • 跨平台框架:Tauri2.12.0
  • 前端技术框架:vite^8.3.4+vue^3.5.43+vue-router^5.4.0
  • 状态管理:pinia^4.0.3
  • 本地存储:pinia-plugin-persistedstate^4.7.1
  • 组件库:element-plus^2.14.7
  • 样式管理:sass^1.105.0
  • 短视频滑动组件:swiper^14.3.0

项目目录结构

使用最新跨平台框架tauri2.12结合vite8+vue3创建项目模板。

tauri-wechat客户端聊天项目已经正式的发布到我的原创小店,欢迎下载使用哈~
Tauri2.12+Vite8+ElementPlus桌面聊天Exe程序

作者:xiaoyan2017
链接:https://www.cnblogs.com/xiaoyan2017/p/23249495
来源:博客园
本文原创发布于博客园 ,转载请注明出处,谢谢合作

收起阅读 »

专业金融K线图表原生插件 Chen KChart Pro

Chen-KChartPro

UniApp Android/iOS 专业 K 线图原生插件

Chen-KChartPro 是基于 Flutter KChart 渲染引擎封装的 uni-app App 原生插件,提供 Android 和 iOS 双端一致的 K 线、深度图、技术指标、绘图工具及交易叠加能力。

插件提供两种使用方式:

  1. 使用 <chen-kchart-pro> 将 KChart 作为原生组件嵌入 .nvue 页面,页面、行情数据和工具栏由 uni-app 业务层控制。
  2. 使用 openDemo() 直接打开完整 Flutter KChart Demo,用于功能体验和效果对照。

如有接入问题、功能需求或商业合作,请添加VX:Chen-Taurus-0510(添加时请备注 KChart)。

在线体验

类型 地址 说明
Web 效果预览 打开 KChart 在线演示 用于 PC、H5 预览 KChart 功能和交互效果
Android Demo 下载 KChart APK 下载并安装到 Android 手机体验完整 Demo

平台要求

平台 最低版本 接入方式
Android API 21 AAR 本地原生插件
iOS iOS 13.0 Framework 本地原生插件

当前插件版本:1.0.0。

主要功能

  • 支持蜡烛图、分时图、深度图和成交量图。
  • 支持 MA、EMA、BOLL、SAR、MACD、KDJ、RSI、WR、CCI、OBV、StochRSI 等指标。
  • 支持拖动浏览、双指缩放、十字线、回到最新、指定时间跳转和自定义价格范围。
  • 支持趋势线、趋势角、箭头、垂直线、水平线、水平射线、射线和十字线绘图。
  • 支持磁铁吸附、连续绘图、撤销、重做、清空和绘图数据恢复。
  • 支持买卖 B/S 标记、订单线、持仓线、开仓价、强平价、止盈止损和未实现盈亏。
  • 支持历史行情分页、实时 K 线更新、亮色/深色主题和色觉友好模式。
  • 支持通过 Props、ref 方法和事件与 uni-app 页面进行双向交互。

插件接入

1. 复制插件文件

将以下目录完整复制到业务项目:

nativeplugins/Chen-KChartPro/  
uni_modules/chen-kchart/

其中:

  • nativeplugins/Chen-KChartPro 包含 Android/iOS 原生插件产物。
  • uni_modules/chen-kchart 包含可直接在 .nvue 页面使用的组件封装。

2. 配置本地原生插件

在 HBuilderX 中打开:

manifest.json -> App 原生插件配置 -> 选择本地插件

勾选 Chen-KChartPro,保存后重新制作 Android/iOS 自定义基座。新增或更新本地原生插件后,旧基座不会自动包含新插件,必须重新制作基座或重新云打包。

3. 页面中使用组件

该组件用于 uni-app App 端 .nvue 页面。将组件放入页面并设置明确的宽高:

<template>  
  <view class="page">  
    <chen-kchart-pro  
      ref="chart"  
      :data="bars"  
      :options="chartOptions"  
      theme="light"  
      mainIndicator="MA"  
      secondaryIndicator="KDJ"  
      :showVolume="true"  
      :tradeMarkers="tradeMarkers"  
      :tradingOverlay="tradingOverlay"  
      chartStyle="width:750rpx;height:900rpx;"  
      @ready="onChartReady"  
      @crosshair="onCrosshair"  
      @viewport-change="onViewportChange"  
      @load-more="onLoadMore"  
      @error="onChartError"  
    />  
  </view>  
</template>  

<script>  
export default {  
  data() {  
    return {  
      bars: [],  
      tradeMarkers: [],  
      tradingOverlay: {},  
      chartOptions: {  
        showNowPrice: true,  
        showInfoDialog: true,  
        enableDrawingTools: true,  
        precision: 4,  
        minScale: 0.35,  
        maxScale: 5  
      }  
    }  
  },  
  methods: {  
    onChartReady() {  
      this.$refs.chart.setData(this.bars)  
    },  
    onCrosshair(event) {  
      console.log('crosshair:', event)  
    },  
    onViewportChange(event) {  
      console.log('viewport:', event)  
    },  
    onLoadMore(event) {  
      if (event && event.history) this.loadHistory()  
    },  
    onChartError(event) {  
      console.error('KChart error:', event)  
    }  
  }  
}  
</script>

K 线数据格式

每根 K 线至少需要以下字段:

{  
  time: 1790481600000, // Unix 毫秒时间戳  
  open: 50000,  
  high: 50200,  
  low: 49800,  
  close: 50100,  
  vol: 123.45  
}

数据要求:

  • time 使用 Unix 毫秒时间戳,建议直接使用行情服务返回的 UTC 时间戳。
  • open、high、low、close、vol 必须是有效数字。
  • 完整数据应按时间从旧到新排列。
  • 业务端负责根据当前周期请求或生成 OHLCV,插件不负责将逐笔成交聚合为 K 线。
  • 切换交易对或周期后,应重新请求数据并调用 setData()。

组件属性

属性 类型 默认值 说明
data Array [] K 线数据,按时间从旧到新排列
options Object {} 图表配置
theme String light light 或 dark
mainIndicator String MA MA/BOLL/EMA/SAR/NONE
secondaryIndicator String KDJ KDJ/MACD/RSI/WR/CCI/OBV/STOCH_RSI/NONE
showVolume Boolean true 是否显示成交量区域
lineMode Boolean false 是否显示分时线模式
mode String KLINE KLINE 或 DEPTH
depth Object {bids: [], asks: []} 深度图买卖盘数据
tradeMarkers Array [] 买入/卖出成交标记
tradingOverlay Object {} 订单、持仓、TP/SL 等交易叠加数据
chartStyle String width:750rpx;height:900rpx; 原生图表组件宽高样式

options 配置

参数 类型 说明
theme String light/dark
mainIndicator String 主图指标
secondaryIndicator String 副图指标
showVolume Boolean 是否显示成交量
isLine Boolean 是否启用分时模式
mode String KLINE/DEPTH
showNowPrice Boolean 是否显示最新价线
showInfoDialog Boolean 是否显示十字线详情
enableDrawingTools Boolean 是否启用绘图能力
colorBlind Boolean 是否启用色觉友好配色
candleBodyMode String solid/hollow,实心或空心 K 线
precision Number 价格小数精度,范围 0-12
minScale Number 最小缩放比例
maxScale Number 最大缩放比例
indicatorConfigs Array 指标计算参数、线色、序列显隐和启停配置

指标设置

indicatorConfigs 会直接传入纯 Flutter KChart 指标计算和渲染层,支持
MA/EMA/BOLL/SAR/VOL/MACD/KDJ/RSI/WR/CCI/OBV/STOCH_RSI:

chartOptions: {  
  indicatorConfigs: [  
    {  
      id: 'BOLL',  
      parameters: { period: 20, multiplier: 2 },  
      colors: { mb: '#2962ff', up: '#ff9800', dn: '#7e57c2' },  
      hiddenSeries: [],  
      enabled: true  
    },  
    {  
      id: 'KDJ',  
      parameters: { period: 9, kSmoothing: 3, dSmoothing: 3 },  
      colors: { k: '#2962ff', d: '#ff9800', j: '#7e57c2' },  
      hiddenSeries: ['j']  
    }  
  ]  
}

绑定的 options 支持深度响应式更新,也可以显式调用
this.$refs.chart.setOptions(this.chartOptions)。完整设置面板实现可直接复用
pages/sample/kchart-module.nvue 中的指标设置数据结构与方法。

数据更新方法

方法 参数 使用场景
setData(bars) Array 首次加载、刷新、切换交易对或周期时,全量替换数据
appendData(bars) Array 合并历史或新增数据,插件会按时间重新排序
updateLastData(bar) Object 实时更新当前最新 K 线,时间相同则替换,否则追加
// 第一次加载或切换周期  
this.$refs.chart.setData(bars)  

// 加载更早历史数据  
this.$refs.chart.appendData(olderBars)  

// WebSocket/轮询更新最新 K 线  
this.$refs.chart.updateLastData(realtimeBar)

注意:

  • appendData() 不应传入已经存在的重复时间数据,业务端应先按 time 去重。
  • updateLastData() 只用于当前最后一根或新生成的一根 K 线,不要传入早于当前最后时间的数据。
  • Props 响应式更新和 ref 方法更新应选择一种,不要在同一次行情更新中同时修改 :data 并调用 updateLastData(),否则会同时触发全量和增量更新。
  • 用户正在浏览历史区域时,实时更新不会强制拉回最新位置;可通过 viewport-change 的 isAtLatest 判断当前状态。

图表控制方法

基础配置

方法 参数 说明
setOptions(options) Object 批量更新图表配置
setTheme(theme) String 设置 light/dark 主题
setMainIndicator(value) String 设置主图指标
setSecondaryIndicator(value) String 设置副图指标
setShowVolume(value) Boolean 显示或隐藏成交量
setLineMode(value) Boolean 切换分时模式
setChartMode(value) String 切换 KLINE/DEPTH

深度与交易

方法 参数 说明
setDepthData(data) Object 设置 {bids, asks} 深度数据
setTradeMarkers(markers) Array 设置成交 B/S 标记
setTradingOverlay(overlay) Object 设置订单、持仓、止盈止损等交易线

绘图工具

方法 参数 说明
setDrawingTool(type) String 设置当前绘图工具,NONE 取消当前工具
setDrawingMode(enabled) Boolean 开启或关闭绘图模式
setDrawingOptions(options) Object 设置连续绘图、磁铁、颜色、线宽等
setDrawings(drawings) Array 恢复序列化的绘图数据
clearDrawings() 无 清除全部绘图
undoDrawing() 无 撤销
redoDrawing() 无 重做

支持的绘图类型:

trendLine、trendAngle、arrow、verticalLine、horizontalLine、  
horizontalRay、ray、crossLine、NONE

setDrawingOptions() 支持:

this.$refs.chart.setDrawingOptions({  
  continuous: true,  
  magnet: true,  
  magnetThreshold: 50,  
  color: '#f2b84b',  
  strokeWidth: 2,  
  lineStyle: 'solid', // solid/dashed/dotted  
  visible: true  
})

视口与十字线

方法 参数 说明
zoomIn() 无 放大图表
zoomOut() 无 缩小图表
resetViewport() 无 重置缩放并回到最新位置
fitContent() 无 自适应显示全部数据
scrollToLatest() 无 滚动到最新 K 线
jumpToIndex(index) Number 跳转到指定数据索引
jumpToTime(time) Number 跳转到指定 Unix 毫秒时间
setLogicalRange(range) Object 设置 {from, to} 逻辑范围
setPriceRange(range) Object 设置 {min, max} 价格范围
clearPriceRange() 无 恢复自动价格范围
showCrosshair(value) Object 使用 {time, price} 或 {index, price} 显示十字线
hideCrosshair() 无 隐藏十字线

深度与交易数据

深度图

this.$refs.chart.setDepthData({  
  bids: [  
    { price: 50000, volume: 10 },  
    { price: 49990, volume: 18 }  
  ],  
  asks: [  
    { price: 50010, volume: 8 },  
    { price: 50020, volume: 15 }  
  ]  
})

volume 建议传入从盘口中心向外累计后的数量。

成交标记

this.$refs.chart.setTradeMarkers([  
  {  
    id: 'buy-1',  
    time: 1790481600000,  
    price: 50000,  
    side: 'buy', // buy/sell  
    label: 'B',  
    style: 'badge', // badge/arrow  
    color: '#00c087',  
    size: 12,  
    visible: true  
  }  
])

订单与持仓线

this.$refs.chart.setTradingOverlay({  
  visible: true,  
  showOrders: true,  
  showPositions: true,  
  showLiquidationPrice: true,  
  showTakeProfitStopLoss: true,  
  showTradeHistory: true,  
  lines: [  
    {  
      id: 'position-1',  
      price: 50000,  
      kind: 'position',  
      side: 'buy',  
      label: '多仓',  
      quantity: '0.50 BTC',  
      unrealizedPnl: 42.8,  
      unrealizedPnlPercent: 1.72  
    },  
    {  
      id: 'tp-1',  
      price: 51000,  
      kind: 'takeProfit',  
      side: 'sell',  
      label: '止盈',  
      draggable: true,  
      dashed: true  
    }  
  ]  
})

kind 支持 order、position、liquidation、takeProfit、stopLoss。订单 status 支持 pending、open、partiallyFilled、filled、canceled、rejected。

组件事件

事件 返回数据 说明
ready 图表状态 原生图表初始化完成
crosshair index/time/price/x/y 及当前 OHLCV 十字线选中变化
crosshair-hidden 无 十字线隐藏
crossline-label-tap {price} 点击十字线价格标签
viewport-change 可见索引、时间、价格范围及 isAtLatest 可见区域变化
scale-change {scale} 缩放比例变化
drawing-change count/canUndo/canRedo/drawings 绘图数据或历史状态变化
load-more {history, prefetch} 滑动到历史边缘,请求更早数据
trade-marker-tap {id, time, price, side} 点击成交标记
trading-line-tap {id, price, kind, side} 点击交易线
trading-line-drag-end {id, price} 确认拖拽改价后触发
error {method, message} 原生调用或数据处理异常

可拖动交易线在松手后会先显示价格修改确认弹窗,用户确认后才触发 trading-line-drag-end。

打开完整 Flutter Demo

通过 js_sdk 调用

import { openDemo } from '@/nativeplugins/Chen-KChartPro/js_sdk/index.js'  

openDemo({}, result => {  
  console.log('open demo:', result.success)  
})

直接引用原生模块

const kchartModule = uni.requireNativePlugin('Chen-KChartPro')  

kchartModule.openDemo({}, result => {  
  console.log(result)  
})

打包说明

  • 本地调试必须使用包含 Chen-KChartPro 的自定义基座,普通标准基座不包含该插件。
  • 正式发布时需要在 manifest.json 中勾选插件后重新云打包。
  • Android 插件保留 armeabi-v7a、arm64-v8a、x86_64 三种 ABI。
  • 不要把 Flutter、Android 的 build 目录或 uni-app 的旧 unpackage 缓存当作插件依赖提交。
  • 如果替换了插件原生产物,需要重新制作自定义基座后再验证。

完整示例

项目中的完整 uni-app 自定义交易页可参考:

pages/sample/kchart-module.nvue

可复用组件封装位于:

uni_modules/chen-kchart/components/chen-kchart-pro/chen-kchart-pro.nvue
继续阅读 »

Chen-KChartPro

UniApp Android/iOS 专业 K 线图原生插件

Chen-KChartPro 是基于 Flutter KChart 渲染引擎封装的 uni-app App 原生插件,提供 Android 和 iOS 双端一致的 K 线、深度图、技术指标、绘图工具及交易叠加能力。

插件提供两种使用方式:

  1. 使用 <chen-kchart-pro> 将 KChart 作为原生组件嵌入 .nvue 页面,页面、行情数据和工具栏由 uni-app 业务层控制。
  2. 使用 openDemo() 直接打开完整 Flutter KChart Demo,用于功能体验和效果对照。

如有接入问题、功能需求或商业合作,请添加VX:Chen-Taurus-0510(添加时请备注 KChart)。

在线体验

类型 地址 说明
Web 效果预览 打开 KChart 在线演示 用于 PC、H5 预览 KChart 功能和交互效果
Android Demo 下载 KChart APK 下载并安装到 Android 手机体验完整 Demo

平台要求

平台 最低版本 接入方式
Android API 21 AAR 本地原生插件
iOS iOS 13.0 Framework 本地原生插件

当前插件版本:1.0.0。

主要功能

  • 支持蜡烛图、分时图、深度图和成交量图。
  • 支持 MA、EMA、BOLL、SAR、MACD、KDJ、RSI、WR、CCI、OBV、StochRSI 等指标。
  • 支持拖动浏览、双指缩放、十字线、回到最新、指定时间跳转和自定义价格范围。
  • 支持趋势线、趋势角、箭头、垂直线、水平线、水平射线、射线和十字线绘图。
  • 支持磁铁吸附、连续绘图、撤销、重做、清空和绘图数据恢复。
  • 支持买卖 B/S 标记、订单线、持仓线、开仓价、强平价、止盈止损和未实现盈亏。
  • 支持历史行情分页、实时 K 线更新、亮色/深色主题和色觉友好模式。
  • 支持通过 Props、ref 方法和事件与 uni-app 页面进行双向交互。

插件接入

1. 复制插件文件

将以下目录完整复制到业务项目:

nativeplugins/Chen-KChartPro/  
uni_modules/chen-kchart/

其中:

  • nativeplugins/Chen-KChartPro 包含 Android/iOS 原生插件产物。
  • uni_modules/chen-kchart 包含可直接在 .nvue 页面使用的组件封装。

2. 配置本地原生插件

在 HBuilderX 中打开:

manifest.json -> App 原生插件配置 -> 选择本地插件

勾选 Chen-KChartPro,保存后重新制作 Android/iOS 自定义基座。新增或更新本地原生插件后,旧基座不会自动包含新插件,必须重新制作基座或重新云打包。

3. 页面中使用组件

该组件用于 uni-app App 端 .nvue 页面。将组件放入页面并设置明确的宽高:

<template>  
  <view class="page">  
    <chen-kchart-pro  
      ref="chart"  
      :data="bars"  
      :options="chartOptions"  
      theme="light"  
      mainIndicator="MA"  
      secondaryIndicator="KDJ"  
      :showVolume="true"  
      :tradeMarkers="tradeMarkers"  
      :tradingOverlay="tradingOverlay"  
      chartStyle="width:750rpx;height:900rpx;"  
      @ready="onChartReady"  
      @crosshair="onCrosshair"  
      @viewport-change="onViewportChange"  
      @load-more="onLoadMore"  
      @error="onChartError"  
    />  
  </view>  
</template>  

<script>  
export default {  
  data() {  
    return {  
      bars: [],  
      tradeMarkers: [],  
      tradingOverlay: {},  
      chartOptions: {  
        showNowPrice: true,  
        showInfoDialog: true,  
        enableDrawingTools: true,  
        precision: 4,  
        minScale: 0.35,  
        maxScale: 5  
      }  
    }  
  },  
  methods: {  
    onChartReady() {  
      this.$refs.chart.setData(this.bars)  
    },  
    onCrosshair(event) {  
      console.log('crosshair:', event)  
    },  
    onViewportChange(event) {  
      console.log('viewport:', event)  
    },  
    onLoadMore(event) {  
      if (event && event.history) this.loadHistory()  
    },  
    onChartError(event) {  
      console.error('KChart error:', event)  
    }  
  }  
}  
</script>

K 线数据格式

每根 K 线至少需要以下字段:

{  
  time: 1790481600000, // Unix 毫秒时间戳  
  open: 50000,  
  high: 50200,  
  low: 49800,  
  close: 50100,  
  vol: 123.45  
}

数据要求:

  • time 使用 Unix 毫秒时间戳,建议直接使用行情服务返回的 UTC 时间戳。
  • open、high、low、close、vol 必须是有效数字。
  • 完整数据应按时间从旧到新排列。
  • 业务端负责根据当前周期请求或生成 OHLCV,插件不负责将逐笔成交聚合为 K 线。
  • 切换交易对或周期后,应重新请求数据并调用 setData()。

组件属性

属性 类型 默认值 说明
data Array [] K 线数据,按时间从旧到新排列
options Object {} 图表配置
theme String light light 或 dark
mainIndicator String MA MA/BOLL/EMA/SAR/NONE
secondaryIndicator String KDJ KDJ/MACD/RSI/WR/CCI/OBV/STOCH_RSI/NONE
showVolume Boolean true 是否显示成交量区域
lineMode Boolean false 是否显示分时线模式
mode String KLINE KLINE 或 DEPTH
depth Object {bids: [], asks: []} 深度图买卖盘数据
tradeMarkers Array [] 买入/卖出成交标记
tradingOverlay Object {} 订单、持仓、TP/SL 等交易叠加数据
chartStyle String width:750rpx;height:900rpx; 原生图表组件宽高样式

options 配置

参数 类型 说明
theme String light/dark
mainIndicator String 主图指标
secondaryIndicator String 副图指标
showVolume Boolean 是否显示成交量
isLine Boolean 是否启用分时模式
mode String KLINE/DEPTH
showNowPrice Boolean 是否显示最新价线
showInfoDialog Boolean 是否显示十字线详情
enableDrawingTools Boolean 是否启用绘图能力
colorBlind Boolean 是否启用色觉友好配色
candleBodyMode String solid/hollow,实心或空心 K 线
precision Number 价格小数精度,范围 0-12
minScale Number 最小缩放比例
maxScale Number 最大缩放比例
indicatorConfigs Array 指标计算参数、线色、序列显隐和启停配置

指标设置

indicatorConfigs 会直接传入纯 Flutter KChart 指标计算和渲染层,支持
MA/EMA/BOLL/SAR/VOL/MACD/KDJ/RSI/WR/CCI/OBV/STOCH_RSI:

chartOptions: {  
  indicatorConfigs: [  
    {  
      id: 'BOLL',  
      parameters: { period: 20, multiplier: 2 },  
      colors: { mb: '#2962ff', up: '#ff9800', dn: '#7e57c2' },  
      hiddenSeries: [],  
      enabled: true  
    },  
    {  
      id: 'KDJ',  
      parameters: { period: 9, kSmoothing: 3, dSmoothing: 3 },  
      colors: { k: '#2962ff', d: '#ff9800', j: '#7e57c2' },  
      hiddenSeries: ['j']  
    }  
  ]  
}

绑定的 options 支持深度响应式更新,也可以显式调用
this.$refs.chart.setOptions(this.chartOptions)。完整设置面板实现可直接复用
pages/sample/kchart-module.nvue 中的指标设置数据结构与方法。

数据更新方法

方法 参数 使用场景
setData(bars) Array 首次加载、刷新、切换交易对或周期时,全量替换数据
appendData(bars) Array 合并历史或新增数据,插件会按时间重新排序
updateLastData(bar) Object 实时更新当前最新 K 线,时间相同则替换,否则追加
// 第一次加载或切换周期  
this.$refs.chart.setData(bars)  

// 加载更早历史数据  
this.$refs.chart.appendData(olderBars)  

// WebSocket/轮询更新最新 K 线  
this.$refs.chart.updateLastData(realtimeBar)

注意:

  • appendData() 不应传入已经存在的重复时间数据,业务端应先按 time 去重。
  • updateLastData() 只用于当前最后一根或新生成的一根 K 线,不要传入早于当前最后时间的数据。
  • Props 响应式更新和 ref 方法更新应选择一种,不要在同一次行情更新中同时修改 :data 并调用 updateLastData(),否则会同时触发全量和增量更新。
  • 用户正在浏览历史区域时,实时更新不会强制拉回最新位置;可通过 viewport-change 的 isAtLatest 判断当前状态。

图表控制方法

基础配置

方法 参数 说明
setOptions(options) Object 批量更新图表配置
setTheme(theme) String 设置 light/dark 主题
setMainIndicator(value) String 设置主图指标
setSecondaryIndicator(value) String 设置副图指标
setShowVolume(value) Boolean 显示或隐藏成交量
setLineMode(value) Boolean 切换分时模式
setChartMode(value) String 切换 KLINE/DEPTH

深度与交易

方法 参数 说明
setDepthData(data) Object 设置 {bids, asks} 深度数据
setTradeMarkers(markers) Array 设置成交 B/S 标记
setTradingOverlay(overlay) Object 设置订单、持仓、止盈止损等交易线

绘图工具

方法 参数 说明
setDrawingTool(type) String 设置当前绘图工具,NONE 取消当前工具
setDrawingMode(enabled) Boolean 开启或关闭绘图模式
setDrawingOptions(options) Object 设置连续绘图、磁铁、颜色、线宽等
setDrawings(drawings) Array 恢复序列化的绘图数据
clearDrawings() 无 清除全部绘图
undoDrawing() 无 撤销
redoDrawing() 无 重做

支持的绘图类型:

trendLine、trendAngle、arrow、verticalLine、horizontalLine、  
horizontalRay、ray、crossLine、NONE

setDrawingOptions() 支持:

this.$refs.chart.setDrawingOptions({  
  continuous: true,  
  magnet: true,  
  magnetThreshold: 50,  
  color: '#f2b84b',  
  strokeWidth: 2,  
  lineStyle: 'solid', // solid/dashed/dotted  
  visible: true  
})

视口与十字线

方法 参数 说明
zoomIn() 无 放大图表
zoomOut() 无 缩小图表
resetViewport() 无 重置缩放并回到最新位置
fitContent() 无 自适应显示全部数据
scrollToLatest() 无 滚动到最新 K 线
jumpToIndex(index) Number 跳转到指定数据索引
jumpToTime(time) Number 跳转到指定 Unix 毫秒时间
setLogicalRange(range) Object 设置 {from, to} 逻辑范围
setPriceRange(range) Object 设置 {min, max} 价格范围
clearPriceRange() 无 恢复自动价格范围
showCrosshair(value) Object 使用 {time, price} 或 {index, price} 显示十字线
hideCrosshair() 无 隐藏十字线

深度与交易数据

深度图

this.$refs.chart.setDepthData({  
  bids: [  
    { price: 50000, volume: 10 },  
    { price: 49990, volume: 18 }  
  ],  
  asks: [  
    { price: 50010, volume: 8 },  
    { price: 50020, volume: 15 }  
  ]  
})

volume 建议传入从盘口中心向外累计后的数量。

成交标记

this.$refs.chart.setTradeMarkers([  
  {  
    id: 'buy-1',  
    time: 1790481600000,  
    price: 50000,  
    side: 'buy', // buy/sell  
    label: 'B',  
    style: 'badge', // badge/arrow  
    color: '#00c087',  
    size: 12,  
    visible: true  
  }  
])

订单与持仓线

this.$refs.chart.setTradingOverlay({  
  visible: true,  
  showOrders: true,  
  showPositions: true,  
  showLiquidationPrice: true,  
  showTakeProfitStopLoss: true,  
  showTradeHistory: true,  
  lines: [  
    {  
      id: 'position-1',  
      price: 50000,  
      kind: 'position',  
      side: 'buy',  
      label: '多仓',  
      quantity: '0.50 BTC',  
      unrealizedPnl: 42.8,  
      unrealizedPnlPercent: 1.72  
    },  
    {  
      id: 'tp-1',  
      price: 51000,  
      kind: 'takeProfit',  
      side: 'sell',  
      label: '止盈',  
      draggable: true,  
      dashed: true  
    }  
  ]  
})

kind 支持 order、position、liquidation、takeProfit、stopLoss。订单 status 支持 pending、open、partiallyFilled、filled、canceled、rejected。

组件事件

事件 返回数据 说明
ready 图表状态 原生图表初始化完成
crosshair index/time/price/x/y 及当前 OHLCV 十字线选中变化
crosshair-hidden 无 十字线隐藏
crossline-label-tap {price} 点击十字线价格标签
viewport-change 可见索引、时间、价格范围及 isAtLatest 可见区域变化
scale-change {scale} 缩放比例变化
drawing-change count/canUndo/canRedo/drawings 绘图数据或历史状态变化
load-more {history, prefetch} 滑动到历史边缘,请求更早数据
trade-marker-tap {id, time, price, side} 点击成交标记
trading-line-tap {id, price, kind, side} 点击交易线
trading-line-drag-end {id, price} 确认拖拽改价后触发
error {method, message} 原生调用或数据处理异常

可拖动交易线在松手后会先显示价格修改确认弹窗,用户确认后才触发 trading-line-drag-end。

打开完整 Flutter Demo

通过 js_sdk 调用

import { openDemo } from '@/nativeplugins/Chen-KChartPro/js_sdk/index.js'  

openDemo({}, result => {  
  console.log('open demo:', result.success)  
})

直接引用原生模块

const kchartModule = uni.requireNativePlugin('Chen-KChartPro')  

kchartModule.openDemo({}, result => {  
  console.log(result)  
})

打包说明

  • 本地调试必须使用包含 Chen-KChartPro 的自定义基座,普通标准基座不包含该插件。
  • 正式发布时需要在 manifest.json 中勾选插件后重新云打包。
  • Android 插件保留 armeabi-v7a、arm64-v8a、x86_64 三种 ABI。
  • 不要把 Flutter、Android 的 build 目录或 uni-app 的旧 unpackage 缓存当作插件依赖提交。
  • 如果替换了插件原生产物,需要重新制作自定义基座后再验证。

完整示例

项目中的完整 uni-app 自定义交易页可参考:

pages/sample/kchart-module.nvue

可复用组件封装位于:

uni_modules/chen-kchart/components/chen-kchart-pro/chen-kchart-pro.nvue
收起阅读 »

【公告】旧版 HBuilder(红色图标) Android 云端打包服务下线通知

云打包 HBuilder

亲爱的开发者:

旧版HBuilder(红色图标)已于2018年停止维护,为保证老用户正常使用,HBuilder对应的Android云端打包服务器一直还坚守在岗位上(iOS打包机由于iOS系统兼容问题,前期已经下线)。随着开发者基本上已升级到HBuilderX,HBuilder云端打包服务器计划于2026年10月30日正式下线。具体事项公告如下:

一、下线时间与影响范围

  • 下线时间:2026 年 10 月 30 日 24:00
  • 影响范围:届时,基于旧版 HBuilder 发起的 Android 云端打包请求 将无法继续处理。

二、迁移与升级建议

为避免影响您的业务正常迭代与版本发布,请使用旧版 HBuilder 的开发者尽快迁移至下一代开发工具 HBuilderX:

  • 下载安装:请前往官网下载并安装最新版本的 HBuilderX。
  • 项目导入:将原 HBuilder 项目直接导入 HBuilderX 中,项目结构与代码完全兼容。

请相关开发者提前安排升级计划,感谢您的理解与配合!

DCloud 官方团队

继续阅读 »

亲爱的开发者:

旧版HBuilder(红色图标)已于2018年停止维护,为保证老用户正常使用,HBuilder对应的Android云端打包服务器一直还坚守在岗位上(iOS打包机由于iOS系统兼容问题,前期已经下线)。随着开发者基本上已升级到HBuilderX,HBuilder云端打包服务器计划于2026年10月30日正式下线。具体事项公告如下:

一、下线时间与影响范围

  • 下线时间:2026 年 10 月 30 日 24:00
  • 影响范围:届时,基于旧版 HBuilder 发起的 Android 云端打包请求 将无法继续处理。

二、迁移与升级建议

为避免影响您的业务正常迭代与版本发布,请使用旧版 HBuilder 的开发者尽快迁移至下一代开发工具 HBuilderX:

  • 下载安装:请前往官网下载并安装最新版本的 HBuilderX。
  • 项目导入:将原 HBuilder 项目直接导入 HBuilderX 中,项目结构与代码完全兼容。

请相关开发者提前安排升级计划,感谢您的理解与配合!

DCloud 官方团队

收起阅读 »

HBuilderX 云打包上传 iOS IPA 报错 90085,执行 xcode-select --install 后解决

解决 HBuilderX iOS 云打包上传 Transporter 报错 90085 的方法:

我之前使用 HBuilderX 5.07 打包 iOS IPA,通过 Mac 上的 Transporter 上传 App Store Connect 时,遇到了这个错误:

No architectures in the binary. Lipo failed to detect any architectures in the bundle executable. (90085)

一开始检查了 IPA 主程序,确认主程序是 arm64 架构,Transporter 也已经是 1.4.5,但仍然无法正常上传。

最后解决方法:

打开 Mac 终端。

执行命令:

xcode-select --install

按照系统提示安装 Xcode Command Line Tools。
安装完成后,重新使用 Transporter 上传原来的 IPA。

我这边实测,安装完成后重新上传就可以了!

如果你也遇到了同样的 90085 架构错误,可以先尝试这个方法,不一定需要先修改项目代码、反复重新打包或逐个检查 Framework。

说明:这是我自己的实测结果,不保证所有开发环境都适用。如果安装后仍然报错,再继续检查打包产物和上传环境。

补充说明:

我使用的 Transporter 已经是 1.4.5,检查 IPA 主程序后确认是 arm64 架构,但仍然出现 90085 错误。

后来在 Mac 终端执行 xcode-select --install,按照系统提示安装 Xcode Command Line Tools。安装完成后,重新使用 Transporter 上传 IPA,之前的 90085 错误就没有再出现,上传进入了 Apple 处理阶段。

目前这是我自己实测有效的方法,分享给遇到相同问题的开发者参考。不同电脑环境可能存在差异,如果此方法无效,还需要进一步排查。

继续阅读 »

解决 HBuilderX iOS 云打包上传 Transporter 报错 90085 的方法:

我之前使用 HBuilderX 5.07 打包 iOS IPA,通过 Mac 上的 Transporter 上传 App Store Connect 时,遇到了这个错误:

No architectures in the binary. Lipo failed to detect any architectures in the bundle executable. (90085)

一开始检查了 IPA 主程序,确认主程序是 arm64 架构,Transporter 也已经是 1.4.5,但仍然无法正常上传。

最后解决方法:

打开 Mac 终端。

执行命令:

xcode-select --install

按照系统提示安装 Xcode Command Line Tools。
安装完成后,重新使用 Transporter 上传原来的 IPA。

我这边实测,安装完成后重新上传就可以了!

如果你也遇到了同样的 90085 架构错误,可以先尝试这个方法,不一定需要先修改项目代码、反复重新打包或逐个检查 Framework。

说明:这是我自己的实测结果,不保证所有开发环境都适用。如果安装后仍然报错,再继续检查打包产物和上传环境。

补充说明:

我使用的 Transporter 已经是 1.4.5,检查 IPA 主程序后确认是 arm64 架构,但仍然出现 90085 错误。

后来在 Mac 终端执行 xcode-select --install,按照系统提示安装 Xcode Command Line Tools。安装完成后,重新使用 Transporter 上传 IPA,之前的 90085 错误就没有再出现,上传进入了 Apple 处理阶段。

目前这是我自己实测有效的方法,分享给遇到相同问题的开发者参考。不同电脑环境可能存在差异,如果此方法无效,还需要进一步排查。

收起阅读 »

【免费】Android / iOS / 鸿蒙 DLNA 投屏插件,一套 API 推到电视播放

uts插件 uniapp原生插件

【免费】Android / iOS / 鸿蒙 DLNA 投屏插件,一套 API 推到电视播放

插件 ID:msh-dlna-cast
形态:UTS 插件 · 免费 · Vue3 App
适用:把手机里的视频 / 图片推到同一 Wi-Fi 下的电视、盒子播放


做短视频、教育、相册类 App 时,经常会被问一句:「能不能投到电视上看?」

以前要自己啃 DLNA / SSDP / SOAP,Android、iOS、鸿蒙还各写一套。现在用 msh-dlna-cast,三端同一套 JavaScript 接口,搜索设备 → 选中 → 播放 → 暂停 / 进度 / 音量,业务代码只写一份。

插件市场搜索:msh-dlna-cast(或点文末链接)


能做什么

能力 说明
搜设备 局域网 SSDP 搜索;iOS 同时搜 AirPlay
推媒体 http / https 地址,或手机本地文件(插件自建临时 HTTP,不用先上传)
播控 播放、暂停、继续、从头播、停止
进度 查询时长 / 进度,seek,快进 / 快退 10 秒
音量 0–100 绝对音量、静音
状态 onStateChange 实时回调状态、进度、音量

平台:Android 5.0+ · iOS 15+ · 鸿蒙 NEXT(API 12+)
协议:三端都支持 DLNA;iOS 额外支持 AirPlay
不支持:屏幕镜像、Miracast、Chromecast、小程序 / H5 / uni-app x


5 分钟接入

1. 导入插件

从插件市场导入,或把 uni_modules/msh-dlna-cast 放进工程。uni_modules 会自动识别,不必在 manifest.json 里勾选本地插件。

2. 做自定义调试基座(必做)

插件带原生配置(权限、引擎),标准基座无效。HBuilderX 会提示:

uts插件[msh-dlna-cast]依赖的原生配置或三方SDK在运行至标准基座时不能生效

路径:运行 → 运行到手机或模拟器 → 制作自定义调试基座 → 用该基座真机跑。
模拟器收不到组播,请用真机。

3. 写代码

import * as dlna from '@/uni_modules/msh-dlna-cast'  

// 发现设备(同一 id 重复发现会覆盖并再次回调)  
dlna.onDeviceFound((res) => {  
  if (res.code !== 0) return  
  console.log(res.data.name, res.data.protocol) // DLNA / AIRPLAY  
})  

// 状态变化  
dlna.onStateChange((res) => {  
  if (res.code !== 0) return  
  const { state, position, duration, volume, mute } = res.data  
  console.log(state, position, duration, volume, mute)  
})  

// 开始搜索(timeout 默认 8000ms)  
dlna.startSearch({ timeout: 8000 }, (res) => {  
  if (res.code === 0) console.log('搜索已启动')  
  if (res.code === 1001) console.log('超时未发现设备')  
})  

// 选中设备后播放  
dlna.selectDevice({ id: deviceId }, (res) => {  
  if (res.code !== 0) return  
  dlna.play({  
    url: 'https://player.alicdn.com/video/aliyunmedia.mp4',  
    title: '示例视频',  
    mimeType: 'video/mp4'  
  }, (playRes) => {  
    console.log(playRes.code, playRes.data.url)  
  })  
})  

// 常用控制  
dlna.pause(() => {})  
dlna.resume(() => {})  
dlna.seek({ position: 30000 }, () => {})      // 毫秒  
dlna.setVolume({ volume: 30 }, () => {})  
dlna.setMute({ mute: true }, () => {})  
dlna.stop(() => {})

回调统一为 { code, message, data },成功时 code === 0。

Android 请开启明文 HTTP(电视控制地址多为 HTTP):

{  
  "app-plus": {  
    "android": {  
      "usesCleartextTraffic": true  
    }  
  }  
}

本地视频怎么投

play 的 url 传本地绝对路径(以 / 开头,不要带 file://)。插件在手机上起临时 HTTP,回调里的 data.url 就是电视能访问的地址。

uni.chooseVideo({  
  sourceType: ['album'],  
  compressed: false,  
  success: (res) => {  
    let path = res.tempFilePath || ''  
    if (typeof plus !== 'undefined' && plus.io?.convertLocalFileSystemURL) {  
      path = plus.io.convertLocalFileSystemURL(path)  
    }  
    if (path.indexOf('file://') === 0) path = path.substring(7)  

    dlna.play({ url: path, title: '本地视频' }, (r) => {  
      if (r.code === 0) console.log('终端地址', r.data.url)  
    })  
  }  
})

Demo 怎么跑通

仓库 / 插件包里附带 dlna-cast-demo,界面大致如下:

  1. 确认顶部本机 IP 已显示(说明连上 Wi-Fi)
  2. 点「搜索设备」,列表里选中电视
  3. 用「示例视频」或粘贴自己的地址,点「播放」
  4. 试暂停、进度条、快进快退、音量、静音

示例素材(国内可直连):

  • 视频:https://player.alicdn.com/video/aliyunmedia.mp4
  • 图片:https://www.w3school.com.cn/i/eg_tulip.jpg

发帖时可附 Demo 截图:顶部 IP、搜索按钮、播放控件、最近回调。


iOS 特别说明(DLNA vs AirPlay)

DLNA AirPlay
选中后 直接连上,可 play 先点系统投屏按钮,选好接收端,再 play
音量 setVolume 走系统音量;接收端不跟随时中间音量返回 1009

首次运行务必允许「本地网络」。iOS 16+ 搜不到设备,常见原因是缺组播能力:向 Apple 申请 Multicast Networking,描述文件具备后再写入 UTS.entitlements,并重新做自定义基座。

AirPlay 是推媒体,不是屏幕镜像。


使用前 checklist

  • [ ] 手机与电视同一 Wi-Fi,路由器未开 AP 隔离
  • [ ] 电视已开启 DLNA / 媒体渲染(或对应投屏开关)
  • [ ] 已用自定义基座真机运行
  • [ ] Android 已开 usesCleartextTraffic
  • [ ] iOS 已允许本地网络

常见问题速查

现象 怎么处理
1001 一台都没有 同一 Wi-Fi?AP 隔离关了?电视 DLNA 开了?
提示标准基座不能生效 制作自定义调试基座
1008 iOS 本地网络 / 组播;Android 组播权限
1007 手机没连 Wi-Fi
1010 换过网络,重新搜索并选设备
本地文件电视打不开 电视访问不到手机临时 HTTP,再查同一 Wi-Fi
AirPlay 调音量 1009 用接收端自身音量

完整错误码、接口表见插件 readme / 使用手册。


本期边界(避免踩坑)

不做:屏幕镜像、字幕、播放列表、多机同时播、倍速。
系统 DLNA 的 Play 只保证 1 倍速,多数电视会忽略其他 Speed。


获取方式

  • 插件市场搜索:msh-dlna-cast
  • 插件链接:(上架后填入)https://ext.dcloud.net.cn/plugin?id=29885
  • 免费,无广告,不采集、不上传个人数据;网络行为只发生在局域网

有问题欢迎评论区留言,请尽量带上:平台版本、手机与电视型号、完整 { code, message, data } 回调。祝投屏顺利 📺

继续阅读 »

【免费】Android / iOS / 鸿蒙 DLNA 投屏插件,一套 API 推到电视播放

插件 ID:msh-dlna-cast
形态:UTS 插件 · 免费 · Vue3 App
适用:把手机里的视频 / 图片推到同一 Wi-Fi 下的电视、盒子播放


做短视频、教育、相册类 App 时,经常会被问一句:「能不能投到电视上看?」

以前要自己啃 DLNA / SSDP / SOAP,Android、iOS、鸿蒙还各写一套。现在用 msh-dlna-cast,三端同一套 JavaScript 接口,搜索设备 → 选中 → 播放 → 暂停 / 进度 / 音量,业务代码只写一份。

插件市场搜索:msh-dlna-cast(或点文末链接)


能做什么

能力 说明
搜设备 局域网 SSDP 搜索;iOS 同时搜 AirPlay
推媒体 http / https 地址,或手机本地文件(插件自建临时 HTTP,不用先上传)
播控 播放、暂停、继续、从头播、停止
进度 查询时长 / 进度,seek,快进 / 快退 10 秒
音量 0–100 绝对音量、静音
状态 onStateChange 实时回调状态、进度、音量

平台:Android 5.0+ · iOS 15+ · 鸿蒙 NEXT(API 12+)
协议:三端都支持 DLNA;iOS 额外支持 AirPlay
不支持:屏幕镜像、Miracast、Chromecast、小程序 / H5 / uni-app x


5 分钟接入

1. 导入插件

从插件市场导入,或把 uni_modules/msh-dlna-cast 放进工程。uni_modules 会自动识别,不必在 manifest.json 里勾选本地插件。

2. 做自定义调试基座(必做)

插件带原生配置(权限、引擎),标准基座无效。HBuilderX 会提示:

uts插件[msh-dlna-cast]依赖的原生配置或三方SDK在运行至标准基座时不能生效

路径:运行 → 运行到手机或模拟器 → 制作自定义调试基座 → 用该基座真机跑。
模拟器收不到组播,请用真机。

3. 写代码

import * as dlna from '@/uni_modules/msh-dlna-cast'  

// 发现设备(同一 id 重复发现会覆盖并再次回调)  
dlna.onDeviceFound((res) => {  
  if (res.code !== 0) return  
  console.log(res.data.name, res.data.protocol) // DLNA / AIRPLAY  
})  

// 状态变化  
dlna.onStateChange((res) => {  
  if (res.code !== 0) return  
  const { state, position, duration, volume, mute } = res.data  
  console.log(state, position, duration, volume, mute)  
})  

// 开始搜索(timeout 默认 8000ms)  
dlna.startSearch({ timeout: 8000 }, (res) => {  
  if (res.code === 0) console.log('搜索已启动')  
  if (res.code === 1001) console.log('超时未发现设备')  
})  

// 选中设备后播放  
dlna.selectDevice({ id: deviceId }, (res) => {  
  if (res.code !== 0) return  
  dlna.play({  
    url: 'https://player.alicdn.com/video/aliyunmedia.mp4',  
    title: '示例视频',  
    mimeType: 'video/mp4'  
  }, (playRes) => {  
    console.log(playRes.code, playRes.data.url)  
  })  
})  

// 常用控制  
dlna.pause(() => {})  
dlna.resume(() => {})  
dlna.seek({ position: 30000 }, () => {})      // 毫秒  
dlna.setVolume({ volume: 30 }, () => {})  
dlna.setMute({ mute: true }, () => {})  
dlna.stop(() => {})

回调统一为 { code, message, data },成功时 code === 0。

Android 请开启明文 HTTP(电视控制地址多为 HTTP):

{  
  "app-plus": {  
    "android": {  
      "usesCleartextTraffic": true  
    }  
  }  
}

本地视频怎么投

play 的 url 传本地绝对路径(以 / 开头,不要带 file://)。插件在手机上起临时 HTTP,回调里的 data.url 就是电视能访问的地址。

uni.chooseVideo({  
  sourceType: ['album'],  
  compressed: false,  
  success: (res) => {  
    let path = res.tempFilePath || ''  
    if (typeof plus !== 'undefined' && plus.io?.convertLocalFileSystemURL) {  
      path = plus.io.convertLocalFileSystemURL(path)  
    }  
    if (path.indexOf('file://') === 0) path = path.substring(7)  

    dlna.play({ url: path, title: '本地视频' }, (r) => {  
      if (r.code === 0) console.log('终端地址', r.data.url)  
    })  
  }  
})

Demo 怎么跑通

仓库 / 插件包里附带 dlna-cast-demo,界面大致如下:

  1. 确认顶部本机 IP 已显示(说明连上 Wi-Fi)
  2. 点「搜索设备」,列表里选中电视
  3. 用「示例视频」或粘贴自己的地址,点「播放」
  4. 试暂停、进度条、快进快退、音量、静音

示例素材(国内可直连):

  • 视频:https://player.alicdn.com/video/aliyunmedia.mp4
  • 图片:https://www.w3school.com.cn/i/eg_tulip.jpg

发帖时可附 Demo 截图:顶部 IP、搜索按钮、播放控件、最近回调。


iOS 特别说明(DLNA vs AirPlay)

DLNA AirPlay
选中后 直接连上,可 play 先点系统投屏按钮,选好接收端,再 play
音量 setVolume 走系统音量;接收端不跟随时中间音量返回 1009

首次运行务必允许「本地网络」。iOS 16+ 搜不到设备,常见原因是缺组播能力:向 Apple 申请 Multicast Networking,描述文件具备后再写入 UTS.entitlements,并重新做自定义基座。

AirPlay 是推媒体,不是屏幕镜像。


使用前 checklist

  • [ ] 手机与电视同一 Wi-Fi,路由器未开 AP 隔离
  • [ ] 电视已开启 DLNA / 媒体渲染(或对应投屏开关)
  • [ ] 已用自定义基座真机运行
  • [ ] Android 已开 usesCleartextTraffic
  • [ ] iOS 已允许本地网络

常见问题速查

现象 怎么处理
1001 一台都没有 同一 Wi-Fi?AP 隔离关了?电视 DLNA 开了?
提示标准基座不能生效 制作自定义调试基座
1008 iOS 本地网络 / 组播;Android 组播权限
1007 手机没连 Wi-Fi
1010 换过网络,重新搜索并选设备
本地文件电视打不开 电视访问不到手机临时 HTTP,再查同一 Wi-Fi
AirPlay 调音量 1009 用接收端自身音量

完整错误码、接口表见插件 readme / 使用手册。


本期边界(避免踩坑)

不做:屏幕镜像、字幕、播放列表、多机同时播、倍速。
系统 DLNA 的 Play 只保证 1 倍速,多数电视会忽略其他 Speed。


获取方式

  • 插件市场搜索:msh-dlna-cast
  • 插件链接:(上架后填入)https://ext.dcloud.net.cn/plugin?id=29885
  • 免费,无广告,不采集、不上传个人数据;网络行为只发生在局域网

有问题欢迎评论区留言,请尽量带上:平台版本、手机与电视型号、完整 { code, message, data } 回调。祝投屏顺利 📺

收起阅读 »

开发者资料索引:页面阅读与核对清单

android11微信分享

开发者资料索引:页面阅读与核对清单

整理日期:20260929
本次整理 300 条公开页面,地址以纯文本列出,方便按需浏览和复核。

阅读建议:先查看页面标题与正文,再结合其他来源核对信息。页面内容和更新时间以原站展示为准。

资料地址:

  1. http://wap.baiduzzc.org.cn/article/news/k-UhDAyZ6iGqQRJnQWoR1p.html
  2. http://wap.baiduzzc.org.cn/article/news/k-kgcGBJMISBqBQipHOTEV.html
  3. http://wap.baiduzzc.org.cn/article/news/k-A8SbKTW5YO4VJKHWp0fo.html
  4. http://wap.baiduzzc.org.cn/article/news/k-VIEC21H9kKzeRw8RdXuw.html
  5. http://wap.baiduzzc.org.cn/article/news/k-lRbSChZBVkuLUxeJNv64.html
  6. http://wap.baiduzzc.org.cn/article/news/k-mvYyImnEutNrwF1TwBfZ.html
  7. http://wap.baiduzzc.org.cn/article/news/k-7kvo2VtgFGom4RkYaVIU.html
  8. http://wap.baiduzzc.org.cn/article/news/k-8iwBH13Jml2cTaUfTbMW.html
  9. http://wap.baiduzzc.org.cn/article/news/k-l4P7wNln97Zxumjhvoi9.html
  10. http://wap.baiduzzc.org.cn/article/news/k-0uPqwj5KLWKteCmXXqI7.html
  11. http://wap.baiduzzc.org.cn/article/news/k-9DLawRF5ckGVcs3bBeEE.html
  12. http://wap.baiduzzc.org.cn/article/news/k-RwUZXztY1yJqPGpSuIbs.html
  13. http://wap.baiduzzc.org.cn/article/news/k-UTxdswqB2CHOVQ0RXsP3.html
  14. http://wap.baiduzzc.org.cn/article/news/k-BoOXN9oOHXw9toCl2mdX.html
  15. http://wap.baiduzzc.org.cn/article/news/k-Mz3zdVpgwrf1hAddXOB1.html
  16. http://wap.baiduzzc.org.cn/article/news/k-BCRlNWUflpOa5DVRcKTJ.html
  17. http://wap.baiduzzc.org.cn/article/news/k-PcVeasV3mYkCJLpn2JcQ.html
  18. http://wap.baiduzzc.org.cn/article/news/k-ZFkQVlWtk3oCAgdb6iCy.html
  19. http://wap.baiduzzc.org.cn/article/news/k-NI6ozu7ta3SJmk8lSrvj.html
  20. http://wap.baiduzzc.org.cn/article/news/k-pkG3pXkyfTuIvZtQV5dR.html
  21. http://wap.baiduzzc.org.cn/article/news/k-x8xwJt46zUdxZLZyqGKA.html
  22. http://wap.baiduzzc.org.cn/article/news/k-umbCPixBMW4SoM1HKDSt.html
  23. http://wap.baiduzzc.org.cn/article/news/k-Jwy76DhIKbiyjlsSmtHe.html
  24. http://wap.baiduzzc.org.cn/article/news/k-jfafWQbt2g18dFuQYoTI.html
  25. http://wap.baiduzzc.org.cn/article/news/k-FYXGh4F7dA3K914PFK0a.html
  26. http://wap.baiduzzc.org.cn/article/news/k-2mF5UQJiqLnZUf2tki4O.html
  27. http://wap.baiduzzc.org.cn/article/news/k-MDuaeOfvxdfsQU0xRoNH.html
  28. http://wap.baiduzzc.org.cn/article/news/k-4YUrgrExEWNeBrmmXU3Y.html
  29. http://wap.baiduzzc.org.cn/article/news/k-Vd0c6ZAzVuWy5HDKQhyf.html
  30. http://wap.baiduzzc.org.cn/article/news/k-JubsRxXh73slxhIjwATS.html
  31. http://wap.baiduzzc.org.cn/article/news/k-fpDVIYDzJtgXEM7wGXAj.html
  32. http://wap.baiduzzc.org.cn/article/news/k-ROHysbO0lSfPgRrk0D4D.html
  33. http://wap.baiduzzc.org.cn/article/news/k-0T6xrAoEijjToBvuyL7f.html
  34. http://wap.baiduzzc.org.cn/article/news/k-ge4Qv7ctgHhdNo6EHTZu.html
  35. http://wap.baiduzzc.org.cn/article/news/k-ZYUVyKb0CG7n084Lrgf7.html
  36. http://wap.baiduzzc.org.cn/article/news/k-PDz3RU5I28peykALdmaM.html
  37. http://wap.baiduzzc.org.cn/article/news/k-IDfJZznBDcdje5x0jIJO.html
  38. http://wap.baiduzzc.org.cn/article/news/k-bowUtkY8Vh1efcFdTVuJ.html
  39. http://wap.baiduzzc.org.cn/article/news/k-ipQvBvIKKhAsyPIO3DJ0.html
  40. http://wap.baiduzzc.org.cn/article/news/k-Q2z8ZTaHnCc1NEgHWdFx.html
  41. http://wap.baiduzzc.org.cn/article/news/k-Qaht0xLilBEVvpl53lxs.html
  42. http://wap.baiduzzc.org.cn/article/news/k-sVp0ZF8ixcjLcDt3VVdq.html
  43. http://wap.baiduzzc.org.cn/article/news/k-N3jmLabzlnoWLuoNMciE.html
  44. http://wap.baiduzzc.org.cn/article/news/k-HrO7hpbbPy8usYPrFDoM.html
  45. http://wap.baiduzzc.org.cn/article/news/k-yQQV4kGgYLYLt5knkKOO.html
  46. http://wap.baiduzzc.org.cn/article/news/k-PUHLXerP2YgYUwIZaU7j.html
  47. http://wap.baiduzzc.org.cn/article/news/k-dukVXgdNSV8FViKCitTr.html
  48. http://wap.baiduzzc.org.cn/article/news/k-5eaFYodjdxWaQXbEDE8b.html
  49. http://wap.baiduzzc.org.cn/article/news/k-hGy45TOeLo7IDzw4CcPv.html
  50. http://wap.baiduzzc.org.cn/article/news/k-cmvpaH7lW2RBdXIcLP0F.html
  51. http://wap.baiduzzc.org.cn/article/news/k-VgP1XH9CwRtvUhRO7yRt.html
  52. http://wap.baiduzzc.org.cn/article/news/k-dw7tJCmHPqK0DFzuyN8t.html
  53. http://wap.baiduzzc.org.cn/article/news/k-1J7pcJF7t13qxZx5eupC.html
  54. http://wap.baiduzzc.org.cn/article/news/k-2goQLvTOiaHmlPEfSHsM.html
  55. http://wap.baiduzzc.org.cn/article/news/k-dJsM7gZlKapDU1A2XczG.html
  56. http://wap.baiduzzc.org.cn/article/news/k-b7y2c8k6quuItHt76A9L.html
  57. http://wap.baiduzzc.org.cn/article/news/k-rd884aRYavAxjfz26FD4.html
  58. http://wap.baiduzzc.org.cn/article/news/k-ZRDIbTpyZc1mf7ZIP36N.html
  59. http://wap.baiduzzc.org.cn/article/news/k-8SOjjHBpAJJ1k1Rf3FIy.html
  60. http://wap.baiduzzc.org.cn/article/news/k-5s23NyWfesdZLTCdkhyf.html
  61. http://wap.baiduzzc.org.cn/article/news/k-PNJmXbEM1uSQcQPJxUd3.html
  62. http://wap.baiduzzc.org.cn/article/news/k-KhYvH3wJVfaS2vc7Soww.html
  63. http://wap.baiduzzc.org.cn/article/news/k-JpdFEugwarJoDG5c9blw.html
  64. http://wap.baiduzzc.org.cn/article/news/k-59DQgC4q1UZKHi22uBHd.html
  65. http://wap.baiduzzc.org.cn/article/news/k-2PzVuL8CmAOmtJZ4T7Lc.html
  66. http://wap.baiduzzc.org.cn/article/news/k-jL7OVavS6jQzbRVtJPSB.html
  67. http://wap.baiduzzc.org.cn/article/news/k-ZsysOT4PcWpMRSQh7mbV.html
  68. http://wap.baiduzzc.org.cn/article/news/k-hXvh02zmJ4Or2evHj9Im.html
  69. http://wap.baiduzzc.org.cn/article/news/k-JngZi4fUfblcV09PQTMW.html
  70. http://wap.baiduzzc.org.cn/article/news/k-2h71HiGqFOpxCeQfxIaG.html
  71. http://wap.baiduzzc.org.cn/article/news/k-8YRyACjSPldbRL7Ulik0.html
  72. http://wap.baiduzzc.org.cn/article/news/k-YyCGFnWy6dCf5v16afJ8.html
  73. http://wap.baiduzzc.org.cn/article/news/k-JGydAMwih3eB6aZKCInU.html
  74. http://wap.baiduzzc.org.cn/article/news/k-fZbjQLlKfHy3vWgplQTF.html
  75. http://wap.baiduzzc.org.cn/article/news/k-JFIjIR6KlYT5psvNVa6P.html
  76. http://wap.baiduzzc.org.cn/article/news/k-ioSoIEwKYllrjYzjo0Th.html
  77. http://wap.baiduzzc.org.cn/article/news/k-DDdLKOmonXhyc76dlGg8.html
  78. http://wap.baiduzzc.org.cn/article/news/k-tIqqTvyDRnhcuUmoHrGp.html
  79. http://wap.baiduzzc.org.cn/article/news/k-9B3UQqfyCFobd7rHsBid.html
  80. http://wap.baiduzzc.org.cn/article/news/k-dKk19C0IbO8aHfxnrJ1u.html
  81. http://wap.baiduzzc.org.cn/article/news/k-y8CVGMDFFTaxKhq46RSB.html
  82. http://wap.baiduzzc.org.cn/article/news/k-g1CiqcNZYY3XJZ3aPecJ.html
  83. http://wap.baiduzzc.org.cn/article/news/k-eAzgOKIKBuh7KJIbmUlO.html
  84. http://wap.baiduzzc.org.cn/article/news/k-IZSKXDQimZAy8ymiapqc.html
  85. http://wap.baiduzzc.org.cn/article/news/k-3IFezgarFacPlKaKrMjd.html
  86. http://wap.baiduzzc.org.cn/article/news/k-ig1LAI0E8nB4sbqm4vF6.html
  87. http://wap.baiduzzc.org.cn/article/news/k-3EJlWw3u4gwsvVT2yv0j.html
  88. http://wap.baiduzzc.org.cn/article/news/k-wMljPG3RRLLg7S2BzWbl.html
  89. http://wap.baiduzzc.org.cn/article/news/k-d1fh7swcdMmLZMPQmLua.html
  90. http://wap.baiduzzc.org.cn/article/news/k-sPujNeusebuKFZQznCVn.html
  91. http://wap.baiduzzc.org.cn/article/news/k-LvwwZ6tjHAxwnUIFWAc0.html
  92. http://wap.baiduzzc.org.cn/article/news/k-i53Ui4fcHgKEsHl4WDOc.html
  93. http://wap.baiduzzc.org.cn/article/news/k-Nle1jDtNb3N3vjsQlXD5.html
  94. http://wap.baiduzzc.org.cn/article/news/k-0qPNffdtOhk42QmEoDk3.html
  95. http://wap.baiduzzc.org.cn/article/news/k-GuaqR7pPHr72ETelD0dR.html
  96. http://wap.baiduzzc.org.cn/article/news/k-etMUqFfwtRv53mca3KeM.html
  97. http://wap.baiduzzc.org.cn/article/news/k-iYR0QDt6OslNjctUg6Ak.html
  98. http://wap.baiduzzc.org.cn/article/news/k-70ZckzQuCR3xfxmQnCvR.html
  99. http://wap.baiduzzc.org.cn/article/news/k-Mbh1ULlWhUgsEYFn1vmu.html
  100. http://wap.baiduzzc.org.cn/article/news/k-Ls5J66iNWchmVUjs0vlo.html
  101. http://wap.baiduzzc.org.cn/article/news/k-46een9Zsu4Ts5Yzh20ee.html
  102. http://wap.baiduzzc.org.cn/article/news/k-bB99GSUFrJ1xkd8EvZIr.html
  103. http://wap.baiduzzc.org.cn/article/news/k-IqIpHIgkbSIjUt9ifPGX.html
  104. http://wap.baiduzzc.org.cn/article/news/k-zWnWiRtLMhpJPyRFqiCr.html
  105. http://wap.baiduzzc.org.cn/article/news/k-c3KvpMfXhTiHF1ukG7gc.html
  106. http://wap.baiduzzc.org.cn/article/news/k-H5e6yyboCk6KPXsS96Up.html
  107. http://wap.baiduzzc.org.cn/article/news/k-HmIoAhhz9Pbia5IkF4bB.html
  108. http://wap.baiduzzc.org.cn/article/news/k-U5ccAZRlB5dkPKGhx454.html
  109. http://wap.baiduzzc.org.cn/article/news/k-5v2W9DufN2fMjz5ZbQRc.html
  110. http://wap.baiduzzc.org.cn/article/news/k-mJqYhBGn9gmWCeebKMQt.html
  111. http://wap.baiduzzc.org.cn/article/news/k-RP81JbmocRfkEjf2SzGN.html
  112. http://wap.baiduzzc.org.cn/article/news/k-g5NefoIfKzZb20xbcbrO.html
  113. http://wap.baiduzzc.org.cn/article/news/k-JqxKukJ855isPFWyfEtC.html
  114. http://wap.baiduzzc.org.cn/article/news/k-htzacMb8mJzeTnMsgqXl.html
  115. http://wap.baiduzzc.org.cn/article/news/k-6oB4P4f7wkoboReJ3TKL.html
  116. http://wap.baiduzzc.org.cn/article/news/k-PGhBn4GFEO22RrKLPFsj.html
  117. http://wap.baiduzzc.org.cn/article/news/k-KfWUV0dT6RfPCrfbIqjn.html
  118. http://wap.baiduzzc.org.cn/article/news/k-4ye8C6Yj27CjcxjyEOu0.html
  119. http://wap.baiduzzc.org.cn/article/news/k-JKpOVLPRymjn6c4O1vGM.html
  120. http://wap.baiduzzc.org.cn/article/news/k-MZpJjrjbCH5VuQgjKgRK.html
  121. http://wap.baiduzzc.org.cn/article/news/k-rTz0LoyW76NebeQeDBh8.html
  122. http://wap.baiduzzc.org.cn/article/news/k-EYANRqmqZbhNz5ST5Ed6.html
  123. http://wap.baiduzzc.org.cn/article/news/k-A4ip70jUmhdsJXdXv8wb.html
  124. http://wap.baiduzzc.org.cn/article/news/k-aPyXbjvqRWDw21VuiVDA.html
  125. http://wap.baiduzzc.org.cn/article/news/k-2vONbLFAj96vrjDnORwv.html
  126. http://wap.baiduzzc.org.cn/article/news/k-47qxfN2rIBOBAzrhPl1U.html
  127. http://wap.baiduzzc.org.cn/article/news/k-J9QP7YOwm5rmFp9htm6t.html
  128. http://wap.baiduzzc.org.cn/article/news/k-J1FZedAhNgBTvqbSRXJV.html
  129. http://wap.baiduzzc.org.cn/article/news/k-5e5hkGrd4ppXGa6sxuXd.html
  130. http://wap.baiduzzc.org.cn/article/news/k-5n8m0ykeCEJJPSaDjUdt.html
  131. http://wap.baiduzzc.org.cn/article/news/k-BadtrLG5hnoOrUWsw3YB.html
  132. http://wap.baiduzzc.org.cn/article/news/k-OMOeZhHZmfTYsaA5yMIf.html
  133. http://wap.baiduzzc.org.cn/article/news/k-D1CXqJ96IOTJges34ib7.html
  134. http://wap.baiduzzc.org.cn/article/news/k-cDk1LMBbYdlVr6kRSMrF.html
  135. http://wap.baiduzzc.org.cn/article/news/k-cWcVFtdpEm1kSi6gT0nf.html
  136. http://wap.baiduzzc.org.cn/article/news/k-G4wphXZGCnSHBrki9fWh.html
  137. http://wap.baiduzzc.org.cn/article/news/k-083iUW5787chsO4toKPX.html
  138. http://wap.baiduzzc.org.cn/article/news/k-Qhdjs8Xqz30vlceUte5B.html
  139. http://wap.baiduzzc.org.cn/article/news/k-VdwsSK3a6YYYvZDVToFn.html
  140. http://wap.baiduzzc.org.cn/article/news/k-Jb2EGXD2MaISty9kk1LC.html
  141. http://wap.baiduzzc.org.cn/article/news/k-EcJg4T1IjGIZRWHHycVH.html
  142. http://wap.baiduzzc.org.cn/article/news/k-dmWCoFYncXDLnBWH6oen.html
  143. http://wap.baiduzzc.org.cn/article/news/k-OC64zXviVO0BnYjwBht9.html
  144. http://wap.baiduzzc.org.cn/article/news/k-G14PcklgOFkc7tP8Naqs.html
  145. http://wap.baiduzzc.org.cn/article/news/k-RJwca2REUkjJcNH1ceTf.html
  146. http://wap.baiduzzc.org.cn/article/news/k-ToQKGclXxsRgQN4OYyQi.html
  147. http://wap.baiduzzc.org.cn/article/news/k-JeF6KsjO0donomKsr1pw.html
  148. http://wap.baiduzzc.org.cn/article/news/k-5GbLUealmo3w4Ig4TtNf.html
  149. http://wap.baiduzzc.org.cn/article/news/k-UW0FfoagrbHe8Lmrgmpy.html
  150. http://wap.baiduzzc.org.cn/article/news/k-B3Fzh2POkuwyFElkT8Xg.html
  151. http://wap.baiduzzc.org.cn/article/news/k-jVTZbh0QEuqvabW1Gxro.html
  152. http://wap.baiduzzc.org.cn/article/news/k-PpkW1H8xAuYIXNoxlzY1.html
  153. http://wap.baiduzzc.org.cn/article/news/k-FrStzpt0aj1U7ZH79jhL.html
  154. http://wap.baiduzzc.org.cn/article/news/k-MRcO7DLwkSBtHI3rRtQm.html
  155. http://wap.baiduzzc.org.cn/article/news/k-YRTnUEPHSdMvXrIFW8Q7.html
  156. http://wap.baiduzzc.org.cn/article/news/k-dpDjP77YwEQk2ateF09h.html
  157. http://wap.baiduzzc.org.cn/article/news/k-DuLfsxv8M6eBqkxlqaQY.html
  158. http://wap.baiduzzc.org.cn/article/news/k-2Yrr9wIb74ceLWUUnq6C.html
  159. http://wap.baiduzzc.org.cn/article/news/k-O6rKUaGK2iVKcPuyea33.html
  160. http://wap.baiduzzc.org.cn/article/news/k-tTZ6qaT6YAXVxVQrErOm.html
  161. http://wap.baiduzzc.org.cn/article/news/k-IeTvThdIfaP6Z1QiaSDe.html
  162. http://wap.baiduzzc.org.cn/article/news/k-2KNlWbx66HnxPiGgcNHV.html
  163. http://wap.baiduzzc.org.cn/article/news/k-RjSEkMHEba7jIJzSYDmU.html
  164. http://wap.baiduzzc.org.cn/article/news/k-sDvFQHSwnFIhLCW2NJgg.html
  165. http://wap.baiduzzc.org.cn/article/news/k-Vheay5dYCWPJsB1Z03Jx.html
  166. http://wap.baiduzzc.org.cn/article/news/k-i12Wc3JdLtaUIN6rhUSt.html
  167. http://wap.baiduzzc.org.cn/article/news/k-m0Wvjz6dkheNdPtqpMkb.html
  168. http://wap.baiduzzc.org.cn/article/news/k-o2G1IuwBWq1lx0vm5Wkw.html
  169. http://wap.baiduzzc.org.cn/article/news/k-KuyYXhPxEuz08ofhMe0f.html
  170. http://wap.baiduzzc.org.cn/article/news/k-dcp1zNQf5Lat8DhmXGSW.html
  171. http://wap.baiduzzc.org.cn/article/news/k-j0kYECRx0qslxbsvD10e.html
  172. http://wap.baiduzzc.org.cn/article/news/k-6SIHQBFGOKMJsDLNbA5D.html
  173. http://wap.baiduzzc.org.cn/article/news/k-JBuLAMvudWOqhtmPoN0M.html
  174. http://wap.baiduzzc.org.cn/article/news/k-iFw2DLEtpP5xnNOKEBIe.html
  175. http://wap.baiduzzc.org.cn/article/news/k-bqgqlXTJj5BqUVjcqwhx.html
  176. http://wap.baiduzzc.org.cn/article/news/k-GJL05IZtwv2WyT0zgFAL.html
  177. http://wap.baiduzzc.org.cn/article/news/k-Kp6cta93UNHqVlRjDfoX.html
  178. http://wap.baiduzzc.org.cn/article/news/k-tPlVlc1bc71DopygfnAQ.html
  179. http://wap.baiduzzc.org.cn/article/news/k-PC07tiieE0fQiCVqF9bQ.html
  180. http://wap.baiduzzc.org.cn/article/news/k-WabkeNhHofHV5QhuOFsL.html
  181. http://wap.baiduzzc.org.cn/article/news/k-dHbUH8OJnj2NW6rSkUw4.html
  182. http://wap.baiduzzc.org.cn/article/news/k-i9F3Elr1mDQ7JcXaXSWj.html
  183. http://wap.baiduzzc.org.cn/article/news/k-rPtqydrMptsnJ9SAnS92.html
  184. http://wap.baiduzzc.org.cn/article/news/k-uyCZAlivVqY0hbCbufKj.html
  185. http://wap.baiduzzc.org.cn/article/news/k-a7apqHnzBsnHcMwgLk8Q.html
  186. http://wap.baiduzzc.org.cn/article/news/k-X9upWvBQpM2H7UVs2pv6.html
  187. http://wap.baiduzzc.org.cn/article/news/k-ihXofbmxDGbdAbhYR4cX.html
  188. http://wap.baiduzzc.org.cn/article/news/k-lnaWCCJCrYpkKodtxcf4.html
  189. http://wap.baiduzzc.org.cn/article/news/k-dSzyPa9rFvUODC4KPBui.html
  190. http://wap.baiduzzc.org.cn/article/news/k-9qC3VoegR1evU2hZ4uIG.html
  191. http://wap.baiduzzc.org.cn/article/news/k-zU5sW2IabsSMWtALbqJ4.html
  192. http://wap.baiduzzc.org.cn/article/news/k-K7AuAt7KA0AydOXpp8bd.html
  193. http://wap.baiduzzc.org.cn/article/news/k-HEYeiBpzh4qbX39JewWo.html
  194. http://wap.baiduzzc.org.cn/article/news/k-B26XLpgyRDYoIxrSIRtO.html
  195. http://wap.baiduzzc.org.cn/article/news/k-dYd7rxDSwtu6PkW7d4yn.html
  196. http://wap.baiduzzc.org.cn/article/news/k-U673daf7SrVA5g8Lq06H.html
  197. http://wap.baiduzzc.org.cn/article/news/k-EQ4Tg02BFyt4OeDXiHh0.html
  198. http://wap.baiduzzc.org.cn/article/news/k-M0NPYJL9GLdUVc0KBd2c.html
  199. http://wap.baiduzzc.org.cn/article/news/k-QFfSM7woaFuxMn8orODH.html
  200. http://wap.baiduzzc.org.cn/article/news/k-xY4znjauKrQXJ59RJfga.html
  201. http://wap.baiduzzc.org.cn/article/news/k-MdgQYzHZfmvav42WLLeN.html
  202. http://wap.baiduzzc.org.cn/article/news/k-voNUTlgbm5St3qc5PLBD.html
  203. http://wap.baiduzzc.org.cn/article/news/k-K0QQVj0FcLuCLaPpdgcy.html
  204. http://wap.baiduzzc.org.cn/article/news/k-AblKD81LeXsGLY13HV1d.html
  205. http://wap.baiduzzc.org.cn/article/news/k-0uhlSBzWhkmb5Me2ouIc.html
  206. http://wap.baiduzzc.org.cn/article/news/k-Zp16WhmwUnKeeRe70Lp4.html
  207. http://wap.baiduzzc.org.cn/article/news/k-eJSQaNqZBRifImk0UclA.html
  208. http://wap.baiduzzc.org.cn/article/news/k-cF4ZEepZTV1evQTAJeqq.html
  209. http://wap.baiduzzc.org.cn/article/news/k-srlHW3DnnjR2uQgb7RgA.html
  210. http://wap.baiduzzc.org.cn/article/news/k-DXZdet5ZZPWBhkomVXzS.html
  211. http://wap.baiduzzc.org.cn/article/news/k-JlnneqqCXhveifg2MJL3.html
  212. http://wap.baiduzzc.org.cn/article/news/k-N6f7oKj1EXOjq1Yb5xCT.html
  213. http://wap.baiduzzc.org.cn/article/news/k-cV42sLVdqAldmXy8ydT6.html
  214. http://wap.baiduzzc.org.cn/article/news/k-IlfThoimqpYBNnjaeQV6.html
  215. http://wap.baiduzzc.org.cn/article/news/k-0iUN9NrpG4LjYaoNO9WP.html
  216. http://wap.baiduzzc.org.cn/article/news/k-EwPnZGS4oymiACy57KvW.html
  217. http://wap.baiduzzc.org.cn/article/news/k-xTvPC8Lk3MBs30wtAxGX.html
  218. http://wap.baiduzzc.org.cn/article/news/k-JplRIsBaa98ZFaHkFcd8.html
  219. http://wap.baiduzzc.org.cn/article/news/k-GEAO1JXp4HW2zFHwMKVI.html
  220. http://wap.baiduzzc.org.cn/article/news/k-9qSNIN84fOaLNieCTp0v.html
  221. http://wap.baiduzzc.org.cn/article/news/k-5FxEdTLdMnRuWIWIec2O.html
  222. http://wap.baiduzzc.org.cn/article/news/k-EgPIa9RdQdXGyhEt0IIe.html
  223. http://wap.baiduzzc.org.cn/article/news/k-wwzLJdrFdKXoXcBPxbzr.html
  224. http://wap.baiduzzc.org.cn/article/news/k-kYc5fTWKrkQXKihxeY62.html
  225. http://wap.baiduzzc.org.cn/article/news/k-Fl5zWWuXa03AHioJtoOZ.html
  226. http://wap.baiduzzc.org.cn/article/news/k-qVySdVMKwpeO8SMfPdvM.html
  227. http://wap.baiduzzc.org.cn/article/news/k-MWlaFJTujnBZXoSKeFZp.html
  228. http://wap.baiduzzc.org.cn/article/news/k-g8jEWuupsaQHcEiWbk08.html
  229. http://wap.baiduzzc.org.cn/article/news/k-FlkFXXie6zWtPmliJuWX.html
  230. http://wap.baiduzzc.org.cn/article/news/k-c735JI5YzE91OH6Owp7x.html
  231. http://wap.baiduzzc.org.cn/article/news/k-aw0xxhPGfGztdiNAD8Fx.html
  232. http://wap.baiduzzc.org.cn/article/news/k-kbvzOBuPjMuSfj6xEpze.html
  233. http://wap.baiduzzc.org.cn/article/news/k-cMGwSsmc6a4Mhe7uHkr0.html
  234. http://wap.baiduzzc.org.cn/article/news/k-wQUW1q6zE2uWunNO23cD.html
  235. http://wap.baiduzzc.org.cn/article/news/k-pxJa84cpKY9MquiiTd6M.html
  236. http://wap.baiduzzc.org.cn/article/news/k-fKzab0wEUVKHfY68yFjZ.html
  237. http://wap.baiduzzc.org.cn/article/news/k-Tog2chyC8Q1TWp62BXId.html
  238. http://wap.baiduzzc.org.cn/article/news/k-1yiLxT9ejz9bRVQUFBJD.html
  239. http://wap.baiduzzc.org.cn/article/news/k-rA8QouuxU21vnn3MRKh8.html
  240. http://wap.baiduzzc.org.cn/article/news/k-bnhOCa4haTVrIdDSciYJ.html
  241. http://wap.baiduzzc.org.cn/article/news/k-jdoYJowcmal4mllnY2BW.html
  242. http://wap.baiduzzc.org.cn/article/news/k-P3y6EzW1aRa8v2DYSlt5.html
  243. http://wap.baiduzzc.org.cn/article/news/k-2m35Ten1gnBFpdgfAKfz.html
  244. http://wap.baiduzzc.org.cn/article/news/k-WU6GW2Kc48XMYeCuyeus.html
  245. http://wap.baiduzzc.org.cn/article/news/k-WhFjpmkmbKhw5MvJI42h.html
  246. http://wap.baiduzzc.org.cn/article/news/k-sNhvfR3cisAqyrJYF0hK.html
  247. http://wap.baiduzzc.org.cn/article/news/k-Z7M9i8fs5jIgsgPE73fg.html
  248. http://wap.baiduzzc.org.cn/article/news/k-aAkri1i3uBgY4hwVmNhi.html
  249. http://wap.baiduzzc.org.cn/article/news/k-uyY1BUGCfSoOQXMEFIDy.html
  250. http://wap.baiduzzc.org.cn/article/news/k-NIPJHZI4glfWjpda68lc.html
  251. http://wap.baiduzzc.org.cn/article/news/k-v530nHq9M0I1WZirbX8V.html
  252. http://wap.baiduzzc.org.cn/article/news/k-I28lVZNoBhnLQNgvyffj.html
  253. http://wap.baiduzzc.org.cn/article/news/k-f3ISs7NO97hnykCLz2Gt.html
  254. http://wap.baiduzzc.org.cn/article/news/k-Uct7LVQoerCgH6yPFi5B.html
  255. http://wap.baiduzzc.org.cn/article/news/k-1uIvDqwrMQ1UZmOenJx7.html
  256. http://wap.baiduzzc.org.cn/article/news/k-fAd9LckdnKy31zPG1Hfv.html
  257. http://wap.baiduzzc.org.cn/article/news/k-pGZfdJJ32S2LQdPsgsIw.html
  258. http://wap.baiduzzc.org.cn/article/news/k-nRCApWgMfloce3UU9XNh.html
  259. http://wap.baiduzzc.org.cn/article/news/k-bCe7qGiRVdnZWgVLHV1O.html
  260. http://wap.baiduzzc.org.cn/article/news/k-oVrGSbSCOc9iIbwKTUNc.html
  261. http://wap.baiduzzc.org.cn/article/news/k-jRD0WpnTyfECdhkQebGK.html
  262. http://wap.baiduzzc.org.cn/article/news/k-pymvukHQyG9MYO8vWsFZ.html
  263. http://wap.baiduzzc.org.cn/article/news/k-20eom9AZ1GK0hOQYd0fY.html
  264. http://wap.baiduzzc.org.cn/article/news/k-fTKpeRsA65jJcrvzjmhv.html
  265. http://wap.baiduzzc.org.cn/article/news/k-ApGg3ymixXVYXyT8OLMq.html
  266. http://wap.baiduzzc.org.cn/article/news/k-zPTFnv7vVbaPwG2gyIsa.html
  267. http://wap.baiduzzc.org.cn/article/news/k-EskTpKzE5tyesbnkrB7K.html
  268. http://wap.baiduzzc.org.cn/article/news/k-gjotjNLzyDyplidNiRFz.html
  269. http://wap.baiduzzc.org.cn/article/news/k-sc09PlQqHyNVJpCvAVXl.html
  270. http://wap.baiduzzc.org.cn/article/news/k-BI7wy2qna5woWDrMOSCm.html
  271. http://wap.baiduzzc.org.cn/article/news/k-G1VMuWuDZiuJygZhYnll.html
  272. http://wap.baiduzzc.org.cn/article/news/k-LcBTBaL4lYVIcId0bBka.html
  273. http://wap.baiduzzc.org.cn/article/news/k-HSfhIytuPHpBPoVjxH3E.html
  274. http://wap.baiduzzc.org.cn/article/news/k-fQOvEcpzsdeKvYLeTnpG.html
  275. http://wap.baiduzzc.org.cn/article/news/k-2KoujcY1QqSFIqwrCwTe.html
  276. http://wap.baiduzzc.org.cn/article/news/k-YVcsl3iGLyli68oW69B9.html
  277. http://wap.baiduzzc.org.cn/article/news/k-d5yXrXTv8xS25CZfayDb.html
  278. http://wap.baiduzzc.org.cn/article/news/k-5E7eJe6gsHyVR3Bz5fWd.html
  279. http://wap.baiduzzc.org.cn/article/news/k-y1dYNCcsnq9R1eZeYZ3u.html
  280. http://wap.baiduzzc.org.cn/article/news/k-LbDz5YZwlEidXXdfS3cb.html
  281. http://wap.baiduzzc.org.cn/article/news/k-cZrphSLypCeB7wxhYM7K.html
  282. http://wap.baiduzzc.org.cn/article/news/k-ZzHZldSWCCZvcPNqKybj.html
  283. http://wap.baiduzzc.org.cn/article/news/k-pKPPWGBr7Ri3Ifu3Jtr5.html
  284. http://wap.baiduzzc.org.cn/article/news/k-5TXlstwuuMywT0oXzxmp.html
  285. http://wap.baiduzzc.org.cn/article/news/k-z3mnSrbzyXpOPCWSRPMI.html
  286. http://wap.baiduzzc.org.cn/article/news/k-A42YZpAXxqifBGfeDROC.html
  287. http://wap.baiduzzc.org.cn/article/news/k-NfOCRyXc5uemzyzUJmmJ.html
  288. http://wap.baiduzzc.org.cn/article/news/k-sWzpWsA4pK65He6H1b0a.html
  289. http://wap.baiduzzc.org.cn/article/news/k-ZcuKHERKhLaYPlvsav98.html
  290. http://wap.baiduzzc.org.cn/article/news/k-doETOoU2kNaGNc2nx6de.html
  291. http://wap.baiduzzc.org.cn/article/news/k-rsbhMykzF1R2AHL4bcTe.html
  292. http://wap.baiduzzc.org.cn/article/news/k-wcb5raOa2DHzffHJRu3q.html
  293. http://wap.baiduzzc.org.cn/article/news/k-TEAqc5Bka238hB4feePX.html
  294. http://wap.baiduzzc.org.cn/article/news/k-XDUcDeExqKQkWYDDQmNO.html
  295. http://wap.baiduzzc.org.cn/article/news/k-NYBPBVM4IgQ32HvicZyT.html
  296. http://wap.baiduzzc.org.cn/article/news/k-TPYiMReGuIqRczZKdzJN.html
  297. http://wap.baiduzzc.org.cn/article/news/k-sqlkVZHn3SGGyUyDjEj1.html
  298. http://wap.baiduzzc.org.cn/article/news/k-tML3aMZLLFyFHpcfxOmX.html
  299. http://wap.baiduzzc.org.cn/article/news/k-AIub5UWATcrAmyHfnZN8.html
  300. http://wap.baiduzzc.org.cn/article/news/k-4lUe1MJXADEqDYsmq8Sd.html

以上为资料索引,欢迎按主题补充和校对。

继续阅读 »

开发者资料索引:页面阅读与核对清单

整理日期:20260929
本次整理 300 条公开页面,地址以纯文本列出,方便按需浏览和复核。

阅读建议:先查看页面标题与正文,再结合其他来源核对信息。页面内容和更新时间以原站展示为准。

资料地址:

  1. http://wap.baiduzzc.org.cn/article/news/k-UhDAyZ6iGqQRJnQWoR1p.html
  2. http://wap.baiduzzc.org.cn/article/news/k-kgcGBJMISBqBQipHOTEV.html
  3. http://wap.baiduzzc.org.cn/article/news/k-A8SbKTW5YO4VJKHWp0fo.html
  4. http://wap.baiduzzc.org.cn/article/news/k-VIEC21H9kKzeRw8RdXuw.html
  5. http://wap.baiduzzc.org.cn/article/news/k-lRbSChZBVkuLUxeJNv64.html
  6. http://wap.baiduzzc.org.cn/article/news/k-mvYyImnEutNrwF1TwBfZ.html
  7. http://wap.baiduzzc.org.cn/article/news/k-7kvo2VtgFGom4RkYaVIU.html
  8. http://wap.baiduzzc.org.cn/article/news/k-8iwBH13Jml2cTaUfTbMW.html
  9. http://wap.baiduzzc.org.cn/article/news/k-l4P7wNln97Zxumjhvoi9.html
  10. http://wap.baiduzzc.org.cn/article/news/k-0uPqwj5KLWKteCmXXqI7.html
  11. http://wap.baiduzzc.org.cn/article/news/k-9DLawRF5ckGVcs3bBeEE.html
  12. http://wap.baiduzzc.org.cn/article/news/k-RwUZXztY1yJqPGpSuIbs.html
  13. http://wap.baiduzzc.org.cn/article/news/k-UTxdswqB2CHOVQ0RXsP3.html
  14. http://wap.baiduzzc.org.cn/article/news/k-BoOXN9oOHXw9toCl2mdX.html
  15. http://wap.baiduzzc.org.cn/article/news/k-Mz3zdVpgwrf1hAddXOB1.html
  16. http://wap.baiduzzc.org.cn/article/news/k-BCRlNWUflpOa5DVRcKTJ.html
  17. http://wap.baiduzzc.org.cn/article/news/k-PcVeasV3mYkCJLpn2JcQ.html
  18. http://wap.baiduzzc.org.cn/article/news/k-ZFkQVlWtk3oCAgdb6iCy.html
  19. http://wap.baiduzzc.org.cn/article/news/k-NI6ozu7ta3SJmk8lSrvj.html
  20. http://wap.baiduzzc.org.cn/article/news/k-pkG3pXkyfTuIvZtQV5dR.html
  21. http://wap.baiduzzc.org.cn/article/news/k-x8xwJt46zUdxZLZyqGKA.html
  22. http://wap.baiduzzc.org.cn/article/news/k-umbCPixBMW4SoM1HKDSt.html
  23. http://wap.baiduzzc.org.cn/article/news/k-Jwy76DhIKbiyjlsSmtHe.html
  24. http://wap.baiduzzc.org.cn/article/news/k-jfafWQbt2g18dFuQYoTI.html
  25. http://wap.baiduzzc.org.cn/article/news/k-FYXGh4F7dA3K914PFK0a.html
  26. http://wap.baiduzzc.org.cn/article/news/k-2mF5UQJiqLnZUf2tki4O.html
  27. http://wap.baiduzzc.org.cn/article/news/k-MDuaeOfvxdfsQU0xRoNH.html
  28. http://wap.baiduzzc.org.cn/article/news/k-4YUrgrExEWNeBrmmXU3Y.html
  29. http://wap.baiduzzc.org.cn/article/news/k-Vd0c6ZAzVuWy5HDKQhyf.html
  30. http://wap.baiduzzc.org.cn/article/news/k-JubsRxXh73slxhIjwATS.html
  31. http://wap.baiduzzc.org.cn/article/news/k-fpDVIYDzJtgXEM7wGXAj.html
  32. http://wap.baiduzzc.org.cn/article/news/k-ROHysbO0lSfPgRrk0D4D.html
  33. http://wap.baiduzzc.org.cn/article/news/k-0T6xrAoEijjToBvuyL7f.html
  34. http://wap.baiduzzc.org.cn/article/news/k-ge4Qv7ctgHhdNo6EHTZu.html
  35. http://wap.baiduzzc.org.cn/article/news/k-ZYUVyKb0CG7n084Lrgf7.html
  36. http://wap.baiduzzc.org.cn/article/news/k-PDz3RU5I28peykALdmaM.html
  37. http://wap.baiduzzc.org.cn/article/news/k-IDfJZznBDcdje5x0jIJO.html
  38. http://wap.baiduzzc.org.cn/article/news/k-bowUtkY8Vh1efcFdTVuJ.html
  39. http://wap.baiduzzc.org.cn/article/news/k-ipQvBvIKKhAsyPIO3DJ0.html
  40. http://wap.baiduzzc.org.cn/article/news/k-Q2z8ZTaHnCc1NEgHWdFx.html
  41. http://wap.baiduzzc.org.cn/article/news/k-Qaht0xLilBEVvpl53lxs.html
  42. http://wap.baiduzzc.org.cn/article/news/k-sVp0ZF8ixcjLcDt3VVdq.html
  43. http://wap.baiduzzc.org.cn/article/news/k-N3jmLabzlnoWLuoNMciE.html
  44. http://wap.baiduzzc.org.cn/article/news/k-HrO7hpbbPy8usYPrFDoM.html
  45. http://wap.baiduzzc.org.cn/article/news/k-yQQV4kGgYLYLt5knkKOO.html
  46. http://wap.baiduzzc.org.cn/article/news/k-PUHLXerP2YgYUwIZaU7j.html
  47. http://wap.baiduzzc.org.cn/article/news/k-dukVXgdNSV8FViKCitTr.html
  48. http://wap.baiduzzc.org.cn/article/news/k-5eaFYodjdxWaQXbEDE8b.html
  49. http://wap.baiduzzc.org.cn/article/news/k-hGy45TOeLo7IDzw4CcPv.html
  50. http://wap.baiduzzc.org.cn/article/news/k-cmvpaH7lW2RBdXIcLP0F.html
  51. http://wap.baiduzzc.org.cn/article/news/k-VgP1XH9CwRtvUhRO7yRt.html
  52. http://wap.baiduzzc.org.cn/article/news/k-dw7tJCmHPqK0DFzuyN8t.html
  53. http://wap.baiduzzc.org.cn/article/news/k-1J7pcJF7t13qxZx5eupC.html
  54. http://wap.baiduzzc.org.cn/article/news/k-2goQLvTOiaHmlPEfSHsM.html
  55. http://wap.baiduzzc.org.cn/article/news/k-dJsM7gZlKapDU1A2XczG.html
  56. http://wap.baiduzzc.org.cn/article/news/k-b7y2c8k6quuItHt76A9L.html
  57. http://wap.baiduzzc.org.cn/article/news/k-rd884aRYavAxjfz26FD4.html
  58. http://wap.baiduzzc.org.cn/article/news/k-ZRDIbTpyZc1mf7ZIP36N.html
  59. http://wap.baiduzzc.org.cn/article/news/k-8SOjjHBpAJJ1k1Rf3FIy.html
  60. http://wap.baiduzzc.org.cn/article/news/k-5s23NyWfesdZLTCdkhyf.html
  61. http://wap.baiduzzc.org.cn/article/news/k-PNJmXbEM1uSQcQPJxUd3.html
  62. http://wap.baiduzzc.org.cn/article/news/k-KhYvH3wJVfaS2vc7Soww.html
  63. http://wap.baiduzzc.org.cn/article/news/k-JpdFEugwarJoDG5c9blw.html
  64. http://wap.baiduzzc.org.cn/article/news/k-59DQgC4q1UZKHi22uBHd.html
  65. http://wap.baiduzzc.org.cn/article/news/k-2PzVuL8CmAOmtJZ4T7Lc.html
  66. http://wap.baiduzzc.org.cn/article/news/k-jL7OVavS6jQzbRVtJPSB.html
  67. http://wap.baiduzzc.org.cn/article/news/k-ZsysOT4PcWpMRSQh7mbV.html
  68. http://wap.baiduzzc.org.cn/article/news/k-hXvh02zmJ4Or2evHj9Im.html
  69. http://wap.baiduzzc.org.cn/article/news/k-JngZi4fUfblcV09PQTMW.html
  70. http://wap.baiduzzc.org.cn/article/news/k-2h71HiGqFOpxCeQfxIaG.html
  71. http://wap.baiduzzc.org.cn/article/news/k-8YRyACjSPldbRL7Ulik0.html
  72. http://wap.baiduzzc.org.cn/article/news/k-YyCGFnWy6dCf5v16afJ8.html
  73. http://wap.baiduzzc.org.cn/article/news/k-JGydAMwih3eB6aZKCInU.html
  74. http://wap.baiduzzc.org.cn/article/news/k-fZbjQLlKfHy3vWgplQTF.html
  75. http://wap.baiduzzc.org.cn/article/news/k-JFIjIR6KlYT5psvNVa6P.html
  76. http://wap.baiduzzc.org.cn/article/news/k-ioSoIEwKYllrjYzjo0Th.html
  77. http://wap.baiduzzc.org.cn/article/news/k-DDdLKOmonXhyc76dlGg8.html
  78. http://wap.baiduzzc.org.cn/article/news/k-tIqqTvyDRnhcuUmoHrGp.html
  79. http://wap.baiduzzc.org.cn/article/news/k-9B3UQqfyCFobd7rHsBid.html
  80. http://wap.baiduzzc.org.cn/article/news/k-dKk19C0IbO8aHfxnrJ1u.html
  81. http://wap.baiduzzc.org.cn/article/news/k-y8CVGMDFFTaxKhq46RSB.html
  82. http://wap.baiduzzc.org.cn/article/news/k-g1CiqcNZYY3XJZ3aPecJ.html
  83. http://wap.baiduzzc.org.cn/article/news/k-eAzgOKIKBuh7KJIbmUlO.html
  84. http://wap.baiduzzc.org.cn/article/news/k-IZSKXDQimZAy8ymiapqc.html
  85. http://wap.baiduzzc.org.cn/article/news/k-3IFezgarFacPlKaKrMjd.html
  86. http://wap.baiduzzc.org.cn/article/news/k-ig1LAI0E8nB4sbqm4vF6.html
  87. http://wap.baiduzzc.org.cn/article/news/k-3EJlWw3u4gwsvVT2yv0j.html
  88. http://wap.baiduzzc.org.cn/article/news/k-wMljPG3RRLLg7S2BzWbl.html
  89. http://wap.baiduzzc.org.cn/article/news/k-d1fh7swcdMmLZMPQmLua.html
  90. http://wap.baiduzzc.org.cn/article/news/k-sPujNeusebuKFZQznCVn.html
  91. http://wap.baiduzzc.org.cn/article/news/k-LvwwZ6tjHAxwnUIFWAc0.html
  92. http://wap.baiduzzc.org.cn/article/news/k-i53Ui4fcHgKEsHl4WDOc.html
  93. http://wap.baiduzzc.org.cn/article/news/k-Nle1jDtNb3N3vjsQlXD5.html
  94. http://wap.baiduzzc.org.cn/article/news/k-0qPNffdtOhk42QmEoDk3.html
  95. http://wap.baiduzzc.org.cn/article/news/k-GuaqR7pPHr72ETelD0dR.html
  96. http://wap.baiduzzc.org.cn/article/news/k-etMUqFfwtRv53mca3KeM.html
  97. http://wap.baiduzzc.org.cn/article/news/k-iYR0QDt6OslNjctUg6Ak.html
  98. http://wap.baiduzzc.org.cn/article/news/k-70ZckzQuCR3xfxmQnCvR.html
  99. http://wap.baiduzzc.org.cn/article/news/k-Mbh1ULlWhUgsEYFn1vmu.html
  100. http://wap.baiduzzc.org.cn/article/news/k-Ls5J66iNWchmVUjs0vlo.html
  101. http://wap.baiduzzc.org.cn/article/news/k-46een9Zsu4Ts5Yzh20ee.html
  102. http://wap.baiduzzc.org.cn/article/news/k-bB99GSUFrJ1xkd8EvZIr.html
  103. http://wap.baiduzzc.org.cn/article/news/k-IqIpHIgkbSIjUt9ifPGX.html
  104. http://wap.baiduzzc.org.cn/article/news/k-zWnWiRtLMhpJPyRFqiCr.html
  105. http://wap.baiduzzc.org.cn/article/news/k-c3KvpMfXhTiHF1ukG7gc.html
  106. http://wap.baiduzzc.org.cn/article/news/k-H5e6yyboCk6KPXsS96Up.html
  107. http://wap.baiduzzc.org.cn/article/news/k-HmIoAhhz9Pbia5IkF4bB.html
  108. http://wap.baiduzzc.org.cn/article/news/k-U5ccAZRlB5dkPKGhx454.html
  109. http://wap.baiduzzc.org.cn/article/news/k-5v2W9DufN2fMjz5ZbQRc.html
  110. http://wap.baiduzzc.org.cn/article/news/k-mJqYhBGn9gmWCeebKMQt.html
  111. http://wap.baiduzzc.org.cn/article/news/k-RP81JbmocRfkEjf2SzGN.html
  112. http://wap.baiduzzc.org.cn/article/news/k-g5NefoIfKzZb20xbcbrO.html
  113. http://wap.baiduzzc.org.cn/article/news/k-JqxKukJ855isPFWyfEtC.html
  114. http://wap.baiduzzc.org.cn/article/news/k-htzacMb8mJzeTnMsgqXl.html
  115. http://wap.baiduzzc.org.cn/article/news/k-6oB4P4f7wkoboReJ3TKL.html
  116. http://wap.baiduzzc.org.cn/article/news/k-PGhBn4GFEO22RrKLPFsj.html
  117. http://wap.baiduzzc.org.cn/article/news/k-KfWUV0dT6RfPCrfbIqjn.html
  118. http://wap.baiduzzc.org.cn/article/news/k-4ye8C6Yj27CjcxjyEOu0.html
  119. http://wap.baiduzzc.org.cn/article/news/k-JKpOVLPRymjn6c4O1vGM.html
  120. http://wap.baiduzzc.org.cn/article/news/k-MZpJjrjbCH5VuQgjKgRK.html
  121. http://wap.baiduzzc.org.cn/article/news/k-rTz0LoyW76NebeQeDBh8.html
  122. http://wap.baiduzzc.org.cn/article/news/k-EYANRqmqZbhNz5ST5Ed6.html
  123. http://wap.baiduzzc.org.cn/article/news/k-A4ip70jUmhdsJXdXv8wb.html
  124. http://wap.baiduzzc.org.cn/article/news/k-aPyXbjvqRWDw21VuiVDA.html
  125. http://wap.baiduzzc.org.cn/article/news/k-2vONbLFAj96vrjDnORwv.html
  126. http://wap.baiduzzc.org.cn/article/news/k-47qxfN2rIBOBAzrhPl1U.html
  127. http://wap.baiduzzc.org.cn/article/news/k-J9QP7YOwm5rmFp9htm6t.html
  128. http://wap.baiduzzc.org.cn/article/news/k-J1FZedAhNgBTvqbSRXJV.html
  129. http://wap.baiduzzc.org.cn/article/news/k-5e5hkGrd4ppXGa6sxuXd.html
  130. http://wap.baiduzzc.org.cn/article/news/k-5n8m0ykeCEJJPSaDjUdt.html
  131. http://wap.baiduzzc.org.cn/article/news/k-BadtrLG5hnoOrUWsw3YB.html
  132. http://wap.baiduzzc.org.cn/article/news/k-OMOeZhHZmfTYsaA5yMIf.html
  133. http://wap.baiduzzc.org.cn/article/news/k-D1CXqJ96IOTJges34ib7.html
  134. http://wap.baiduzzc.org.cn/article/news/k-cDk1LMBbYdlVr6kRSMrF.html
  135. http://wap.baiduzzc.org.cn/article/news/k-cWcVFtdpEm1kSi6gT0nf.html
  136. http://wap.baiduzzc.org.cn/article/news/k-G4wphXZGCnSHBrki9fWh.html
  137. http://wap.baiduzzc.org.cn/article/news/k-083iUW5787chsO4toKPX.html
  138. http://wap.baiduzzc.org.cn/article/news/k-Qhdjs8Xqz30vlceUte5B.html
  139. http://wap.baiduzzc.org.cn/article/news/k-VdwsSK3a6YYYvZDVToFn.html
  140. http://wap.baiduzzc.org.cn/article/news/k-Jb2EGXD2MaISty9kk1LC.html
  141. http://wap.baiduzzc.org.cn/article/news/k-EcJg4T1IjGIZRWHHycVH.html
  142. http://wap.baiduzzc.org.cn/article/news/k-dmWCoFYncXDLnBWH6oen.html
  143. http://wap.baiduzzc.org.cn/article/news/k-OC64zXviVO0BnYjwBht9.html
  144. http://wap.baiduzzc.org.cn/article/news/k-G14PcklgOFkc7tP8Naqs.html
  145. http://wap.baiduzzc.org.cn/article/news/k-RJwca2REUkjJcNH1ceTf.html
  146. http://wap.baiduzzc.org.cn/article/news/k-ToQKGclXxsRgQN4OYyQi.html
  147. http://wap.baiduzzc.org.cn/article/news/k-JeF6KsjO0donomKsr1pw.html
  148. http://wap.baiduzzc.org.cn/article/news/k-5GbLUealmo3w4Ig4TtNf.html
  149. http://wap.baiduzzc.org.cn/article/news/k-UW0FfoagrbHe8Lmrgmpy.html
  150. http://wap.baiduzzc.org.cn/article/news/k-B3Fzh2POkuwyFElkT8Xg.html
  151. http://wap.baiduzzc.org.cn/article/news/k-jVTZbh0QEuqvabW1Gxro.html
  152. http://wap.baiduzzc.org.cn/article/news/k-PpkW1H8xAuYIXNoxlzY1.html
  153. http://wap.baiduzzc.org.cn/article/news/k-FrStzpt0aj1U7ZH79jhL.html
  154. http://wap.baiduzzc.org.cn/article/news/k-MRcO7DLwkSBtHI3rRtQm.html
  155. http://wap.baiduzzc.org.cn/article/news/k-YRTnUEPHSdMvXrIFW8Q7.html
  156. http://wap.baiduzzc.org.cn/article/news/k-dpDjP77YwEQk2ateF09h.html
  157. http://wap.baiduzzc.org.cn/article/news/k-DuLfsxv8M6eBqkxlqaQY.html
  158. http://wap.baiduzzc.org.cn/article/news/k-2Yrr9wIb74ceLWUUnq6C.html
  159. http://wap.baiduzzc.org.cn/article/news/k-O6rKUaGK2iVKcPuyea33.html
  160. http://wap.baiduzzc.org.cn/article/news/k-tTZ6qaT6YAXVxVQrErOm.html
  161. http://wap.baiduzzc.org.cn/article/news/k-IeTvThdIfaP6Z1QiaSDe.html
  162. http://wap.baiduzzc.org.cn/article/news/k-2KNlWbx66HnxPiGgcNHV.html
  163. http://wap.baiduzzc.org.cn/article/news/k-RjSEkMHEba7jIJzSYDmU.html
  164. http://wap.baiduzzc.org.cn/article/news/k-sDvFQHSwnFIhLCW2NJgg.html
  165. http://wap.baiduzzc.org.cn/article/news/k-Vheay5dYCWPJsB1Z03Jx.html
  166. http://wap.baiduzzc.org.cn/article/news/k-i12Wc3JdLtaUIN6rhUSt.html
  167. http://wap.baiduzzc.org.cn/article/news/k-m0Wvjz6dkheNdPtqpMkb.html
  168. http://wap.baiduzzc.org.cn/article/news/k-o2G1IuwBWq1lx0vm5Wkw.html
  169. http://wap.baiduzzc.org.cn/article/news/k-KuyYXhPxEuz08ofhMe0f.html
  170. http://wap.baiduzzc.org.cn/article/news/k-dcp1zNQf5Lat8DhmXGSW.html
  171. http://wap.baiduzzc.org.cn/article/news/k-j0kYECRx0qslxbsvD10e.html
  172. http://wap.baiduzzc.org.cn/article/news/k-6SIHQBFGOKMJsDLNbA5D.html
  173. http://wap.baiduzzc.org.cn/article/news/k-JBuLAMvudWOqhtmPoN0M.html
  174. http://wap.baiduzzc.org.cn/article/news/k-iFw2DLEtpP5xnNOKEBIe.html
  175. http://wap.baiduzzc.org.cn/article/news/k-bqgqlXTJj5BqUVjcqwhx.html
  176. http://wap.baiduzzc.org.cn/article/news/k-GJL05IZtwv2WyT0zgFAL.html
  177. http://wap.baiduzzc.org.cn/article/news/k-Kp6cta93UNHqVlRjDfoX.html
  178. http://wap.baiduzzc.org.cn/article/news/k-tPlVlc1bc71DopygfnAQ.html
  179. http://wap.baiduzzc.org.cn/article/news/k-PC07tiieE0fQiCVqF9bQ.html
  180. http://wap.baiduzzc.org.cn/article/news/k-WabkeNhHofHV5QhuOFsL.html
  181. http://wap.baiduzzc.org.cn/article/news/k-dHbUH8OJnj2NW6rSkUw4.html
  182. http://wap.baiduzzc.org.cn/article/news/k-i9F3Elr1mDQ7JcXaXSWj.html
  183. http://wap.baiduzzc.org.cn/article/news/k-rPtqydrMptsnJ9SAnS92.html
  184. http://wap.baiduzzc.org.cn/article/news/k-uyCZAlivVqY0hbCbufKj.html
  185. http://wap.baiduzzc.org.cn/article/news/k-a7apqHnzBsnHcMwgLk8Q.html
  186. http://wap.baiduzzc.org.cn/article/news/k-X9upWvBQpM2H7UVs2pv6.html
  187. http://wap.baiduzzc.org.cn/article/news/k-ihXofbmxDGbdAbhYR4cX.html
  188. http://wap.baiduzzc.org.cn/article/news/k-lnaWCCJCrYpkKodtxcf4.html
  189. http://wap.baiduzzc.org.cn/article/news/k-dSzyPa9rFvUODC4KPBui.html
  190. http://wap.baiduzzc.org.cn/article/news/k-9qC3VoegR1evU2hZ4uIG.html
  191. http://wap.baiduzzc.org.cn/article/news/k-zU5sW2IabsSMWtALbqJ4.html
  192. http://wap.baiduzzc.org.cn/article/news/k-K7AuAt7KA0AydOXpp8bd.html
  193. http://wap.baiduzzc.org.cn/article/news/k-HEYeiBpzh4qbX39JewWo.html
  194. http://wap.baiduzzc.org.cn/article/news/k-B26XLpgyRDYoIxrSIRtO.html
  195. http://wap.baiduzzc.org.cn/article/news/k-dYd7rxDSwtu6PkW7d4yn.html
  196. http://wap.baiduzzc.org.cn/article/news/k-U673daf7SrVA5g8Lq06H.html
  197. http://wap.baiduzzc.org.cn/article/news/k-EQ4Tg02BFyt4OeDXiHh0.html
  198. http://wap.baiduzzc.org.cn/article/news/k-M0NPYJL9GLdUVc0KBd2c.html
  199. http://wap.baiduzzc.org.cn/article/news/k-QFfSM7woaFuxMn8orODH.html
  200. http://wap.baiduzzc.org.cn/article/news/k-xY4znjauKrQXJ59RJfga.html
  201. http://wap.baiduzzc.org.cn/article/news/k-MdgQYzHZfmvav42WLLeN.html
  202. http://wap.baiduzzc.org.cn/article/news/k-voNUTlgbm5St3qc5PLBD.html
  203. http://wap.baiduzzc.org.cn/article/news/k-K0QQVj0FcLuCLaPpdgcy.html
  204. http://wap.baiduzzc.org.cn/article/news/k-AblKD81LeXsGLY13HV1d.html
  205. http://wap.baiduzzc.org.cn/article/news/k-0uhlSBzWhkmb5Me2ouIc.html
  206. http://wap.baiduzzc.org.cn/article/news/k-Zp16WhmwUnKeeRe70Lp4.html
  207. http://wap.baiduzzc.org.cn/article/news/k-eJSQaNqZBRifImk0UclA.html
  208. http://wap.baiduzzc.org.cn/article/news/k-cF4ZEepZTV1evQTAJeqq.html
  209. http://wap.baiduzzc.org.cn/article/news/k-srlHW3DnnjR2uQgb7RgA.html
  210. http://wap.baiduzzc.org.cn/article/news/k-DXZdet5ZZPWBhkomVXzS.html
  211. http://wap.baiduzzc.org.cn/article/news/k-JlnneqqCXhveifg2MJL3.html
  212. http://wap.baiduzzc.org.cn/article/news/k-N6f7oKj1EXOjq1Yb5xCT.html
  213. http://wap.baiduzzc.org.cn/article/news/k-cV42sLVdqAldmXy8ydT6.html
  214. http://wap.baiduzzc.org.cn/article/news/k-IlfThoimqpYBNnjaeQV6.html
  215. http://wap.baiduzzc.org.cn/article/news/k-0iUN9NrpG4LjYaoNO9WP.html
  216. http://wap.baiduzzc.org.cn/article/news/k-EwPnZGS4oymiACy57KvW.html
  217. http://wap.baiduzzc.org.cn/article/news/k-xTvPC8Lk3MBs30wtAxGX.html
  218. http://wap.baiduzzc.org.cn/article/news/k-JplRIsBaa98ZFaHkFcd8.html
  219. http://wap.baiduzzc.org.cn/article/news/k-GEAO1JXp4HW2zFHwMKVI.html
  220. http://wap.baiduzzc.org.cn/article/news/k-9qSNIN84fOaLNieCTp0v.html
  221. http://wap.baiduzzc.org.cn/article/news/k-5FxEdTLdMnRuWIWIec2O.html
  222. http://wap.baiduzzc.org.cn/article/news/k-EgPIa9RdQdXGyhEt0IIe.html
  223. http://wap.baiduzzc.org.cn/article/news/k-wwzLJdrFdKXoXcBPxbzr.html
  224. http://wap.baiduzzc.org.cn/article/news/k-kYc5fTWKrkQXKihxeY62.html
  225. http://wap.baiduzzc.org.cn/article/news/k-Fl5zWWuXa03AHioJtoOZ.html
  226. http://wap.baiduzzc.org.cn/article/news/k-qVySdVMKwpeO8SMfPdvM.html
  227. http://wap.baiduzzc.org.cn/article/news/k-MWlaFJTujnBZXoSKeFZp.html
  228. http://wap.baiduzzc.org.cn/article/news/k-g8jEWuupsaQHcEiWbk08.html
  229. http://wap.baiduzzc.org.cn/article/news/k-FlkFXXie6zWtPmliJuWX.html
  230. http://wap.baiduzzc.org.cn/article/news/k-c735JI5YzE91OH6Owp7x.html
  231. http://wap.baiduzzc.org.cn/article/news/k-aw0xxhPGfGztdiNAD8Fx.html
  232. http://wap.baiduzzc.org.cn/article/news/k-kbvzOBuPjMuSfj6xEpze.html
  233. http://wap.baiduzzc.org.cn/article/news/k-cMGwSsmc6a4Mhe7uHkr0.html
  234. http://wap.baiduzzc.org.cn/article/news/k-wQUW1q6zE2uWunNO23cD.html
  235. http://wap.baiduzzc.org.cn/article/news/k-pxJa84cpKY9MquiiTd6M.html
  236. http://wap.baiduzzc.org.cn/article/news/k-fKzab0wEUVKHfY68yFjZ.html
  237. http://wap.baiduzzc.org.cn/article/news/k-Tog2chyC8Q1TWp62BXId.html
  238. http://wap.baiduzzc.org.cn/article/news/k-1yiLxT9ejz9bRVQUFBJD.html
  239. http://wap.baiduzzc.org.cn/article/news/k-rA8QouuxU21vnn3MRKh8.html
  240. http://wap.baiduzzc.org.cn/article/news/k-bnhOCa4haTVrIdDSciYJ.html
  241. http://wap.baiduzzc.org.cn/article/news/k-jdoYJowcmal4mllnY2BW.html
  242. http://wap.baiduzzc.org.cn/article/news/k-P3y6EzW1aRa8v2DYSlt5.html
  243. http://wap.baiduzzc.org.cn/article/news/k-2m35Ten1gnBFpdgfAKfz.html
  244. http://wap.baiduzzc.org.cn/article/news/k-WU6GW2Kc48XMYeCuyeus.html
  245. http://wap.baiduzzc.org.cn/article/news/k-WhFjpmkmbKhw5MvJI42h.html
  246. http://wap.baiduzzc.org.cn/article/news/k-sNhvfR3cisAqyrJYF0hK.html
  247. http://wap.baiduzzc.org.cn/article/news/k-Z7M9i8fs5jIgsgPE73fg.html
  248. http://wap.baiduzzc.org.cn/article/news/k-aAkri1i3uBgY4hwVmNhi.html
  249. http://wap.baiduzzc.org.cn/article/news/k-uyY1BUGCfSoOQXMEFIDy.html
  250. http://wap.baiduzzc.org.cn/article/news/k-NIPJHZI4glfWjpda68lc.html
  251. http://wap.baiduzzc.org.cn/article/news/k-v530nHq9M0I1WZirbX8V.html
  252. http://wap.baiduzzc.org.cn/article/news/k-I28lVZNoBhnLQNgvyffj.html
  253. http://wap.baiduzzc.org.cn/article/news/k-f3ISs7NO97hnykCLz2Gt.html
  254. http://wap.baiduzzc.org.cn/article/news/k-Uct7LVQoerCgH6yPFi5B.html
  255. http://wap.baiduzzc.org.cn/article/news/k-1uIvDqwrMQ1UZmOenJx7.html
  256. http://wap.baiduzzc.org.cn/article/news/k-fAd9LckdnKy31zPG1Hfv.html
  257. http://wap.baiduzzc.org.cn/article/news/k-pGZfdJJ32S2LQdPsgsIw.html
  258. http://wap.baiduzzc.org.cn/article/news/k-nRCApWgMfloce3UU9XNh.html
  259. http://wap.baiduzzc.org.cn/article/news/k-bCe7qGiRVdnZWgVLHV1O.html
  260. http://wap.baiduzzc.org.cn/article/news/k-oVrGSbSCOc9iIbwKTUNc.html
  261. http://wap.baiduzzc.org.cn/article/news/k-jRD0WpnTyfECdhkQebGK.html
  262. http://wap.baiduzzc.org.cn/article/news/k-pymvukHQyG9MYO8vWsFZ.html
  263. http://wap.baiduzzc.org.cn/article/news/k-20eom9AZ1GK0hOQYd0fY.html
  264. http://wap.baiduzzc.org.cn/article/news/k-fTKpeRsA65jJcrvzjmhv.html
  265. http://wap.baiduzzc.org.cn/article/news/k-ApGg3ymixXVYXyT8OLMq.html
  266. http://wap.baiduzzc.org.cn/article/news/k-zPTFnv7vVbaPwG2gyIsa.html
  267. http://wap.baiduzzc.org.cn/article/news/k-EskTpKzE5tyesbnkrB7K.html
  268. http://wap.baiduzzc.org.cn/article/news/k-gjotjNLzyDyplidNiRFz.html
  269. http://wap.baiduzzc.org.cn/article/news/k-sc09PlQqHyNVJpCvAVXl.html
  270. http://wap.baiduzzc.org.cn/article/news/k-BI7wy2qna5woWDrMOSCm.html
  271. http://wap.baiduzzc.org.cn/article/news/k-G1VMuWuDZiuJygZhYnll.html
  272. http://wap.baiduzzc.org.cn/article/news/k-LcBTBaL4lYVIcId0bBka.html
  273. http://wap.baiduzzc.org.cn/article/news/k-HSfhIytuPHpBPoVjxH3E.html
  274. http://wap.baiduzzc.org.cn/article/news/k-fQOvEcpzsdeKvYLeTnpG.html
  275. http://wap.baiduzzc.org.cn/article/news/k-2KoujcY1QqSFIqwrCwTe.html
  276. http://wap.baiduzzc.org.cn/article/news/k-YVcsl3iGLyli68oW69B9.html
  277. http://wap.baiduzzc.org.cn/article/news/k-d5yXrXTv8xS25CZfayDb.html
  278. http://wap.baiduzzc.org.cn/article/news/k-5E7eJe6gsHyVR3Bz5fWd.html
  279. http://wap.baiduzzc.org.cn/article/news/k-y1dYNCcsnq9R1eZeYZ3u.html
  280. http://wap.baiduzzc.org.cn/article/news/k-LbDz5YZwlEidXXdfS3cb.html
  281. http://wap.baiduzzc.org.cn/article/news/k-cZrphSLypCeB7wxhYM7K.html
  282. http://wap.baiduzzc.org.cn/article/news/k-ZzHZldSWCCZvcPNqKybj.html
  283. http://wap.baiduzzc.org.cn/article/news/k-pKPPWGBr7Ri3Ifu3Jtr5.html
  284. http://wap.baiduzzc.org.cn/article/news/k-5TXlstwuuMywT0oXzxmp.html
  285. http://wap.baiduzzc.org.cn/article/news/k-z3mnSrbzyXpOPCWSRPMI.html
  286. http://wap.baiduzzc.org.cn/article/news/k-A42YZpAXxqifBGfeDROC.html
  287. http://wap.baiduzzc.org.cn/article/news/k-NfOCRyXc5uemzyzUJmmJ.html
  288. http://wap.baiduzzc.org.cn/article/news/k-sWzpWsA4pK65He6H1b0a.html
  289. http://wap.baiduzzc.org.cn/article/news/k-ZcuKHERKhLaYPlvsav98.html
  290. http://wap.baiduzzc.org.cn/article/news/k-doETOoU2kNaGNc2nx6de.html
  291. http://wap.baiduzzc.org.cn/article/news/k-rsbhMykzF1R2AHL4bcTe.html
  292. http://wap.baiduzzc.org.cn/article/news/k-wcb5raOa2DHzffHJRu3q.html
  293. http://wap.baiduzzc.org.cn/article/news/k-TEAqc5Bka238hB4feePX.html
  294. http://wap.baiduzzc.org.cn/article/news/k-XDUcDeExqKQkWYDDQmNO.html
  295. http://wap.baiduzzc.org.cn/article/news/k-NYBPBVM4IgQ32HvicZyT.html
  296. http://wap.baiduzzc.org.cn/article/news/k-TPYiMReGuIqRczZKdzJN.html
  297. http://wap.baiduzzc.org.cn/article/news/k-sqlkVZHn3SGGyUyDjEj1.html
  298. http://wap.baiduzzc.org.cn/article/news/k-tML3aMZLLFyFHpcfxOmX.html
  299. http://wap.baiduzzc.org.cn/article/news/k-AIub5UWATcrAmyHfnZN8.html
  300. http://wap.baiduzzc.org.cn/article/news/k-4lUe1MJXADEqDYsmq8Sd.html

以上为资料索引,欢迎按主题补充和校对。

收起阅读 »

让页面切换,也成为体验的一部分|uni-app x 原生路由插件

uni-app x

让每一次进入与返回,都自然衔接。

kongbai-native-route 原生路由 现已上线。

面向 uni-app x · iOS / Android,把页面转场、手势返回与弹窗交互放进同一套导航体验。打开详情时的层次、滑动返回时的反馈、收起面板后的衔接,都可以做得更细腻。

前往插件市场 · 查看详情与试用

先看真机,再感受细节

动画有没有合适的节奏,拖动与回弹是否自然,实际操作最直观。

观看 iOS 真机演示

观看 Android 真机演示

也可以从插件市场导入示例项目,在自己的设备上体验。

01 / 九种转场,让内容有自己的出场方式

日常页面,轻快进入;重点内容,适当强调层次。根据页面的用途选择转场,让动效服务于内容。

横向滑动 · 景深推进 · 层叠上浮
斜向旋入 · 立体翻转 · 中心展开
交叉淡入 · 顶部落入 · 纵向翻入

进入与返回的动画时长可以按需调整,也支持无动画切换。从列表到详情,从浏览到编辑,为不同操作安排合适的节奏。

02 / 跟手返回,把选择留在手指之间

从页面左侧边缘滑动,页面跟随手势响应。完成滑动,返回上一页;中途取消,回到当前页面。

对于仍保留在导航流程中的上一页,返回后可以继续之前的输入与浏览位置。看完详情接着浏览,临时查看其他内容后继续填写,让操作保持连贯。

03 / 三种弹窗,承接不同分量的内容

半屏 · 先展示重点,再展开更多

支持半屏与展开状态切换,以及下拉关闭。适合筛选条件、选项面板、内容预览和轻量编辑,让用户在当前场景中完成操作。

遮罩 · 聚焦眼前这一步

适合信息提示、操作确认与短内容展示。示例提供点击空白区域关闭的交互,用清晰的前后层次突出当前内容。

卡片 · 展开一段独立的操作

拖动顶部区域,卡片随手势变化;松手后,根据操作关闭或回弹。适合详情预览与临时操作面板,让展开和收起都有自然的反馈。

弹窗支持多层打开、逐层返回。 关闭上层后,可以继续操作仍打开的下层内容,保留其中已输入的文字与当前状态。

04 / 深浅外观,与应用保持协调

支持浅色与深色外观切换,覆盖导航栏和弹窗的相关外观,示例项目可直接体验两种主题。

接入业务时,再配合页面自身的文字、背景与组件配色,让导航和内容保持统一。

从示例开始,把体验带进自己的项目

使用 HBuilderX 5.26 + VDOM 打开示例项目,编译原生插件并运行到 iOS 或 Android 真机,即可体验页面转场、手势返回、弹窗与主题切换。

插件市场已提供完整接入说明,包含项目配置、业务页面注册、启动导航、页面跳转与返回。按文档接入后,应用可在启动页就绪时自动进入业务首页。

当前适用于 uni-app x 的 iOS / Android App,暂不支持普通 uni-app、Web、小程序、HarmonyOS 和 Vapor。 平台环境与系统版本要求请查看插件市场说明;两端的手势与外观细节请结合对应演示体验。页面关闭或应用重启后的数据保存,仍由业务自行处理。

把页面之间的衔接,也认真做好。

如果你正在打磨 uni-app x App 的交互细节,欢迎先看演示,再用示例项目体验。

查看 kongbai-native-route 原生路由 · 获取插件与接入文档 →

欢迎在评论区交流使用场景与体验建议。

继续阅读 »

让每一次进入与返回,都自然衔接。

kongbai-native-route 原生路由 现已上线。

面向 uni-app x · iOS / Android,把页面转场、手势返回与弹窗交互放进同一套导航体验。打开详情时的层次、滑动返回时的反馈、收起面板后的衔接,都可以做得更细腻。

前往插件市场 · 查看详情与试用

先看真机,再感受细节

动画有没有合适的节奏,拖动与回弹是否自然,实际操作最直观。

观看 iOS 真机演示

观看 Android 真机演示

也可以从插件市场导入示例项目,在自己的设备上体验。

01 / 九种转场,让内容有自己的出场方式

日常页面,轻快进入;重点内容,适当强调层次。根据页面的用途选择转场,让动效服务于内容。

横向滑动 · 景深推进 · 层叠上浮
斜向旋入 · 立体翻转 · 中心展开
交叉淡入 · 顶部落入 · 纵向翻入

进入与返回的动画时长可以按需调整,也支持无动画切换。从列表到详情,从浏览到编辑,为不同操作安排合适的节奏。

02 / 跟手返回,把选择留在手指之间

从页面左侧边缘滑动,页面跟随手势响应。完成滑动,返回上一页;中途取消,回到当前页面。

对于仍保留在导航流程中的上一页,返回后可以继续之前的输入与浏览位置。看完详情接着浏览,临时查看其他内容后继续填写,让操作保持连贯。

03 / 三种弹窗,承接不同分量的内容

半屏 · 先展示重点,再展开更多

支持半屏与展开状态切换,以及下拉关闭。适合筛选条件、选项面板、内容预览和轻量编辑,让用户在当前场景中完成操作。

遮罩 · 聚焦眼前这一步

适合信息提示、操作确认与短内容展示。示例提供点击空白区域关闭的交互,用清晰的前后层次突出当前内容。

卡片 · 展开一段独立的操作

拖动顶部区域,卡片随手势变化;松手后,根据操作关闭或回弹。适合详情预览与临时操作面板,让展开和收起都有自然的反馈。

弹窗支持多层打开、逐层返回。 关闭上层后,可以继续操作仍打开的下层内容,保留其中已输入的文字与当前状态。

04 / 深浅外观,与应用保持协调

支持浅色与深色外观切换,覆盖导航栏和弹窗的相关外观,示例项目可直接体验两种主题。

接入业务时,再配合页面自身的文字、背景与组件配色,让导航和内容保持统一。

从示例开始,把体验带进自己的项目

使用 HBuilderX 5.26 + VDOM 打开示例项目,编译原生插件并运行到 iOS 或 Android 真机,即可体验页面转场、手势返回、弹窗与主题切换。

插件市场已提供完整接入说明,包含项目配置、业务页面注册、启动导航、页面跳转与返回。按文档接入后,应用可在启动页就绪时自动进入业务首页。

当前适用于 uni-app x 的 iOS / Android App,暂不支持普通 uni-app、Web、小程序、HarmonyOS 和 Vapor。 平台环境与系统版本要求请查看插件市场说明;两端的手势与外观细节请结合对应演示体验。页面关闭或应用重启后的数据保存,仍由业务自行处理。

把页面之间的衔接,也认真做好。

如果你正在打磨 uni-app x App 的交互细节,欢迎先看演示,再用示例项目体验。

查看 kongbai-native-route 原生路由 · 获取插件与接入文档 →

欢迎在评论区交流使用场景与体验建议。

收起阅读 »

单页H5界面定制|响应式对话页概念与可运行示例(AI制作)

外包

这里展示一页“汐间”对话界面概念,供需要直接交付前端页面的开发者评估。由AI设计、编码及检查,不是客户案例,也不是完整聊天产品。

可以先看什么

海湾矢量场景、独立滚动消息区、窄屏输入区、长文本换行、消息入场和帆船轻动效。系统开启减少动态效果后关闭动画。附件ZIP中的index.html可本地打开;不联网、不调用模型、不保存输入,发送只返回固定示例文字。

已验证与边界

在本机Chrome模拟1280、390、320宽度无横向溢出,长消息、重置、Tab键切换已检查。尚未做真实手机和其他浏览器验收,也未验证uni-app/小程序打包。示例没有第三方图片和字体文件。

可讨论的定制范围

一个响应式H5界面的排版、配色、有限微动效及HTML/CSS/JS源码交付。参考价800元/页,限约定的一页和一轮集中样式修改;后端、登录支付、模型接入和全站开发需另行评估。最终价款、交期、兼容范围及验收清单须看素材和目标页面后确认,暂不接受即时下单或付款。

由获授权的AI助手负责日常文字沟通、制作与检查,个人承担必要签约和身份确认。合作前须落实合法结算、开票需求和可承担的售后责任,不承诺无限修改或长期随叫随到。

有相关需求可在本帖留言,或邮件联系qmbgyy0216@gmail.com。请说明技术栈、目标页面、参考风格、截止日期及预算;仅提供有权使用且脱敏的资料。

预览

继续阅读 »

这里展示一页“汐间”对话界面概念,供需要直接交付前端页面的开发者评估。由AI设计、编码及检查,不是客户案例,也不是完整聊天产品。

可以先看什么

海湾矢量场景、独立滚动消息区、窄屏输入区、长文本换行、消息入场和帆船轻动效。系统开启减少动态效果后关闭动画。附件ZIP中的index.html可本地打开;不联网、不调用模型、不保存输入,发送只返回固定示例文字。

已验证与边界

在本机Chrome模拟1280、390、320宽度无横向溢出,长消息、重置、Tab键切换已检查。尚未做真实手机和其他浏览器验收,也未验证uni-app/小程序打包。示例没有第三方图片和字体文件。

可讨论的定制范围

一个响应式H5界面的排版、配色、有限微动效及HTML/CSS/JS源码交付。参考价800元/页,限约定的一页和一轮集中样式修改;后端、登录支付、模型接入和全站开发需另行评估。最终价款、交期、兼容范围及验收清单须看素材和目标页面后确认,暂不接受即时下单或付款。

由获授权的AI助手负责日常文字沟通、制作与检查,个人承担必要签约和身份确认。合作前须落实合法结算、开票需求和可承担的售后责任,不承诺无限修改或长期随叫随到。

有相关需求可在本帖留言,或邮件联系qmbgyy0216@gmail.com。请说明技术栈、目标页面、参考风格、截止日期及预算;仅提供有权使用且脱敏的资料。

预览

收起阅读 »