Android NFC卡实例详解

公司最近在做一个NFC卡片的工程,经过几天的时间,终于写了一个Demo出来,在此记录下在此过程中遇到的问题。由于之前本人是做iOS的,Android写起来并不是那么的顺手,其中有一些比较基础的问题也会做出解答,水平不高,唯愿不被吐槽。另外最近写java发现,不得不说java还是比较好写的,不用考虑循环引用的问题,而且没有指针的存在理解起来也不是很费劲,内部类用起来的便捷性,底层库也比较好用,下面直接进入Demo吧;

项目地址:NFCDemo

NFC

由于本篇主要讲的是Android手机对NFC卡片的处理,所以先来介绍几个NFC的概念,定义并不完全,如需了解更多请自行谷歌;

NFC,全称是近场通信(Near Field Communication),是一种短距离无线技术;

一个带有NFC支持的android设备通常是一个发起者。也可以作为NFC的读写设备。他将检测NFC tags并且打开一个Activity来处理. Android 2.3.3还有支持有限的P2P。;

Android NFC同时支持三个主要的操作模式:

设备读/写模式,允许NFC设备的读/写NFC目标设备(本例中我们用的是这种操作模式);

P2P模式,使NFC设备与其他NFC节点交换数据;这种运作模式被使用在Android Beam中;

卡仿真模式,使NFC设备本身作为一个NFC卡。然后模拟NFC卡可以通过一个外部的NFC读写访问,如销售终端NFC点。

NDEF(NFC data exchange format)

为实现NFC标签、NFC设备以及NFC设备之间的交互通信,NFC论坛(NFC Forum)定义了称为NFC数据交换格式(NDEF)的通用数据格式;

NDEF是轻量级的紧凑的二进制格式,可带有URL,vCard和NFC定义的各种数据类型;

NDEF使NFC的各种功能更加容易的使用各种支持的标签类型进行数据传输,因为NDEF已经封装了NFC标签的种类细节信息,使得应用不用关心是在与何种标签通信;

大致可以理解为就是NFC通信用的一种传输格式;

Android Beam

Android Beam是一个基于近场通信所做的新功能,这个功能可以为其他手机分享你正在使用的功能。 Android升级到4.1后,Android Beam现在可以在两台支持NFC的Android设备间分享照片和视频,还可以与支持NFC的蓝牙设备相连。

?这里有一个标签的概念比较模糊,原文是“当Android设备扫描包含NDEF格式数据的NFC标签,它对消息进行解析,试图找出其中的数据的MIME类型或URI标识”,从该句可看,所谓的标签就是基于NDEF格式的捆绑数据,从标签可获取到NFC设备数据;这里有待确认!

NFC逻辑封装

由于NFC相关是独立于Activity的,所以将NFC的逻辑全部封装在了一个叫做NfcManager的类中,注意该类并不需要做成一个单例;

  • 获取权限

AndroidManifest.xml文件中添加NFC权限:

<uses-permission android:name="android.permission.NFC"/>

另外获取NFC设备数据需要在<activity/>内添加如下内容:

<intent-filter><action android:name="android.nfc.action.TECH_DISCOVERED"/>
</intent-filter><meta-dataandroid:name="android.nfc.action.TECH_DISCOVERED"android:resource="@xml/nfc_tech_filter"/>

上面的nfc_tech_filter是在res/xml文件下的自定义xml文件,用于对NFC服务的筛选:

<?xml version="1.0" encoding="utf-8"?><resources><tech-list><tech>android.nfc.tech.IsoDep</tech></tech-list><tech-list><tech>android.nfc.tech.NfcA</tech></tech-list>
</resources>
  • Intent

Intent是Android中的一个用于传递信息的封装类,可以理解为不同组件通信的媒介或者信使。

在进行Intent的查询过程中了解到Android开发的四大组件,分别是Activity,Service,Broadcast,ContentProvider,而Intent可作为前三者的传递者;

在SDK中给出了Intent作用的表现形式为:

  • 通过Context.startActivity() orActivity.startActivityForResult() 启动一个Activity;

  • 通过 Context.startService() 启动一个服务,或者通过Context.bindService() 和后台服务交互;

  • 通过广播方法(比如 Context.sendBroadcast(),Context.sendOrderedBroadcast(), Context.sendStickyBroadcast()) 发给broadcast receivers。

本例中,我们的NFC卡片信息就是从Intent中读取到的;

  • 初始化NFC

自定义NFCActivity,并在其中声明并定义一个实例变量:

NfcManager  nfcManager_  = new NfcManager();

这里要说一下从谷歌开源项目风格中吸收到的一种命名规则,私有实例变量会在名称后加下划线,而OC的风格是在前面加,不管哪种命名风格,都会有可能性的增加程序的易读性,易用,宜用;

接下来初始化nfc模块,在onCreat()函数中:

nfcManager_.initAdapter(this);

NFCManager声明:


public class NfcManager{//NFCprivate NfcAdapter nfcAdapter_;private PendingIntent pendingIntent_;private NFCActivity activity_;//初始化public void initAdapter(NFCActivity activity){System.out.println ("初始化NFC");//初始化nfc适配器nfcAdapter_ = NfcAdapter.getDefaultAdapter(activity);//初始化卡片信息pendingIntent_ = PendingIntent.getActivity(activity, 0,new Intent(activity, activity.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);//保留外部变量activity_ = activity;}
}

从这里可以看到,NFCActivity保留了NfcManager的实例变量,而反过来NfcManager也保留了NFCActivity的实例变量,这如果是在OC中会造成循环引用问题的;

  • 接收Intent

同样,在onCreat()中:

onNewIntent (getIntent ());

这里这个貌似不用主动调用,onNewIntent()方法也会初调用;这个onNewIntent()Activity的重写方法,Activity检测到有新的Intent时就会调用该方法,我们的NFC事件也是通过这个方法被传送回来的。

接下来:

//处理NFC触发@Overrideprotected void onNewIntent(Intent intent) {//读取数据nfcManager_.readData(intent);}

我们再来看看这个readData()

     private IsoDep isodep_; //ISO14443-4 NFC操作//从Intent中读卡public void readData(Intent intent){if (!NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())){//这里我们做了一个判断,即如果返回的不是NFC事件,直接返回,不做处理;return;}System.out.println ("从intent中获取标签信息!");//从intent中获取标签信息Parcelable p = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);if (p != null) {Tag tag = (Tag) p;isodep_ = IsoDep.get(tag);if (isodep_ != null){readData();}}else {//那么这里就是没有获取到Intent喽}}private void readData() {//毫无疑问,这里就是读卡的操作了//如果想要了解读卡的具体细节,那么这就与外围的NFC设备有关了,Tag里的逻辑将是由NFC设备厂商定义//本工程中的是调用NFC卡厂商的sdk进行读卡的,在实际工程中具体问题需要具体分析,本文中只讨论过程//如果读者有兴趣,稍后会贴出本工程git地址,本例读卡写卡处理sdk为 package com.broadstar.nfccardsdk;}

另外在activity生命周期函数内:

    //程序恢复@Overrideprotected void onResume() {super.onResume();nfcManager_.enableForegroundDispatch(this);}//程序暂停@Overrideprotected void onPause() {super.onPause();nfcManager_.disableForegroundDispatch(this);}

同样NfcManager内部实现:

     public static String[][] TECHLISTS; //NFC技术列表public static IntentFilter[] FILTERS; //过滤器static {try {TECHLISTS = new String[][] { { IsoDep.class.getName() }, { NfcA.class.getName() } };FILTERS = new IntentFilter[] { new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED, "*/*") };} catch (Exception ignored) {}}   public void enableForegroundDispatch(NFCActivity activity){if (nfcAdapter_ != null) {nfcAdapter_.enableForegroundDispatch(activity, pendingIntent_, FILTERS, TECHLISTS);}}public void disableForegroundDispatch(NFCActivity activity){if (nfcAdapter_ != null)nfcAdapter_.disableForegroundDispatch(activity);}

一些其他的问题

  • String parseInt(,)
 String str="123";int i = Integer.parseInt(str,8);

parseInt(,)后面的参数表示当str被看作是多少进制时,i所得到的值(i 是10进制)

  • instanceOf关键字

判断某个子类对象是否属于某个子类的方法:


public class CardInfo{}
public class ReadCardInfo extends CardInfo{}public void someMethod(CardInfo info) {if (info instanceof ReadCardInfo) {//是否是ReadCardInfo的实例}
}
  • 手机访问网络权限

出现java.net.SocketException: socket failed: EACCES (Permission denied)抱错时,AndroidManifest.xml中:

<!--网络访问权限-->
<uses-permission android:name="android.permission.INTERNET" />
  • Android Studio第三方Sdk无法识别的问题

安卓工程的第三方sdk都是放在libs文件夹下的,当无法识别时,点击工程树目录处点击Project,右键libs里的jar包,点击Add as a library,然后再点击同步工程即可解决;

  • 不要在子线程中更新UI,切记,网上有方法可以调用,如果想这样做,那么请自行研究

  • 外部类中new另外一个类的内部类

例如本例中,NFCActivity中有一个CardHandler的实例:

CardHandler中有一个内部公共类:

public class CardHandler{//内部类public class sendCommand implements Runnable {private Map<String, Object> param_ = null;private Message msg = null;public sendCommand(Map<String, Object> param) {sendCommand.this.param_ = param;}//子线程中不可以操作UI,使用Handler进行消息传递@Overridepublic void run() {}}
}

NFCActivityoperateCard()函数想要实例化一个sendCommand的内部类对象,那么:

CardHandler cardHandler_ = new CardHandler(this,nfcManager_);
private void operateCard(Map<String, Object> param) {//内部类的用法ThreadPoolUtils.execute(cardHandler_.new sendCommand(param));//上面的这个方法把sendCommnad操作放在了子线程中
}

Android NFC卡实例详解相关推荐

  1. 《Android NFC开发实战详解》——6.4节Android NFC P2P开发进阶

    本节书摘来自异步社区<Android NFC开发实战详解>一书中的第6章,第6.4节Android NFC P2P开发进阶,作者 赵波,更多章节内容可以访问云栖社区"异步社区&q ...

  2. Android NFC开发实战详解

    Android NFC开发实战详解 Android开发实战详解NFC国内第一本AndroidNFC开发书籍带你开启AndroidNFC开发的神秘之旅大综合案例帮助读者快速进入实战角色:WiFi快速连接 ...

  3. Android百度地图实例详解之仿摩拜单车APP(包括附近车辆、规划路径、行驶距离、行驶轨迹记录,导航等)

    Android百度地图实例详解之仿摩拜单车APP(包括附近车辆.规划路径.行驶距离.行驶轨迹记录,导航等) 标签: android百度地图行驶轨迹记录共享单车行驶距离和时间 2017-03-08 20 ...

  4. Android NFC开发实战详解PDF

    最近找书做毕设,有的还要加会员注册什么的,下面是<Android NFC开发详解>和<第一行代码>,自取,不用谢,来波点赞呗 链接:https://pan.baidu.com/ ...

  5. android 调用oracle,Android 调用WCF实例详解

    Android 调用WCF实例 1. 构建服务端程序 using System.ServiceModel; namespace yournamespace { [ServiceContract(Nam ...

  6. android手机自动化测试,Android手机自动化测试实例详解

    2014-9-24 本人从参加工作以来,一直在做自动化测试方面的工作.最初接触的是Web自动化,后来又做接口自动化测试.由于最近几年手机应用越来越广泛,手机应用的自动化测试也发展的很快,所以我就利用工 ...

  7. android自定义dialog 例子,android dialog自定义实例详解

    本人工作有一个月多了.对于android很多东西,都有了新的了解或者说真正的掌握.为了让更多的像我这样的小白少走弯路,所以我会坚持将我在工作中遇到的一些比较令我印象深刻的知识点整合出来给大家(顺序是按 ...

  8. android的cantext对象,安卓Android Context类实例详解

    1.例如下面的代码片段,Toast类的第一个参数接受一个Context对象: @Override protected Dialog onCreateDialog(int id) { switch (i ...

  9. android sd卡目录查看,Android sd卡目录详解

    一直以来对Android系统目录的获取方法和具体代表含义没有掌握清楚,今天特意整理了一下,分享给大家,对自己也是一个总结. 在android 6.0以前,你可以只关注外置存储是否挂载即可,但是从6.0 ...

最新文章

  1. 最短路径-Floyd(佛洛伊德算法)
  2. typecho引入php文件,Typecho的functions.php
  3. HarmonyOS之深入解析蓝牙Bluetooth的功能和使用
  4. day32—CSS多列布局学习
  5. VS2010中C#添加图片(资源)
  6. spark的rdd的含义_Spark里边:到底是什么RDD
  7. linux管理防火墙开放端口
  8. Java RSA加密(一)--BCD输出
  9. 预防AD对象被误删除
  10. 解密新一代 Java JIT 编译器 Graal
  11. Kafka之sync、async以及oneway
  12. 使用matplotlib和pywaffle绘制象形图(PictorialBar)
  13. 群论(Burnside引理和Polya定理)
  14. MOOC翁恺老师零基础学Java语言课程编程题——第六周
  15. 前端es6 require动态引入图片报错Error: Cannot find module
  16. 着被拍红的手,咯咯一
  17. Codex Popup List
  18. LIKE 后的%和_代表什么?
  19. Myeclipse WebServer 之 简单局域网服务器使用(简单实现局域网IP:Port端口访问局域网数据)
  20. C++ 字符、字符串转十六进制(支持中文字符串转换)

热门文章

  1. 用米思齐(Mixly)进行Arduino编程后上传失败问题记录与解决
  2. 浪潮NF5568M4落地猿题库 让机器老师更智能
  3. 新手入门Linux-Ubuntu20.04
  4. JAVA并发都没搞明白,怎么进大厂?
  5. android usb adb流程
  6. SSM大学生兼职平台源码
  7. Git教程之Linux平台
  8. 2021年优秀信创解决方案名单公布,艺赛旗成功入选
  9. python OpenCV 按(帧数/时间)间隔截取视频帧
  10. 连接超时 服务器无法连到指定,运行blat命令发送邮件时,无法连接到服务器(超时如果winsock.dll错误10060)...