Upgrade to Pro — share decks privately, control downloads, hide ads and more …

iPhoneでFeliCaを読み取ってみた

 iPhoneでFeliCaを読み取ってみた

iPhoneでFeliCaを読み取ってみた
#potatotips #64

作ったライブラリ
https://github.com/tattn/NFCReader

Tatsuya Tanaka

August 27, 2019
Tweet

More Decks by Tatsuya Tanaka

Other Decks in Programming

Transcript

  1. ాத ୡ໵ / ͨͳͨͭ (@tattn) • Yahoo!৐׵Ҋ಺ • iOSΞϓϦΤϯδχΞ @tattn

    @tanakasan2525 @tattn Copyright (C) 2019 Yahoo Japan Corporation. All Rights Reserved.
  2. Sessionͷ࡞੒ & ϙʔϦϯάͷ։࢝ let session = NFCTagReaderSession( pollingOption: NFCTagReaderSession.PollingOption.iso18092, delegate:

    self ) session.alertMessage = "iPhoneΛSuicaʹ͚͍ۙͮͯͩ͘͞" session.begin() FeliCaΛಡΈࠐΉ࣌͸ISO18092Λࢦఆ /** * @enum NFCPollingOption * * @constant NFCPollingISO14443 Support both Type A & B modulation. NFCTagTypeISO7816Compatible and NFCTagTypeMiFare tags will be discovered. * @constant NFCPollingISO15693 NFCTagTypeISO15693 tag will be discovered. * @constant NFCPollingISO18092 NFCTagTypeFeliCa tag will be discovered. */ public struct PollingOption : OptionSet { public init(rawValue: Int) public static var iso14443: NFCTagReaderSession.PollingOption { get } public static var iso15693: NFCTagReaderSession.PollingOption { get } public static var iso18092: NFCTagReaderSession.PollingOption { get } }
  3. Tag ͷಡΈࠐΈ४උ public func tagReaderSession(_ session: NFCTagReaderSession, didDetect tags: [NFCTag])

    { guard case .feliCa(let tag) = tags.first else { return } session.connect(to: tag) { error in guard error == nil else { return } // TagͷಡΈࠐΈ (࣍ϖʔδ) } } delegateͰݕग़ͨ͠λάΛड͚औͬͯ
 ઀ଓ͢Δ public enum NFCTag { case feliCa(NFCFeliCaTag) case iso7816(NFCISO7816Tag) case iso15693(NFCISO15693Tag) case miFare(NFCMiFareTag) }
  4. ϒϩοΫσʔλͷಡΈࠐΈ let serviceCodeList = [Data([0x0f, 0x09])] let blockList = (0..<UInt8(10)).map

    { Data([0x80, $0]) } feliCaTag.requestService(nodeCodeList: serviceCodeList) { nodes, error in guard error == nil, nodes.first == Data([0xff, 0xff]) else { return } feliCaTag.readWithoutEncryption( serviceCodeList: serviceCodeList, blockList: blockList) { status1, status2, dataList, error in guard error == nil, status1 == 0, status2 == 0 else { return } // dataͷಡΈࠐΈ (࣍ϖʔδ) } } Service code: αʔϏε(σʔλ)Λಛఆ͢Δίʔυ Block list: σʔλͷऔಘํ๏/ҐஔΛܾΊΔ
  5. Suicaͷσʔλͷσίʔυ for data in dataList { let year = data[4]

    >> 1 let month = UInt16(bytes: data[4...5]) >> 5 & 0b1111 let day = data[5] & 0b11111 print("ར༻೔: \(year)/\(month)/\(day)") // 19/8/27 let entrance = UInt16(bytes: data[6...7]) let exit = UInt16(bytes: data[8...9]) print("ೖ৔Ӻ: \(entrance), ग़৔Ӻ: \(exit)") let balance = UInt16(bytes: data[10...11].reversed()) print("࢒ߴ: ", balance) } IUUQTXXXXEJDPSHX3"*-αΠόωن֨ *$Χʔυ year͕2000೥Λج४ʹ͍ͯ͠Δͷ͕໘ന͍
  6. όΠτ഑ྻΛIntܕʹม׵͢Δ֦ு extension FixedWidthInteger { init(bytes: UInt8...) { self.init(bytes: bytes) }

    init<T: DataProtocol>(bytes: T) { let count = bytes.count - 1 self = bytes.enumerated().reduce(into: 0) { (result, item) in result += Self(item.element) << (8 * (count - item.offset)) } } } XCTAssertEqual(UInt16(bytes: 0x35, 0x0B), 13579) XCTAssertEqual(Int(bytes: 0x07, 0x5B, 0xCD, 0x15), 123456789)
  7. NFCReader - ࢖͍ํ let reader = Reader<Suica>() reader.read(didBecomeActive: { _

    in print("ಡΈࠐΈ։࢝") }, didDetect: { reader, result in switch result { case .success(let suica): let balance = suica.boardingHistories.first?.balance ?? 0 reader.setMessage(balance) case .failure(let error): reader.setMessage("ಡΈࠐΈʹࣦഊ͠·ͨ͠") } }) ௒؆୯
  8. NFCReader - ࢖͍ํ Reader<Suica>() Reader<Nanaco>() Reader<Waon>() Reader<Edy>() Reader<FeliCa>() Reader<CustomTag>() ৭ʑରԠͯ͠Έ·ͨ͠

    ←Suica ←nanaco ←WAON ←্هͷશͯΛೝࣝ ←ࣗ࡞ͷλά ←Edy Pasmo, Kitaca, ICOCA, TOICAɺ manacaɺPiTaPaɺnimocaɺ SUGOCAɺ͸΍͔͚Μɺଞ ( )