Android / NFC: Get Tag in onCreate() without new I

2019-01-18 17:15发布

问题:

I am working on an NFC-application. To start my app, I am using a NDEF-tag with an AAR NDEF Record inside.

This works fine. But now I want to read the tag content with the app directly. How can I do this?

(It already works, when I remove the tag from the phone and touch it again, but I want to eliminate this step.)

Update: Some more details Ok, to make it more clear, here are some parts of my current code.

private NfcAdapter nfcAdapter;
private static final int PENDING_INTENT_TECH_DISCOVERED = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_l);
    text_output = (TextView) findViewById(R.id.textView2);

    NfcAdapter adapter = ((NfcManager) getSystemService(Context.NFC_SERVICE))
            .getDefaultAdapter();       
}

@Override
public void onResume() {
    super.onResume();

    nfcAdapter = ((NfcManager) this.getSystemService(Context.NFC_SERVICE))
            .getDefaultAdapter();

    PendingIntent pi = createPendingResult(PENDING_INTENT_TECH_DISCOVERED,
            new Intent(), 0);

    nfcAdapter.enableForegroundDispatch(this, pi,
            new IntentFilter[] { new IntentFilter(
                    NfcAdapter.ACTION_TECH_DISCOVERED) }, new String[][] {
                    new String[] { "android.nfc.tech.NdefFormatable" },
                    new String[] { "android.nfc.tech.Ndef" } });
} 

@Override
public void onPause() {
    super.onPause();
    nfcAdapter.disableForegroundDispatch(this);
}

@Override
protected void onActivityResult(int requestCode, int resultCode,
        final Intent data) {
    switch (requestCode) {
    case PENDING_INTENT_TECH_DISCOVERED:
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                doTagOperation(data);
            }
        };
        new Thread(runnable).start();

        break;
    }
}

private void doTagOperation(Intent data) {

    try {           
        String action = data.getAction();
        if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {

            Tag tag = data.getParcelableExtra(NfcAdapter.EXTRA_TAG);                                
            Ndef ndefTag = Ndef.get(tag);
        }
    } catch (Exception ex) {
                ...
    }
}

To start the app I use an AAR-NDEF-Record on the tag, which can be created in this way: NdefRecord ndr = NdefRecord.createApplicationRecord("com.example.something");

So what I want is: Touch the tag when the app is not started makes the app starting (works already) and then it should directly read the tag without the need of moving the phone away from the tag and touch it again.

回答1:

If you want to receive the NDEF discovery intent upon the start of your activity, you need to add an intent filter that triggers on the tag's NDEF message to your application manifest:

<activity ... >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

I guess you already have the above, so you will need to add an NDEF intent filter:

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

You can use either a URI based trigger:

        <data android:scheme="http" android:host="mroland.at" android:pathPrefix="/test" />

Or a MIME based scheme:

        <data android:mimeType="application/vnd.mroland.test" />

Or if you want to receive the NDEF discovered intent for a tag that contains only an AAR (I have to admit that I never tested this so I only assume that this should work):

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

But you have to use one of them. (At least on most devices you have to. Some devices/Android versions will accept the intent filter even without a data element.)

    </intent-filter>
</activity>

You can then get the intent in onCreate(), onStart(), onResume() or wherever you want to read it using the getIntent() method.

Note that if you don't add an intent filter for NDEF_DISCOVERED to your manifest, an NDEF message with an AAR for your application will cause the intent action MAIN with the category LAUNCHER to be passed to your first activity that declares such an intent filter. In that case you will not receive the NDEF message. So if you want to receive the NDEF message you have to to declare an intent filter for NDEF_DISCOVERED. In that case, you can choose which activity is started by the AAR by setting the NDEF_DISCOVERED intent filter for that specific activity.



回答2:

You need to use the onNewIntent() method as discussed in the documentation. The onCreate() method should contain the setup code that you currently have in onResume(). This will cause the app to work in all cases.

From the Android documentation (http://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc.html):

public void onPause() {
    super.onPause();
    mAdapter.disableForegroundDispatch(this);
}

public void onResume() {
    super.onResume();
    mAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
}

public void onNewIntent(Intent intent) {
    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    //do something with tagFromIntent
}