Search code examples
androidandroid-intentmime-typesnfcmifare

How do you create an application-specific intent filter for a Mifare card? (Android)


How would you open your application directly using an intent filter when using the NFC service with a Mifare card? I know that you can use an intent filter using a specific mimeType directly for a P2P Connection like

<data android:mimeType="application/com.sticknotes.android"/>

I'm just not sure how I'd set up the sectors of a Mifare1K to do the same thing. Anybody have any ideas on how to do this? Or am I just limited to having the application chooser pop-up?

I suppose I could create a completely separate activity to handle passive tags versus active devices but is there any way to handle this all in one activity??


Solution

  • If your app already has an intent filter for the MIME type "application/com.sticknotes.android" that works with Android Beam (P2P connection), then it will also work with tags that contain and NDEF message with the same MIME type. Android Beam and tag discovery both generate an ACTION_NDEF_DISCOVERED intent in the receiving/reading device.

    To write such an NDEF message to a MIFARE Classic 1K tag, you can create a simple app that does that for you. In this app's manifest file put:

    <activity>
    ...
    <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" />
    ...
    </activity>
    

    And in project's res/xml folder put a file nfc_tech_filter.xml with the following contents:

    <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
      <tech-list>
        <tech>android.nfc.tech.MifareClassic</tech>
      </tech-list>
    </resources>
    

    In the app's Activity put:

    onCreate(Bundle savedInstanceState) {
      // put code here to set up your app
      ...
    
      // create NDEF message
      String mime = "application/com.sticknotes.android";
      byte[] payload = ... ; // put your payload here
      NdefRecord record = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, mime.toBytes(), null, payload);
      NdefMessage ndef = new NdefMessage(new NdefRecord[] {ndef});
    
      // write NDEF message
      Intent intent = getIntent();
      if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()) {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        NdefFormatable nf = NdefFormatable.get(tag);
        if (nf != null) {
          // tag not yet formatted with NDEF
          try {
            nf.connect();
            nf.format(ndef);
            nf.close();
          } catch (IOException e) {
            // tag communication error occurred
          }
        } else {
          Ndef n = Ndef.get(tag);
          if (n != null && n.isWritable() ) {
            // can write NDEF
            try {
              n.connect();
              n.writeNdefMessage(ndef);
              n.close();
            } catch (IOException e) {
              // tag communication error occurred
            }
          }
        }
      }
    }
    

    This formats and writes an NDEF message to unformatted (blank) MIFARE Classic tags or overwrites tags that are already formatted with NDEF. If you want to write other tag types besides MIFARE Classic ones, adjust nfc_tech_filter.xml accordingly.