ScanService.cs
5.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
// File: Services/ScanService.cs
using System;
using Microsoft.Maui.Controls;
#if ANDROID
using Android.Content;
using Android.Util;
using IndustrialControl.Droid; // 引用 DynamicScanReceiver
#endif
namespace IndustrialControl.Services
{
/// <summary>
/// 统一的扫码服务:支持软键盘回车、手动发布、以及 Android 广播动态接收
/// </summary>
public class ScanService
{
public event Action<string, string?>? Scanned;
/// <summary>可选:前缀过滤(匹配到则裁剪)</summary>
public string? Prefix { get; set; }
/// <summary>可选:后缀过滤(匹配到则裁剪)</summary>
public string? Suffix { get; set; }
/// <summary>去抖间隔(毫秒):相同码在该间隔内只触发一次</summary>
public int DebounceMs { get; set; } = 250;
private string? _lastData;
private DateTime _lastAt = DateTime.MinValue;
// 约定的广播/键名(与你的设备或发送方对齐)
public const string BroadcastAction = "lc";
public const string DataKey = "data";
public const string TypeKey = "SCAN_BARCODE_TYPE_NAME";
/// <summary>
/// 绑定一个 Entry:回车或换行时触发扫码
/// </summary>
public void Attach(Entry entry)
{
// 回车(Completed)
entry.Completed += (s, e) =>
{
var data = entry.Text?.Trim();
if (!string.IsNullOrEmpty(data))
{
#if ANDROID
Log.Info("ScanService", $"[Attach] Entry.Completed -> {data}");
#endif
FilterAndRaise(data, "kbd");
entry.Text = string.Empty;
}
};
// 文本变化:遇到 \n/\r 也触发
entry.TextChanged += (s, e) =>
{
if (string.IsNullOrEmpty(e.NewTextValue)) return;
if (e.NewTextValue.EndsWith("\n") || e.NewTextValue.EndsWith("\r"))
{
var data = e.NewTextValue.Trim();
#if ANDROID
Log.Info("ScanService", $"[Attach] Entry.TextChanged -> {data}");
#endif
FilterAndRaise(data, "kbd");
entry.Text = string.Empty;
}
};
}
/// <summary>
/// 代码侧模拟一次扫码(用于调试/联调)
/// </summary>
public void Publish(string code, string? type = null)
{
#if ANDROID
Log.Info("ScanService", $"[Publish] 模拟扫码 -> {code}, type={type}");
#endif
FilterAndRaise(code, type ?? string.Empty);
}
/// <summary>
/// 开始监听 Android 广播(动态注册)
/// </summary>
public void StartListening()
{
#if ANDROID
Log.Info("ScanService", "[StartListening] ENTER");
if (_receiver != null) return;
_receiver = new DynamicScanReceiver();
_receiver.OnScanned += OnScannedFromPlatform;
_filter = new IntentFilter(BroadcastAction);
Android.App.Application.Context.RegisterReceiver(_receiver, _filter);
Log.Info("ScanService", $"[StartListening] 已注册广播 Action={BroadcastAction}");
#endif
}
/// <summary>
/// 停止监听 Android 广播(反注册)
/// </summary>
public void StopListening()
{
#if ANDROID
if (_receiver == null) return;
try
{
Android.App.Application.Context.UnregisterReceiver(_receiver);
Log.Info("ScanService", "[StopListening] 已注销广播");
}
catch (Exception ex)
{
Log.Warn("ScanService", $"[StopListening] 注销异常: {ex.Message}");
}
_receiver.OnScanned -= OnScannedFromPlatform;
_receiver = null;
_filter = null;
#endif
}
/// <summary>
/// 统一过滤 + 去抖 + 触发事件
/// </summary>
private bool FilterAndRaise(string data, string? type)
{
if (!string.IsNullOrEmpty(Prefix) && data.StartsWith(Prefix, StringComparison.Ordinal))
data = data.Substring(Prefix.Length);
if (!string.IsNullOrEmpty(Suffix) && data.EndsWith(Suffix, StringComparison.Ordinal))
data = data.Substring(0, data.Length - Suffix.Length);
var now = DateTime.UtcNow;
if (_lastData == data && (now - _lastAt).TotalMilliseconds < DebounceMs)
{
#if ANDROID
Log.Info("ScanService", $"[FilterAndRaise] 去抖丢弃: {data}");
#endif
return false;
}
_lastData = data;
_lastAt = now;
#if ANDROID
Log.Info("ScanService", $"[FilterAndRaise] 触发 -> {data}, type={type}");
#endif
Scanned?.Invoke(data, type);
return true;
}
#if ANDROID
private DynamicScanReceiver? _receiver;
private IntentFilter? _filter;
private void OnScannedFromPlatform(string data, string? type)
{
Log.Info("ScanService", $"[OnScannedFromPlatform] 原始 -> {data}, type={type}");
FilterAndRaise(data, type);
}
#endif
}
}