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

Android 13下Xamarin Forms NFC扫描触发应用选择窗口问题求助

Android 13设备NFC读取弹出应用选择窗口的解决方案(Xamarin Forms)

问题描述

使用Xamarin Forms开发应用,采用Android 31 SDK编译后,在Android 13设备上启动应用时,NFC读取流程会弹出应用选择窗口,但其他Android版本无此现象。

已配置的清单权限:

<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.BIND_NFC_SERVICE" />
<uses-permission android:name="android.permission.NFC_TRANSACTION_EVENT" />

监听代码:

var intent = new Intent(this, this.GetType()).AddFlags(ActivityFlags.SingleTop);
this.NFCdevice.EnableForegroundDispatch(
this, 
PendingIntent.GetActivity(this, 0, intent, 0), 
new[] { new IntentFilter(NfcAdapter.ActionTechDiscovered) }, 
new[]
    {
        new[] { NFCTechs.Ndef }, new[] { NFCTechs.MifareClassic }, new[] { NFCTechs.MifareUltralight }, 
        new[] { NFCTechs.NdefFormatable }, new[] { NFCTechs.NfcA }
    });

已尝试操作:

  • 添加应用NFC需求声明:[assembly: UsesFeature("android.hardware.nfc", Required = true)]
  • 补充监听NFCTechs.NfcB、NFCTechs.NfcF、NFCTechs.NfcV格式,但问题仍存在。

解决方案

1. 适配Android 13的PendingIntent标志位

Android 13(API 33)对PendingIntent的创建逻辑做了调整,原代码中使用的0标志位在高版本系统中无法保证前台调度的正常触发,需替换为PendingIntentFlags.Mutable(目标API 31+必须使用该标志,系统要求明确指定Intent是否可修改):

var intent = new Intent(this, this.GetType()).AddFlags(ActivityFlags.SingleTop);
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.Mutable);
this.NFCdevice.EnableForegroundDispatch(
    this, 
    pendingIntent, 
    new[] { new IntentFilter(NfcAdapter.ActionTechDiscovered) }, 
    new[]
    {
        new[] { NFCTechs.Ndef }, new[] { NFCTechs.MifareClassic }, new[] { NFCTechs.MifareUltralight }, 
        new[] { NFCTechs.NdefFormatable }, new[] { NFCTechs.NfcA }, new[] { NFCTechs.NfcB },
        new[] { NFCTechs.NfcF }, new[] { NFCTechs.NfcV }
    });

2. 完善IntentFilter覆盖范围

仅监听ActionTechDiscovered可能无法覆盖所有NFC标签的触发场景,建议同时添加ActionTagDiscovered和ActionNdefDiscovered,确保系统能将NFC事件优先分发给你的应用:

var filters = new[]
{
    new IntentFilter(NfcAdapter.ActionTechDiscovered),
    new IntentFilter(NfcAdapter.ActionTagDiscovered),
    new IntentFilter(NfcAdapter.ActionNdefDiscovered)
};

// 若标签包含NDEF数据,需为ActionNdefDiscovered添加MIME类型过滤
var ndefFilter = new IntentFilter(NfcAdapter.ActionNdefDiscovered);
try
{
    ndefFilter.AddDataType("*/*"); // 匹配所有MIME类型,可根据业务需求调整为具体类型
}
catch (IntentFilter.MalformedMimeTypeException e)
{
    throw new RuntimeException("无效的MIME类型过滤器", e);
}
// 将ndefFilter加入filters数组

3. 确保Activity的LaunchMode配置匹配

在AndroidManifest.xml中,处理NFC事件的Activity需设置launchMode="singleTop",与代码中ActivityFlags.SingleTop保持一致,避免重复创建Activity实例导致前台调度失效:

<activity 
    android:name=".MainActivity" 
    android:launchMode="singleTop">
    <!-- 其他配置 -->
</activity>

4. 规范ForegroundDispatch的生命周期管理

必须在Activity的OnResume方法中启用前台调度,OnPause方法中禁用,确保应用在前台时才拦截NFC事件,避免后台时系统触发应用选择窗口:

protected override void OnResume()
{
    base.OnResume();
    if (NFCdevice != null && NFCdevice.IsEnabled)
    {
        var intent = new Intent(this, this.GetType()).AddFlags(ActivityFlags.SingleTop);
        var pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.Mutable);
        var filters = new[]
        {
            new IntentFilter(NfcAdapter.ActionTechDiscovered),
            new IntentFilter(NfcAdapter.ActionTagDiscovered),
            new IntentFilter(NfcAdapter.ActionNdefDiscovered)
        };
        var techLists = new[]
        {
            new[] { NFCTechs.Ndef }, new[] { NFCTechs.MifareClassic }, new[] { NFCTechs.MifareUltralight }, 
            new[] { NFCTechs.NdefFormatable }, new[] { NFCTechs.NfcA }, new[] { NFCTechs.NfcB },
            new[] { NFCTechs.NfcF }, new[] { NFCTechs.NfcV }
        };
        NFCdevice.EnableForegroundDispatch(this, pendingIntent, filters, techLists);
    }
}

protected override void OnPause()
{
    base.OnPause();
    if (NFCdevice != null)
    {
        NFCdevice.DisableForegroundDispatch(this);
    }
}

5. 验证TechLists的完整性

确认TechLists包含目标NFC标签支持的所有技术类型,部分NFC标签可能同时支持多种技术标准(如MifareClassic同时属于NfcA),遗漏技术类型会导致系统无法匹配,进而弹出应用选择窗口。可以通过读取标签的TechList来确认:

// 在OnNewIntent中获取标签并打印支持的技术
protected override void OnNewIntent(Intent intent)
{
    base.OnNewIntent(intent);
    var tag = intent.GetParcelableExtra(NfcAdapter.ExtraTag) as Tag;
    if (tag != null)
    {
        var techs = tag.GetTechList();
        // 打印techs,查看标签支持的所有技术,补充到TechLists中
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 03:50:20