android NFC读写卡Demo

学习链接:

https://developer.android.com/guide/topics/connectivity/nfc/nfc

https://www.kancloud.cn/alex_wsc/android-wifi-nfc-gps/414141

第一步:AndroidManifest.xml中申明权限


 添加了这句代码,会使得在应用商店下载应用是过滤掉不支持NFC功能的设备。

第二步:AndroidManifest.xml中申明与NFC目标交互的activity


            
                

                
            

            
                
                
                
            
            
                
            

            
                
            

            

这里声明了三种intent筛选条件,分别是action为

android.nfc.action.NDEF_DISCOVERED,

android.nfc.action.TECH_DISCOVERED,

android.nfc.action.TAG_DISCOVERED。

这一步可以帮助android系统内的NFC模块在扫描到一个NFC目标的时候寻找到我们的activity来进行交互。

android系统内的NFC模块在扫描到一个NFC目标后会通过以下几步来寻找到合适的处理NFC消息的activity。在这之前先介绍两个概念,1、Tag代表一个NFC目标,当android设备扫描到一个NFC目标的时候会将相关数据封装成一个Tag实例,通过Intent传递给合适的activity去做处理。2、TagTechnology表示NFC标签支持的技术,可以通过Tag的getTechList()获取。

Tag的分发步骤:

1、先看Tag中是否包含了系统支持的NDEF数据,如果包含则分发给注册了action为ACTION_NEDF_DISCOVERED的activity。

2、如果Tag中不包含系统支持的NDEF数据或者没有找到注册了action为ACTION_NDEF_DISCOVERED的activity,则NFC系统模块尝试分发给一个action为ACTION_TECH_DISCOVERED的activity。NFC系统模块在分发是首先分析NFC Tag支持的Tag Technology,然后寻找支持这类Tag Technology的activity,然后封装了Tag数据的Intent分发给对应的activity。

3、如果上面两种都不满足,则发送action为ACTION_TAG_DISCOVERED的intent

第三步,编写activity及相关工具类,和NFC目标进行读卡,发送指令等交互动作

public class MainActivity extends AppCompatActivity implements NfcView{

    private static final String TAG = MainActivity.class.getName();

    @BindView(R.id.rev_data) EditText mRevDataEt;
    @BindView(R.id.send_command_et) EditText mSendCommandEt;
    @BindView(R.id.read_btn) Button mReadCardBtn;
    @BindView(R.id.send_command_btn) Button mSendCommandBtn;

    private NfcHandler mNfcHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate()! ");
        mNfcHandler = new NfcHandler(this);
        mNfcHandler.init(this);
        ButterKnife.bind(this);
    }

    @Override
    protected void onNewIntent(Intent intent) {
        Log.d(TAG, "onNewIntent()! action is:" + intent.getAction());
        super.onNewIntent(intent);
        setIntent(intent);
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume()! intent action is:" + getIntent().getAction());
        mNfcHandler.enableNfc(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mNfcHandler.disableNfc(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mNfcHandler.onDestroy();
    }

    @Override
    public void appendResponse(String response) {
        mRevDataEt.append(response);
    }

    @OnClick({R.id.send_command_btn, R.id.read_btn})
    void onBtnClick(View view) {
        switch (view.getId()) {
            case R.id.read_btn:
                mNfcHandler.readCardId(getIntent());
                break;
            case R.id.send_command_btn:
                mNfcHandler.sendCommand(this, mSendCommandEt.getText().toString());
                break;
            default:
                break;
        }
    }

}
public class NfcHandler {

    private NfcAdapter mNfcAdapter;
    private IsoDep mIsoDep;
    private NfcView mView;
    public NfcHandler(NfcView view) {
        this.mView = view;
    }

    public void init(Context context) {
        mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
    }

    private boolean checkNfc(Context context) {
        if (mNfcAdapter == null) {
            Toast.makeText(context, "未找到NFC设备!", Toast.LENGTH_SHORT).show();
            return false;
        } else if (!mNfcAdapter.isEnabled()) {
            Toast.makeText(context, "请在设置中打开NFC开关!", Toast.LENGTH_SHORT).show();
            return false;
        }
        return true;
    }

    /**
     * 通过tag.getTechList()可以获取当前目标Tag支持的Tag Technology,这里默认支持IsoDep。
     * 通过IsoDep.get(tag)方式获取IsoDep的实例。然后通过函数connect()我们应用和IC卡之间建立联系,
     * 建立联系后我们可以往IC卡发送指令进行交互。
     * @param intent
     */
    private void connectNfc(Intent intent) {
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()) ||
                NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()) ||
                NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            if (tag != null) {
                mIsoDep = IsoDep.get(tag);
                try {
                    mIsoDep.connect();  //这里建立我们应用和IC卡
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 这个函数可以获取IC卡的序列号
     * @param intent
     */
    public void readCardId(Intent intent) {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        if (tag != null && mView != null) {
            byte[] ids = tag.getId();
            String uid = DataUtil.bytesToHexString(ids, ids.length);
            mView.appendResponse("\n uid is:" + uid);
        }

    }

    public void sendCommand(final Context context, final String command) {
        Observable observable = Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter emitter){
                if (mIsoDep == null) {
                    emitter.onError(new Throwable("NFC设备未连接!"));
                    return;
                }
                try {
                    if (!mIsoDep.isConnected()) {
                        mIsoDep.connect();
                    }
                    byte[] sendData = DataUtil.hexStringToBytes(command);
                    if (sendData == null) {
                        emitter.onError(new Throwable("指令输入有误!"));
                        return;
                    }
                    byte[] responseData = mIsoDep.transceive(sendData);
                    emitter.onNext(DataUtil.bytesToHexString(responseData, responseData.length));
                } catch (IOException e) {
                    emitter.onError(new Throwable("NFC连接中断!"));
                }
            }
        });
        observable.subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer() {
                    @Override
                    public void accept(String s) {
                        if (s == null) {
                            Toast.makeText(context, "指令输入有误!", Toast.LENGTH_SHORT).show();
                        } else {
                            mView.appendResponse("\n apdu is:" + s);
                        }
                    }
                }, new Consumer() {
                    @Override
                    public void accept(Throwable throwable) {
                        Toast.makeText(context, throwable.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                });
    }

    public void enableNfc(Activity activity) {
        if (checkNfc(activity)) {
            PendingIntent pendingIntent = PendingIntent.getActivity(activity,
                    0, new Intent(activity, activity.getClass()), 0);
            mNfcAdapter.enableForegroundDispatch(activity, pendingIntent, null, null);
            connectNfc(activity.getIntent());
        }
    }

    public void disableNfc(Activity activity) {
        if (mIsoDep != null && mIsoDep.isConnected()) {
            try{
                mIsoDep.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (mNfcAdapter != null) {
            mNfcAdapter.disableForegroundDispatch(activity);
        }
    }

    public void onDestroy() {
        mView = null;
    }
}

 Demo地址:https://github.com/Wcuren/android_nfc_demo

 

你可能感兴趣的:(Android杂记)