読み取りAPIガイド

LibJeIDは各種IDカード内のデータを読み取るための統一されたAPIを提供します。

基本的に以下の流れでカード内データを読み出します。

  1. 暗証番号の入力またはアクセスコントロールの開始
  2. readFiles()メソッドを呼び出しFilesオブジェクトの読み出し
  3. Filesオブジェクトから各種データを取得

目次

運転免許証

運転免許証は暗証番号1(PIN1)、暗証番号2(PIN2)を入力して各種データを読み取ります。

共通データ要素の読み出しに暗証番号の入力は必要ありません。

真正性検証を行うには、PIN1とPIN2の両方を入力する必要があります。

運転免許証の読み取り

運転免許証を読み取るJavaのサンプルコードです。

try {
    JeidReader reader = new JeidReader(nfcTag);
    DriverLicenseAP ap = reader.selectDriverLicenseAP();

    // 暗証番号1を入力
    try {
        ap.verifyPin1("XXXX");
    } catch (InvalidPinException e) {
        if (e.isBlocked()) {
            System.out.println("暗証番号1がブロックされています。");
        } else {
            System.out.println("暗証番号1が間違っています。残り回数: " + e.getCounter());
        }
        return;
    }

    // 暗証番号2を入力
    try {
        ap.verifyPin2("XXXX");
    } catch (InvalidPinException e) {
        if (e.isBlocked()) {
            System.out.println("暗証番号2がブロックされています。");
        } else {
            System.out.println("暗証番号2が間違っています。残り回数: " + e.getCounter());
        }
        return;
    }

    // Filesオブジェクトの読み出し
    DriverLicenseFiles files = ap.readFiles();

    // Filesオブジェクトから共通データ要素を取得
    DriverLicenseCommonData commonData = files.getCommonData();
    System.out.println(commonData.toString());

    // Filesオブジェクトから券面情報を取得
    DriverLicenseEntries entries = files.getEntries();
    System.out.println(entries.toString());

    // Filesオブジェクトから顔写真を取得
    DriverLicensePhoto photo = files.getPhoto();
} catch (IOException e) {
    System.out.println("読み取りエラー");
}

運転免許証を読み取るSwiftのサンプルコードです。

do {
    let reader = try JeidReader(tag)
    let ap = try reader.selectDL()

    // 暗証番号1を入力
    do {
        try ap.verifyPin1("XXXX")
    } catch let jeidError as JeidError {
        if case .invalidPin(let counter) = jeidError {
            if jeidError.isBlocked! {
                session.invalidate(errorMessage: "暗証番号1がブロックされています")
            } else {
                session.invalidate(errorMessage: "暗証番号1が間違っています。残り回数: \(counter)")
            }
            return
        }
    }

    // 暗証番号2を入力
    do {
        try ap.verifyPin2("XXXX")
    } catch let jeidError as JeidError {
        if case .invalidPin(let counter) = jeidError {
            if jeidError.isBlocked! {
                session.invalidate(errorMessage: "暗証番号2がブロックされています")
            } else {
                session.invalidate(errorMessage: "暗証番号2が間違っています。残り回数: \(counter)")
            }
            return
        }
    }

    // Filesオブジェクトの読み出し
    let files = try ap.readFiles()

    // Filesオブジェクトから共通データ要素を取得
    let commonData = try files.getCommonData()
    print(commonData.description)

    // Filesオブジェクトから券面情報を取得
    let entries = try files.getEntries()
    print(entries.description)

    // Filesオブジェクトから顔写真を取得
    let photo = try files.getPhoto()
    session.invalidate()
} catch {
    session.invalidate(errorMessage: "読み取りエラー")
}

マイナ運転免許証

マイナ運転免許証は基本的に顔写真および免許関連情報が記録されており、氏名、住所、生年月日などの情報は記録されていません。 取得できる情報はINDLEntriesなどのドキュメントをご確認ください。

マイナ運転免許証を読み取るJavaのサンプルコードです。

try {
    JeidReader reader = new JeidReader(nfcTag);
    INDriverLicenseAP ap = reader.selectINDriverLicenseAP();

    // 暗証番号を入力
    try {
        ap.verifyPin("XXXX");
    } catch (InvalidPinException e) {
        if (e.isBlocked()) {
            System.out.println("暗証番号がブロックされています。");
        } else {
            System.out.println("暗証番号が間違っています。残り回数: " + e.getCounter());
        }
        return;
    }

    // Filesオブジェクトの読み出し
    INDLFiles files = ap.readFiles();

    // Filesオブジェクトから券面情報を取得
    INDLEntries entries = files.getEntries();
    System.out.println(entries.toString());

    // Filesオブジェクトから顔写真を取得
    INDLPhoto photo = entries.getPhoto();
} catch (IOException e) {
    System.out.println("読み取りエラー");
}

マイナ運転免許証を読み取るSwiftのサンプルコードです。

do {
    let reader = try JeidReader(tag)
    let ap = try reader.selectINDL()

    // 暗証番号を入力
    do {
        try ap.verifyPin("XXXX")
    } catch let jeidError as JeidError {
        if case .invalidPin(let counter) = jeidError {
            if jeidError.isBlocked! {
                session.invalidate(errorMessage: "暗証番号がブロックされています")
            } else {
                session.invalidate(errorMessage: "暗証番号が間違っています。残り回数: \(counter)")
            }
            return
        }
    }

    // Filesオブジェクトの読み出し
    let files = try ap.readFiles()

    // Filesオブジェクトから券面情報を取得
    let entries = try files.getEntries()
    print(entries.description)

    // Filesオブジェクトから顔写真を取得
    let photo = entries.photo
    session.invalidate()
} catch {
    session.invalidate(errorMessage: "読み取りエラー")
}

マイナンバーカード

券面入力補助APの読み取り

マイナンバーカードの券面入力補助APを読み取るJavaのサンプルコードです。

try {
    String pin = "XXXX";
    JeidReader reader = new JeidReader(nfcTag);
    INTextAP ap = reader.selectINTextAP();

    // 暗証番号を入力
    try {
        ap.verifyPin(pin);
    } catch (InvalidPinException e) {
        if (e.isBlocked()) {
            System.out.println("暗証番号がブロックされています。");
        } else {
            System.out.println("暗証番号が間違っています。残り回数: " + e.getCounter());
        }
        return;
    }

    // Filesオブジェクトの読み出し
    INTextFiles files = ap.readFiles();

    // Filesオブジェクトから個人番号を取得
    INTextMyNumber mynumber = files.getMyNumber();
    System.out.println("マイナンバー: " + mynumber.getMyNumber());

    // Filesオブジェクトから4属性を取得
    INTextAttributes attrs = files.getAttributes();
    System.out.println("氏名    : " + attrs.getName());
    System.out.println("住所    : " + attrs.getAddr());
    System.out.println("生年月日  : " + attrs.getBirth());
    System.out.println("性別    : " + attrs.getSexString());
} catch(IOException e) {
    System.out.println("読み取りエラー");
}

マイナンバーカードの券面入力補助APを読み取るSwiftのサンプルコードです。

do {
    let reader = try JeidReader(tag)
    let ap = try reader.selectINText()

    // 暗証番号を入力
    do {
        try ap.verifyPin("XXXX")
    } catch let jeidError as JeidError {
        if case .invalidPin(let counter) = jeidError {
            if jeidError.isBlocked! {
                session.invalidate(errorMessage: "暗証番号がブロックされています")
            } else {
                session.invalidate(errorMessage: "暗証番号が間違っています。残り回数: \(counter)")
            }
            return
        }
    }

    // Filesオブジェクトの読み出し
    let files = try ap.readFiles()

    // Filesオブジェクトから個人番号を取得
    let mynumber = try files.getMyNumber()
    print("マイナンバー: " + mynumber.myNumber!)

    // Filesオブジェクトから4属性を取得
    let attrs = try files.getAttributes()
    print("氏名    : " + attrs.name!)
    print("住所    : " + attrs.address!)
    print("生年月日  : " + attrs.birthDate!)
    print("性別    : " + attrs.sexString!)
    session.invalidate()
} catch {
    session.invalidate(errorMessage: "読み取りエラー")
}

券面入力補助APで読み出される情報について

券面入力補助APの読み出しAPIINTextAP.readFiles()は入力された暗証番号のアクセス制御に従い、以下の情報を読み出します。

  • 4桁の暗証番号を入力した場合、マイナンバーと4属性の両方を読み出します。
  • 照合番号Aを入力した場合、マイナンバーのみを読み出します。
  • 照合番号Bを入力した場合、4属性のみを読み出します。

4桁の暗証番号を入力したうえで、読み出すデータを制限したい場合はINTextAP.readFiles()にパラメーターを指定します。

詳細は下記APIドキュメントを参照してください。

以下は券面入力補助APで4桁の暗証番号を入力して4属性のみを読み出し、真正性検証を行うサンプルコードです。 この場合、カード内の個人番号にはアクセスしません。

try {
    JeidReader reader = new JeidReader(nfcTag);
    INTextAP ap = reader.selectINTextAP();

    // 暗証番号を入力
    ap.verifyPin("XXXX");

    // 4属性のみを読み出し(個人番号は読み出しません)
    INTextFiles files = ap.readFiles(false, true);

    // Filesオブジェクトから4属性を取得
    INTextAttributes attrs = files.getAttributes();
    System.out.println("氏名    : " + attrs.getName());
    System.out.println("住所    : " + attrs.getAddr());
    System.out.println("生年月日  : " + attrs.getBirth());
    System.out.println("性別    : " + attrs.getSexString());

    // 4属性のみに対して真正性検証
    ValidationParameters param = new ValidationParameters();
    param.setValidateMyNumber(false);
    param.setValidateAttributes(true);
    ValidationResult result = files.validate(param);
    System.out.println("検証結果: " + result);

} catch(IOException e) {
    System.out.println("読み取りエラー");
}
do {
    let reader = try JeidReader(tag)
    let ap = try reader.selectINText()

    // 暗証番号を入力
    try ap.verifyPin("XXXX")

    // 4属性のみを読み出し(個人番号は読み出しません)
    let files = try ap.readFiles(false, true)

    // Filesオブジェクトから4属性を取得
    let attrs = try files.getAttributes()
    print("氏名    : " + attrs.name!)
    print("住所    : " + attrs.address!)
    print("生年月日  : " + attrs.birthDate!)
    print("性別    : " + attrs.sexString!)

    // 4属性のみに対して真正性検証
    let params = ValidationParameters()
    params.validateMyNumber = false
    params.validateAttributes = true
    let result = try files.validate(params)
    print("検証結果: " + result.description)

} catch {
    session.invalidate(errorMessage: "読み取りエラー")
}

券面APの読み取り

マイナンバーカードの券面APを読み取るJavaのサンプルコードです。

try {
    String pin = "XXXX";
    JeidReader reader = new JeidReader(nfcTag);
    INVisualAP ap = reader.selectINVisualAP();

    // 暗証番号を入力
    try {
        ap.verifyPin(pin);
    } catch (InvalidPinException e) {
        if (e.isBlocked()) {
            System.out.println("PINがブロックされています。");
        } else {
            System.out.println("PINが間違っています。残り回数: " + e.getCounter());
        }
        return;
    }

    // Filesオブジェクトの読み出し
    INVisualFiles files = ap.readFiles();

    // Filesオブジェクトから個人番号(画像)を取得
    INVisualMyNumber myNumber = files.getMyNumber();

    // Filesオブジェクトから券面の表面を取得
    INVisualEntries entries = files.getEntries();
    System.out.println("生年月日  : " + entries.getBirth());
    System.out.println("性別    : " + entries.getSexString());
    System.out.println("有効期限  : " + entries.getExpire());
} catch(IOException e) {
    System.out.println("読み取りエラー");
}

マイナンバーカードの券面APを読み取るSwiftのサンプルコードです。

do {
    let reader = try JeidReader(tag)
    let ap = try reader.selectINVisual()

    // 暗証番号を入力
    do {
        try ap.verifyPin("XXXX")
    } catch let jeidError as JeidError {
        if case .invalidPin(let counter) = jeidError {
            if jeidError.isBlocked! {
                session.invalidate(errorMessage: "PINがブロックされています")
            } else {
                session.invalidate(errorMessage: "PINが間違っています。残り回数: \(counter)")
            }
            return
        }
    }

    // Filesオブジェクトの読み出し
    let files = try ap.readFiles()

    // Filesオブジェクトから個人番号(画像)を取得
    let mynumber = try files.getMyNumber()

    // Filesオブジェクトから券面の表面を取得
    let entries = try files.getEntries()
    print("生年月日  : " + entries.birthDate!)
    print("性別    : " + entries.sexString!)
    print("有効期限  : " + entries.expireDate!)
    session.invalidate()
} catch {
    session.invalidate(errorMessage: "読み取りエラー")
}

公的個人認証(製品版のみ)

try {
    // ユーザー認証用暗証番号
    String authPin = "XXXX";
    // デジタル署名用パスワード
    String signPin = "XXXXXXXX";

    JeidReader reader = new JeidReader(nfcTag);
    JPKIAP jpki = reader.selectJPKIAP();

    // ユーザー認証用証明書を取得
    JPKICertificate authCert = jpki.getAuthCert();

    // ユーザー認証用鍵で署名
    JPKISignature authSignature = jpki.getAuthSignature("SHA1withRSA");
    authSignature.update("hello".getBytes());
    byte[] signed = authSignature.sign(authPin);

    // デジタル署名用証明書を取得
    jpki.verifySignPin(signPin);
    JPKICertificate signCert = jpki.getSignCert();

    // デジタル署名用鍵で署名
    JPKISignature signSignature = jpki.getSignSignature("SHA1withRSA");
    signSignature.update("hello".getBytes());
    signed = signSignature.sign(signPin);
} catch (InvalidPinException e) {
    if (e.isBlocked()) {
        System.out.println("PINがブロックされています。");
    } else {
        System.out.println("PINが間違っています。残り回数: " + e.getCounter());
    }
} catch (IOException e) {
    System.out.println("読み取りエラー");
}

パスポート

パスポートの読み取り

パスポートは旅券番号(9桁)、生年月日(YYMMDDの6桁)、有効期限(YYMMDDの6桁)を 鍵としてアクセスコントロールを行います。

鍵オブジェクトのクラス名はJavaとSwiftで異なり、JavaはEPMRZ、SwiftはEPKeyです。

アクセスコントロールの方式にはPACE(Password Authenticated Connection Establishment)とBAC(Basic Access Control)の2種類があり、新しいパスポートは PACEに対応しています。

startAC()はPACEに対応したカードではPACEを、 対応していなければBACを実行します。戻り値として実際に使用した方式 ("PACE"または"BAC")が返ります。パスポートの読み取りでは startAC()を使用してください。

PACEに対応していないパスポートのみを対象とする場合は、 startBAC()を直接呼び出すこともできます。

パスポートを読み取るJavaのサンプルコードです。

try {
    // パスポート番号
    String passportNumber = "XXXXXXXXX";
    // 生年月日(YYMMDDの6桁)
    String birthDate = "YYYYYY";
    // 有効期限(YYMMDDの6桁)
    String expireDate = "ZZZZZZ";

    JeidReader reader = new JeidReader(nfcTag);
    PassportAP ap = reader.selectPassportAP();

    // EPMRZのインスタンスを生成
    EPMRZ mrz = new EPMRZ(passportNumber, birthDate, expireDate);

    // アクセスコントロールの開始(PACEを試行し、非対応ならBACにフォールバック)
    try {
        String acMethod = ap.startAC(mrz);
        System.out.println("アクセスコントロール方式: " + acMethod);
    } catch (InvalidBACKeyException e) {
        System.out.println("旅券番号、生年月日または有効期限が間違っています");
        return;
    }

    // Filesオブジェクトの読み出し
    EPFiles files = ap.readFiles();

    // FilesオブジェクトからCommon Dataを取得
    EPCommonData commonData = files.getCommonData();
    System.out.println(commonData.toString());

    // FilesオブジェクトからData Group 1 (MRZの情報)を取得
    EPDataGroup1 dg1 = files.getDataGroup1();
    System.out.println(dg1.toString());

    // FilesオブジェクトからData Group 2 (顔写真)を取得
    EPDataGroup2 dg2 = files.getDataGroup2();
} catch (IOException e) {
    System.out.println("読み取りエラー");
}

パスポートを読み取るSwiftのサンプルコードです。

do {
    // パスポート番号
    let passportNumber = "XXXXXXXXX"
    // 生年月日(YYMMDDの6桁)
    let birthDate = "YYYYYY"
    // 有効期限(YYMMDDの6桁)
    let expireDate = "ZZZZZZ"

    let reader = try JeidReader(tag)
    let ap = try reader.selectEP()

    // EPKeyのインスタンスを生成
    // 桁数が不正な場合はJeidError.encodeFailedがスローされます
    let epKey = try EPKey(passportNumber, birthDate, expireDate)

    // アクセスコントロールの開始(PACEを試行し、非対応ならBACにフォールバック)
    do {
        let acMethod = try ap.startAC(epKey)
        print("アクセスコントロール方式: \(acMethod)")
    } catch JeidError.invalidKey {
        session.invalidate(errorMessage: "旅券番号、生年月日または有効期限が間違っています")
        return
    }

    // Filesオブジェクトの読み出し
    let files = try ap.readFiles()

    // FilesオブジェクトからCommon Dataを取得
    let commonData = try files.getCommonData()
    print(commonData.description)

    // FilesオブジェクトからData Group 1 (MRZの情報)を取得
    let dg1 = try files.getDataGroup1()
    print(dg1.description)

    // FilesオブジェクトからData Group 2 (顔写真)を取得
    let dg2 = try files.getDataGroup2()
    session.invalidate()
} catch {
    session.invalidate(errorMessage: "読み取りエラー")
}

在留カード

第1世代在留カードの読み取り

読み出したデータはRCFilesを通じて取得します。

第1世代在留カードを読み取るJavaのサンプルコードです。

try {
    JeidReader reader = new JeidReader(nfcTag);
    ResidenceCardAP ap = reader.selectResidenceCardAP();

    // 在留カード番号または特別永住者証明書番号からRCKeyオブジェクトを生成
    RCKey rckey = new RCKey("XXXXXXXXXXXX");

    // アクセスコントロールの開始
    try {
        ap.startAC(rckey);
    } catch (InvalidACKeyException e) {
        System.out.println("在留カード番号または特別永住者証明書番号が間違っています");
        return;
    }

    // Filesオブジェクトの読み出し
    RCFiles files = ap.readFiles();

    // Filesオブジェクトから券面情報を取得
    RCCardEntries entries = files.getCardEntries();
    System.out.println(entries.toString());

} catch (Exception e) {
    System.out.println("読み取りエラー");
}

第1世代在留カードを読み取るSwiftのサンプルコードです。

do {
    let reader = try JeidReader(tag)
    let ap = try reader.selectRC()

    // 在留カード番号または特別永住者証明書番号からRCKeyオブジェクトを生成
    let rckey = try RCKey("XXXXXXXXXXXX")

    // アクセスコントロールの開始
    do {
        try ap.startAC(rckey)
    } catch JeidError.invalidKey {
        session.invalidate(errorMessage: "在留カード番号または特別永住者証明書番号が間違っています")
        return
    }

    // Filesオブジェクトの読み出し
    let files = try ap.readFiles()

    // Filesオブジェクトから共通データ要素を取得
    let commonData = try files.getCommonData()
    print(commonData.description)

    // Filesオブジェクトから券面情報を取得
    let entries = try files.getCardEntries()
    print(entries.description)

    // Filesオブジェクトから顔写真を取得
    let photo = try files.getPhoto()
    session.invalidate()
} catch {
    session.invalidate(errorMessage: "読み取りエラー")
}

第2世代在留カードの読み取り

第2世代在留カード・第2世代特別永住者証明書は、第1世代と同様に在留カード等番号を 用いてアクセスコントロールを開始しますが、セキュアメッセージングの方式が 変更されています。

読み出したデータはRC2Filesを通じて取得します。第1世代のRCFilesとは クラスが異なる点にご注意ください。

JeidReader.detectCardType()は第2世代在留カード等に対してCardType.RC2を返します。

共通データ要素とカード種別はアクセスコントロールを行わずに読み出せます。 カード種別は第2世代在留カードが"05"、第2世代特別永住者証明書が"06"です。

資格外活動許可欄(getPermission())と在留期間更新等許可申請ステータス (getUpdateStatus())は在留カードのみに記録されており、 記録されていない場合はnullを返します。

第2世代在留カードを読み取るJavaのサンプルコードです。

try {
    JeidReader reader = new JeidReader(nfcTag);
    ResidenceCard2AP ap = reader.selectResidenceCard2AP();

    // 共通データ要素とカード種別はアクセスコントロールなしで読み出せます
    RC2CommonData commonData = ap.readCommonData();
    System.out.println(commonData.toString());
    RC2CardType cardType = ap.readCardType();
    System.out.println(cardType.toString());

    // 在留カード等番号からRCKeyオブジェクトを生成
    RCKey rckey = new RCKey("XXXXXXXXXXXX");

    // アクセスコントロールの開始
    try {
        ap.startAC(rckey);
    } catch (InvalidACKeyException e) {
        System.out.println("在留カード番号または特別永住者証明書番号が間違っています");
        return;
    }

    // Filesオブジェクトの読み出し
    RC2Files files = ap.readFiles();

    // Filesオブジェクトから在留カード等の番号を取得
    RC2CardNumber cardNumber = files.getCardNumber();
    System.out.println(cardNumber.getNumber());

    // Filesオブジェクトから券面記載事項を取得
    RC2CardEntries entries = files.getCardEntries();
    System.out.println(entries.toString());

    // Filesオブジェクトから顔画像・氏名イメージ・住居地イメージを取得
    RC2FaceImage faceImage = files.getFaceImage();
    RC2NameImage nameImage = files.getNameImage();
    RC2AddressImage addressImage = files.getAddressImage();

    // 資格外活動許可欄と更新申請ステータスは在留カードのみ(無い場合はnull)
    RC2Permission permission = files.getPermission();
    RC2UpdateStatus updateStatus = files.getUpdateStatus();
} catch (Exception e) {
    System.out.println("読み取りエラー");
}

第2世代在留カードを読み取るSwiftのサンプルコードです。

do {
    let reader = try JeidReader(tag)
    let ap = try reader.selectRC2()

    // 共通データ要素とカード種別はアクセスコントロールなしで読み出せます
    let commonData = try ap.readCommonData()
    print(commonData.description)
    let cardType = try ap.readCardType()
    print(cardType.description)

    // 在留カード等番号からRCKeyオブジェクトを生成
    let rcKey = try RCKey("XXXXXXXXXXXX")

    // アクセスコントロールの開始
    do {
        try ap.startAC(rcKey)
    } catch JeidError.invalidKey {
        session.invalidate(errorMessage: "在留カード番号または特別永住者証明書番号が間違っています")
        return
    }

    // Filesオブジェクトの読み出し
    let files = try ap.readFiles()

    // Filesオブジェクトから在留カード等の番号を取得
    let cardNumber = try files.getCardNumber()
    print(cardNumber.number!)

    // Filesオブジェクトから券面記載事項を取得
    let entries = try files.getCardEntries()
    print(entries.description)

    // Filesオブジェクトから顔画像・氏名イメージ・住居地イメージを取得
    let faceImage = try files.getFaceImage()
    let nameImage = try files.getNameImage()
    let addressImage = try files.getAddressImage()

    // 資格外活動許可欄と更新申請ステータスは在留カードのみ(無い場合はnil)
    let permission = try files.getPermission()
    let updateStatus = try files.getUpdateStatus()
    session.invalidate()
} catch {
    session.invalidate(errorMessage: "読み取りエラー")
}

特定在留カードの読み取り

特定在留カード・特定特別永住者証明書は、個人番号カード上の在留APとして 実装されています。データ構造・署名アルゴリズムは 第2世代在留カード等と共通で、RC2Files系のデータクラスをそのまま使用します。

読み取りにあたっては以下の点にご注意ください。

  • 特定在留カード等は実質的に個人番号カードであるため、 JeidReader.detectCardType()はCardType.INを返します。 在留APの有無で判別してください。 在留APを持たない個人番号カードに対して在留APを選択すると、 JavaではFileNotFoundException、SwiftではJeidError.fileNotFoundが発生します。
  • AP直下にある共通データ要素とカード種別は在留APの再選択が必要になるため、 startAC()より前に読み出してください。
  • カード種別は特定在留カードが"07"、特定特別永住者証明書が"08"です。

特定在留カードを読み取るJavaのサンプルコードです。

try {
    JeidReader reader = new JeidReader(nfcTag);

    // 特定在留カード等は個人番号カードとして判別されます
    CardType type = reader.detectCardType();
    if (type != CardType.IN) {
        System.out.println("個人番号カードではありません");
        return;
    }

    // 在留APの選択。在留APを持たないカードでは例外が発生します
    SpecifiedResidenceCardAP ap;
    try {
        ap = reader.selectSpecifiedResidenceCardAP();
    } catch (FileNotFoundException e) {
        System.out.println("在留APを持たないカードです(特定在留カード等ではありません)");
        return;
    }

    // AP直下のEFは在留APの再選択が必要なためstartAC()より前に読み出します
    RC2CommonData commonData = ap.readCommonData();
    System.out.println(commonData.toString());
    RC2CardType cardType = ap.readCardType();
    System.out.println(cardType.toString());

    // 在留カード等番号からRCKeyオブジェクトを生成
    RCKey rckey = new RCKey("XXXXXXXXXXXX");

    // アクセスコントロール(セッション鍵の配送と認証)の開始
    try {
        ap.startAC(rckey);
    } catch (InvalidACKeyException e) {
        System.out.println("在留カード番号または特別永住者証明書番号が間違っています");
        return;
    }

    // Filesオブジェクトの読み出し(第2世代と同じRC2Files)
    RC2Files files = ap.readFiles();

    // Filesオブジェクトから在留カード等の番号を取得
    RC2CardNumber cardNumber = files.getCardNumber();
    System.out.println(cardNumber.getNumber());

    // Filesオブジェクトから券面記載事項を取得
    RC2CardEntries entries = files.getCardEntries();
    System.out.println(entries.toString());

    // Filesオブジェクトから顔画像を取得
    RC2FaceImage faceImage = files.getFaceImage();
} catch (Exception e) {
    System.out.println("読み取りエラー");
}

特定在留カードを読み取るSwiftのサンプルコードです。

do {
    let reader = try JeidReader(tag)

    // 特定在留カード等は個人番号カードとして判別されます
    let type = try reader.detectCardType()
    if type != CardType.IN {
        session.invalidate(errorMessage: "個人番号カードではありません")
        return
    }

    // 在留APの選択。在留APを持たないカードではエラーになります
    let ap: SpecifiedResidenceCardAP
    do {
        ap = try reader.selectRCS()
    } catch JeidError.fileNotFound {
        session.invalidate(errorMessage: "特定在留カード等ではありません")
        return
    }

    // AP直下のEFは在留APの再選択が必要なためstartAC()より前に読み出します
    let commonData = try ap.readCommonData()
    print(commonData.description)
    let cardType = try ap.readCardType()
    print(cardType.description)

    // 在留カード等番号からRCKeyオブジェクトを生成
    let rcKey = try RCKey("XXXXXXXXXXXX")

    // アクセスコントロール(セッション鍵の配送と認証)の開始
    do {
        try ap.startAC(rcKey)
    } catch JeidError.invalidKey {
        session.invalidate(errorMessage: "在留カード番号または特別永住者証明書番号が間違っています")
        return
    }

    // Filesオブジェクトの読み出し(第2世代と同じRC2Files)
    let files = try ap.readFiles()

    // Filesオブジェクトから在留カード等の番号を取得
    let cardNumber = try files.getCardNumber()
    print(cardNumber.number!)

    // Filesオブジェクトから券面記載事項を取得
    let entries = try files.getCardEntries()
    print(entries.description)

    // Filesオブジェクトから顔画像を取得
    let faceImage = try files.getFaceImage()
    session.invalidate()
} catch {
    session.invalidate(errorMessage: "読み取りエラー")
}