We have a financial application where we want to use NFC to broadcast a Payment URL to another iPhone or Android device when initiating a payment transaction. This will then open the banking application installed on the recipient’s device, allowing the transaction to be completed.
We have already made the necessary requests to Apple and configured the entitlements file as follows:
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.nfc.hce</key>
<true/>
<key>com.apple.developer.nfc.hce.iso7816.select-identifier-prefixes</key>
<array>
<string>D2760000850101</string>
</array>
<key>com.apple.developer.nfc.readersession.formats</key>
<array>
<string>TAG</string>
<string>NDEF</string>
</array>
</dict>
I've tried to use CardSession with the sample code provided by Apple on their site: Card Session
The connection between the devices (two iPhones, OS is above iOS 17.4) is established, the event stream's case .received(let cardAPDU):
works, however, when I send the response, nothing really happens
Initial APDU response:
CLA | 0x00
INS | 0xA4
P1 | 0x04
P2 | 0x00
DATA | 0x7D2760000850101 (guess this is the AID)
Le | 00
Sending the apdu response in the event stream via:
do {
guard let request = APDUUtil.createAPDURequest(from: paymentUrl) else { return }
try await cardAPDU.respond(response: request)
await cardSession.stopEmulation(status: .success)
}
static func createAPDURequest(from paymentUrl: URL?) -> Data? {
guard let paymentUrl else { return nil }
let ndefMessage = APDUUtil.createNDEFMessage(from: paymentUrl)
APDUUtil.updateNdefRecordFile(ndefMessage: ndefMessage)
let data = Data(mNdefRecordFile)
let apdu = NFCISO7816APDU(instructionClass: 0x00,
instructionCode: 0xA4,
p1Parameter: 0x04,
p2Parameter: 0x00,
data: data,
expectedResponseLength: -1) // Tried with different values
return apdu.data
}
static func createNDEFMessage(from url: URL?) -> NFCNDEFMessage? {
guard let url,
let payload = NFCNDEFPayload.wellKnownTypeURIPayload(url: url) else {
return nil
}
return NFCNDEFMessage(records: [payload])
}
static func updateNdefRecordFile(ndefMessage: NFCNDEFMessage?) {
guard let ndefMessage else {
return
}
// Convert the NFCNDEFMessage to Data
let ndefMessageData = ndefMessage.records.reduce(Data()) { result, record -> Data in
var result = result
result.append(record.payload)
return result
}
let nlen = ndefMessageData.count
mNdefRecordFile = [UInt8](repeating: 0, count: nlen + 2)
// Store the length in the first two bytes (big-endian format)
mNdefRecordFile[0] = UInt8((nlen & 0xFF00) >> 8)
mNdefRecordFile[1] = UInt8(nlen & 0xFF)
// Copy the NDEF message data into the data starting at index 2
mNdefRecordFile.replaceSubrange(2..<mNdefRecordFile.count, with: ndefMessageData)
}
Could someone please help? I also tried to send the payment url as Data made from url.
We have a working Android application, which uses HCE too (they use NDEF message and byte arrays in communication).
As I've seen, the NFCNDEFReaderSessionDelegate and NFCTagReaderSessionDelegate is not suitable for communication between two iOS devices...