iis服务器助手广告广告
返回顶部
首页 > 资讯 > 移动开发 >Android开发实现NFC刷卡读取的两种方式
  • 1039
分享到

Android开发实现NFC刷卡读取的两种方式

2024-04-02 19:04:59 1039人浏览 泡泡鱼
摘要

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

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

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

Manifest配置:


<!--权限要加,这是一个普通权限,不需要动态申请,但是在小米手机里需要动态申请-->
     <uses-permission android:name="android.permission.NFC" />
   
     <uses-feature
        android:name="android.hardware.nfc"
        android:required="false" />
 
     <application> 
        ...   
        <activity
            android: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-data
                android: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 {
 
    @Override
    protected 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();
    }
 
    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        initData();
    }
 
    
    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();
    }
 
    
    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:



public class NfcTestActivity extends AppCompatActivity {
 
    NfcAdapter mNfcAdapter;
    PendingIntent pIntent;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nfc_test);
        initNfc();
        Log.i("FlashTestNFC", "onCreate");
    }
 
    @Override
    protected void onStop() {
        super.onStop();
        Log.i("FlashTestNFC", "onStop");
    }
 
    @Override
    protected 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);
    }
 
    @Override
    protected 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()));
    }
 
    @Override
    protected void onResume() {
        super.onResume();
        Log.i("FlashTestNFC", "onResume");
        if (mNfcAdapter != null) {
            //添加intent-filter
            IntentFilter 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);
        }
    }
 
    @Override
    protected void onPause() {
        super.onPause();
        Log.i("FlashTestNFC", "onPause");
        if (mNfcAdapter != null) {
            mNfcAdapter.disableForegroundDispatch(this);
        }
    }
 
    
    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响应,现在我终于找到了答案并进行了一定深度的挖掘。
对于这两种方案,我更加偏向于方案②,因为交互上能够体验更好,使用方案①用户可能还会有一个选择的过程。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: Android开发实现NFC刷卡读取的两种方式

本文链接: https://www.lsjlt.com/news/136168.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android开发实现NFC刷卡读取的两种方式
    场景:NFC是目前Android手机一个主流的配置硬件项,本文主要讲解一下Android开发中,NFC刷卡的两种实现方式以及相关方法源码解析。 ①:Manifest注册方式:这种方式...
    99+
    2024-04-02
  • Android实现NFC读取校园卡
    本文实例为大家分享了Android实现NFC读取校园卡的具体代码,供大家参考,具体内容如下 主程序: package com.nfclab.stuCard; import j...
    99+
    2024-04-02
  • Android实现读取NFC卡的编号
    本文实例为大家分享了Android读取NFC卡的编号具体代码,供大家参考,具体内容如下 NFC相关androidManifest文件设置: 一、权限:<uses-permiss...
    99+
    2024-04-02
  • android实现通过NFC读取卡号
    本文实例为大家分享了android通过NFC读取卡号的具体代码,供大家参考,具体内容如下 1.获取权限 <uses-permission android:name="and...
    99+
    2024-04-02
  • Android 实现 NFC 读取卡片信息
    效果图: 因为朋友需要个读取NFC卡片数据的功能,所以最近看了一下Android 系统下NFC 读取卡片信息的操作。 NFC(近距离无线通信 ) 是一组近距离无线技术,通常只有在距离不超过 ...
    99+
    2023-09-09
    android android studio ide Powered by 金山文档
  • Android NFC开发详解 总结和NFC读卡实例解析
    文章目录 前言一、什么是NFC?二、基础知识1.什么是NDEF?2.NFC技术的操作模式3.标签的技术类型4.实现方式的分类5.流程 三、获取标签内容1.检查环境2.获取NFC标签2.1 Manifest中注册的方式获取Tag2...
    99+
    2023-08-24
    android 物联网 嵌入式硬件 android studio java
  • android中NFC读写功能的实现方法
    本文实例为大家分享了android中NFC读写功能的具体代码,供大家参考,具体内容如下 首先检查一下设备是否支持NFC功能 private void checkNFCFuncti...
    99+
    2024-04-02
  • Excel文件读取的两种方式
    1、Pandas库的读取操作 from pandas import read_excel dr=read_excel(filename,header) dr#dataframe数据 dw=DataFrams(data=dict,colum...
    99+
    2023-01-31
    两种 方式 文件
  • Golang 实现超大文件读取的两种方法
    Golang超大文件读取的两个方案 流处理方式 分片处理 去年的面试中我被问到超大文件你怎么处理,这个问题确实当时没多想,回来之后仔细研究和讨论了下这个问题,对大文件读取做了一个分析...
    99+
    2024-04-02
  • Android开发实现读取Assets下文件及文件写入存储卡的方法
    本文实例讲述了Android开发实现读取Assets下文件及文件写入存储卡的方法。分享给大家供大家参考,具体如下:调用一个反编译的.so文件,查看起加密和解密情况,需要解析上万的数组,而so文件加密解密都是通过Byte来进行,又需要把Str...
    99+
    2023-05-30
    android assets roi
  • Android中Handler实现倒计时的两种方式
    背景:最近项目中,正好做到登录/注册这个功能块。它需要通过发送验证码,在规定的时间内用验证码来完成登录/注册。之前的项目中也有这个功能,但是觉得太复杂了,只好自己重新实现一遍。用Handler来做,觉得代码简介,逻辑也清楚。代码一://在向...
    99+
    2023-05-31
    handler 倒计时 roi
  • C#实现文本读取的7种方式
    目录前言第一个方式第二个方式第三个方式第四个方式第五个方式第六个方式第七个方式前言 文本读取在上位机开发中经常会使用到,实现的方式也有很多种,今天跟大家分享一下C#实现读取读取的7种...
    99+
    2024-04-02
  • Python实现获取弹幕的两种方式分享
    目录前言环境获取方式一: <简单, 但是弹幕很少>请求数据获取数据解析数据保存数据获取方式二: <复杂一点点, 弹幕比较多,按日期来>请求数据解析数据翻页保存...
    99+
    2023-03-07
    Python获取弹幕方式 Python获取弹幕 Python 弹幕
  • ListView中实现部分刷新的两种方法
    在ListView中实现部分刷新的两种方法如下:1. 使用notifyDataSetChanged()方法刷新整个ListView:...
    99+
    2023-09-20
    ListView
  • Android实现跑马灯效果的两种简单方式
    第一种:较简单,但是局限性强,貌似只能从右至左跑,且有一个要求:字体的长度需大于控件的长度, 不然没有效果,重要的代码为深色部分,具体代码在文章最后。 重要代码的介绍 1. and...
    99+
    2024-04-02
  • Android开发实现读取excel数据并保存为xml的方法
    本文实例讲述了Android开发实现读取excel数据并保存为xml的方法。分享给大家供大家参考,具体如下:前阵子,公司请外面人翻译了一些android中values中的一些strings,然而保存的都是excel格式,如果单纯的将exce...
    99+
    2023-05-30
    android excel xml
  • JavaScript中实现new的两种方式引发的探究
    前言 当你 new 一个构造函数时发生了什么? “众所周知”的三步: 创建一个空对象,将它的引用赋给 this,继承函数的原型;通过 this 将属性和方法添加至这个对象;最后返回 ...
    99+
    2024-04-02
  • python实现单例的两种方法解读
    目录python 实现单例的方法第一种方法:使用基类第二种方法:使用装饰器python 单例对象单列模式总结python 实现单例的方法 第一种方法:使用基类 New 是真正创建实例...
    99+
    2023-03-02
    python实现单例 python单例 python单例方法
  • 详解SpringMVC的两种实现方式
    目录一、方法一:实现Controller接口二、方法二:使用注解开发一、方法一:实现Controller接口 这个在我的第一个SpringMVC程序中已经学习过了,在此不作赘述,现在...
    99+
    2022-11-13
    SpringMVC实现方式 SpringMVC的两种实现方式
  • Android实现旋转动画的两种方式案例详解
    目录练习案例效果展示前期准备自定义 View java代码编写方法一方法二易错点总结:练习案例 视差动画 - 雅虎新闻摘要加载 效果展示 前期准备 第一步:准备好颜色数组 res ...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作