简体   繁体   中英

Android app auto launch the particular activity by tapping nfc tag

I want to launch the app's particular activity by tapping the nfc tag. I can able to write only package name. but along with package name, i want to add one string and based on the string, i want to launch the activity.

So there is a more standard way for static and dynamic mapping of tag data to activity and a better way for static mapping.

The better way for static mapping is your Tag needs to have an AAR Record on the Tag and then another NDEF Record with a custom mimetype with the String encoded in to the mimeType (content of the NDEF record does not matter). (see https://developer.android.com/reference/android/nfc/NdefRecord#createMime(java.lang.String,%20byte[]) on how to create mimeType NDEF records)
This is a better way because you can use the manifest Intent filters to guide Android OS to which activity to start.

eg
Tag A which is to start "Activity A" has an AAR record for you App and a NDEF record with mimeType "my-app/activity-a"
Tag B which is to start "Activity B" has an AAR record for you App and a NDEF record with mimeType "my-app/activity-b"

Your manifest would then look like :-

<activity
  android:name=".MainActivity">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
     <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity>
<activity
  android:name=".ActivityA">
  <intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="my-app/activity-a" />
  </intent-filter>
</activity>
<activity
  android:name=".ActivityB">
  <intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="my-app/activity-b" />
  </intent-filter>
</activity>

All Activities must handle Tag reading with enableForegroundDispatch (or the better enableReaderMode ) and read the mimeType of the record and then StartActivity based on the custom mimeType of the Tag to start the right Activity. (You might be able to get the Android OS to do this for you with all your Activities having launch mode of "singleTask" but I'm not sure this will work correctly for you)

So then there are a number of scenarios to handle

  1. No App installed - AAR Record on the Tag will cause Android to open the Play Store to prompt the user to install your App. Once your App is installed the Tag needs to go out of range and enter range again to Trigger Android OS to read it again and Trigger scenario 2

  2. App already installed - The custom mimeType on the Tag will cause Android to start the matching activity.

  3. The App is already running - enableForegroundDispatch (or the better enableReaderMode ) will read the Tag's custom mimeType and switch to the right Activity based on the mimeType read.

Note I've not personally tried using multiple custom mimeTypes, I've only needed a single custom mimeType.

Updated:

The standard way is your Tag needs to have an AAR Record on the Tag as well as an NDEF Text Record with your String in it or you could use a custom mimeType with createMime as this stops Android from asking which NFC App to launch if there are other NFC Apps that also handle NDEF Text Records (they are less likely to handle your custom mimeType)

Then a combination of AAR record on the Tag and Intent filters in the application manifest and Handling an initial Intent in Main Activity and enableForegroundDispatch (or the better enableReaderMode ) with one Activity that reads the Text or custom mimeType NDEF message and then launches the correct Activity based on the text string directly or as using it to look up which Activity to launch.

Example using a custom mimeType with Dynamic lookup. Your manifest would then look like :-

<activity
  android:name=".MainActivity">
  <intent-filter>
     <action android:name="android.intent.action.MAIN" />
     <category android:name="android.intent.category.LAUNCHER" />
     <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
     <category android:name="android.intent.category.DEFAULT"/>
     <data android:mimeType="my-app/text" />
  </intent-filter>
</activity>

Main Activity using enableForegroundDispatch


....
private NfcAdapter adapter;

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent mIntent = getIntent();

        // Check to see if the App was started because of the Intent filter in the manifest, if yes read the data from the Intent
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
          handleIntent(intent);
        }

        // Show other stuff here for Manual App start from Icon
        // Which could be just start the Default other Activity
    }

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    // Check intent is from NFC NDEF from foregroundDispatch
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
      handleIntent(intent);
    }
}

public void onResume() {
    super.onResume();
    pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
            getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
    IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
    try {
        // Only look for custom mimeType
        ndef.addDataType("my-app/text");
    }
    catch (MalformedMimeTypeException e) {
        throw new RuntimeException("fail", e);
    }
    intentFiltersArray = new IntentFilter[] {ndef, };

    adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, null);
}

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

}

private void handleIntent(Intent intent) {

  Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    if ((rawMessages != null) && (rawMessages.length > 0)) {
        ndefMessage = (NdefMessage)rawMessages[0];
    }
    NdefRecord firstRecord = ndefMessage.getRecords()[0];
    String payload = firstRecord.getPayload();
    // Dynamically Lookup Activity to start
    int activityId = lookup(payload);
    // Start the right Activity
    Intent intent;
    switch (activityId) {
      case 0:
         intent = new Intent(this, ActivityA.class);
      case 1:
         intent = new Intent(this, ActivityB.class);
     }
     startActivity(intent);

}

The onPause , onResume , onNewIntent and handleIntent should be in all activities, so that if a card is presented during these then the correct activity is started.

So then there are a number of scenarios to handle

  1. No App installed - AAR Record on the Tag will cause Android to open the Play Store to prompt the user to install your App. Once your App is installed the Tag needs to go out of range and enter range again to Trigger Android OS to read it again and Trigger scenario 2

  2. App already installed - The custom mimeType on the Tag will cause Android to start the Main activity with will read the payload and start the correct Activity.

  3. The App is already running - enableForegroundDispatch (or the better enableReaderMode ) will read the Tag's custom mimeType and payload String and switch to the right Activity based on the mimeType read.

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