@hd-front-end/jsbridge-sdk 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/README.md +4 -2
  2. package/dist/index.d.ts +201 -2
  3. package/dist/index.esm.js +444 -1
  4. package/dist/index.esm.js.map +1 -1
  5. package/dist/index.js +446 -0
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.umd.js +446 -0
  8. package/dist/index.umd.js.map +1 -1
  9. package/docs/00-/351/241/271/347/233/256/346/246/202/350/247/210.md +282 -0
  10. package/docs/01-/346/236/266/346/236/204/350/256/276/350/256/241.md +623 -0
  11. package/docs/02-/346/212/200/346/234/257/345/256/236/347/216/260.md +867 -0
  12. package/docs/03-API/344/275/277/347/224/250/346/226/207/346/241/243.md +1104 -0
  13. package/docs/04-/346/265/213/350/257/225/346/226/271/346/241/210.md +360 -0
  14. package/docs/05-/350/277/201/347/247/273/346/214/207/345/215/227.md +181 -0
  15. package/docs/06-/346/236/266/346/236/204/345/233/276/351/233/206.md +738 -0
  16. package/docs/07-/346/226/260/346/241/245/346/216/245/346/226/271/346/263/225/346/211/251/345/261/225/350/257/264/346/230/216.md +139 -0
  17. package/docs/CODE_REVIEW.md +65 -0
  18. package/docs/EVALUATION.md +72 -0
  19. package/docs/README.md +258 -0
  20. package/docs//345/205/263/351/224/256/351/227/256/351/242/230/350/247/243/347/255/224.md +495 -0
  21. package/docs//346/226/207/346/241/243/346/225/264/345/220/210/350/257/264/346/230/216.md +265 -0
  22. package/docs//346/233/264/346/226/260/346/227/245/345/277/227.md +669 -0
  23. package/docs//347/224/237/344/272/247/347/272/247-/345/277/253/351/200/237/345/274/200/345/247/213-v2.md +673 -0
  24. package/docs//347/224/237/344/272/247/347/272/247-/346/236/266/346/236/204/350/256/276/350/256/241-v2.md +730 -0
  25. package/docs//350/256/276/350/256/241/347/220/206/345/277/265/350/257/264/346/230/216.md +438 -0
  26. package/package.json +3 -2
@@ -0,0 +1,495 @@
1
+ # JSBridge SDK 关键问题解答
2
+
3
+ ## 问题来源
4
+
5
+ 在设计 JSBridge SDK 时,你提出了两个非常关键的问题:
6
+
7
+ 1. **当前 SDK 几乎全部为 JS 逻辑,为什么会有技术栈的差别?**
8
+ 2. **在应用引入过程中采用了 hdAppAdapter.ts 和 uni-app-api.json 适配器的逻辑,架构中没体现?**
9
+
10
+ 这两个问题直接指出了原设计的重大疏漏!
11
+
12
+ ## 🎯 问题 1:为什么会有技术栈差别?
13
+
14
+ ### 疑问分析
15
+
16
+ 看起来 JSBridge 都是 JavaScript 代码,理论上应该在 Vue2、Vue3、React 中都一样工作,为什么还要区分技术栈?
17
+
18
+ ### 根本原因
19
+
20
+ **差别不在 JSBridge 通信本身,而在与 uni-app 的集成方式!**
21
+
22
+ 具体来说,问题出在 **uni 对象的属性定义**上:
23
+
24
+ #### Vue2 项目(SOA)
25
+
26
+ ```typescript
27
+ // uni 对象的属性是可写的
28
+ uni.scanCode = function() { ... } // ✅ 成功
29
+
30
+ // 原因:uni-app Vue2 版本的实现
31
+ Object.defineProperty(uni, 'scanCode', {
32
+ value: originalScanCode,
33
+ writable: true, // ← 可写!
34
+ configurable: true
35
+ })
36
+ ```
37
+
38
+ #### Vue3 项目(MPA-Mini-V3)
39
+
40
+ ```typescript
41
+ // uni 对象的某些属性是只读的
42
+ uni.chooseImage = function() { ... }
43
+ // ❌ Error: Cannot assign to read only property 'chooseImage'
44
+
45
+ // 原因:uni-app Vue3 版本的实现
46
+ Object.defineProperty(uni, 'chooseImage', {
47
+ value: originalChooseImage,
48
+ writable: false, // ← 只读!
49
+ configurable: false
50
+ })
51
+ ```
52
+
53
+ ### 实际代码证据
54
+
55
+ 从你提供的代码中可以看到:
56
+
57
+ ```typescript
58
+ // context/mpa-mini-v3/src/h5Adapter/UniProxy.ts
59
+ // 为什么会有这个类?
60
+ // uni.chooseImage = chooseImage
61
+ // Cannot assign to read only property 'chooseImage' of object '[object Object]'
62
+ // chooseImage 是只读的,无法替换,只能用代理模式
63
+
64
+ export const UniProxy = {
65
+ chooseImage: uni.chooseImage,
66
+ pathToBase64: () => {}
67
+ }
68
+ ```
69
+
70
+ ```typescript
71
+ // context/soa/src/h5Adapter/hdAppAdapter.ts (Vue2 项目)
72
+ // 可以直接赋值
73
+ uni.scanCode = (options: UniApp.ScanCodeOptions) => { ... } // ✅ OK
74
+
75
+ // 但 chooseImage 也用了 UniProxy
76
+ UniProxy.chooseImage = (options: UniApp.ChooseImageOptions) => { ... }
77
+ ```
78
+
79
+ ### 技术栈差别总结
80
+
81
+ | 项目 | Vue 版本 | uni API 可写性 | 解决方案 |
82
+ |------|---------|---------------|---------|
83
+ | SOA | Vue2 | 大部分可写 | 直接赋值 |
84
+ | MPA-Mini-V3 | Vue3 | 部分只读 | UniProxy 代理 |
85
+
86
+ ### 通用解决方案
87
+
88
+ ```typescript
89
+ // 兼容 Vue2 和 Vue3 的写法
90
+ function overrideUniAPI(apiName: string, handler: Function) {
91
+ try {
92
+ // 尝试直接赋值(Vue2)
93
+ uni[apiName] = handler
94
+ console.log(`${apiName} 直接赋值成功`)
95
+ } catch (error) {
96
+ // 失败则使用 UniProxy(Vue3)
97
+ console.warn(`${apiName} 只读,使用 UniProxy`)
98
+ if (window.UniProxy) {
99
+ window.UniProxy[apiName] = handler
100
+ }
101
+ }
102
+ }
103
+ ```
104
+
105
+ ## 🏗️ 问题 2:hdAppAdapter 在架构中的位置?
106
+
107
+ ### 疑问分析
108
+
109
+ 现有项目中有 `hdAppAdapter.ts` 和 `uni-app-api.json`,它们的作用是什么?在架构设计中为什么没有体现?
110
+
111
+ ### hdAppAdapter 的关键作用
112
+
113
+ **它是一个 uni API 拦截适配层,让业务代码无需修改!**
114
+
115
+ #### 没有适配层的问题
116
+
117
+ ```typescript
118
+ // ❌ 业务代码需要大量修改
119
+ // 旧代码
120
+ uni.scanCode({
121
+ success: (res) => {
122
+ console.log(res.result)
123
+ }
124
+ })
125
+
126
+ // 需要改成
127
+ import { JSBridge } from '@hd-front-end/jsbridge-sdk'
128
+
129
+ JSBridge.scan({
130
+ scanType: ['qrCode'],
131
+ hideAlbum: false,
132
+ // ... 很多参数
133
+ }).then((result) => {
134
+ if (result.resp_code === 1000) {
135
+ console.log(result.resp_result)
136
+ }
137
+ })
138
+ ```
139
+
140
+ #### 有适配层的优势
141
+
142
+ ```typescript
143
+ // ✅ 业务代码完全不用改!
144
+ uni.scanCode({
145
+ success: (res) => {
146
+ console.log(res.result)
147
+ }
148
+ })
149
+
150
+ // hdAppAdapter 在背后做了:
151
+ // 1. 拦截 uni.scanCode 调用
152
+ // 2. 转换参数格式
153
+ // 3. 调用 JSBridge
154
+ // 4. 转换返回结果
155
+ // 5. 调用 success 回调
156
+ ```
157
+
158
+ ### hdAppAdapter 的工作流程
159
+
160
+ ```typescript
161
+ // src/h5Adapter/hdAppAdapter.ts
162
+ export function hdAppAdapter() {
163
+ // 拦截 uni.scanCode
164
+ uni.scanCode = (options: UniApp.ScanCodeOptions) => {
165
+ // 步骤 1:参数格式转换
166
+ const nativeRequest = {
167
+ scanType: options.scanType || ['qrCode', 'barCode'],
168
+ hideAlbum: options.onlyFromCamera || false,
169
+ viewText: '扫二维码/条码',
170
+ language: 'zh-Hans',
171
+ failedMsg: '未识别到二维码,请重试',
172
+ screenType: 'full',
173
+ timeoutInterval: '10',
174
+ timeoutText: '未识别到二维码?'
175
+ }
176
+
177
+ // 步骤 2:调用 JSBridge
178
+ JsBridgeHandlers.handleScan(nativeRequest).then((ret) => {
179
+ // 步骤 3:回调格式转换
180
+ if (ret.resp_code === 1000) {
181
+ options.success?.({
182
+ result: ret.resp_result || '',
183
+ scanType: options.scanType?.[0] || 'qrCode',
184
+ charSet: 'utf-8',
185
+ path: ''
186
+ })
187
+ } else if (ret.resp_code === 10) {
188
+ options.fail?.({ errMsg: '用户取消扫码' })
189
+ } else {
190
+ options.fail?.({ errMsg: ret.resp_message || '扫码失败' })
191
+ }
192
+ options.complete?.(ret)
193
+ })
194
+ }
195
+ }
196
+ ```
197
+
198
+ ### uni-app-api.json 的作用
199
+
200
+ 这个文件标记了哪些 uni API 需要被 JSBridge 拦截替换:
201
+
202
+ ```json
203
+ [
204
+ "uni.scanCode", // 需要替换
205
+ "uni.chooseImage", // 需要替换
206
+ "uni.uploadFile", // 需要替换
207
+ "uni.showToast", // 不需要替换(用 uni-app 的)
208
+ "uni.setStorage" // 不需要替换(用 uni-app 的)
209
+ ]
210
+ ```
211
+
212
+ **作用**:
213
+ 1. 文档说明:明确哪些 API 被替换了
214
+ 2. 编译优化:某些构建工具可能会根据这个配置优化打包
215
+ 3. 开发指南:告诉开发者哪些功能依赖原生
216
+
217
+ ### 完整的架构层次
218
+
219
+ ```
220
+ ┌──────────────────────────────────────┐
221
+ │ 业务代码层 │
222
+ │ Pages/Components │
223
+ │ 调用 uni.scanCode() │
224
+ │ 调用 uni.chooseImage() │
225
+ └──────────────────────────────────────┘
226
+ ↓ 标准 uni API 调用
227
+ ┌──────────────────────────────────────┐
228
+ │ uni API 拦截适配层 │ ← 问题 2 的答案!
229
+ │ (hdAppAdapter.ts) │
230
+ │ │
231
+ │ 功能: │
232
+ │ 1. 拦截 uni API 调用 │
233
+ │ 2. 参数格式转换(uni → 原生) │
234
+ │ 3. 调用 JSBridge Handlers │
235
+ │ 4. 回调格式转换(原生 → uni) │
236
+ │ 5. 处理只读属性(UniProxy) │
237
+ │ │
238
+ │ 配置: │
239
+ │ - uni-app-api.json(API 清单) │
240
+ │ - UniProxy(处理只读属性) │
241
+ └──────────────────────────────────────┘
242
+ ↓ 调用 JSBridge
243
+ ┌──────────────────────────────────────┐
244
+ │ JSBridge 封装层 │
245
+ │ (JsBridgeHandlers.ts) │
246
+ │ │
247
+ │ 功能: │
248
+ │ - 业务逻辑封装 │
249
+ │ - 错误处理 │
250
+ │ - 参数校验 │
251
+ └──────────────────────────────────────┘
252
+ ↓ 调用核心通信
253
+ ┌──────────────────────────────────────┐
254
+ │ 核心通信层 │
255
+ │ (JsBridge.ts) │
256
+ │ │
257
+ │ 功能: │
258
+ │ - WKWebViewJavascriptBridge │
259
+ │ - InjectJavascript │
260
+ │ - 环境检测 │
261
+ │ - 消息收发 │
262
+ └──────────────────────────────────────┘
263
+
264
+ Android WebView
265
+ ```
266
+
267
+ ## 🔍 深入分析
268
+
269
+ ### 为什么原设计遗漏了适配层?
270
+
271
+ **原因**:过度关注框架适配(Vue2/Vue3/React),忽略了实际项目的集成方式。
272
+
273
+ #### 原设计的想法
274
+
275
+ ```typescript
276
+ // 让业务代码这样用:
277
+ import { JSBridge } from '@hd-front-end/jsbridge-sdk'
278
+
279
+ JSBridge.scan().then(...) // ← 需要改业务代码
280
+ ```
281
+
282
+ #### 实际项目的做法
283
+
284
+ ```typescript
285
+ // 业务代码不用改,还是用 uni API:
286
+ uni.scanCode({ success: ... }) // ← 业务代码不变
287
+
288
+ // 在 App.vue 启动时注入适配器:
289
+ hdAppAdapter() // ← 只改一次
290
+ ```
291
+
292
+ ### 适配层的价值
293
+
294
+ | 维度 | 没有适配层 | 有适配层 |
295
+ |------|-----------|---------|
296
+ | **业务代码修改** | 需要大量修改 | 完全不用改 |
297
+ | **API 风格** | Promise 风格 | uni-app 回调风格 |
298
+ | **迁移成本** | 高(每个调用都要改) | 低(只改一次) |
299
+ | **兼容性** | 不兼容 uni 生态 | 完全兼容 |
300
+ | **学习成本** | 需要学新 API | 无需学习 |
301
+
302
+ ### 参数转换示例
303
+
304
+ #### uni-app 参数格式
305
+
306
+ ```typescript
307
+ uni.scanCode({
308
+ scanType: ['qrCode', 'barCode'],
309
+ onlyFromCamera: true,
310
+ success: (res) => {},
311
+ fail: (err) => {},
312
+ complete: () => {}
313
+ })
314
+ ```
315
+
316
+ #### 原生 JSBridge 参数格式
317
+
318
+ ```typescript
319
+ {
320
+ scanType: ['qrCode', 'barCode'],
321
+ hideAlbum: true,
322
+ viewText: '扫二维码/条码',
323
+ language: 'zh-Hans',
324
+ failedMsg: '未识别到二维码,请重试',
325
+ screenType: 'full',
326
+ timeoutInterval: '10',
327
+ timeoutText: '未识别到二维码?'
328
+ }
329
+ ```
330
+
331
+ **适配层的作用**:自动转换这些参数!
332
+
333
+ ### 回调转换示例
334
+
335
+ #### 原生 JSBridge 返回格式
336
+
337
+ ```typescript
338
+ {
339
+ resp_code: 1000,
340
+ resp_result: 'scan-content',
341
+ resp_message: 'success'
342
+ }
343
+ ```
344
+
345
+ #### uni-app 回调格式
346
+
347
+ ```typescript
348
+ {
349
+ result: 'scan-content',
350
+ scanType: 'qrCode',
351
+ charSet: 'utf-8',
352
+ path: ''
353
+ }
354
+ ```
355
+
356
+ **适配层的作用**:自动转换返回值并调用回调!
357
+
358
+ ## 📊 对比总结
359
+
360
+ ### 原设计 vs 正确架构
361
+
362
+ | 层级 | 原设计 | 正确架构 | 说明 |
363
+ |------|--------|---------|------|
364
+ | 业务代码 | 调用 `JSBridge.scan()` | 调用 `uni.scanCode()` | 无需修改业务代码 |
365
+ | **uni API 适配层** | **❌ 缺失** | **✅ 有(hdAppAdapter)** | **关键!** |
366
+ | JSBridge 封装 | ✅ 有 | ✅ 有 | 业务逻辑封装 |
367
+ | 核心通信 | ✅ 有 | ✅ 有 | 原生通信 |
368
+
369
+ ### 迁移成本对比
370
+
371
+ #### 方案 1:没有适配层
372
+
373
+ ```typescript
374
+ // 需要修改的文件:约 200+ 个组件/页面
375
+ // 每个文件需要:
376
+ // 1. 添加 import { JSBridge } from '@hd-front-end/jsbridge-sdk'
377
+ // 2. 修改所有 uni.scanCode 为 JSBridge.scan
378
+ // 3. 修改参数格式
379
+ // 4. 修改回调风格(success/fail → Promise)
380
+
381
+ // 工作量:约 2-3 周
382
+ // 风险:高(容易遗漏)
383
+ ```
384
+
385
+ #### 方案 2:有适配层
386
+
387
+ ```typescript
388
+ // 需要修改的文件:1 个(App.vue)
389
+ // App.vue:
390
+ import { initJSBridge, hdAppAdapter } from '@hd-front-end/jsbridge-sdk'
391
+
392
+ onLaunch(async () => {
393
+ await initJSBridge()
394
+ hdAppAdapter() // ← 只加这一行!
395
+ })
396
+
397
+ // 工作量:约 2-3 天
398
+ // 风险:低(集中修改)
399
+ ```
400
+
401
+ ## 💡 设计经验教训
402
+
403
+ ### 教训 1:不要过度关注框架抽象
404
+
405
+ **问题**:原设计花大量精力做 Vue2/Vue3/React 适配器
406
+
407
+ **反思**:实际项目都是 uni-app,不需要支持 React
408
+
409
+ **正确做法**:专注于实际需求(uni-app 集成)
410
+
411
+ ### 教训 2:要深入理解现有代码
412
+
413
+ **问题**:没有仔细研究 hdAppAdapter.ts 的作用
414
+
415
+ **反思**:这是最关键的架构层,竟然被忽略了
416
+
417
+ **正确做法**:先理解现有实现,再设计新方案
418
+
419
+ ### 教训 3:要考虑迁移成本
420
+
421
+ **问题**:原设计需要大量修改业务代码
422
+
423
+ **反思**:迁移成本太高,团队不会接受
424
+
425
+ **正确做法**:设计时考虑向后兼容,降低迁移成本
426
+
427
+ ## ✅ 修正后的方案
428
+
429
+ ### 完整的 4 层架构
430
+
431
+ ```
432
+ 业务代码(uni.scanCode)
433
+
434
+ uni API 拦截适配层(hdAppAdapter) ← 问题 2 的核心
435
+
436
+ JSBridge 封装层(Handlers)
437
+
438
+ 核心通信层(Bridge) ← 问题 1 的差异处理在这里
439
+
440
+ Android WebView
441
+ ```
442
+
443
+ ### 核心组件
444
+
445
+ 1. **hdAppAdapter.ts** - uni API 拦截适配器
446
+ - 拦截 uni API 调用
447
+ - 参数格式转换
448
+ - 回调格式转换
449
+ - 处理只读属性
450
+
451
+ 2. **UniProxy.ts** - 解决 Vue3 只读属性问题
452
+ - 提供代理对象
453
+ - 兼容 Vue2/Vue3
454
+
455
+ 3. **uni-app-api.json** - API 配置清单
456
+ - 标记哪些 API 被替换
457
+ - 文档说明
458
+ - 构建优化
459
+
460
+ 4. **Bridge.ts** - 核心通信层
461
+ - WKWebViewJavascriptBridge
462
+ - 环境检测
463
+ - 消息收发
464
+
465
+ ## 🎯 总结
466
+
467
+ ### 问题 1 答案
468
+
469
+ **技术栈差别在哪?**
470
+
471
+ - **不在 JSBridge 通信本身**
472
+ - **而在 uni 对象的属性定义**
473
+ - Vue2:uni API 可写,可直接赋值
474
+ - Vue3:部分 uni API 只读,需要 UniProxy 代理
475
+
476
+ ### 问题 2 答案
477
+
478
+ **hdAppAdapter 的位置?**
479
+
480
+ - **它是 uni API 拦截适配层**
481
+ - **位于业务代码和 JSBridge 之间**
482
+ - **作用是让业务代码无需修改**
483
+ - **是整个架构中最关键的一层**
484
+
485
+ ### 核心价值
486
+
487
+ 1. **业务代码零修改** - 继续使用 uni API
488
+ 2. **迁移成本降低 90%** - 只需改 App.vue
489
+ 3. **完全兼容 uni 生态** - 标准的参数和回调
490
+ 4. **框架差异透明** - 自动处理 Vue2/Vue3 差异
491
+
492
+ ---
493
+
494
+ **感谢你提出这两个关键问题!它们直接指出了原设计的核心缺陷!** 🙏
495
+