如何读取 Kivy + Python 中的 NFC 标签?
How to read NFC tag in Kivy + Python?
我正在尝试读取 NFC 标签,如果标签只有文本,则读取正常。但是,如果标签包含 URL 或为空,则它不起作用。我认为问题出在 nfc_filter.xml 文件上。
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="*/*" />
</intent-filter>
Python代码:
def nfc_init(self):
activity.bind(on_new_intent=self.on_new_intent)
self.j_context = context = PythonActivity.mActivity
self.nfc_adapter = NfcAdapter.getDefaultAdapter(context)
self.nfc_pending_intent = PendingIntent.getActivity(context, 0, Intent(context, context.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)
return True
def on_new_intent(self, intent):
print 'on_new_intent()', intent.getAction()
# get TAG details
tag = cast('android.nfc.Tag', intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
details = self.get_ndef_details(tag)
def on_pause(self):
print 'paused'
return True
def on_resume(self):
print 'resumed'
我想要的是,当我的应用程序处于活动状态并且您读取了 NFC 标签时,它总是会收到意图。现在我可以在日志中看到它不会从 on_pause 恢复,以防标签包含文本以外的内容或为空。
有人可以帮我解决这个问题吗?
由于清单中的 Intent 过滤器,您的应用目前正在接收 NFC 事件:
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="*/*" />
</intent-filter>
这个 intent 过滤器有几个问题:
此意图过滤器将匹配具有意图操作 TAG_DISCOVERED
、NDEF_DISCOVERED
或 TECH_DISCOVERED
、 和 [=88= 的意图] 同时包含类别 DEFAULT 或 BROWSABLE, 和 同时包含任何 (?) MIME 类型。
问题是只有 NDEF_DISCOVERED
意图可能包含 MIME 类型。因此,TAG_DISCOVERED
和 TECH_DISCOVERED
永远不会匹配。
MIME 类型 */*
(即匹配任何 MIME 类型)不会(不应该?)在清单意图过滤器中工作,因为只有子类型部分(即斜线)可能包含通配符 (*)。参见 android:mimeType。
类别 BROWSABLE 无用,因为 NFC 意图永远不会包含该类别。
NDEF_DISCOVERED
包含 URL 的标签的意图不包含 MIME 类型。由于您将 NDEF_DISCOVERED
意向过滤器限制为包含 MIME 类型的意向,因此它不会匹配包含 URLs.
的意向
TECH_DISCOVERED
意图过滤器需要声明技术列表 XML 文件。
因此,您需要更改意图过滤器以匹配您的标签。如果你想匹配任何 NDEF 格式的标签,你可以简单地使用 intent 过滤器:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
但是,这有一些限制:任何注册了更具体 NDEF_DISCOVERED
意图的应用程序(例如包含 MIME 类型过滤器或 URL 过滤器的应用程序)将优先于您的应用程序,您将不会收到意图。此外,有报告称不带 <data ...>
的 NDEF_DISCOVERED
intent 过滤器在某些设备上不起作用。
因此,为了匹配 MIME 类型和 URLs,您可能需要使用更具体的意图过滤器,例如为了匹配所有 text/
、image/
和 application/
MIME 类型、所有 HTTP(S) URLs 和所有 NFC 论坛外部类型:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/*" />
<data android:mimeType="image/*" />
<data android:mimeType="application/*" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="vnd.android.nfc" android:host="ext" android:pathPrefix="/" />
</intent-filter>
不过,如果其他一些应用注册了更具体的 Intent 过滤器,您的应用将不会收到任何符合这些“更具体”标准的 Intent(参见 How NFC Tags are Dispatched to Applications)。
如果您的应用还应收到关于非 NDEF 格式标签的通知,您可以使用 TECH_DISCOVERED
意图过滤器(请注意,无需为此特定意图过滤器指定任何类别)。在这种情况下,您还需要声明一个 XML 资源文件,其中包含应匹配的技术列表(声明必须在 <intent-filter ... />
元素之外!):
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
</intent-filter>
<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
您还需要 XML 资源 nfc_tech_filter.xml
(位于 res/xml/
下)。为了匹配任何标签,您可以使用:
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.NfcA</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcB</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcF</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcV</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcBarcode</tech>
</tech-list>
</resources>
最后,不要 在清单中使用 TAG_DISCOVERED
意图过滤器,除非您真的了解它的所有含义(特别是在用户体验和用户期望方面)。此 Intent 过滤器只是 API 级别 9(在 Android 2.3.3 之前)的兼容模式,其中 NFC 支持非常非常有限,并且是一种后备模式,可用于创建处理的应用程序任何其他应用程序都不支持的 NFC 标签。
检测前台应用程序中的标签
由于您写道您希望您的应用始终接收这些意图“当它处于活动状态并且您读取 NFC 标签”时,您可能需要考虑从完全显示并改用前台调度系统。在这种情况下,您的应用程序将 not 在读取 NFC 标签时启动,但它会收到 all NFC 发现事件,并且它会优先于所有 个处于前台的其他应用程序。
您可以通过简单地将其添加到您的应用程序中来做到这一点(虽然不太确定 Python 语法):
def on_pause(self):
print 'paused'
self.nfc_adapter.disableForegroundDispatch(PythonActivity.mActivity)
return True
def on_resume(self):
print 'resumed'
self.nfc_adapter.enableForegroundDispatch(PythonActivity.mActivity, self.nfc_pending_intent, None, None)
我正在尝试读取 NFC 标签,如果标签只有文本,则读取正常。但是,如果标签包含 URL 或为空,则它不起作用。我认为问题出在 nfc_filter.xml 文件上。
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="*/*" />
</intent-filter>
Python代码:
def nfc_init(self):
activity.bind(on_new_intent=self.on_new_intent)
self.j_context = context = PythonActivity.mActivity
self.nfc_adapter = NfcAdapter.getDefaultAdapter(context)
self.nfc_pending_intent = PendingIntent.getActivity(context, 0, Intent(context, context.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0)
return True
def on_new_intent(self, intent):
print 'on_new_intent()', intent.getAction()
# get TAG details
tag = cast('android.nfc.Tag', intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
details = self.get_ndef_details(tag)
def on_pause(self):
print 'paused'
return True
def on_resume(self):
print 'resumed'
我想要的是,当我的应用程序处于活动状态并且您读取了 NFC 标签时,它总是会收到意图。现在我可以在日志中看到它不会从 on_pause 恢复,以防标签包含文本以外的内容或为空。
有人可以帮我解决这个问题吗?
由于清单中的 Intent 过滤器,您的应用目前正在接收 NFC 事件:
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="*/*" />
</intent-filter>
这个 intent 过滤器有几个问题:
此意图过滤器将匹配具有意图操作
TAG_DISCOVERED
、NDEF_DISCOVERED
或TECH_DISCOVERED
、 和 [=88= 的意图] 同时包含类别 DEFAULT 或 BROWSABLE, 和 同时包含任何 (?) MIME 类型。问题是只有
NDEF_DISCOVERED
意图可能包含 MIME 类型。因此,TAG_DISCOVERED
和TECH_DISCOVERED
永远不会匹配。MIME 类型
*/*
(即匹配任何 MIME 类型)不会(不应该?)在清单意图过滤器中工作,因为只有子类型部分(即斜线)可能包含通配符 (*)。参见 android:mimeType。类别 BROWSABLE 无用,因为 NFC 意图永远不会包含该类别。
的意向NDEF_DISCOVERED
包含 URL 的标签的意图不包含 MIME 类型。由于您将NDEF_DISCOVERED
意向过滤器限制为包含 MIME 类型的意向,因此它不会匹配包含 URLs.TECH_DISCOVERED
意图过滤器需要声明技术列表 XML 文件。
因此,您需要更改意图过滤器以匹配您的标签。如果你想匹配任何 NDEF 格式的标签,你可以简单地使用 intent 过滤器:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
但是,这有一些限制:任何注册了更具体 NDEF_DISCOVERED
意图的应用程序(例如包含 MIME 类型过滤器或 URL 过滤器的应用程序)将优先于您的应用程序,您将不会收到意图。此外,有报告称不带 <data ...>
的 NDEF_DISCOVERED
intent 过滤器在某些设备上不起作用。
因此,为了匹配 MIME 类型和 URLs,您可能需要使用更具体的意图过滤器,例如为了匹配所有 text/
、image/
和 application/
MIME 类型、所有 HTTP(S) URLs 和所有 NFC 论坛外部类型:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/*" />
<data android:mimeType="image/*" />
<data android:mimeType="application/*" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="vnd.android.nfc" android:host="ext" android:pathPrefix="/" />
</intent-filter>
不过,如果其他一些应用注册了更具体的 Intent 过滤器,您的应用将不会收到任何符合这些“更具体”标准的 Intent(参见 How NFC Tags are Dispatched to Applications)。
如果您的应用还应收到关于非 NDEF 格式标签的通知,您可以使用 TECH_DISCOVERED
意图过滤器(请注意,无需为此特定意图过滤器指定任何类别)。在这种情况下,您还需要声明一个 XML 资源文件,其中包含应匹配的技术列表(声明必须在 <intent-filter ... />
元素之外!):
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
</intent-filter>
<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
您还需要 XML 资源 nfc_tech_filter.xml
(位于 res/xml/
下)。为了匹配任何标签,您可以使用:
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.NfcA</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcB</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcF</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcV</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.NfcBarcode</tech>
</tech-list>
</resources>
最后,不要 在清单中使用 TAG_DISCOVERED
意图过滤器,除非您真的了解它的所有含义(特别是在用户体验和用户期望方面)。此 Intent 过滤器只是 API 级别 9(在 Android 2.3.3 之前)的兼容模式,其中 NFC 支持非常非常有限,并且是一种后备模式,可用于创建处理的应用程序任何其他应用程序都不支持的 NFC 标签。
检测前台应用程序中的标签
由于您写道您希望您的应用始终接收这些意图“当它处于活动状态并且您读取 NFC 标签”时,您可能需要考虑从完全显示并改用前台调度系统。在这种情况下,您的应用程序将 not 在读取 NFC 标签时启动,但它会收到 all NFC 发现事件,并且它会优先于所有 个处于前台的其他应用程序。
您可以通过简单地将其添加到您的应用程序中来做到这一点(虽然不太确定 Python 语法):
def on_pause(self):
print 'paused'
self.nfc_adapter.disableForegroundDispatch(PythonActivity.mActivity)
return True
def on_resume(self):
print 'resumed'
self.nfc_adapter.enableForegroundDispatch(PythonActivity.mActivity, self.nfc_pending_intent, None, None)