最近在看NFC功能,重点就是我在页面上设置了一个按钮,要点击此按钮才会开启NFC读卡功能(并非跳转下个Activity),为了方便使用,为此可以专门设置一个基类Activity作为NFC功能的管理,此处我命名为TestNfcBaseActivity



public abstract class TestNfcBaseActivity extends BaseActivity {

//    private NfcManager mNfc;
    private boolean mIsWidthLifeCycle = true;
    public static final int REQ_NFC_OPEN = 0X9000;
    private boolean isOpenNfcByManual = false;


    private Activity activity;
    private NfcAdapter nfcAdapter;
    private PendingIntent pendingIntent;

    private static String[][] TECHLISTS;  //设置你要处理的tag technologies到String数组中
    private static IntentFilter[] TAGFILTERS;
    private int status;

    /** 设备不支持NFC */
    public static final int NFC_NOT_SUPPORT = -1;
    /** NFC已关闭 */
    public static final int NFC_DISABLED = 0;
    /** NFC开启了 */
    public static final int NFC_ABLED = 1;

    /** nfc tag */
    private Tag mTag;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        initDatas();
    }


    /**
     * 是否需要开启NFC相关对象,由于nfc 圈存和ble 圈存公用一套UI,ble圈存是不需要初始化NFC,所以需要让子类决定。
     * @return true 需要初始化nfc
     */
    public abstract boolean isOpenNfc();

    private void initDatas() {
        setTECHLISTSandTAGFILTERS();
        activity = getActivity();
        pendingIntent = PendingIntent.getActivity(activity, 0,
                new Intent(activity, activity.getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
//        pendingIntent = PendingIntent.getActivity(activity, 0,
//                new Intent(activity, getClass()), 0);
        if(isOpenNfc()){
            initNfcManagerByManual(false);
        }
        if(isOpenNfcByManual){
            initNfcManagerByManual(true);
        }
    }

    public BaseNfcNewActivity getActivity(){
        return this;
    }

    public void initNfcManagerByManual(boolean isOpenNfcByManual){
        this.isOpenNfcByManual = isOpenNfcByManual;
        if(nfcAdapter != null){
            ReaderManager.destory();
            nfcAdapter = null;
        }
        nfcAdapter = NfcAdapter.getDefaultAdapter(activity);
        status = getNfcStatus();
        LogUtils.LogError("lenita","nfc status = "+status);
        if(isOpenNfcByManual){
            onResume(); //在生成Adapte后执行,否则无法进入
        }
    }

    public Tag getNfcTag() {
        return mTag;
    }

    public void setNfcTag(Tag mTag) {
        this.mTag = mTag;
    }

    private void setTECHLISTSandTAGFILTERS(){
        try {
            TECHLISTS = new String[][] { {  IsoDep.class.getName() } };
            TAGFILTERS = new IntentFilter[] { new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED, "*/*") };
        } catch (Exception e) {
        }
    }

    public boolean updateNfcStatus() {
        int sta = getNfcStatus();
        if (sta != status) {
            status = sta;
            return true;
        }
        return false;
    }

    /** 获取设备NFC状态 */
    public int getNfcStatus() {
        return (nfcAdapter == null) ? NFC_NOT_SUPPORT : nfcAdapter.isEnabled() ? NFC_ABLED : NFC_DISABLED;
    }

    /**
     * 读卡信息并初始化android.nfc.Tag
     *
     * @param intent
     * @param requesetCode
     *            请求码,回调使用
     * @param listener
     *            回调监听
     * @return 是否执行成功
     */
    public boolean readCard(Intent intent, int requesetCode, ReaderListener listener) {
        final Tag tag = (Tag) intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        this.mTag = tag;
        if (tag != null) {
            ReaderManager.readCardExecute(requesetCode, tag, listener);
            return true;
        }
        return false;
    }

    /**
     * 已经初始化tag,可直接调用读取方法
     *
     * @param requesetCode
     * @param listener
     * @return
     */
    public boolean readCard(int requesetCode, ReaderListener listener) {
        if (mTag != null) {
            ReaderManager.readCardExecute(requesetCode, mTag, listener);
            return true;
        }
        return false;
    }

    /**
     * 发送tlv格式指令,执行出错根据tlv解析
     *
     * @param requesetCode
     * @param instructions
     *            tlv指令集
     * @param listener
     * @return 是否执行成功
     */
    public boolean sendTlvCmd(int requesetCode, String instructions, ReaderListener listener) {
        if (mTag != null) {
            ReaderManager.sendTlvCmdExecute(requesetCode, mTag, instructions, listener);
            return true;
        }
        return false;
    }

    public boolean sendCmd(int requesetCode, String cmd, ReaderListener listener) {
        return sendCmds(requesetCode, new String[] { cmd }, listener);
    }

    /**
     * 发送数组指令集,执行当条出错时,仍然继续执行
     *
     * @param requesetCode
     * @param cmds
     *            数组指令集
     * @param listener
     * @return 是否执行成功
     */
    public boolean sendCmds(int requesetCode, String[] cmds, ReaderListener listener) {
        if (mTag != null) {
            ReaderManager.sendArrayCmdExecute(requesetCode, mTag, cmds, listener);
            return true;
        }
        return false;
    }

    public void destory() {
        ReaderManager.destory();
    }

   /* public final NfcManager getNfc() {
        return mNfc;
    }*/

    @Override
    protected void onResume() {
        super.onResume();
        LogUtils.LogError("lenita","onResume() - isOpenNfcByManual = " +isOpenNfcByManual);
        if(isOpenNfc() || isOpenNfcByManual){
            if (mIsWidthLifeCycle) {
                //设置处理优于所有其他NFC的处理
                if (nfcAdapter != null){
                    nfcAdapter.enableForegroundDispatch(activity, pendingIntent, TAGFILTERS, TECHLISTS);
                }
            }
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        LogUtils.LogError("lenita","onPause()");
        if(isOpenNfc() || isOpenNfcByManual){
            if (mIsWidthLifeCycle) {
                if (nfcAdapter != null){
                    nfcAdapter.disableForegroundDispatch(activity);
                }
            }
        }
    }

    /**
     * Nfc 是否根据生命开启关闭
     *
     * @param enable
     */
    public void setNfcWidthLifeCycle(boolean enable) {
        mIsWidthLifeCycle = enable;
    }

    /**
     * 如果nfc 不支持,或未开启。打开对话提示
     * @return 如果已经开启,返回true 不做任何对话框提示
     */
    public final boolean showNfcProblemDialog() {
        /*if(mNfc == null){
            showLongToastCenter("NFC管理器为空,无法初始化NFC功能");
        }*/
        int nfcStatus = getNfcStatus();
        if (!isFinishing()) {
            if (nfcStatus == NfcManager.NFC_NOT_SUPPORT) {
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.setCancelable(false);
                builder.setTitle("提示").setMessage(com.uroad.nfc.R.string.info_nfc_not_support).setPositiveButton(android.R.string.ok,
                        new DialogInterface.OnClickListener() {

                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                onNfcNotSupportClick();
                            }
                        });
                builder.create().show();
            } else if (nfcStatus == NfcManager.NFC_DISABLED) {
                DialogHelper.showComfirmDialog(this, getString(android.R.string.cancel), "去开启", getString(com.uroad.nfc.R.string.info_nfc_tips_open),  new ComfirmDialog.DialogOnclick() {

                    @Override
                    public void PerDialogclick(ComfirmDialog dialog) {//取消
                        onNfcDisabledCancelClick(dialog);
                    }

                }, new ComfirmDialog.DialogOnclick() {

                    @Override
                    public void PerDialogclick(ComfirmDialog dialog) {//确定
                        onNfcDisabledGoOpenClick(dialog);
                    }

                });

            }
        }

        if(nfcStatus == NfcManager.NFC_ABLED){
            return true;
        }

        return false;

    }

    /**
     * 设备不支持NFC功能
     */
    public void onNfcNotSupportClick() {

    };

    /**
     * NFC 未开启,前往开启
     */
    public void onNfcDisabledGoOpenClick(ComfirmDialog dialog) {
        startNfcSettingsActivity();
        dialog.dismiss();
    }

    /**
     * NFC 未开启,前往开启
     */
    public void onNfcDisabledCancelClick(ComfirmDialog dialog) {
        dialog.dismiss();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        LogUtils.i("onActivityResult requestCode:"+requestCode);
        LogUtils.i("onActivityResult resultCode:"+resultCode);
    }

    private void startNfcSettingsActivity() {
        try {
            startActivityForResult(new Intent("android.settings.NFC_SETTINGS"), REQ_NFC_OPEN);
        } catch (Exception e) {
            startActivityForResult(new Intent(ACTION_SETTINGS), REQ_NFC_OPEN);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if(isOpenNfc() || isOpenNfcByManual){
            destory();
        }
    }
}





封装好基类后,首先先分析一下,上面弄了两种方法,一种是重写isOpenNfc()方法,一种是手动开启方法,下面将写出这两种启动方法的区别,我们设计一个布局来显现,一段提示文字和一张图片



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="vertical"
        android:layout_marginTop="40dp">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:text = "点击图片开启NFC读卡功能"
            android:textColor="@color/red"
            android:gravity="center"
            android:textSize="20dp"/>
        <ImageView
            android:id="@+id/iv_nfc_click"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"
            android:src="@drawable/bg_quancun_connect_nfc" />
    </LinearLayout>

</LinearLayout>





然后是使用的Activity:
一、自动开启NFC,不需要点击才开启的


/**
 *@date 创建时间:2018/01/15
 *@author  lan.zheng
 */
public class PhotographActivity extends TestNfcBaseActivity{
    ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //初始化
        setBaseContentLayout(R.layout.test_nfc_activity);
//        initView();
    }


    /**
     * 是否是自动进入该页面初始化Nfc功能,false:不启动,true:初始化
     * @return
     */
    @Override
    public boolean isOpenNfc() {
        return true;
    }

}
二、手动开启的,假设点击图片可以开启Nfc功能

/**
 *@date 创建时间:2018/01/15
 *@author  lan.zheng
 */
public class PhotographActivity extends TestNfcBaseActivity{
    ImageView imageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //初始化
        setBaseContentLayout(R.layout.test_nfc_activity);
        initView();
    }

    
    private void initView() {
        imageView = (ImageView) findViewById(R.id.iv_nfc_click);
        imageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //TODO 手动开启Nfc
                initNfcManagerByManual(true);
            }
        });
    }

    /**
     * 是否是自动进入该页面初始化Nfc功能,false:不启动,true:初始化
     * @return
     */
    @Override
    public boolean isOpenNfc() {
        return false;
    }

}


开启了Nfc功能,接下来就是要进行贴卡后数据的监听回调和处理,此处需要实现implements ReaderListener接口,然后重写onReadEvent方法,首先我们先写用于监听读卡的,在Activity中:





public final static int REQ_READ_CARD = 0x01;


@Override
    protected void onNewIntent(final Intent intent) {
        super.onNewIntent(intent);
        LogUtils.i("onNewIntent Thread ID:" + Thread.currentThread().getId());
        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                readCard(intent, REQ_READ_CARD, PhotographActivity.this);
            }
        });

    }

当贴卡后,onReadEvent就会拦截到读到的卡片:
@Override
    public void onReadEvent(int requestCode, SPEC.EVENT event, Object... obj) {
        if (requestCode == REQ_READ_CARD) {
            if (event == SPEC.EVENT.SUCCESS) {
                PCard pCard = (PCard) obj[0];
                LogUtils.e(pCard.toString());
                if (XXX) {
                    //是否为满足条件的卡
                    final String cardno = pCard.getSn()+pCard.getCardNumber();
                    showLongToastCenter("卡号为:"+cardno);
                }
            }
            else if (event == SPEC.EVENT.ERROR) {
            Integer resultCode = (Integer) obj[0];
            LogUtils.e("onReadEvent - error - code :" + resultCode);
            showLongToastCenter(getString(R.string.info_nfc_read_card_error));
        }
    }
来手动启动NFC读卡的图片,首先需要你赋予应用NFC权限:


开启后拿卡片进行读卡,此处模拟读到卡号:

好了,以上就是NFC读卡的功能,网上面的参考资料很多,由于没有太多注解,所以还是给个参考文章吧:




   
   


@Override
    public void onReadEvent(int requestCode, SPEC.EVENT event, Object... obj) {
        if (requestCode == REQ_READ_CARD) {
            if (event == SPEC.EVENT.SUCCESS) {
                PCard pCard = (PCard) obj[0];
                LogUtils.e(pCard.toString());
                if (XXX) {
                    //是否为满足条件的卡
                    final String cardno = pCard.getSn()+pCard.getCardNumber();
                    showLongToastCenter("卡号为:"+cardno);
                }
            }
            else if (event == SPEC.EVENT.ERROR) {
            Integer resultCode = (Integer) obj[0];
            LogUtils.e("onReadEvent - error - code :" + resultCode);
            showLongToastCenter(getString(R.string.info_nfc_read_card_error));
        }
    }