安卓开发,NFC读取NFC标签ID(二)。

安卓开发,NFC读取NFC标签ID(二)。

后续会整理出demo来,也会免费放出来。
(一的)链接: 安卓开发,NFC读取NFC标签ID,包含Dome和个人见解。

在研究完一中的NFC功能后,由于需求的变动,其中主要是想要用户能够设置NFC贴卡时手机触发的震动和声音。(震动大家都知道。声音的话年轻人的手机可能大多是静音模式只打开媒体声音,如果关掉静音模式你会发现,NFC的声音还挺大的,而且如果要频繁使用,不论是震动还是声音都是不太友好的)
于是发现了NFC既然不仅仅有上次我写的那些。

NFC的两种调用方式

1、前台调度系统

前台调度也就是我在上一篇NFC文章中所用到的NfcAdapter.enableForegroundDispatch()

抄了一些八股文。从 Android 2.3.3 开始就存在(这基本上是 Android NFC 的开始)。因此,所有具有 NFC 功能的 Android 设备都支持此方法。前台调度系统用于为当前在前台处理 NFC 发现事件(即发现的 NFC 标签和从对等设备接收的 NDEF 消息)提供优先级的 Activity 。这意味着即使为特定标签类型或 NDEF 数据注册了另一个应用程序(通过 AndroidManifest.xml 中的 Intent 过滤器),NFC 事件仍将被传递到前台 Activity 的其他 Activity 。因此,该方法不会改变 Android 监听 NFC 设备(NFC 标签、P2P 设备)的方式,它只会改变处理已发现设备的优先级。

简单来说就是这种方式是通过清单中声明的过滤器来实现的,会提高整个应用的NFC优先级。而且在桌面就扫NFC就会显示你的APP(注意:可能会存在一个问题,如果手机只有一个声明了前台NFC调度的APP在桌面刷NFC系统会直接跳转打开该应用,多个时会弹出底部弹窗显示多个APP共选择

2、阅读器模式 API

阅读器模式 API也就我这篇想要讲的NfcAdapter.enableReaderMode()

八股文*2。阅读器模式 API (NfcAdapter.enableReaderMode()) 是在 Android 4.4 中引入的。因此,并非所有具有 NFC 功能的 Android 设备都支持此方法。与前台调度系统相反,阅读器模式 API 确实改变了 Android 监听 NFC 设备的方式。 reader-mode API 禁用对等模式。例如,这允许您发现同时启用了点对点模式和卡模拟模式的其他设备的卡模拟模式(如 Android HCE 的情况)。 (通常情况下,此类设备会被发现为点对点设备,Android 应用将无法访问卡模拟功能。)此外,您可以更改 NFC 阅读器模式的特定参数,例如你可以:定义 NFC 读取器轮询的标签技术,通过向标签发送特定命令序列并检查是否仍收到响应来定义 Android 测试标签是否仍然存在的时间间隔,阻止 Android 自动向标签发送命令以测试标签是否包含 NDEF 消息,在标签发现时阻止 Android 播放声音。

简单来说就是比起前台调度,阅读器模式有着更细致的定义,其中就包含我所需要的阻止系统播放声音。

废话有点多了,我从来不是一个喜欢说废话的人,直接上代码。

/**
 * Created by bob
 * Date : 21-10-29
 * Describe :
 */
import android.app.Activity;
import android.content.Context;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.util.Log;
import android.widget.Toast;

import com.mieasy.chilin.es.pt.Constants;
import com.mieasy.chilin.es.pt.interfaces.RebootListener;

/**
 * 对NFC调用的封装
 */
public class NfcUtils implements RebootListener {

    private static final String TAG = "NfcUtils";

    private static NfcAdapter mNfcAdapter;

    private NfcUtils(){}

    private static NfcUtils nfcUtils = null;

    private static boolean isOpen = false;

    /**
     * 获取NFC的单例
     * @return NfcUtils
     */
    public static NfcUtils getInstance(){
        if (nfcUtils == null){
            synchronized (NfcUtils.class){
                if (nfcUtils == null){
                    nfcUtils = new NfcUtils();
                }
            }
        }
        return nfcUtils;
    }

    /**
     * 在onStart中检测是否支持nfc功能
     * @param context 当前页面上下文
     */
    public void onStartNfcAdapter(Context context){
        mNfcAdapter = NfcAdapter.getDefaultAdapter(context);//设备的NfcAdapter对象
        if(mNfcAdapter==null){//判断设备是否支持NFC功能
            Toast.makeText(context,"设备不支持NFC功能!",Toast.LENGTH_SHORT).show();
            return;
        }
        if (!mNfcAdapter.isEnabled()){//判断设备NFC功能是否打开
            Toast.makeText(context,"请到系统设置中打开NFC功能!",Toast.LENGTH_SHORT).show();
            return;
        }
        Log.d(TAG,"NFC is start");
    }

    /**
     * 在onResume中开启nfc功能
     * @param activity
     */
    public void onResumeNfcAdapter(Activity activity){
        if (mNfcAdapter!=null && mNfcAdapter.isEnabled()){
//            mNfcAdapter.enableForegroundDispatch(this,mPendingIntent,null,null);//打开前台发布系统,使页面优于其它nfc处理.当检测到一个Tag标签就会执行mPendingItent
            if (!isOpen)
            mNfcAdapter.enableReaderMode(activity, new NfcAdapter.ReaderCallback() {
                        @Override
                        public void onTagDiscovered(Tag tag) {
                            Log.d(TAG,CommonUtils.ByteArrayToHexString(tag.getId()));
                            if (nfcListener != null)
                            (activity).runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    nfcListener.doing(tag);
                                }
                            });
                        }
                    },
                    (MMKVUtils.getBoolean(Constants.VOICESWITCH) ?
                            NfcAdapter.FLAG_READER_NFC_A |
                                    NfcAdapter.FLAG_READER_NFC_B |
                                    NfcAdapter.FLAG_READER_NFC_F |
                                    NfcAdapter.FLAG_READER_NFC_V |
                                    NfcAdapter.FLAG_READER_NFC_BARCODE

                            :NfcAdapter.FLAG_READER_NFC_A |
                            NfcAdapter.FLAG_READER_NFC_B |
                            NfcAdapter.FLAG_READER_NFC_F |
                            NfcAdapter.FLAG_READER_NFC_V |
                            NfcAdapter.FLAG_READER_NFC_BARCODE|
                            NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS),
                    null);
            isOpen = true;
            Log.d(TAG,"Resume");
        }
    }

    /**
     * 在onPause中关闭nfc功能
     * @param activity
     */
    public void onPauseNfcAdapter(Activity activity){
        if(mNfcAdapter!=null && mNfcAdapter.isEnabled()){
            if (isOpen)
            mNfcAdapter.disableReaderMode(activity);
            isOpen = false;
        }
        Log.d("myNFC","onPause");
    }

    private  NfcListener nfcListener;

    public void setNfcListener(NfcListener listener){
        nfcListener = listener;
    }

    @Override
    public void Reboot(Activity activity) {
        if(mNfcAdapter!=null){
            mNfcAdapter.disableReaderMode(activity);
            mNfcAdapter.enableReaderMode(activity, new NfcAdapter.ReaderCallback() {
                        @Override
                        public void onTagDiscovered(Tag tag) {
                            Log.d(TAG,CommonUtils.ByteArrayToHexString(tag.getId()));
                            (activity).runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    nfcListener.doing(tag);
                                }
                            });
                        }
                    },
                    (SpCommonUtils.getVoiceSwitch() ?
                            NfcAdapter.FLAG_READER_NFC_A |
                                    NfcAdapter.FLAG_READER_NFC_B |
                                    NfcAdapter.FLAG_READER_NFC_F |
                                    NfcAdapter.FLAG_READER_NFC_V |
                                    NfcAdapter.FLAG_READER_NFC_BARCODE

                            :NfcAdapter.FLAG_READER_NFC_A |
                            NfcAdapter.FLAG_READER_NFC_B |
                            NfcAdapter.FLAG_READER_NFC_F |
                            NfcAdapter.FLAG_READER_NFC_V |
                            NfcAdapter.FLAG_READER_NFC_BARCODE|
                            NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS),
                    null);
        }
    }

    /**
     * 自定义的NFC接口
     */
    public interface NfcListener{
        /**
         * 用于扫到nfc后的后续操作
         */
        void doing(Tag tag);
    }
}

涉及工具类

public class CommonUtils {

    public static String ByteArrayToHexString(byte[] inarray) {
        int i, j, in;
        String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A",
                "B", "C", "D", "E", "F"};
        String out = "";


        for (j = 0; j < inarray.length; ++j) {
            in = (int) inarray[j] & 0xff;
            i = (in >> 4) & 0x0f;
            out += hex[i];
            i = in & 0x0f;
            out += hex[i];
        }
        return out;
    }
   }

以上是我自己封装的工具类,非常实用。简单讲下,首先这是个单例工具,用于全局使用。毕竟NFC这种东西只有当前界面应该起反应。

从onResume生命周期开始便与之前的前台调度截然不同。前台调度的NFC识别类型是通过清单声明,类型列表是写在资源文件里的。而阅读器模式则是在开启阅读器模式时传进去的。如下图
在这里插入图片描述

而(MMKVUtils.getBoolean(Constants.VOICESWITCH)代码中的这是我用来控制声音的,阅读器模式下,声音的控制是与卡类型一同传入的。当加入NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS时,系统将不再扫NFC发出声音,但同时震动也消失了。我看了源码,并没有发现有单独的控制。

然后这个工具类继承的接口

import android.app.Activity;

/**
 * Created by bob
 * Date : 2022/1/17
 * Describe : 用于重启nfc功能以关闭声音和振动
 */
public interface RebootListener {
    void Reboot(Activity activity);
}

功能如注释所言。
用的话就是普通接口,例:

private RebootListener listener = (RebootListener)getActivity();

voice_bt.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                 if (isChecked){
                	MMKVUtils.put(Constants.VOICESWITCH,true);
            	}else{
                	MMKVUtils.put(Constants.VOICESWITCH,false);
            	}
                listener.Reboot();
            }
        });

最后也是最重要的,就是工具类里的NfcListener接口,用于向外界传递扫NFC所获取到的tag(也就是ID之类的信息)。需要使用的地方,不论是act还是fragment必须要实现这个接口。然后就可以在实现的doing方法里干自己想干的。

整个工具的使用样例:

public class MainActivity extends BaseActivity implements NfcUtils.NfcListener{
	
	@Override
    protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		 NfcUtils.getInstance().setNfcListener(this);
    }

	@Override
    protected void onStart() {
        super.onStart();
        nfcUtils.onStartNfcAdapter(context);
    }

    @Override
    protected void onResume() {
        super.onResume();
        nfcUtils.onResumeNfcAdapter(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        nfcUtils.onPauseNfcAdapter(this);
    }

    @Override
    public void doing(Tag tag) {
        Log.d("test", CommonUtils.ByteArrayToHexString(tag.getId()));
    }
}

如果是在fragment中使用也是一样的。简单来讲就是onStart中判断(其实这里可以优化,设备是否支持没必要每次检查),onResume中开启阅读器模式,onPause中关闭阅读器模式。

NfcUtils.getInstance().setNfcListener(this);是为了每个页面的或者每个碎片的doing方法独立开来。

好了希望此文章对你的NFC之旅有所帮助。

动图展示

在这里插入图片描述

免费demo地址

(免费)Demo地址:https://download.csdn.net/download/weixin_45920642/87699832

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值