|
|
|
using CommunityToolkit.Mvvm.Messaging;
|
|
|
|
using System;
|
|
|
|
using Microsoft.Maui.Controls;
|
|
|
|
|
|
|
|
namespace IndustrialControl.Services;
|
|
|
|
#if ANDROID
|
|
|
|
using Android.Content;
|
|
|
|
using Android.Util; // ✅ 用于 Log
|
|
|
|
using IndustrialControl.Droid; // 需要 DynamicScanReceiver
|
|
|
|
#endif
|
|
|
|
|
|
|
|
public record ScanMessage(string Data);
|
|
|
|
|
|
|
|
public class ScanService
|
|
|
|
namespace IndustrialControl.Services
|
|
|
|
{
|
|
|
|
public void Publish(string data)
|
|
|
|
public class ScanService
|
|
|
|
{
|
|
|
|
if (string.IsNullOrWhiteSpace(data)) return;
|
|
|
|
MainThread.BeginInvokeOnMainThread(() =>
|
|
|
|
WeakReferenceMessenger.Default.Send(new ScanMessage(data.Trim())));
|
|
|
|
}
|
|
|
|
public event Action<string, string>? Scanned;
|
|
|
|
|
|
|
|
public string? Prefix { get; set; }
|
|
|
|
public string? Suffix { get; set; }
|
|
|
|
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";
|
|
|
|
|
|
|
|
public void Attach(Entry entry)
|
|
|
|
{
|
|
|
|
entry.Completed += (s, e) => Publish(((Entry)s!).Text ?? string.Empty);
|
|
|
|
entry.Completed += (s, e) =>
|
|
|
|
{
|
|
|
|
var data = entry.Text?.Trim();
|
|
|
|
if (!string.IsNullOrEmpty(data))
|
|
|
|
{
|
|
|
|
#if ANDROID
|
|
|
|
Log.Info("ScanService", $"[Attach] Entry.Completed -> {data}");
|
|
|
|
#endif
|
|
|
|
Scanned?.Invoke(data, "kbd");
|
|
|
|
entry.Text = string.Empty;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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
|
|
|
|
Scanned?.Invoke(data, "kbd");
|
|
|
|
entry.Text = string.Empty;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Publish(string code, string type = "")
|
|
|
|
{
|
|
|
|
#if ANDROID
|
|
|
|
Log.Info("ScanService", $"[Publish] 模拟扫码 -> {code}, type={type}");
|
|
|
|
#endif
|
|
|
|
FilterAndRaise(code, type);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void StartListening()
|
|
|
|
{
|
|
|
|
#if ANDROID
|
|
|
|
Android.Util.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
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool FilterAndRaise(string data, string type)
|
|
|
|
{
|
|
|
|
if (!string.IsNullOrEmpty(Prefix) && data.StartsWith(Prefix))
|
|
|
|
data = data.Substring(Prefix.Length);
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(Suffix) && data.EndsWith(Suffix))
|
|
|
|
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
|
|
|
|
}
|
|
|
|
} |
...
|
...
|
|