You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Xamarin Forms中隐藏模拟键盘读卡器的接收数据并存入变量

刚好做过类似的需求,咱们用Xamarin Forms的依赖服务来实现跨平台的读卡器数据捕获,全程不显示输入内容,直接存到变量里。具体步骤如下:

1. 定义共享接口(Xamarin Forms项目)

首先在共享代码层定义一个接口,统一跨平台的调用契约,这样咱们不用关心每个平台的具体实现:

public interface ICardReaderService
{
    // 读到卡号后触发的事件
    event EventHandler<string> CardReadCompleted;
    // 启动监听
    void StartListening();
    // 停止监听
    void StopListening();
}

2. Android平台实现

Android这边咱们用一个完全隐藏的EditText来捕获读卡器的模拟键盘输入,既不需要额外权限,又能确保输入不会显示出来:

[assembly: Dependency(typeof(CardReaderService_Android))]
namespace YourAppName.Droid
{
    public class CardReaderService_Android : ICardReaderService
    {
        private EditText _hiddenInput;
        private string _currentInput = string.Empty;
        public event EventHandler<string> CardReadCompleted;

        public void StartListening()
        {
            var mainActivity = MainActivity.Instance;
            if (mainActivity == null || _hiddenInput != null) return;

            // 创建隐藏的输入框
            _hiddenInput = new EditText(mainActivity)
            {
                Visibility = ViewStates.Invisible,
                Focusable = true,
                FocusableInTouchMode = true
            };

            // 添加到当前页面的根布局
            var rootLayout = mainActivity.FindViewById<ViewGroup>(Android.Resource.Id.Content);
            rootLayout.AddView(_hiddenInput);

            // 让输入框获取焦点,确保能捕获键盘输入
            _hiddenInput.RequestFocus();

            // 绑定监听事件
            _hiddenInput.TextChanged += OnTextUpdated;
            _hiddenInput.KeyPress += OnKeyPressed;
        }

        private void OnTextUpdated(object sender, Android.Text.TextChangedEventArgs e)
        {
            _currentInput = _hiddenInput.Text;
        }

        private void OnKeyPressed(object sender, View.KeyEventArgs e)
        {
            // 捕获回车键(读卡器最后会触发回车)
            if (e.KeyCode == Keycode.Enter)
            {
                e.Handled = true; // 拦截回车事件,不让它扩散
                CardReadCompleted?.Invoke(this, _currentInput.Trim());
                // 清空输入框,准备下一次读取
                _hiddenInput.Text = string.Empty;
                _currentInput = string.Empty;
                // 重新获取焦点,防止焦点丢失
                _hiddenInput.RequestFocus();
            }
        }

        public void StopListening()
        {
            if (_hiddenInput == null) return;
            var mainActivity = MainActivity.Instance;
            var rootLayout = mainActivity.FindViewById<ViewGroup>(Android.Resource.Id.Content);
            rootLayout.RemoveView(_hiddenInput);
            // 解绑事件,避免内存泄漏
            _hiddenInput.TextChanged -= OnTextUpdated;
            _hiddenInput.KeyPress -= OnKeyPressed;
            _hiddenInput.Dispose();
            _hiddenInput = null;
        }
    }
}

注意:需要在MainActivity里保存静态实例,方便服务调用:

public class MainActivity : FormsAppCompatActivity
{
    public static MainActivity Instance { get; private set; }

    protected override void OnCreate(Bundle savedInstanceState)
    {
        Instance = this;
        // ...其他初始化代码
    }
}

3. iOS平台实现

iOS这边同样用隐藏的UITextField来捕获输入,逻辑和Android基本一致:

[assembly: Dependency(typeof(CardReaderService_iOS))]
namespace YourAppName.iOS
{
    public class CardReaderService_iOS : ICardReaderService
    {
        private UITextField _hiddenInput;
        private string _currentInput = string.Empty;
        public event EventHandler<string> CardReadCompleted;

        public void StartListening()
        {
            if (_hiddenInput != null) return;

            _hiddenInput = new UITextField
            {
                Hidden = true,
                Enabled = true,
                UserInteractionEnabled = true
            };

            // 添加到当前窗口
            var window = UIApplication.SharedApplication.KeyWindow;
            window.AddSubview(_hiddenInput);

            // 成为第一响应者,捕获键盘输入
            _hiddenInput.BecomeFirstResponder();

            // 绑定监听事件
            _hiddenInput.EditingChanged += OnTextUpdated;
            _hiddenInput.ShouldReturn += OnShouldReturn;
        }

        private void OnTextUpdated(object sender, EventArgs e)
        {
            _currentInput = _hiddenInput.Text;
        }

        private bool OnShouldReturn(UITextField textField)
        {
            // 捕获回车,触发完成事件
            CardReadCompleted?.Invoke(this, _currentInput.Trim());
            // 清空输入,保持响应状态
            _hiddenInput.Text = string.Empty;
            _currentInput = string.Empty;
            _hiddenInput.BecomeFirstResponder();
            return true; // 拦截默认回车行为
        }

        public void StopListening()
        {
            if (_hiddenInput == null) return;
            _hiddenInput.ResignFirstResponder();
            _hiddenInput.EditingChanged -= OnTextUpdated;
            _hiddenInput.ShouldReturn -= OnShouldReturn;
            _hiddenInput.RemoveFromSuperview();
            _hiddenInput.Dispose();
            _hiddenInput = null;
        }
    }
}

4. 在Xamarin Forms中使用服务

现在回到共享代码层,咱们可以在App.xaml.cs或者页面里初始化服务,监听卡号读取事件,把数据存到变量里:

public partial class App : Application
{
    private ICardReaderService _cardReaderService;
    // 存储读取到的卡号
    public string LastReadCardNumber { get; private set; }

    public App()
    {
        InitializeComponent();
        MainPage = new MainPage();

        // 获取依赖服务实例
        _cardReaderService = DependencyService.Get<ICardReaderService>();
        if (_cardReaderService != null)
        {
            _cardReaderService.CardReadCompleted += CardReader_CardReadCompleted;
            _cardReaderService.StartListening();
        }
    }

    private void CardReader_CardReadCompleted(object sender, string cardNumber)
    {
        // 把卡号存到变量里,这里可以做后续处理(比如存数据库、发起请求等)
        LastReadCardNumber = cardNumber;
        Console.WriteLine($"成功读取卡号:{cardNumber}");
    }

    // 生命周期处理,避免后台浪费资源
    protected override void OnSleep()
    {
        _cardReaderService?.StopListening();
    }

    protected override void OnResume()
    {
        _cardReaderService?.StartListening();
    }

    protected override void OnTerminate()
    {
        _cardReaderService?.StopListening();
    }
}

额外注意事项

  • 有些读卡器会输出前缀/后缀字符,可以在CardReadCompleted事件里对cardNumber做字符串过滤处理
  • 确保隐藏输入控件始终保持焦点,比如页面切换后,可以在页面的OnAppearing方法里重新调用服务的焦点设置逻辑(或者在服务里做自动焦点恢复)
  • 测试时可以用键盘手动输入数字+回车,模拟读卡器行为,验证功能是否正常

内容的提问来源于stack exchange,提问作者RDMM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:06:38