从“选择应用程序”列表中隐藏 NFC 应用程序/禁用通过外部 NFC 意图启动

Ale*_*mer 2 android nfc intentfilter android-intent android-activity

我目前正在为 Android 编写几个支持 NFC 的应用程序,想知道如何阻止我的应用程序出现在从启动器或非 NFC 应用程序扫描标签时打开的“选择应用程序”列表中。我只希望我的应用程序在打开时能够读取标签。

我目前的意图过滤器:

<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
    <action android:name="android.nfc.action.TECH_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<meta-data android:name="android.nfc.action.TECH_DISCOVERED" android:resource="@xml/nfc_tech_filter" />
Run Code Online (Sandbox Code Playgroud)

nfc_tech_filter.xml:

<tech-list>
    <tech>android.nfc.tech.MifareUltralight</tech>
</tech-list>
<tech-list>
    <tech>android.nfc.tech.Ndef</tech>
</tech-list>
Run Code Online (Sandbox Code Playgroud)

Mic*_*and 5

您的应用清单中目前有几个与 NFC 相关的 Intent 过滤器:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
    <action android:name="android.nfc.action.TECH_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
Run Code Online (Sandbox Code Playgroud)

通过将此类 Intent 过滤器添加到您的应用程序清单中,您可以指示应在这些 NFC 标签发现事件时启动某些Activity(或者,如果为同一 Intent 注册了多个 Activity,则在 Intent 选择器中显示为选项)。

因此,如果您不希望您的应用可由这些意图启动,则需要从AndroidManifest.xml 中删除这些意图过滤器。

但是,当您的应用程序的活动在前台时,您也将失去监听这些意图的能力。由于 NFC 意图是活动意图,因此您无法通过动态注册的广播接收器接收它们(参见RubbelDieKatz的回答)。相反,Android API 提供了替代方法来捕获 NFC 相关事件,同时您的应用程序的活动显示在前台(这也允许您的应用程序优先于其他应用程序,这对于基于清单的 NFC 意图过滤器是不可能的):

  1. 从 API 级别 10(基本上是从 Android NFC 开始),Android 具有前台调度系统。您可以使用NfcAdapter.enableForegroundDispatch()on方法注册您的前台活动以接收 NFC 事件onResume()(不要忘记在您的活动失去焦点时取消注册onPause()):

    public void onResume() {
        super.onResume();
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
        adapter.enableForegroundDispatch(this, pendingIntent, null, null);
    }
    
    public void onPause() {
        super.onPause();
        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
        adapter.disableForegroundDispatch(this);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    您甚至可以通过向enableForegroundDispatch().

    在前台调度系统注册您的活动后,您将通过onNewIntent()回调接收 NFC 事件:

    public void onNewIntent(Intent intent) {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 从 API 级别 19 开始,有新的 NFC 读取器模式 API。您现在可以注册以接收常规回调(而不是通过有时会导致一些问题的意图调度)。您可以使用以下方法执行此操作NfcAdpater.enableReaderMode()

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        ...
    
        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
        adapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A, null);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    除了(或代替)使用其他标志,NfcAdapter.FLAG_READER_NFC_A您还可以将阅读器模式设置为侦听其他标签技术。

    然后您将在标签发现时接收回调(接收者需要实现回调接口NfcAdapter.ReaderCallback):

    public void onTagDiscovered(Tag tag) {
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

另请参阅enableReaderMode 和 enableForegroundDispatch 之间有什么区别?两个选项之间的更详细的比较。

  • 感谢您的回答,我已经在使用前台调度系统,我的应用程序现在按预期工作。我还删除了清单中的过滤器。 (2认同)