NFC标签检测不会调用onNewIntent并且它是从主活动启动的

and*_*dev 11 android nfc android-beam nfc-p2p android-applicationrecord

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

我在两台设备和一台设备上安装我的应用程序,打开我的应用程序,然后开始将设备点击到另一台设备,以便通过Beam传输数据.

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

此外,它没有调用该onNewIntent()方法.我试图打电话onNewIntent给onCreate,但在那种情况下,意图行动仍然是主要的.我希望能够获得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>
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*and 28

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

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

+---------------------------------------------------------------------------------------+
| WKT:URI | http://play.google.com/store/apps/details?id=your.package.name&feature=beam |
+---------------------------------------------------------------------------------------+
| EXT:android:com:pkg | your.package.name                                               |
+---------------------------------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

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

为了在您的应用程序中接收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>
Run Code Online (Sandbox Code Playgroud)

现在,Android将识别您的应用/活动已准备好接收NFC意图并将意图传递NDEF_DISCOVERED给您的活动.请注意,onNewIntent()如果您的应用尚未运行,您仍然无法获得该意图.相反,您可以使用activity的getIntent()方法获得启动活动的意图.例如在onCreate/ onStart/ onResume,你可以使用

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
}
Run Code Online (Sandbox Code Playgroud)

获取意图和NDEF消息.

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

  1. NDEF_DISCOVERED:

    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    
    Run Code Online (Sandbox Code Playgroud)

    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" />
    
    Run Code Online (Sandbox Code Playgroud)

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

  3. TAG_DISCOVERED:

    <intent-filter>
        <action android:name="android.nfc.action.TAG_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
    
    Run Code Online (Sandbox Code Playgroud)

    通常不应在清单中使用此意图过滤器.它意味着如果没有其他应用程序可能处理检测到的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);
Run Code Online (Sandbox Code Playgroud)

这样,您将收到活动在您的活动onNewIntent方法中处于前台时发生的任何NFC发现事件.他们将通过ACTION_TAG_DISCOVERED意图发送.