移动支付之智能IC卡与Android手机进行NFC通信

浅谈Android开发中的NFC功能 本文章对Android开发中的NFC技术的基础知识、类别、作用、实现原理等进行了阐述与分析,旨在让对NFC无了解的人能够快速了解NFC功能的大体情况。 阅读详情

本文来自http://blog.youkuaiyun.com/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.youkuaiyun.com/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 registration
		new 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.youkuaiyun.com/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 intent
			TECHLISTS = 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 device
				isoDep.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;
    }
}



从机械臂示教到厨房做饭:ACT模仿学习如何让机器人更“人性化”? 本文探讨了ACT(Action Chunking with Transformers)模仿学习技术如何让机器人更“人性化”,特别是在厨房等复杂场景中的应用。通过动作分块(Action Chunking)和时态融合(Temporal Ensemble)技术,机器人能够像人类一样记忆和执行复杂任务,如烹饪。文章还分析了ACT在家庭场景中的落地挑战及其在康复医疗、柔性制造等领域的跨领域应用潜力。 阅读详情

相关推荐

LTspice导入德州仪器SPICE模型的实用指南与常见问题解析

本文详细介绍了如何在LTspice中导入德州仪器的SPICE模型,包括模型文件获取、路径管理、导入步骤及常见问题解析。通过实用指南帮助工程师精确仿真电路性能,提升设计效率,重点涵盖了第三方模型的导入教程和最佳实践。

kk1234的博客 307

NFC开发 —————实用工具以及开发文档(四)

       关于开发NFC必不可少的就是官方开发软件,以及开发文档,这篇文章给大家详细讲解一下,关于官方软件合集《文章末尾有下载地址》 文档资源:        有些开发者看到这么多工具肯定有困难选中症,不知道用哪个工具,不知道哪个是自己需要合适的,这里做一些详细讲解: Mifare Classic Tool (MCT) 一款用来读取/编辑/分析Mi..

拉莫帅的博客 9727

F5 Shape逆向工程实战:从美西南航空到xbk的风控突破

本文以美西南航空和xbk为例,深入剖析了F5 Shape风控系统的逆向工程实战。文章拆解了其核心防线,包括通信加密、JSVMP逆向分析和无孔不入的环境指纹检测,并分享了定位Header生成入口、模拟算法输出及构建真实浏览器环境的系统性方法与思路,为合规的技术研究与测试提供参考。

weixin_29327525的博客 1387

Android NFC开发详解:NFC读卡实例解析及总结

NFC是目前Android手机一个主流的配置硬件项,全称是Near Field Communication,中为近场通信,也叫做近距离无线通信技术。使用了NFC技术的设备(例如移动电话)可以在彼此靠近的情况下进行数据交换,是由非接触式射频识别(RFID)及互连互通技术整合演变而来。存储在NFC标签中的数据可以采用多种格式编写,但许多 Android 框架 API 都基于名为 NDEF(NFC 数据交换格式)的 NFC Forum 标准。。简单说就是一种普遍的数据格式标准。

缘来的精彩的博客 6220

VisionPro动态坐标系构建:CogFixtureTool与CogFixtureNPointToNPointTool实战解析

本文深入解析了VisionPro中动态坐标系构建的核心技术,重点对比了CogFixtureTool与CogFixtureNPointToNPointTool的原理与应用。通过实战案例,阐述了如何利用坐标跟随(Fixturing)技术解决工业视觉检测中因零件位置偏移导致的测量不准问题,实现从“固定”到“随动”的思维跃迁,从而构建稳定、精准的检测程序。

weixin_29207439的博客 562

Obsidian和Typora图片路径同步终极指南:告别混乱的assets文件夹

本文详细解析了Obsidian与Typora图片路径同步的终极解决方案,通过Custom Attachment Location插件实现动态路径管理,解决了两款工具间图片兼容性问题。文章提供了从基础配置到高级应用的完整指南,帮助用户告别混乱的assets文件夹,提升工作效率。

g9h0i1的博客 821

Android NFC APDU

本文来自http://blog.youkuaiyun.com/hellogv/ 最近NFC支付挺火的,趁国庆宅在家,学习下Android 卡模拟(Host-based Card Emulation)。HCE的特点是模拟智能IC卡(ISO 7816-4),可用于金融和行业应用,相应地,CardReader例子中使用IsoDep。 智能IC卡本身是一个微型计算机,常见为Java Card平台,特别是多

okletsgo007的专栏 5168

实战指南:利用 LangGraph 的状态管理实现多轮对话的上下文隔离与持久化

本文详细介绍了如何利用LangGraph的状态管理机制,高效实现多轮对话中的上下文隔离与持久化。通过实战代码演示,从基础的消息历史管理到自定义状态扩展,再到使用SQLite进行生产级持久化,系统讲解了如何借助LangGraph的State和Checkpointer自动化处理对话记忆、用户隔离及数据存储,显著提升开发效率。

weixin_28396629的博客 488

Android NFC开发详解 总结和NFC读卡实例解析

前面的文章介绍了硬件通信中的串口和USB,本篇要讲的是NFC, 结合读卡一起学习这一部分相关的内容

qq_39178733的博客 1万+

YOLO11 改进系列 | 引入2023年 MLCA 的 C3k2_MLCA 模块,近零参数开销的本地-全局通道注意力,适合检测与分割特征增强

本文提出将MLCA(混合局部通道注意力)模块嵌入YOLOv11的C3k2框架中,形成C3k2_MLCA改进结构。该模块通过5×5局部池化和1×1全局池化双路融合,结合ECA式Conv1d生成通道注意力,在几乎不增加参数量的前提下(仅增加66个参数),实现了局部空间信息与全局通道统计的联合建模。相比传统SE和ECA注意力,MLCA保留了空间分布信息,更适合实例分割等需要精细定位的任务。实验表明改进后模型参数量仅增加0.002%,计算量基本不变,是一种高效的注意力增强方案。

qq_44224801的博客 92

华为OD面试八股真题 - 操作系统相关 - 2

华为OD技术面,操作系统相关八股真题提供详细解答,这篇博客主要涉及于进程和线程相关知识点

qq_45776114的博客 965

android nfc 命令,带有APDU命令的Android NFC问题

我正在使用IsoDep Tag Tech处理应用程序,以向支持NFC的卡发出APDU命令.更新:所以下面看到的问题似乎与我正在使用的卡的电源要求有关,当我使用具有较低功率要求的不同卡时,下面的症状不会经常发生.我明确地遵循了文档,并成功地实现了协议.然而,由于混合成功,我遇到了一些超出我的代码控制范围的NFC低级库的问题.我已经实现了以下内容:>前景调度待定意图.>意图有一个技术过滤器...

weixin_36480122的博客 1895

YOLOv11改进策略【模型轻量化】| 使用 MoblieOne 模块,引入结构重参数化,提高模型检测效率

本文记录的是基于MobileOne的YOLOv11骨干网络改进方法研究。MobileOne的基础模块通过重参数化,。在将其替换YOLOv11的骨干网络后,实现模型轻量化。

Limiiiing的博客 1424

Moto 钱包门禁卡用不了?常见问题全解析,轻松搞定刷卡难题

其实外设的驱动问题根本不用逐个解决,也不用到处找官方驱动包,有一个简单的方法就能实现全生态外设的一键串联,一个驱动搞定所有外设的适配与运行,彻底告别驱动安装、兼容的各种麻烦,让各类外设都能稳定工作。不管是办公党还是游戏玩家,电脑上总会搭配多款外设,鼠标、键盘、耳机、手柄一应俱全,但外设多了也容易遇到糟心问题:新外设连电脑识别慢、驱动安装失败,不同品牌外设需要逐个装驱动,桌面堆满驱动程序不说,还容易出现驱动冲突、外设失灵的情况,折腾半天都没法让所有外设正常协同工作。

famous_pengfei的博客 52

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Android NFC 标签读写Demo与历史漏洞概述

NFC 作为 Android 手机一个重要的短距特性,为了深入探索 NFC 的安全风险,本文先来记录学习下 Android NFC 的一些基础知识、玩法、标签读写开发,并简述下业界对 NFC 特性发现的相关历史漏洞情况。

道阻且长,行则将至 5282

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

通信方式——NFC概述(一)

一.基本简介 NFC 芯片是具有相互通信功能,并具有计算能力,在Felica标准中还含有加密逻辑电路,MIFARE的后期标准也追加了加密/解密模块(SAM)。[1] NFC标准兼容了索尼公司的FeliCaTM标准,以及ISO 14443 A,B,也就是使用飞利浦的MIFARE标准。在业界简称为TypeA,TypeB和TypeF,其中A,B为Mifare标准,F为Felica标准。

sum_TW的博客 7942

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

NFC标签IC - NTA5332

什么是NFC? NFC: Near Field Communication NFC或近场通信是一种协议,当两个设备紧挨着对方时,可以帮助它们进行无线通信--例如,智能手机或智能手表可以用于支付或登机牌。 NFC硬件正在被纳入越来越多的设备中--特别是智能手机,但也包括一些笔记本电脑。NFC可能是支付、安全钥匙和登机牌的未来。NFC也是对笨重的QR码的升级。许多新的手机都有硬件来做今天这里的所有事情,然而,许多拥有NFC装备的智能手机的人还没有使用他们的NFC功能。 NFC是一套标准,允许智能手机

guoqx的专栏 3388

学习黑客NFC技术详解

NFC技术详解:近距离通信的无线桥梁 📱💳 > *学习目标:了解NFC技术的基本原理、应用场景及安全注意事项,掌握这一日益普及的近场通信技术* ## 1. NFC的概念与基础 📡 NFC(Near Field Communication,近场通信)是一种短距离的高频无线通信技术,允许电子设备在几厘米范围内进行非接触式数据交换。作为RFID(射频识别)技术的延伸,NFC结合了智能卡和读卡器功能,使设备能够既作为发送者又作为接收者。 **NFC的核心特征:** - 通信距离短(通常<4厘米)🤏

qq_41179365的博客 2251

android nfc读取公交卡信息_手机NFC可以复制小区用的门禁卡吗?

很多带有NFC功能的手机和手环,可以用来代替小区门禁卡、公司门禁,以及各类一卡通。(NFC是一种非接触式通讯技术,工作的理论距离是0~10cm)以前出门必备手机、钱包、钥匙三件套,自移动支付出现、使用手机也可以乘坐公共交通后,出门就和钱包没有多大关系了;再加上家里的门锁换成了指纹锁,出门也和钥匙没多大关系了。慢慢的的小区开始安装小区门禁,小区门禁成为了很多人的噩梦。一般每个家庭都有几口人...

weixin_40006265的博客 2108

读《NFC:Arduino、Android与PhoneGap近场通信》有感

本文结构: 1. NFC 如何运作  2. 能用NFC 做什么  3. 谈谈你对这本书试读章节的看法    1. NFC 如何运作。        NFC是NearFieldCommunication缩写,即近场通信,又称近距离无线通讯技术,是一种短距离的高频无线通信技术,允许电子设备之间进行非接触式点对点数据传输交换数据。NFC提供了一种简单、触控式的解决方案,可以让消费者简单直...

新新 375

别再带一堆卡了!华为/小米/OPPO手机NFC门禁保姆级教程(附各品牌详细步骤)

本文详细解析了华为、小米、OPPO等主流手机品牌的NFC门禁功能实现方法,提供各品牌详细设置步骤和实用技巧,帮助用户告别实体门禁卡。文章涵盖NFC技术原理、安全使用建议及未来发展趋势,特别适合追求智能生活的科技爱好者。

weixin_30493401的博客 598

Android近距离通信

Android近场通信技术三种不同的近距离通信技术1、WiFi2、Bluetooth3、NFC近距离通信技术的未来发展 三种不同的近距离通信技术 1、WiFi WiFi(Wireless Fidelity)又称“行动热点”,是创建于IEEE 802.11标准的无线局域网的技术。 WiFi技术传输的无线通信质量不是很好,数据安全性能比蓝牙差一些,传输质量也有待改进,但传输速度非常快,可以达到54Mbps,符合个人和社会信息化的需求。传输距离一般在10米至数公里之间。同时WiFi最主要的优势在于不需要布线,可以

jelly_grease的博客 3869
上一篇: 移动支付之Android HCE的基本使用
下一篇: 使用JCShell创建/删除辅助安全域
欧巴Godwin
欧巴Godwin 领域专家: 操作系统技术领域 领域专家: 操作系统技术领域
博客等级 码龄20年 9690粉丝 141原创
评论 11
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值