移動支付之智能IC卡與Android手機進行NFC通訊

來源:互聯網
上載者:User

標籤:des   android   style   blog   http   io   os   ar   使用   

本文來自http://blog.csdn.net/hellogv/ ,引用必須註明出處!
       目前常見的智能IC卡運行著JavaCard虛擬機器,智能IC卡上可以運行由精簡後的Java語言編寫的卡應用(簡稱Applet)。智能IC卡的Applet不能自己啟動,必須由外部終端(例如POS機,地鐵刷卡終端等)向卡片發送Select命令,由此選中卡片的Applet,Applet才能運行。Appplet側重於資料的處理,沒有花銷的I/O功能。Applet的程式有生命週期和指定入口,其中最主要的幾個方法如下:
  • public static void install(byte[] bArray, short bOffset, byte bLength)

構建了Applet子類的執行個體,JCRE將會最先調用這個;所有的初始化和分配記憶體的操作應該在這個裡面實現;可以擷取卡外實體傳進來的一些應用初始化參數。

  • public void process(APDU apdu)
類似於正常java class的main,在安裝後,APDU的執行將在這裡實現。

  • protected final void register()
applet用來在JCRE中註冊該applet執行個體

  • register(byte[] bArray, short bOffset, byte bLength)
register( )功能一樣,增加了可以分配其特定的AID的功能。

  • public boolean select()
        JCRE一旦接收到SELECT[by name]命令時,將尋找命令中指示的AID對應的Applet,使之處於活躍狀態,接收並處理接下來的APDU命令;在選擇新的Applet前,JCRE先調用當前Applet的 deselect 方法;Applet可以拒絕被選擇,此時 select 方法返回false;SELECT[by name]命令本身也將傳遞給applet處理,此時通過 selectingApplet 用以判斷目前狀態。

        本文的DEMO運行效果如下,包含一個JavaCard的Applet實現和一個Android端的NFC讀寫程式,實現智能IC卡與Android手機的簡單通訊。

接下來貼段簡單的Applet 源碼,:http://download.csdn.net/detail/hellogv/8090041。

大概的思路是:Applet定義了2個開頭標識皆為CMD_CLA的自訂命令CMD_INS_1和CMD_INS_2,當Android手機通過NFC分別發送CMD_INS_1和CMD_INS_2,Applet分別返回strHello和strWorld。

核心源碼如下:

public class mytest extends Applet {private static final byte[] strHello= { (byte) ‘H‘, (byte) ‘e‘,(byte) ‘l‘, (byte) ‘l‘, (byte) ‘o‘};private static final byte[] strWorld = {(byte) ‘W‘,(byte) ‘o‘, (byte) ‘r‘, (byte) ‘l‘, (byte) ‘d‘, };private static final byte CMD_CLA = (byte) 0x80;private static final byte CMD_INS_1 = (byte) 0x10;private static final byte CMD_INS_2 = (byte) 0x20;public static void install(byte[] bArray, short bOffset, byte bLength) {// GP-compliant JavaCard applet registrationnew mytest().register(bArray, (short) (bOffset + 1), bArray[bOffset]);}/* * 當Java卡Applet被選中時,由JCRE調用。Java卡Applet可以定義select()完成初始化, * 否則,JCRE調用父類的select()。 * @see javacard.framework.Applet#select() */public boolean select() {short debug=100;debug++;//用於斷點調試,當被select時觸發。return super.select();}/* * 當Java卡Applet被放棄時,由JCRE調用。Java卡Applet可以定義deselect()完成清除, * 否則,JCRE調用父類的deselect()。 * @see javacard.framework.Applet#deselect() */public void deselect() {short debug=100;debug++;//用於斷點調試super.deselect();} /* * 每次收到APDU命令,都會執行 * @see javacard.framework.Applet#process(javacard.framework.APDU) */public void process(APDU apdu) {if (selectingApplet()) {return;}//擷取外部終端發過來的資料byte[] buffer = apdu.getBuffer();//擷取第一位元據byte CLA = (byte) (buffer[ISO7816.OFFSET_CLA] & 0xFF);//擷取第二位元據byte INS = (byte) (buffer[ISO7816.OFFSET_INS] & 0xFF);if (CLA != CMD_CLA) {//格式不對ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);}switch (INS) {case CMD_INS_1:sendBytes(apdu,strHello);break;case CMD_INS_2:sendBytes(apdu,strWorld);break;default:ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);}}private void sendBytes(APDU apdu,byte[] arrays) {byte[] buffer = apdu.getBuffer();short length = (short) arrays.length;Util.arrayCopyNonAtomic(arrays, (short) 0, buffer, (short) 0,(short) length);apdu.setOutgoingAndSend((short) 0, length);}}


接下來貼出Android端的核心代碼,:http://download.csdn.net/detail/hellogv/8090053。

大概的思路是:Android端的NFC讀寫程式定義1個Applet的ID(AID),SELECT命令的報文頭(SELECT_APDU_HEADER),2個自訂命令CMD_INS_1和CMD_INS_2。首先使用AID和SELECT_APDU_HEADER產生完整的SELECT命令,transceive(發送)到卡片,用於啟動卡片裡的AID對應的Applet。啟動卡片裡的Applet後,NFC讀寫程式發送SAMPLE_COMMAND裡面的2條自訂命令,Applet分別返回"Hello""World"。

核心源碼如下:

public final class CardReader {    private static final String TAG = "LoyaltyCardReader";    // AID for our loyalty card service.    private static final String SAMPLE_CARD_AID = "1122001122";    // ISO-DEP command HEADER for selecting an AID.    // Format: [Class | Instruction | Parameter 1 | Parameter 2]    private static final String SELECT_APDU_HEADER = "00A40400";    // "OK" status word sent in response to SELECT AID command (0x9000)    private static final byte[] SELECT_OK_SW = {(byte) 0x90, (byte) 0x00};    //自訂的命令    private static final String[] SAMPLE_COMMAND={"8010000000",//卡片收到後返回"Hello"    "8020000000"};//卡片收到後返回"World"    public static String[][] TECHLISTS;public static IntentFilter[] FILTERS;static {try {//the tech lists used to perform matching for dispatching of the ACTION_TECH_DISCOVERED intentTECHLISTS = new String[][] { { IsoDep.class.getName() }};FILTERS = new IntentFilter[] { new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED, "*/*") };} catch (Exception e) {}}    static public String tagDiscovered(Tag tag) {Log.e(TAG, "New tag discovered");String strResult="";IsoDep isoDep = IsoDep.get(tag);if (isoDep != null) {try {// Connect to the remote NFC deviceisoDep.connect();//發送select 命令,卡片會返回SELECT_OK_SW(90 00)byte[] cmdSelect = BuildSelectApdu(SAMPLE_CARD_AID);Log.e(TAG, "Sending: " + ByteArrayToHexString(cmdSelect));byte[] result = isoDep.transceive(cmdSelect);Log.e(TAG, "Receive: " + ByteArrayToHexString(result));byte[][] response = getResponse(result);byte[] statusWord =response[0];if (Arrays.equals(SELECT_OK_SW, statusWord) == false)return "";//迴圈發送自訂命令for(int i=0;i<SAMPLE_COMMAND.length;i++){String command = SAMPLE_COMMAND[i];result = HexStringToByteArray(command);Log.e(TAG, "Sending: " + command);result = isoDep.transceive(result);Log.e(TAG, "Receive: " + ByteArrayToHexString(result));response = getResponse(result);byte[] body =response[1];strResult=strResult+new String(body)+":"+ByteArrayToHexString(body)+"\r\n";}return strResult;} catch (IOException e) {Log.e(TAG, "Error communicating with card: " + e.toString());}}return null;}/*** * 分解卡片返回的資料 * @param b * @return [0]表示返回的狀態值,[1]表示返回的本文 */private static byte[][] getResponse(byte[] b){byte[][] result = new byte[2][];int length = b.length;byte[] status = { b[length - 2],b[length - 1] };byte[] body = Arrays.copyOf(b, length - 2);result[0]=status;result[1]=body;return result;}public static String load(Parcelable parcelable) {// 從Parcelable篩選出各類NFC標準資料final Tag tag = (Tag) parcelable;return tagDiscovered(tag);}    /**     * Build APDU for SELECT AID command. This command indicates which service a reader is     * interested in communicating with. See ISO 7816-4.     *     * @param aid Application ID (AID) to select     * @return APDU for SELECT AID command     */    public static byte[] BuildSelectApdu(String aid) {        // Format: [CLASS | INSTRUCTION | PARAMETER 1 | PARAMETER 2 | LENGTH | DATA]        return HexStringToByteArray(SELECT_APDU_HEADER + String.format("%02X", aid.length() / 2) + aid);    }    /**     * Utility class to convert a byte array to a hexadecimal string.     *     * @param bytes Bytes to convert     * @return String, containing hexadecimal representation.     */    public static String ByteArrayToHexString(byte[] bytes) {        final char[] hexArray = {‘0‘,‘1‘,‘2‘,‘3‘,‘4‘,‘5‘,‘6‘,‘7‘,‘8‘,‘9‘,‘A‘,‘B‘,‘C‘,‘D‘,‘E‘,‘F‘};        char[] hexChars = new char[bytes.length * 2];        int v;        for ( int j = 0; j < bytes.length; j++ ) {            v = bytes[j] & 0xFF;            hexChars[j * 2] = hexArray[v >>> 4];            hexChars[j * 2 + 1] = hexArray[v & 0x0F];        }        return new String(hexChars);    }    /**     * Utility class to convert a hexadecimal string to a byte string.     *     * <p>Behavior with input strings containing non-hexadecimal characters is undefined.     *     * @param s String containing hexadecimal characters to convert     * @return Byte array generated from input     */    public static byte[] HexStringToByteArray(String s) {        int len = s.length();        byte[] data = new byte[len / 2];        for (int i = 0; i < len; i += 2) {            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)                    + Character.digit(s.charAt(i+1), 16));        }        return data;    }}



移動支付之智能IC卡與Android手機進行NFC通訊

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.