历数OpenMobile开发的一些坑

来源:互联网 发布:mac玩lol 编辑:程序博客网 时间:2024/05/15 09:08
一、开发时配置应用程序使用手机系统自带的OpenMObile API库
因为OpenMobile不能向下兼容,各版本支持手机系统版本不同:
15 - API level 15, Android 4.0.316 - not available17 - API level 17, Android 4.218 - API level 18, Android 4.319 - API level 19, Android 4.420 - developer preview, not available21 - 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" />  <application    android: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-library      android:name="org.simalliance.openmobileapi"      android:required="true" />    <activity      android: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



原创粉丝点击