使用HCE将位图从一个设备传输到另一个设备(Android 4.4+)

时间:2015-04-16 08:19:26

标签: android nfc ndef hce

我正在尝试使用HCE将图像从一个设备发送到另一个设备(一个设备处于卡仿真模式,另一个设备处于读卡器模式)。我能够发送一个字符串,但不能发送图像。在读者方面,我总是将TAG作为null

非常感谢你的帮助,谢谢。

HCE方(标签方/发件人):

   private final static byte[] SELECT_APP = new byte[] { (byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xd2, (byte)0x76, (byte)0x00, (byte)0x00, (byte)0x85, (byte)0x01, (byte)0x01, (byte)0x00, };
private final static byte[] SELECT_CC_FILE = new byte[] { (byte)0x00, (byte)0xa4, (byte)0x00, (byte)0x0c, (byte)0x02, (byte)0xe1, (byte)0x03, };
private final static byte[] SELECT_NDEF_FILE = new byte[] { (byte)0x00, (byte)0xa4, (byte)0x00, (byte)0x0c, (byte)0x02, (byte)0xe1, (byte)0x04, };

private final static byte[] SUCCESS_SW = new byte[] { (byte)0x90, (byte)0x00, };
private final static byte[] FAILURE_SW = new byte[] { (byte)0x6a, (byte)0x82, };

private final static byte[] CC_FILE = new byte[] {
        0x00, 0x0f, // CCLEN
        0x20, // Mapping Version
        0x00, 0x3b, // Maximum R-APDU data size
        0x00, 0x34, // Maximum C-APDU data size
        0x04, 0x06, // Tag & Length
        (byte)0xe1, 0x04, // NDEF File Identifier
        0x00, 0x32, // Maximum NDEF size
        0x00, // NDEF file read access granted
        (byte)0xff, // NDEF File write access denied
};

public void onCreate() {
    super.onCreate();

    mAppSelected = false;
    mCcSelected = false;
    mNdefSelected = false;

    Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.transferimage1);
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    mBitmap.compress(Bitmap.CompressFormat.JPEG, 80, stream);
    byte[] byteArray = stream.toByteArray();
    NdefRecord picRecord = NdefRecord.createMime("image/jpeg", byteArray);
    NdefMessage ndefMessage  = new NdefMessage(new NdefRecord[] { picRecord });

    int nlen = ndefMessage.getByteArrayLength();  // <- this is 164906

    mNdefRecordFile = new byte[nlen + 2];

    mNdefRecordFile[0] = (byte)((nlen & 0xff00) / 256);
    mNdefRecordFile[1] = (byte)(nlen & 0xff);
    System.arraycopy(ndefMessage.toByteArray(), 0, mNdefRecordFile, 2, ndefMessage.getByteArrayLength());
}

@Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
    if (Arrays.equals(SELECT_APP, commandApdu)) {
        mAppSelected = true;
        mCcSelected = false;
        mNdefSelected = false;
        return SUCCESS_SW; 
    } else if (mAppSelected && Arrays.equals(SELECT_CC_FILE, commandApdu)) {
        mCcSelected = true;
        mNdefSelected = false;
        return SUCCESS_SW; 
    } else if (mAppSelected && Arrays.equals(SELECT_NDEF_FILE, commandApdu)) {
        mCcSelected = false;
        mNdefSelected = true;
        return SUCCESS_SW; 
    } else if (commandApdu[0] == (byte)0x00 && commandApdu[1] == (byte)0xb0) {
        int offset = (0x00ff & commandApdu[2]) * 256 + (0x00ff & commandApdu[3]);
        int le = 0x00ff & commandApdu[4];
        byte[] responseApdu = new byte[le + SUCCESS_SW.length];

        if (mCcSelected && offset == 0 && le == CC_FILE.length) {
            System.arraycopy(CC_FILE, offset, responseApdu, 0, le);
            System.arraycopy(SUCCESS_SW, 0, responseApdu, le, SUCCESS_SW.length);

            return responseApdu;
        } else if (mNdefSelected) {
            if (offset + le <= mNdefRecordFile.length) {
                System.arraycopy(mNdefRecordFile, offset, responseApdu, 0, le);
                System.arraycopy(SUCCESS_SW, 0, responseApdu, le, SUCCESS_SW.length);

                return responseApdu;
            }
        }
    }

    return FAILURE_SW;
}

@Override
public void onDeactivated(int reason) {
    mAppSelected = false;
    mCcSelected = false;
    mNdefSelected = false;
}

阅读器模式应用(阅读器端/接收器):

@Override
public void onTagDiscovered(Tag tag) {
    Ndef ndef = Ndef.get(tag);  // <- this returns null
    NdefMessage message;

    if (ndef != null) {
        message = ndef.getCachedNdefMessage();  // <- cannot get NDEF message as ndef is null
    } else {
        return;
    }
   }

1 个答案:

答案 0 :(得分:0)

您对模拟Type 4标记的实现存在一些问题:

  1. 功能容器将NDEF文件的最大大小定义为50个字节(0x00, 0x32)。但是,您在NDEF文件中使用的实际长度值(前两个字节)要大得多:

    int nlen = ndefMessage.getByteArrayLength();         // -> 164906
    mNdefRecordFile[0] = (byte)((nlen & 0xff00) / 256);  // -> 0x84
    mNdefRecordFile[1] = (byte)(nlen & 0xff);            // -> 0x2A
    

    请注意,实际长度会被截断为0x842A(参见下一个)!

  2. 对于映射版本为2.0的Type 4标记,使用大于最大可能NDEF大小的NDEF消息。由于READ BINARY命令的格式,在Type 4标记(映射版本2.0)上可寻址的NDEF消息的最大大小为33022字节(0x80FE)。因此,此标记类型不支持您的NDEF消息。

  3. 您应该期望读者只读取功能容器文件的一部分(与NDEF文件的方式类似)。目前,您只允许偏移量为0且长度为0x0F的读取操作。

  4. 如果READ BINARY命令失败(当前返回“找不到文件”),则返回正确的状态字。

  5. 即使没有Le字段,您也可能希望接受SELECT(按AID)命令。