首页 > 解决方案 > How to launch app by scanning NDEF NFC tag?

问题描述

I am trying to launch my app by scanning an NFC tag. I have two tags to test with,

  1. one (lets call this "tag A") with one URI data type "http://panasonic.net" and
  2. the other (lets call this "tag B") with two data types -- a URI (with TNF: TNF_WELL_KNOWN and RTD: RTD_URI) "urn:nfc:testing.com/ecm/ecap" and a URN (TNF: TNF_EXTERNAL_TYPE) "urn:nfc:ext:testing.com:ecm".

Note: My main goal is to get tag B to work. Tag A is my test tag and it does not need to work with this app.

In my manifest, I give the permissions for NFC, and I have added the XML for the tech-discovered list in the manifest.

In the intent-filter tag, I have the following:

<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT"/>

Without TECH_DISCOVERED, tag A is shown in the list of apps to launch automatically but tag B is not shown. With TECH_DISCOVERED, both tags are shown on the list.
Correction: Without TECH_DISCOVERED, for tag A and tag B, the app does not show up in the auto-launch list. But without TECH_DISCOVERED and <data android:scheme="http" android:host="panasonic.net"/>, tag A does get the app to show up in the auto-launch list. For tag A this is correct behavior because Chrome takes over and launches automatically when <data ... android:host="panasonic.net"/> is not there.

Next, I have specified some data tags in the intent-filter:

<data android:scheme="http" android:host="panasonic.net"/>
<data android:scheme="http" android:host="fake.com"/>

When scanning tag A, it gets the app to show up on the list. When scanning tag B, the app is not shown in the list. This is correct behavior.

Then I add a data tag to the intent-filter for tag B:

<data android:scheme="vnd.android.nfc"
      android:host="ext"
      android:pathPrefix="/com.informationmediary:ecm" />

This is where I start having trouble. I scan tag A and tag B, and the app does not show up in the auto-launch list for both. When I remove the HTTP data tags leaving only the "vnd.android.nfc" one and scan tag B again the app still does not show up.

I also tried the following variations to no avail:

EDIT: at this point I have removed the following hoping to get tag B to work only:

<data android:scheme="http" android:host="panasonic.net"/>
<data android:scheme="http" android:host="fake.com"/>

1.

    <data android:scheme="vnd.android.nfc"
          android:host="ext"
          android:pathPrefix="/com.informationmediary:ecm" />

2.

    <data android:scheme="vnd.android.nfc"
          android:host="ext"
          android:pathPrefix="/informationmediary.com:ecm" />

3.

    <data android:scheme="urn:nfc"
          android:host="ext"
          android:pathPrefix="/com.informationmediary:ecm" />

4.

    <data android:scheme="urn:nfc"
          android:host="ext"
          android:pathPrefix="/informationmediary.com:ecm" />

5.

    <data android:scheme="vnd.android.nfc"
          android:host="informationmediary.com"
          android:pathPrefix="/ecm/ecap"/>

6.

    <data android:scheme="urn:nfc"
          android:host="informationmediary.com"
          android:pathPrefix="/ecm/ecap"/>

I have tried all combinations of two of the top four with the bottom two: 1&5, 1&6, 2&5, 2&6, 3&5, 3&6, 4&5 and 4&6

I doubted scheme="urn:nfc" but tried it anyways, "grasping at straws" by this time.

Tag B is the one I need to work, tag A is a test one I have.

I have read the documentation https://developer.android.com/guide/topics/connectivity/nfc/nfc#ext-type And https://developer.android.com/guide/topics/manifest/data-element#mime and several other posts on forums that basically say the same thing as in the developer.android sights.

标签: androidandroid-manifestnfcintentfilterndef

解决方案


为标签 B 添加意图过滤器会导致标签 A 不再被拾取

添加数据元素时

<data android:scheme="vnd.android.nfc"
      android:host="ext"
      android:pathPrefix="/com.informationmediary:ecm" />

到您现有的意图过滤器

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="http" android:host="panasonic.net" />
    <data android:scheme="http" android:host="fake.com" />
</intent-filter>

Android 会将所有数据元素合并为一个。因此,您的表单意图过滤器

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="http" android:host="panasonic.net" />
    <data android:scheme="http" android:host="fake.com" />
    <data android:scheme="vnd.android.nfc"
          android:host="ext"
          android:pathPrefix="/informationmediary.com:ecm" />
</intent-filter>

意味着 Android 将尝试匹配标签上的 URL,如下所示:

(scheme == "http" OR scheme == "vnd.android.nfc") AND
(host == "panasonic.net" OR host == "fake.com" OR host == "ext") AND
(path startsWith "/informationmediary.com:ecm")

因此, android:pathPrefix 属性必须与 URL 匹配,即使它没有在其他数据元素上明确指定。

您可以通过指定两个单独的意图过滤器轻松摆脱该问题:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="http" android:host="panasonic.net" />
    <data android:scheme="http" android:host="fake.com" />
</intent-filter>
<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="vnd.android.nfc"
          android:host="ext"
          android:pathPrefix="/informationmediary.com:ecm" />
</intent-filter>

标签 B 永远不会匹配意图过滤器

只有标签上的第一条记录与意图过滤器匹配。因此,为了匹配外部类型记录,您需要将其设为标签上的第一条记录。然后,如果您的外部类型记录包含 URI “urn:nfc:ext:informationmediary.com:ecm”,它将匹配上述意图过滤器。请注意,该记录实际上必须只包含“informationmediary.com:ecm”部分,因为前缀是隐含的。

如果您无法更改标签 B 的内容,则需要将该标签上的 URI 记录与意图过滤器匹配。不幸的是,您在标签 B 上的 URI 不容易在 Android 上使用。问题是 Android 只能匹配“scheme://host/path”形式的 URL 的主机和路径(注意斜线!)。由于您使用的是 URN,因此它没有主机或路径组件。在这种情况下,您只能尝试自己匹配方案(即“urn”):

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="urn" />
</intent-filter>

但是,您无法区分 URN 的其余组件(即没有主机或路径组件提供的这种区分)。


推荐阅读