场景:NFC是目前Android手机一个主流的配置硬件项,本文主要讲解一下Android开发中,NFC刷卡的两种实现方式以及相关方法源码解析。

①:Manifest注册方式:这种方式主要是在Manifest文件对应的activity下,配置过滤器,以响应不同类型NFC  Action。使用这种方式,在刷卡时,如果手机中有多个应用都存在该NFC实现方案,系统会弹出能响应NFC事件的应用列表供用户选择,用户需要点击目标应用来响应本次NFC刷卡事件。目前我公司这边项目中使用了该逻辑,比较简便,这里先贴一下该方式的实现逻辑。

Manifest配置:

     <!--权限要加,这是一个普通权限,不需要动态申请,但是在小米手机里需要动态申请--><uses-permission android:name="android.permission.NFC" /><uses-featureandroid:name="android.hardware.nfc"android:required="false" /><application> ...   <activityandroid:name=".NfcActivity"android:launchMode="singleTask"android:screenOrientation="portrait"android:theme="@android:style/Theme.Translucent"><!--透明主题,把刷卡变成一个无感知的过程--><intent-filter><action android:name="android.nfc.action.NDEF_DISCOVERED" /></intent-filter><intent-filter><action android:name="android.nfc.action.TAG_DISCOVERED" /><category android:name="android.intent.category.DEFAULT" /></intent-filter><intent-filter><action android:name="android.nfc.action.TECH_DISCOVERED" /><!--使用这个过滤器 这里其实还要用 meta-data 配置一下标签过滤,--><!--我项目中是 NDEF_DISCOVERED 这个TECH_DISCOVERED形同虚设--></intent-filter><meta-dataandroid:name="android.nfc.action.TECH_DISCOVERED"android:resource="@xml/nfc_tech" /></activity></application> 

nfc_tech.xml:这个文件就是TECH_DISCOVERED需要配置的,其中,tech-list之间是逻辑或关系,tech之间是逻辑与关系,与方案②中的techLists原理以及用途是类似的。

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"><tech-list><tech>android.nfc.tech.Ndef</tech><tech>android.nfc.tech.NfcA</tech></tech-list><tech-list><tech>android.nfc.tech.NfcB</tech></tech-list><tech-list><tech>android.nfc.tech.NfcF</tech></tech-list>
</resources>

NfcActivity:

public class NfcActivity extends Activity {@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_nfc);initData();}/*** 初始化数据*/private void initData() {NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);if (null == adapter) {Toast.makeText(this, "不支持NFC功能", Toast.LENGTH_SHORT).show();} else if (!adapter.isEnabled()) {Intent intent = new Intent(Settings.ACTION_NFC_SETTINGS);// 根据包名打开对应的设置界面startActivity(intent);}//我项目中是拿了NFC卡的tag中的id数据,这根据具体情况来;// 可以在NfcAdapter源码中查看,具体能拿到哪些数据Tag tag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);String id = bytesToHex(tag.getId());//TODO 目前我这边项目中,拿到数据后,通过EventBus分发到对应的activity,当然也能使用其他分发响应方式,//关闭动画,毕竟对用户来说,刷卡应当是一个无感知的过程overridePendingTransition(0, 0);finish();}@Overrideprotected void onNewIntent(Intent intent) {super.onNewIntent(intent);initData();}/***  2转10* @param src* @return*/private static String bytesToTenNum(byte[] src) {StringBuilder stringBuilder = new StringBuilder();if (src == null || src.length <= 0) {return null;}char[] buffer = new char[2];for (int i = 0; i < src.length; i++) {buffer[1] = Character.toUpperCase(Character.forDigit((src[i] >>> 4) & 0x0F, 16));buffer[0] = Character.toUpperCase(Character.forDigit(src[i] & 0x0F,16));stringBuilder.append(buffer);}stringBuilder.reverse();BigInteger bigi = new BigInteger(stringBuilder.toString(), 16);return bigi.toString();}/*** 2转16* @param src* @return*/private static String bytesToHex(byte[] src){StringBuffer sb = new StringBuffer();if (src == null || src.length <= 0) {return null;}String sTemp;for (int i = 0; i < src.length; i++) {sTemp = Integer.toHexString(0xFF & src[i]);if (sTemp.length() < 2){sb.append(0);}sb.append(sTemp.toUpperCase());}return sb.toString();}
}

②:前台响应机制;这种方式与第一种的区别如下:方法一中,NFC事件由系统分发,需要选择应用去响应事件;而方法二,直接使用前台activity来捕获NFC事件进行响应,并且优先级高于方案一。

下面对该方案进行解析,直接怼上代码。这里我新建了一个NfcTestActivity进行测试,布局文件就补贴了,随便丢一个就行。

NfcTestActivity:

/*** @author Flash* 创建时间:2021-07-30 11:14*/
public class NfcTestActivity extends AppCompatActivity {NfcAdapter mNfcAdapter;PendingIntent pIntent;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_nfc_test);initNfc();Log.i("FlashTestNFC", "onCreate");}@Overrideprotected void onStop() {super.onStop();Log.i("FlashTestNFC", "onStop");}@Overrideprotected void onDestroy() {super.onDestroy();Log.i("FlashTestNFC", "onDestroy");}/*** 初始化*/private void initNfc(){mNfcAdapter = NfcAdapter.getDefaultAdapter(this);pIntent = PendingIntent.getActivity(this, 0,//在Manifest里或者这里设置当前activity启动模式,否则每次向阳NFC事件,activity会重复创建// 当然也要按照具体情况来,你设置成singleTask也不是不行,new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),0);}@Overrideprotected void onNewIntent(Intent intent) {super.onNewIntent(intent);//这里必须setIntent,set  NFC事件响应后的intent才能拿到数据setIntent(intent);Log.i("FlashTestNFC", "onNewIntent");Tag tag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);//TODO 获取数据进行下一步处理Log.i("FlashTestNFC--Tag", bytesToHex(tag.getId()));}@Overrideprotected void onResume() {super.onResume();Log.i("FlashTestNFC", "onResume");if (mNfcAdapter != null) {//添加intent-filterIntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);IntentFilter tag = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);IntentFilter tech = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);IntentFilter[] filters = new IntentFilter[]{ndef, tag, tech};//添加 ACTION_TECH_DISCOVERED 情况下所能读取的NFC格式,这里列的比较全,实际我这里是没有用到的,因为测试的卡是NDEF的String[][] techList = new String[][]{new String[]{"android.nfc.tech.Ndef","android.nfc.tech.NfcA","android.nfc.tech.NfcB","android.nfc.tech.NfcF","android.nfc.tech.NfcV","android.nfc.tech.NdefFormatable","android.nfc.tech.MifareClassic","android.nfc.tech.MifareUltralight","android.nfc.tech.NfcBarcode"}};mNfcAdapter.enableForegroundDispatch(this, pIntent, filters, techList);}}@Overrideprotected void onPause() {super.onPause();Log.i("FlashTestNFC", "onPause");if (mNfcAdapter != null) {mNfcAdapter.disableForegroundDispatch(this);}}/*** 2进制to 16进制* @param src* @return*/private static String bytesToHex(byte[] src){StringBuffer sb = new StringBuffer();if (src == null || src.length <= 0) {return null;}String sTemp;for (int i = 0; i < src.length; i++) {sTemp = Integer.toHexString(0xFF & src[i]);if (sTemp.length() < 2){sb.append(0);}sb.append(sTemp.toUpperCase());}return sb.toString();}
}

解析:主要其实就是NfcAdapter.enableForegroundDispatch(),开启前台响应;在onNewIntent中获取系统传递过来的数据,并解析;在前台activity停止时,使用NfcAdapter.disableForegroundDispatch()关闭响应。下图是该activity在设置启动模式为singleTop或singleTask情况下,刷卡后该activity生命周期变化:

enableForegroundDispatch源码注释解析,这里大致翻译一下:

  • 将发现的tag(可以理解为NFC刷卡事件)优先分配给应用程序的前台activity;
  • 如果给该方法提供了任何IntentFilters,那么会优先去匹配ACTION_NDEF_DISCOVERED和ACTION_TAG_DISCOVERED。由于ACTION_TECH_DISCOVERED依赖于 IntentFilter 匹配之外的元数据,使用改IntentFilter要通过单独传入techLists来处理的。techLists中的每个第一级条目下的配置必须全部匹配才行。如果任何一级下的内容都匹配,则分派将通过给定的 PendingIntent 进行路由。(这三句话我解释一下:techLists参数是一个二维数组,可以设置很多级,每一级下是第二级,在第二级中放置相关匹配项;看我方法②中对techLists数组的构建方式就能明白)。换句话说,第一级内容是逻辑或关系,第二级内容是逻辑与关系。
  • 如果IntentFilters和techLists都传了null,那么会默认匹配ACTION_TAG_DISCOVERED
  • 这个方法必须在主线程调用,并且activity必须处于前台的情况下。同时,在activity调用enableForegroundDispatch方法后,必须在onPause时调用disableForegroundDispatch进行关闭。
  • Manifest文件中要声明NFC权限。

总结:大概19年8-9月份的时候,那会儿刚开始实习不久,当时手头负责的项目就涉及到NFC刷卡,使用了方案①中的方式。在开发过程中,调试机为自己的华为Mate 20手机,每一次我打开刷卡页面进行刷卡时,都会默认跳转到微信的NFC事件响应页面,这叫一个头大;后来直接找到微信NFC开关,将其关闭后才不影响调试。好在线上手持机设备都是不让用户安装其他应用的。当时还很奇怪,微信到底咋就能强占这NFC响应,现在我终于找到了答案并进行了一定深度的挖掘。

对于这两种方案,我更加偏向于方案②,因为交互上能够体验更好,使用方案①用户可能还会有一个选择的过程。

Android NFC开发(NFC读取)相关推荐

  1. Android 安卓开发板 读取串口

    本文转发自 https://www.logcg.com/archives/2831.html#comments 最近接了个工程,需求是给特制的工程安卓板子做串口读写以实现一些特定外接设备的互动--是的 ...

  2. android nfc ndef mifareclassic,Android NFC开发-实践篇

    Android NFC开发-实践篇 https://blog..net/_GYG/article/details/72899417 在Android NFC开发-理论篇中,我们了解了在Android中 ...

  3. Android NFC开发-实践篇

    Android NFC开发-实践篇 在Android NFC开发-理论篇中,我们了解了在Android中开发NFC的一些理论知识,这篇我们继续应用我们上一篇学到的知识,实现对NDEF格式标签和Mifa ...

  4. Android NFC 开发实例

    http://blog.csdn.net/pku_android/article/details/7430788 类: Android应用开发系列教程 Android应用开发技巧2012-04-06 ...

  5. Android NFC开发详细总结

    Android NFC开发详细总结 Near Field Communication (NFC) 为一短距离无线通信技术,通常有效通讯距离为4厘米以内.NFC工作频率为13.65 兆赫兹,通信速率为1 ...

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

    文章目录 前言 一.什么是NFC? 二.基础知识 1.什么是NDEF? 2.NFC技术的操作模式 3.标签的技术类型 4.实现方式的分类 5.流程 三.获取标签内容 1.检查环境 2.获取NFC标签 ...

  7. Android NFC开发概述

    NFC手机相比普通手机来说,有以下3个附加功能:  1.可以当成POS机来用,也就是"读取"模式   2.可以当成一张卡来刷,也就是NFC技术最核心的移动支付功能  3.可以像蓝牙 ...

  8. Android针对IC卡读写的NFC开发

    菜鸟进场,方圆十里,寸草不生 这两天研究了NFC功能,网上查了很多的资料,不过感觉别人讲的都大同小异,但都缺了那么一点点火候,因为第一次接触有些概念是不清楚的,所以代码看上去很吃力,这个博客呢就是想整 ...

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

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

最新文章

  1. 手把手教你架构3d游戏引擎pdf_一个在游戏行业摸爬滚打了十几年的人,为何我对这本书情有独钟...
  2. 应用程序对象正在关闭_Windows核心编程-内核对象
  3. WHEN OVERSEAS
  4. jQuery表单对象属性过滤选择器
  5. poj 2151 Check the difficulty of problems
  6. Java设计模式6:策略模式
  7. sum()转字符串_Python字符串与内置函数
  8. SQL工作笔记-达梦7存储过程中游标的使用(for循环 IF等)
  9. 软件定义网络文章列表
  10. 大快人心!和P2P网贷彻底说再见
  11. java栈的内存_JVM的栈内存
  12. java毕向东练习题,java中的String类的练习(来自毕向东老师视频资料)
  13. golang base64解码碰到的坑
  14. JavaScript中数组的几种写法
  15. python协程爬取斗鱼美女图片
  16. 算法练习:Sequence II
  17. 凸优化“傻瓜”教程-----凸优化基础知识
  18. ffmpeg 之 hls
  19. python3的txt文件读写
  20. 认知智能中国原生智能科技体系 一文看懂认知智能 道翰天琼认知智能奠基者领导者

热门文章

  1. IE6IE7Firefox浏览器不兼容原因及解决办法
  2. java正则表达式校验手机号,电话号码,邮箱
  3. linux i2c 驱动二 IIC控制器
  4. Android Jelly Bean通知教程
  5. 2022年湖南省一级注册建筑师建筑设计备考模拟题及答案
  6. qq群活动引流php网站源码,QQ群自动私聊引流群发信息器源码
  7. JS--函数--渡一教育(视频笔记)
  8. 如何申请163邮箱账号,商务邮箱这样注册才更COOL!
  9. “五胡乱华”是两汉和曹魏埋下的隐患,为何后世只骂司马家?
  10. 淘宝短视频批量自动发布,无需人工RPA开源