【问题标题】:Reading multiple NFC-tags in Android. IsoDep-tag wont read while screen is unlocked在 Android 中读取多个 NFC 标签。屏幕解锁时不会读取 IsoDep-tag
【发布时间】:2013-12-20 07:21:17
【问题描述】:

我一直在尝试创建一个可以读取两种不同类型 NFC 标签的应用。一个应该是 HCE-IsoDep,在 Nexus 5 上模拟,一个是 Ndef-tag。但是我遇到了一个小问题:

我设法阅读了这两种类型的标签,但不是我想要的方式。 Ndef 标签完全没有问题。当我尝试读取 HCE 标签时,我遇到了问题。我只能在手机开机时读取标签,我模拟标签被锁定(屏幕打开,但锁定)。每当我解锁屏幕时,它就不会再进行交互了,据我所知,它会尝试发射。

如果我尝试在没有onNewIntent 的情况下执行此操作并直接转到onTagDiscovered,则它在 HCE 设备被锁定和解锁时都可以工作,但是我无法读取 Ndef 标记。 在 logcat 中,我收到消息:NfcService LLCP Activation Message,当我在解锁时读取 HCE-tag。

锁定后我收到消息:NativeNfcTag Connect to a tag with a different handle(在此之前我收到:audio_hw_primary select_devices: out_snd_device(2: speaker) in_snd_device(0: )

我的代码如下:

主要:

public class NfcReader extends Activity implements OnMessageReceived {

private static String TAG = NfcReader.class.getSimpleName();

private Button sendButton;
private ProgressBar callProgress;


private NfcAdapter nfcAdapter;
private PendingIntent pIntent;
private IntentFilter[] writeTagFilters;
private String[][] mTechLists;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TextView dateView = (TextView) findViewById(R.id.dateTextView);

    nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    pIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

    IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
    writeTagFilters = new IntentFilter[] { tagDetected };

    mTechLists = new String[][] {new String[] {
            Ndef.class.getName(),
            IsoDep.class.getName()
    }};
}

@Override
protected void onPause() {
    super.onPause();
    disableForegroundMode();
}

@Override
protected void onResume() {
    super.onResume();
    enableForegroundMode();
}

public void enableForegroundMode() {
    Log.d(TAG, "onResume");
    nfcAdapter.enableForegroundDispatch(this, pIntent, writeTagFilters, mTechLists);
}

public void disableForegroundMode() {
    Log.d(TAG, "onPause");
    nfcAdapter.disableForegroundDispatch(this);
}

@Override
public void onNewIntent(Intent intent) {
    Log.d(TAG, "onNewIntent");

    if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())){

        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        Ndef nDef = Ndef.get(tag);

        if (nDef != null) {
            onNdefDiscovered(tag);
        }
        else {
            onTagDiscovered(tag);
        }
    }
}

public void onNdefDiscovered(Tag tag) {
    Log.d(TAG, "Ndef found");
    new ReadTag().execute(tag);
}

public void onTagDiscovered(Tag tag) {
    Log.d(TAG, "HCEfound"); 
    IsoDep isoDep = IsoDep.get(tag);
    IsoDepTransceiver transceiver = new IsoDepTransceiver(isoDep, this);
    transceiver.run();

}

@Override
public void onMessage(final byte[] message) {
    runOnUiThread(new Runnable() {

        @Override
        public void run() {
            String readFromHce = new String(message);
            TextView result = (TextView) findViewById(R.id.refTextView);
            result.setText(readFromHce);

        }
    });
}

@Override
public void onError(Exception exception) {
    onMessage(exception.getMessage().getBytes());
}
}

清单:

<uses-sdk
    android:minSdkVersion="19"
    android:targetSdkVersion="19" />

<uses-permission 
    android:name="android.permission.INTERNET" />

<uses-permission 
    android:name="android.permission.NFC" />

<uses-feature
    android:name="android.hardware.nfc"
    android:required="true" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
    <activity
        android:name=".HceReader"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
            <action android:name="android.nfc.action.TECH_DISCOVERED"/>
            <action android:name="android.nfc.action.TAG_DISCOVERED" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>

        <meta-data
            android:name="android.nfc.action.TECH_DISCOVERED"
            android:resource="@xml/filter_nfc"/>

filter_nfc.xml

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">

    <tech-list>
        <tech>android.nfc.tech.IsoDep</tech>
    </tech-list>

    <tech-list>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
</resources>

有人知道我做错了什么吗?我已经搜索了很多,但没有找到解决方案。 再说一遍。我可以毫无问题地阅读 Ndef 标记。当 HCE 设备上的屏幕被锁定时,我只能读取模拟的 IsoDep-tag。

感谢您的帮助
问候

编辑:下面的代码正在运行

public class NfcReader extends Activity implements OnMessageReceived, ReaderCallback {

private static String TAG = NfcReader.class.getSimpleName();

private NfcAdapter nfcAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    TextView result = (TextView) findViewById(R.id.refTextView);

    nfcAdapter = NfcAdapter.getDefaultAdapter(this);
}

@Override
protected void onPause() {
    super.onPause();
    nfcAdapter.disableReaderMode(this);
}

@Override
protected void onResume() {
    super.onResume();
    nfcAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A, null);
}

public void onTagDiscovered(Tag tag) {
    Log.d(TAG, "Tag Found"); 

    Ndef nDef = Ndef.get(tag);
    IsoDep isoDep = IsoDep.get(tag);

    if (nDef != null) {
        new ReadTag().execute(tag);
    }
    else if (isoDep != null){
        IsoDepTransceiver transceiver = new IsoDepTransceiver(isoDep, this);
        transceiver.run();      
    }
}

@Override
public void onMessage(final byte[] message) {
    runOnUiThread(new Runnable() {

        @Override
        public void run() {
            String readFromHce = new String(message);
            TextView result = (TextView) findViewById(R.id.refTextView);
            result.setText(readFromHce);
        }
    });
}

@Override
public void onError(Exception exception) {
    onMessage(exception.getMessage().getBytes());
}
}

非常感谢 NFC 专家的提示。

【问题讨论】:

    标签: android nfc hce


    【解决方案1】:

    在 Android 4.4 及更高版本上,您应该为此使用 enableReaderMode()

    在此模式下,NFC 控制器将仅充当 NFC 标签读取器/写入器,因此禁用此设备上 NFC 适配器的任何点对点 (Android Beam) 和卡模拟模式。

    为了与使用 Android 的基于主机的卡模拟在另一台 Android 设备上模拟的标签进行交互,推荐的标志是 FLAG_READER_NFC_A 和 FLAG_READER_SKIP_NDEF_CHECK。

    【讨论】:

    • 感谢您的回答。我知道这是我在早期阶段使用它时使用的。但是我当时没有成功实现 Ndef 阅读。我会再看一遍。
    • 你可能想省略标志 FLAG_READER_SKIP_NDEF_CHECK。
    • 这成功了!一切都按照我想要的方式工作,作为奖励,我得到的代码更少:)
    【解决方案2】:

    你没有做错什么。不幸的是,您尝试做的事情不会奏效。

    如果您的手机同时运行卡模拟和点对点(Android Beam),并且读卡器(您的另一部手机)也支持点对点,点对点技术将优先于卡片模拟

    如果您考虑一下,这非常有意义:如果您将启用 NFC 的 SIM 卡放入手机中,您将运行一些基于 SIM 的脱离主机卡仿真。如果点对点不优先于卡模拟,android beam 将停止工作,您将看到与 IsoDep 标签的连接。

    在您的电话被锁定的情况下,点对点将被禁用,卡模拟将获得优先权。因此,您可以在此状态下访问卡仿真。

    如果您想在屏幕解锁状态下访问卡模拟,您唯一的选择是使用不激活点对点协议的读卡器设备(例如独立的支付终端)。

    在 Android 上,无法禁用点对点。在设置中禁用 Android Beam 也无济于事,因为只会禁用高级 Beam 协议。点对点协议仍将运行以主动阻止您看到其他人的卡模拟。这种行为是有意的,因为出于安全原因,Google 不希望人们意外访问支付卡模拟。

    【讨论】:

    • 你的回答很有道理。但我想知道为什么当我不使用 onNewIntent 函数而是直接使用 onTagDiscovery 时它会起作用。我可以在另一台设备上扫描来自 Nexus 5 的模拟标签,而无需在模拟设备上解锁时激活光束功能。我的想法是整个“pendingIntent”部分将确保我的活动会覆盖它。不过我显然错了。
    • 与API19一起引入了两个新方法:enableReaderMode()disableReaderMode()也许这可以帮助模拟手机保持在模拟模式。
    猜你喜欢
    • 2013-05-24
    • 2015-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多