历数OpenMobile开发的一些坑
因為OpenMobile不能向下兼容,各版本支持手機系統版本不同:
15 - API level 15, Android 4.0.3 16 - not available 17 - API level 17, Android 4.2 18 - API level 18, Android 4.3 19 - API level 19, Android 4.4 20 - developer preview, not available 21 - API level 21, Android 5.0
所以在開發時不能使用其中任一版本,使用任一版本將可能導致部分支持NFC手機無法使用應用,出現兼容性問題;
推薦做法是:通過配置使用手機系統自帶OpenMobile庫
配置流程為:
(1)準備某一版本OpenMobile API支撐庫,導入項目libs,該支撐庫只在編譯期間使用,項目打包不將此包打入到項目里,
? ? ?配置項為:(工具Android studio 中app->build.gradle中配置)
dependencies {compile fileTree(include: ['*.jar'], exclude: ['openMobileApi.jar'], dir: 'libs')compile 'com.android.support:appcompat-v7:23.4.0'compile 'com.google.code.gson:gson:2.8.0'compile 'com.squareup.okhttp3:okhttp:3.5.0'//provided表示只在編譯時使用jar包,運行時默認環境中已經存在這個jar包了//jar包在網上有下載,注意要與ROM版本一直,不要一味求最新provided files('libs/openMobileApi.jar') }(2)工程主配置文件AndroidManifest.xml配置使用系統自帶OpenMobile庫:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.cosw"><uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.NFC" /><uses-permission android:name="org.simalliance.openmobileapi.SMARTCARD" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><uses-feature android:name="android.hardware.nfc" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:name="com.cosw.app.MyApplication"android:supportsRtl="true"android:theme="@style/AppTheme"><!--true:使用系統自帶OpenMobile庫--><uses-libraryandroid:name="org.simalliance.openmobileapi"android:required="true" /><activityandroid:name="com.cosw.app.SplashActivity"android:screenOrientation="portrait"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application> </manifest>
以上配置之后,即可實現編譯期使用libs庫,打包時使用系統自帶庫的目標。
二、使用OpenMObile API獲取SWP卡ATR進行密鑰分散時注意點
1、手機必須支持NFC
2、卡片放到手機里之后,手機會獲取卡片ATR,并且保存到手機,此時手機是肯定拿到了ATR的,在此基礎上通過openmobile API的session.getATR()可能存在以下兩種情況
? ?(1)使用openmobile API的session.getATR()獲取ATR時,部分手機獲取為null,也有的手機獲取atr為全0(OPPO N5207支持NFC,但是ATR獲取為全0000000000)
? ?(2)同一張支持NFC的SWP卡,不同的手機獲取的ATR不同,區別在于多了個TCK校驗位(如果想忽略校驗位,可以通過ATRParseUtil判斷是否存在校驗位,存在則去掉校驗位。)
? ? ? ? ATR格式說明參考:
? ? ? ? 說明文檔:https://en.wikipedia.org/wiki/Answer_to_reset
? ? ? ? ATR解析工具:http://ruimtools.com/atr.php
3、ATR:可以作為分散密鑰的因子,主要用的是歷史字節數進行分散。
4、通過手機自帶的openmobile API去獲取atr,同一張卡片可能獲取的atr不同,不同之處在于ATR的校驗位,該校驗位有可能存在,也與可能不存在
示例:
ATR(TCK存在,需要校驗,此時有的手機能拿到20校驗位I,有的手機不行)
? ?(和包UAT測試卡1)華為p10 ? ? ? ------atr=3B9F95803FC7A08031E073FE211B633A104E83009000
? ?(和包UAT測試卡1)華為 honor ? ?------atr=3B9F95803FC7A08031E073FE211B633A104E8300900020
? ?(和包UAT測試卡1)中國移動M812C ------atr=3B9F95803FC7A08031E073FE211B633A104E8300900020
? ?(藍牙卡)atr:3B9194803FC3A0BC65
ATR(TCK不存在,不需要校驗):3B9A96401E4100014308025054E20D
5、如果存在需要判斷ATR是否存在校驗位,存在則去掉校驗位的需求,則可以參考下面代碼:
package com.atr.test;/*** * @author Administrator ATR判斷是否存在檢驗字節 參考:<br/>* (1)http://www.ruimtools.com/atr.php<br/>* (2)https://en.wikipedia.org/wiki/Answer_to_reset<br/>* ATR(TCK存在,需要校驗,此時有的手機能拿到20校驗位I,有的手機不行)<br/>* 華為p10 ------atr=3B9F95803FC7A08031E073FE211B633A104E83009000<br/>* 華為 honor ------atr=3B9F95803FC7A08031E073FE211B633A104E83009000 20<br/>* 中國移動M812C ------atr=3B9F95803FC7A08031E073FE211B633A104E83009000 20* atr:3B9194803FC3A0BC65<br/>* ATR(TCK不存在,不需要校驗):3B9A96401E4100014308025054E20D<br/>* */ public class ATRParseUtil {public static void main(String[] args) {/*System.out.println(parseATR(StringUtil.hexStringToByteArray("3B9194803FC3A0BC65")));*/try {int atrZero=Integer.valueOf("0000000000");} catch (Exception e) {System.out.println("不為全0");}System.out.println("全0");}// 歷史字節數private static int historical_len = 0;// 已經校驗的字節數private static int info_recv_len = 1;public static String parseATR(byte[] atr) {//(1)部分支持NFC機型獲取ATR為null,可能底層沒有緩存卡片ATRif (atr == null || atr.length == 0) {return null;}//(2)ATR為全0也無法做個人化,代表機型://(1)OPPO N5207try {int atrZero=Integer.valueOf(StringUtil.byteArrayToHexString(atr));if(atrZero==0){System.out.println("獲取ATR為全0,不支持");return null;}} catch (Exception e) {}int ta_b = 0;int tb_b = 0;int tc_b = 0;int td_b = 0;int tck_exist = 0;int ta1_exist = 0;// 每次計算之前從新初始化historical_len = 0;info_recv_len = 1;info_recv_len++;ta_b = (atr[info_recv_len - 1] >> 4) & 0x01;tb_b = (atr[info_recv_len - 1] >> 5) & 0x01;tc_b = (atr[info_recv_len - 1] >> 6) & 0x01;td_b = (atr[info_recv_len - 1] >> 7) & 0x01;// 格式字節T0 在范圍[0..15] 中以其4個低位(第4個MSbit到第1個LSbit)編碼歷史字節T i的數量K// 示例1:3B9194803FC3A0BC65:91->10010001 ,此時歷史字節數為1// 示例2:3B9F95803FC7A08031E073FE211B633A104E8300900020:9F->10011111,,此時歷史字節數為15historical_len = atr[info_recv_len - 1] & 0x0F;System.out.println(atr[info_recv_len - 1]);if (ta_b != 0) {ta1_exist = 1;}boolean flag = isTCKExist(ta_b, tb_b, tc_b, td_b, ta1_exist, tck_exist,atr);System.out.println("是否存在TCK校驗位:" + flag);System.out.println("info_recv_len:" + info_recv_len);System.out.println("historical_len:" + historical_len);if (flag) {// 存在TCK校驗位byte[] atrCopy = new byte[historical_len + info_recv_len];System.arraycopy(atr, 0, atrCopy, 0, atrCopy.length);return StringUtil.byteArrayToHexString(atrCopy);} else {// 不存在TCK校驗位return StringUtil.byteArrayToHexString(atr);}}/*** 是否存在TCK校驗位* * @param ta_b* @param tb_b* @param tc_b* @param td_b* @param ta1_exist* @param tck_exist* @param atr* @return*/private static boolean isTCKExist(int ta_b, int tb_b, int tc_b, int td_b,int ta1_exist, int tck_exist, byte atr[]) {if (ta_b != 0) {ta_b = 0;info_recv_len++;if (ta1_exist == 1) {ta1_exist = 0;}return isTCKExist(ta_b, tb_b, tc_b, td_b, ta1_exist, tck_exist, atr);} else if (tb_b != 0) {tb_b = 0;info_recv_len++;return isTCKExist(ta_b, tb_b, tc_b, td_b, ta1_exist, tck_exist, atr);} else if (tc_b != 0) {tc_b = 0;info_recv_len++;return isTCKExist(ta_b, tb_b, tc_b, td_b, ta1_exist, tck_exist, atr);} else if (td_b != 0) {td_b = 0;info_recv_len++;System.out.println("td_b:"+ StringUtil.byteToHexString(atr[info_recv_len - 1]));System.out.println("td_b:" + atr[info_recv_len - 1]);ta_b = (atr[info_recv_len - 1] >> 4) & 0x01;tb_b = (atr[info_recv_len - 1] >> 5) & 0x01;tc_b = (atr[info_recv_len - 1] >> 6) & 0x01;td_b = (atr[info_recv_len - 1] >> 7) & 0x01;System.out.println(atr[info_recv_len - 1] & 0x0F);if ((atr[info_recv_len - 1] & 0x0F) != 0x00)tck_exist = 1;return isTCKExist(ta_b, tb_b, tc_b, td_b, ta1_exist, tck_exist, atr);}return tck_exist != 0 ? true : false;} }參考鏈接:
https://github.com/seek-for-android/pool/wiki/UsingSmartCardAPI
https://stackoverflow.com/questions/32438584/open-mobile-api-with-android-21
http://www.jianshu.com/p/a3a3b3db6b37
NFC讀取sim卡之建立卡連接:http://blog.csdn.net/qq_24224369/article/details/52371153
檢查手機是否連接網絡,sim的存在以及是否支持NFC功能:http://blog.csdn.net/qq_24224369/article/details/52693454
7816 ATR解析工具:http://www.ruimtools.com/atr.php
ATR應答重置:https://en.wikipedia.org/wiki/Answer_to_reset
SIMalliance OMAPI transport test plan介紹之二接口規范篇:http://www.51testing.com/html/36/489136-831212.html
openmobile api:http://seek-for-android.github.io/javadoc/V4.0.0/org/simalliance/openmobileapi/package-summary.html
sim卡與短信息:http://www.ithao123.cn/content-170384.html
總結
以上是生活随笔為你收集整理的历数OpenMobile开发的一些坑的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 十个经典的Android开源项目
- 下一篇: 哪种物联网卡套餐最划算?