简体   繁体   中英

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.

Adding the intent filter for Tag B results in Tag A no longer being picked up

When you add the data element

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

to your existing intent filter

<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 will merge all data elements into a single one. Consequently, your intent filter of the form

<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>

means that Android will try to match the URL on the tag like this:

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

Therefore, the android:pathPrefix attribute must match th URL even if it is not explicitly specified on the other data elements.

You can easily get rid of that issue by specifying two separate intent filters:

<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>

Tag B never matches the intent filter

Only the first record on a tag is matched against intent filters. Hence, in order to match the External Type record, you need to make it the first record on the tag. Then, if your External Type record contains the URI "urn:nfc:ext:informationmediary.com:ecm" it will match the above intent filter. Note that the record actually must contain only the part "informationmediary.com:ecm" since the prefix is implicit.

If you can't change the content of tag B though, you would need to match the URI record on that tag with the intent filter. Unfortunately, your URI on tag B is not easily usable with Android. The problem is that Android can only match host and path for URLs of the form "scheme://host/path" (note the slashes!). Since you use a URN instead, that does not have a host or path component. In this case, you could only try to match the scheme (ie "urn") on its own:

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

You can't differentiate between the remaining components of the URN though (ie there is no such differentiation as provided by host or path components).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM