12

我是 NFC 新手。我尝试连接到 NFC 并将文本数据从一个设备共享到另一个设备。

我在两台设备上都安装了我的应用程序,在一个设备上我打开我的应用程序并开始将设备连接到另一台设备,以便通过 Beam 传输数据。

在另一台设备上,我的应用程序由于 Beam 交互而打开。但是,活动是使用默认的 MAIN 意图操作而不是 TAG_DISCOVERED(或类似的 NFC 意图)启动的。每次它都做同样的事情。

此外,它没有调用该onNewIntent()方法。我试图调用onNewIntentfrom onCreate,但在这种情况下,意图操作仍然是 MAIN 。我希望收到 Beam 交互的 NFC 意图。那么你能告诉我我哪里出错了吗?

在此代码中,我不共享数据。我只需要标签。

显现:

<activity android:name="com.framentos.hellonfc.MainActivity"
        android:clearTaskOnLaunch="true"
        android:label="@string/app_name"
        android:launchMode="singleTop"
        android:screenOrientation="portrait" >
        <intent-filter>
            <action android:name="android.nfc.action.NDEF_DISCOVERED" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.nfc.action.TECH_DISCOVERED" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.nfc.action.TAG_DISCOVERED" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <meta-data
            android:name="android.nfc.action.TECH_DISCOVERED"
            android:resource="@xml/nfc_tech_filter" />
</activity>

Java代码:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    ctx = this;
    // startHandler();
    _handler = new Handler();
    Button btnWrite = (Button) findViewById(R.id.button);
    message = (TextView) findViewById(R.id.nfcwriteTag);
    btnWrite.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

        }
    });
    adapter = NfcAdapter.getDefaultAdapter(this);
    if (adapter == null) {
        message.setText("NFC is not supported on this device.");
    }
    if (adapter.isEnabled()) {
        message.setText("NFC is Enabled on this device.");
    } else {
        message.setText("Please enable NFC to communicate.");
    }
    pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
            getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
    IntentFilter tagDetected = new IntentFilter(
            NfcAdapter.ACTION_NDEF_DISCOVERED);
    tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
    IntentFilter tagTech = new IntentFilter(
            NfcAdapter.ACTION_TECH_DISCOVERED);
    tagTech.addCategory(Intent.CATEGORY_DEFAULT);
    IntentFilter tagDetect = new IntentFilter(
            NfcAdapter.ACTION_TAG_DISCOVERED);
    tagDetect.addCategory(Intent.CATEGORY_DEFAULT);
    writeTagFilters = new IntentFilter[] { tagDetected, tagTech ,tagDetect};
    // handleIntent(getIntent());
}


@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    Log.i(getPackageName(), "on New Intent is called...!");
    handleIntent(getIntent());
}

public void onPause() {
    super.onPause();
    WriteModeOff();
}

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

private void WriteModeOn() {
    writeMode = true;
    adapter.enableForegroundDispatch(this, pendingIntent, writeTagFilters,
            null);
}

private void WriteModeOff() {
    writeMode = false;
    adapter.disableForegroundDispatch(this);
}
4

1 回答 1

32

根据您在问题中发布的代码,我假设您没有注册您的应用程序来发送特定的 NDEF 消息。在这种情况下,如果您的应用程序在一台设备上打开,Android 将自动将包含 URI 记录的 NDEF 消息与您的应用程序的 Play 商店链接和 Android 应用程序记录 (AAR) 发送到另一台设备。

因此,您的第二台设备将收到以下 NDEF 消息:

+---------------------------------------------------------------------------------------+
| WKT:URI | http://play.google.com/store/apps/details?id=your.package.name&feature=beam |
+---------------------------------------------------------------------------------------+
| EXT:android:com:pkg | your.package.name                                               |
+---------------------------------------------------------------------------------------+

如果您的应用程序尚未在第二台设备上打开,现在会发生什么,Android 应用程序记录(第二条记录)将强制您的应用程序启动。但是,查看您的清单,您没有与此 NDEF 消息的第一条记录(Play Store URL)匹配的意图过滤器。因此,Android 认为您不希望收到 NDEF 消息并使用标准android.intent.action.MAIN(使用 category )来启动您的应用程序(或者更确切地说,您的应用程序的第一个 Activity 具有用于使用 categoryandroid.intent.category.LAUNCHER操作的意图过滤器)。MAINLAUNCHER

为了在您的应用程序中接收 NFC 意图和整个 NDEF 消息,您需要定义一个与上述 NDEF 消息中的第一条记录匹配的适当意图过滤器:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="http"
          android:host="play.google.com"
          android:pathPrefix="/store/apps/details?id=your.package.name" />
</intent-filter>

现在,Android 将识别您的应用程序/活动已准备好接收 NFC 意图并将意图传递NDEF_DISCOVERED给您的活动。onNewIntent()请注意,如果您的应用尚未运行,您仍然不会收到该意图。相反,您可以使用活动的getIntent()方法获取启动活动的意图。例如在onCreate// onStartonResume你可以使用

Intent intent = getIntent();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
    NdefMessage ndefMessage = null;
    Parcelable[] rawMessages = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    if ((rawMessages != null) && (rawMessages.length > 0)) {
        ndefMessage = (NdefMessage)rawMessages[0];
    }

    // TODO: do something with the received NDEF message
}

获取意图和 NDEF 消息。

关于清单中已有的意图过滤器:

  1. NDEF_DISCOVERED

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

    没有标签的NDEF_DISCOVERED意图过滤器<data ... />永远不会在许多 NFC 设备上触发。您应该始终定义您希望在启动 NDEF 记录中出现的特定数据。

  2. TECH_DISCOVERED

    <intent-filter>
        <action android:name="android.nfc.action.TECH_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
               android:resource="@xml/nfc_tech_filter" />
    

    如果您不想在检测到某种 NFC 标签技术时启动应用程序(您在nfc_tech_filter.xml文件中定义特定技术。对于您的 Beam 场景,您不会使用这样的意图过滤器。顺便说一句,您应该只使用此意图过滤器。顺便说一句. 该<category ...>标签不用于此意图过滤器。

  3. TAG_DISCOVERED

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

    通常不应在清单中使用此意图过滤器。这意味着如果没有其他应用程序可能处理检测到的 NFC 标签,则会触发回退。使用它可能会导致糟糕的用户体验(例如,您的应用程序正在启动它不能或实际上不想处理的标签)。它主要用于向后兼容 API 级别 9 (?)。

如果您的活动已经开始,为了也捕获 NFC 意图,您可以像这样注册前台调度(在onResume方法中):

PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
nfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null);

这样,您将在 Activity 的onNewIntent方法中接收在您的 Activity 处于前台时发生的任何 NFC 发现事件。它们将通过ACTION_TAG_DISCOVERED意图发送。

于 2014-04-03T15:36:06.723 回答