完善生产查询与登录权限配置
This commit is contained in:
@@ -0,0 +1,498 @@
|
||||
# mas-code-scan 自定义识别区域方案
|
||||
|
||||
## 1. 目标
|
||||
|
||||
在 Android 扫码页面中提供可配置的实时识别区域(ROI,Region of Interest):
|
||||
|
||||
- 摄像头打开后显示一个矩形扫描框;
|
||||
- 只有条码位于矩形区域内时才允许识别成功;
|
||||
- 扫描框外的条码不触发单次扫码成功;
|
||||
- 支持自定义扫描框宽度、高度、水平位置和垂直位置;
|
||||
- 支持不同屏幕尺寸和横竖屏适配;
|
||||
- 不破坏现有的单次扫码、连续扫码、相册识图、多码点选、智能变焦和码制过滤能力。
|
||||
|
||||
## 2. 当前实现核对
|
||||
|
||||
### 2.1 现有接口
|
||||
|
||||
文件:`uni_modules/mas-code-scan/utssdk/interface.uts`
|
||||
|
||||
当前 `CodeScanOptions` 支持:
|
||||
|
||||
```ts
|
||||
{
|
||||
smartZoom?: boolean
|
||||
formats?: string[]
|
||||
vibrate?: boolean
|
||||
continuous?: boolean
|
||||
fromAlbum?: boolean
|
||||
success?: (res) => void
|
||||
fail?: (res) => void
|
||||
complete?: (res) => void
|
||||
}
|
||||
```
|
||||
|
||||
当前没有识别区域配置字段。
|
||||
|
||||
### 2.2 预览层
|
||||
|
||||
文件:`uni_modules/mas-code-scan/utssdk/app-android/CodeCaptureActivity.kt`
|
||||
|
||||
- 使用 `PreviewView.ScaleType.FILL_CENTER` 显示相机预览;
|
||||
- `ScanFrameDecorView` 覆盖在预览层上方绘制扫描动画;
|
||||
- 预览层和装饰层都是全屏 `FrameLayout`;
|
||||
- 触摸缩放绑定在 `PreviewView` 上。
|
||||
|
||||
文件:`uni_modules/mas-code-scan/utssdk/app-android/ScanFrameDecorView.kt`
|
||||
|
||||
当前扫描框是固定的正方形:
|
||||
|
||||
```kotlin
|
||||
val frameWidth = ...
|
||||
val frameHeight = frameWidth
|
||||
```
|
||||
|
||||
它只负责画扫描线,不参与实际识别。
|
||||
|
||||
### 2.3 识别层
|
||||
|
||||
文件:`uni_modules/mas-code-scan/utssdk/app-android/CodeCaptureActivity.kt`
|
||||
|
||||
当前把完整的 `ImageProxy` 图像交给 ML Kit:
|
||||
|
||||
```kotlin
|
||||
val inputImage = InputImage.fromMediaImage(mediaImage, rotationDegrees)
|
||||
scanner.process(inputImage)
|
||||
```
|
||||
|
||||
因此当前扫描框只是视觉提示,框外条码仍可能被识别。
|
||||
|
||||
## 3. 推荐接口设计
|
||||
|
||||
建议新增 `scanRegion`,使用相对比例配置,不使用固定像素作为公共接口。
|
||||
|
||||
```ts
|
||||
openCodeScan({
|
||||
scanRegion: {
|
||||
width: 0.92,
|
||||
height: 0.18,
|
||||
centerX: 0.5,
|
||||
centerY: 0.5
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
字段定义:
|
||||
|
||||
| 字段 | 类型 | 默认值 | 范围 | 含义 |
|
||||
|---|---|---:|---|---|
|
||||
| `fullScreen` | `boolean` | `false` | - | 为 `true` 时整画面识别,不绘制扫描框且不进行区域过滤 |
|
||||
| `width` | `number` | `0.74` | `0.1 ~ 1` | 扫描框宽度,占预览宽度的比例 |
|
||||
| `height` | `number` | `0.74` | `0.1 ~ 1` | 扫描框高度,占预览宽度的比例 |
|
||||
| `centerX` | `number` | `0.5` | `0 ~ 1` | 扫描框中心的水平位置比例 |
|
||||
| `centerY` | `number` | `0.5` | `0 ~ 1` | 扫描框中心的垂直位置比例 |
|
||||
|
||||
全屏识别示例:
|
||||
|
||||
```ts
|
||||
openCodeScan({
|
||||
scanRegion: { fullScreen: true }
|
||||
})
|
||||
```
|
||||
|
||||
二维码区域约束:
|
||||
|
||||
- `width` 与 `height` 使用相同值,严格锁定 `1:1` 正方形比例;
|
||||
- 默认值为 `width: 0.74`、`height: 0.74`;
|
||||
- 原生扫描框使用直角,不绘制圆角。
|
||||
|
||||
推荐默认值:
|
||||
|
||||
```ts
|
||||
{
|
||||
width: 0.74,
|
||||
height: 0.74,
|
||||
centerX: 0.5,
|
||||
centerY: 0.5
|
||||
}
|
||||
```
|
||||
|
||||
业务页面可针对一维码使用横向区域,并通过 `centerY` 调整上下位置、通过 `height` 调整框高:
|
||||
|
||||
```ts
|
||||
{
|
||||
width: 0.96,
|
||||
height: 0.24,
|
||||
centerX: 0.5,
|
||||
centerY: 0.5
|
||||
}
|
||||
```
|
||||
|
||||
原型页提供三档横向条码框高度:
|
||||
|
||||
- 中:`0.24`(24%);
|
||||
- 大:`0.32`(32%);
|
||||
- 特大:`0.40`(40%)。
|
||||
|
||||
### 3.1 为什么使用比例
|
||||
|
||||
- 不依赖具体手机分辨率和 density;
|
||||
- 适配不同 Android 设备;
|
||||
- 与当前全屏预览布局一致;
|
||||
- 后续可在页面中通过滑块或预设配置调整;
|
||||
- 避免将前端 `rpx` 直接与原生像素混用。
|
||||
|
||||
## 4. 实现分层
|
||||
|
||||
### 4.1 UTS 接口层
|
||||
|
||||
修改:`utssdk/interface.uts`
|
||||
|
||||
新增:
|
||||
|
||||
```ts
|
||||
export type ScanRegion = {
|
||||
width?: number
|
||||
height?: number
|
||||
centerX?: number
|
||||
centerY?: number
|
||||
}
|
||||
```
|
||||
|
||||
并在 `CodeScanOptions` 中增加:
|
||||
|
||||
```ts
|
||||
scanRegion?: ScanRegion
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- 字段全部可选;
|
||||
- 不传时保持现有默认扫描框;
|
||||
- 对非法值进行原生端裁剪和兜底;
|
||||
- 不把 UI 颜色、文案等表现层参数与识别区域参数混在一起。
|
||||
|
||||
### 4.2 UTS 到 Android Intent
|
||||
|
||||
修改:`utssdk/app-android/index.uts`
|
||||
|
||||
新增一个 JSON 字符串 Extra,例如:
|
||||
|
||||
```text
|
||||
mas_scan_region
|
||||
```
|
||||
|
||||
将 `scanRegion` 序列化后传递给 `CodeCaptureActivity`。
|
||||
|
||||
推荐传递 JSON,而不是增加多个 Intent Extra,原因是:
|
||||
|
||||
- 字段集中;
|
||||
- 后续增加圆角、边框颜色等非识别参数时更容易扩展;
|
||||
- 保持接口和 Activity 参数数量可控。
|
||||
|
||||
### 4.3 Activity 参数解析
|
||||
|
||||
修改:`CodeCaptureActivity.kt`
|
||||
|
||||
新增:
|
||||
|
||||
```kotlin
|
||||
private data class ScanRegionConfig(
|
||||
val width: Float,
|
||||
val height: Float,
|
||||
val centerX: Float,
|
||||
val centerY: Float
|
||||
)
|
||||
```
|
||||
|
||||
初始化时:
|
||||
|
||||
1. 读取 Intent Extra;
|
||||
2. 解析 JSON;
|
||||
3. 将数值限制在安全范围;
|
||||
4. 对过小区域、越界中心点进行兜底;
|
||||
5. 将同一份配置传给 `ScanFrameDecorView` 和识别过滤逻辑。
|
||||
|
||||
最终必须保证:
|
||||
|
||||
```text
|
||||
视觉扫描框区域 == 实际有效识别区域
|
||||
```
|
||||
|
||||
## 5. 坐标体系设计
|
||||
|
||||
这是本需求的核心难点。项目中至少存在三套坐标:
|
||||
|
||||
1. **屏幕/装饰层坐标**:`ScanFrameDecorView` 的 view 坐标;
|
||||
2. **预览可视区域坐标**:`PreviewView` 中用户看到的相机画面;
|
||||
3. **ImageProxy 图像坐标**:ML Kit `Barcode.boundingBox` 使用的图像坐标。
|
||||
|
||||
由于预览使用 `FILL_CENTER`,图像可能在屏幕两侧或上下被裁剪,不能简单按照屏幕宽高直接换算。
|
||||
|
||||
### 5.1 统一区域定义
|
||||
|
||||
推荐先在预览层坐标中计算扫描框:
|
||||
|
||||
```text
|
||||
frameLeft = viewWidth * (centerX - width / 2)
|
||||
frameTop = viewHeight * (centerY - height / 2)
|
||||
frameRight = viewWidth * (centerX + width / 2)
|
||||
frameBottom = viewHeight * (centerY + height / 2)
|
||||
```
|
||||
|
||||
并限制在预览层范围内。
|
||||
|
||||
### 5.2 预览坐标映射到图像坐标
|
||||
|
||||
当前 `PreviewView` 使用 `FILL_CENTER`,映射应考虑:
|
||||
|
||||
```text
|
||||
scale = max(viewWidth / rotatedImageWidth, viewHeight / rotatedImageHeight)
|
||||
```
|
||||
|
||||
相机图像在屏幕上的实际显示尺寸为:
|
||||
|
||||
```text
|
||||
displayWidth = rotatedImageWidth * scale
|
||||
displayHeight = rotatedImageHeight * scale
|
||||
offsetX = (viewWidth - displayWidth) / 2
|
||||
offsetY = (viewHeight - displayHeight) / 2
|
||||
```
|
||||
|
||||
扫描框转回旋转后的图像坐标:
|
||||
|
||||
```text
|
||||
imageLeft = (frameLeft - offsetX) / scale
|
||||
imageTop = (frameTop - offsetY) / scale
|
||||
imageRight = (frameRight - offsetX) / scale
|
||||
imageBottom = (frameBottom - offsetY) / scale
|
||||
```
|
||||
|
||||
然后再根据 `rotationDegrees` 转换到 `ImageProxy` 原始坐标。
|
||||
|
||||
注意:实际代码需要以 `PreviewView` 的 `viewPort`、绑定的 UseCase 分辨率和设备方向为准验证,不能只凭静态公式上线。
|
||||
|
||||
## 6. 识别限制策略
|
||||
|
||||
### 6.1 第一阶段:结果过滤,推荐先实现
|
||||
|
||||
ML Kit 仍分析整帧,但只接受扫描区域内的条码:
|
||||
|
||||
```kotlin
|
||||
val validBarcodes = barcodes.filter { barcode ->
|
||||
val box = barcode.boundingBox ?: return@filter false
|
||||
isBarcodeInsideScanRegion(box, imageProxy, rotationDegrees)
|
||||
}
|
||||
```
|
||||
|
||||
区域判断建议使用条码边界框中心点,默认规则:
|
||||
|
||||
```text
|
||||
条码中心点位于扫描框内 => 允许识别
|
||||
条码中心点位于扫描框外 => 忽略
|
||||
```
|
||||
|
||||
对于严格业务场景,可以改为:
|
||||
|
||||
```text
|
||||
条码边界框完全位于扫描框内 => 允许识别
|
||||
```
|
||||
|
||||
本项目建议默认使用“中心点在区域内”,原因是:
|
||||
|
||||
- 用户将条码移入框内时体验更自然;
|
||||
- 条码边缘轻微超出时不会频繁丢失;
|
||||
- 对一维横向条码更友好。
|
||||
|
||||
### 6.2 多码识别
|
||||
|
||||
过滤应发生在多码判断之前:
|
||||
|
||||
```text
|
||||
原始 barcodes
|
||||
-> 过滤无 boundingBox 的结果
|
||||
-> 过滤框外结果
|
||||
-> 再执行单码 / 多码判断
|
||||
```
|
||||
|
||||
这样框外多码不会触发点选页面,也不会影响智能变焦。
|
||||
|
||||
### 6.3 相册识图
|
||||
|
||||
实时摄像头的 `scanRegion` 不应默认限制相册识图:
|
||||
|
||||
- 相册图片没有实时预览框坐标;
|
||||
- 用户选择的是整张图片;
|
||||
- 继续保持相册识别整图的现有行为。
|
||||
|
||||
如果未来确实需要对相册图片裁剪,应单独设计 `albumRegion`,不要复用实时预览坐标。
|
||||
|
||||
### 6.4 识别前裁剪
|
||||
|
||||
第二阶段可选做真正的 ROI 图像裁剪,只将区域图像提交给 ML Kit。
|
||||
|
||||
暂不作为第一阶段实现,原因:
|
||||
|
||||
- 需要处理 ImageProxy YUV 裁剪;
|
||||
- 需要处理旋转和 cropRect;
|
||||
- 需要重新映射多码点选坐标;
|
||||
- 可能影响智能变焦依据和现有连续扫码稳定性;
|
||||
- 设备兼容性验证成本更高。
|
||||
|
||||
## 7. 扫描框视觉设计
|
||||
|
||||
修改:`ScanFrameDecorView.kt`
|
||||
|
||||
扫描框应从固定正方形改为配置矩形:
|
||||
|
||||
- 宽度由 `width` 决定;
|
||||
- 高度由 `height` 决定;
|
||||
- 位置由 `centerX`、`centerY` 决定;
|
||||
- 扫描线只在矩形内部移动;
|
||||
- 扫描线左右留出固定 inset;
|
||||
- 其他区域可增加半透明遮罩,增强用户对有效范围的理解。
|
||||
|
||||
建议提供清晰的 UI 语义:
|
||||
|
||||
```text
|
||||
框内:有效识别区域
|
||||
框外:不识别
|
||||
```
|
||||
|
||||
当前截图的横向条码场景推荐:
|
||||
|
||||
```ts
|
||||
scanRegion: {
|
||||
width: 0.96,
|
||||
height: 0.16,
|
||||
centerX: 0.5,
|
||||
centerY: 0.5
|
||||
}
|
||||
```
|
||||
|
||||
## 8. 原型页面示例规划
|
||||
|
||||
文件:`pages/scan/prototype.vue`
|
||||
|
||||
原型页增加“识别区域”配置区,但不直接实现摄像头 UI。页面负责展示和传递配置:
|
||||
|
||||
### 8.1 预设
|
||||
|
||||
提供三个预设:
|
||||
|
||||
- 默认正方形:适合二维码;
|
||||
- 横向条码:适合设备码、物料码;
|
||||
- 自定义:通过宽度、高度、水平位置、垂直位置调整。
|
||||
|
||||
### 8.2 示例数据
|
||||
|
||||
```js
|
||||
scanRegion: {
|
||||
width: 0.96,
|
||||
height: 0.16,
|
||||
centerX: 0.5,
|
||||
centerY: 0.5
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 原型页交互
|
||||
|
||||
- 使用滑块或步进按钮调整四个比例参数;
|
||||
- 页面实时显示当前区域参数;
|
||||
- 单次扫码、连续扫码都使用当前 `scanRegion`;
|
||||
- 相册识图按钮不传实时扫描区域,继续整图识别;
|
||||
- 在 Web 预览中展示“仅 Android App-Plus 支持原生扫码”的提示。
|
||||
|
||||
## 9. 兼容性策略
|
||||
|
||||
### 9.1 不传配置
|
||||
|
||||
现有调用全部保持兼容:
|
||||
|
||||
```ts
|
||||
openCodeScan({
|
||||
smartZoom: true,
|
||||
vibrate: true
|
||||
})
|
||||
```
|
||||
|
||||
行为继续使用默认正方形区域。
|
||||
|
||||
### 9.2 旧构建包
|
||||
|
||||
如果前端代码传入 `scanRegion`,但运行的是旧插件包,旧原生代码会忽略未知 Extra,仍可正常扫码,但不会限制区域。因此必须重新制作自定义基座或正式 APK。
|
||||
|
||||
### 9.3 非 Android 平台
|
||||
|
||||
继续由 `#ifdef APP-PLUS` 控制插件导入和调用,Web、iOS、小程序不加载 Android UTS 实现。
|
||||
|
||||
### 9.4 参数安全
|
||||
|
||||
原生端必须再次校验参数,不能只依赖前端:
|
||||
|
||||
- `width`、`height` 限制在 `0.1 ~ 1`;
|
||||
- `centerX`、`centerY` 限制在 `0 ~ 1`;
|
||||
- 区域超出屏幕时进行边界收敛;
|
||||
- 宽高过小导致不可用时回退默认值。
|
||||
|
||||
## 10. 实施顺序
|
||||
|
||||
### 阶段一:方案验证
|
||||
|
||||
1. 增加 `scanRegion` 接口定义;
|
||||
2. 将参数传入 Android Activity;
|
||||
3. 扫描框支持矩形和位置配置;
|
||||
4. 根据条码中心点过滤框外结果;
|
||||
5. 原型页提供横向条码预设;
|
||||
6. 保持相册整图识别。
|
||||
|
||||
### 阶段二:真机验证
|
||||
|
||||
至少验证:
|
||||
|
||||
- 二维码默认正方形识别;
|
||||
- 横向一维码识别;
|
||||
- 框内识别成功;
|
||||
- 框外完全不识别;
|
||||
- 条码横跨边界时的行为;
|
||||
- 多个条码一内一外时只处理框内条码;
|
||||
- 连续扫码只回传框内结果;
|
||||
- 智能变焦不会被框外条码触发;
|
||||
- 横竖屏和不同分辨率设备;
|
||||
- 相册识图不受实时区域影响;
|
||||
- 关闭、取消、权限拒绝和页面销毁流程。
|
||||
|
||||
### 阶段三:可选优化
|
||||
|
||||
根据真机效果再决定是否:
|
||||
|
||||
- 改为识别前裁剪 ROI;
|
||||
- 增加边框颜色、圆角、遮罩透明度配置;
|
||||
- 增加“中心点在框内 / 完全包含”两种命中规则;
|
||||
- 增加一维码专用默认模板。
|
||||
|
||||
## 11. 验收标准
|
||||
|
||||
功能验收:
|
||||
|
||||
- 扫描框宽高和位置可以通过 `openCodeScan` 参数调整;
|
||||
- 用户看到的扫描框与实际识别区域一致;
|
||||
- 框外条码不会触发成功回调;
|
||||
- 框内条码可以正常触发成功回调;
|
||||
- 多码点选只展示有效区域内的条码;
|
||||
- 旧调用不传 `scanRegion` 时行为不变;
|
||||
- 单次、连续、相册三种模式互不回归。
|
||||
|
||||
工程验收:
|
||||
|
||||
- UTS 接口类型、Intent Extra、Activity 解析三层字段一致;
|
||||
- 不在页面中直接修改原生插件内部逻辑;
|
||||
- 所有新增配置有默认值和越界保护;
|
||||
- 真机重新构建自定义基座后验证;
|
||||
- 不以 Web 预览结果代替 Android 真机验证。
|
||||
|
||||
## 12. 结论
|
||||
|
||||
本项目适合采用“**比例配置 + 原生扫描框绘制 + 条码结果区域过滤**”作为第一版实现。
|
||||
|
||||
该方案能满足截图所示的横向矩形识别场景,改动范围可控,且能保留当前插件已有能力。真正的图像裁剪 ROI 作为后续优化,不在第一版中引入,以降低旋转、坐标映射和多码点选的回归风险。
|
||||
Reference in New Issue
Block a user