如何在Kivy + Python中阅读NFC标签?

时间:2016-06-21 19:34:04

标签: android python nfc kivy ndef

我试图阅读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恢复,以防标签包含除文本以外的内容或为空。

有人可以帮我这个吗?

1 个答案:

答案 0 :(得分:3)

由于清单中的意图过滤器,您的应用当前会收到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>

此意图过滤器存在一些问题:

  1. 此意图过滤器将匹配具有意图操作TAG_DISCOVEREDNDEF_DISCOVEREDTECH_DISCOVERED的意图,同时包含类别DEFAULT或BROWSABLE,同时包含任何(?)MIME类型。

    这个问题是只有NDEF_DISCOVERED意图可能包含MIME类型。因此,TAG_DISCOVEREDTECH_DISCOVERED永远不会匹配。

  2. MIME类型*/*(即匹配任何MIME类型)赢了(不应该?)在清单意图过滤器中工作,因为只有子类型部分(即斜杠之后的部分)可能包含通配符(*)。请参阅android:mimeType

  3. BROWSABLE类别无用,因为任何NFC意图都不会包含该类别。

  4. 包含网址的广告代码的
  5. NDEF_DISCOVERED意图不包含MIME类型。由于您将NDEF_DISCOVERED意图过滤器限制为包含MIME类型的意图,因此它不会匹配包含URL的意图。

  6. TECH_DISCOVERED意图过滤器需要声明技术列表XML文件。

  7. 因此,您需要更改intent过滤器以匹配您的标记。如果要匹配任何NDEF格式的标记,只需使用intent过滤器:

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

    但是,这有一些限制:任何注册了更具体的NDEF_DISCOVERED意图的应用(例如,包含MIME类型过滤器或网址过滤器的应用)将优先于您的应用,并且您赢得了#39 ;收到意图。此外,有报告称NDEF_DISCOVERED意图过滤器<data ...>在某些设备上无效。

    因此,为了匹配MIME类型和网址,您可能需要使用更具体的意图过滤器,例如为了匹配所有text/image/application/ MIME类型,所有HTTP(S)网址以及所有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>
    

    尽管如此,如果某个其他应用注册了更具体的意图过滤器,那么您的应用就不会收到任何符合这些意图的意图&#34;更具体的&#34;标准(见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标签的应用程序。其他应用程序。

    检测前台应用中的标签

    由于您写道,您希望您的应用始终接收这些意图&#34; 当它处于活动状态并且您阅读NFC标记&#34;时,您可能需要考虑删除意图从清单中完全过滤并使用前台调度系统。在这种情况下,当您读取NFC标签时,您的应用会启动,但它会接收所有 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)