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中申明权限

<uses-permission android:name="android.permission.NFC"/>
<uses-feature android:name="android.hardware.nfc" android:required="true"/> 添加了这句代码,会使得在应用商店下载应用是过滤掉不支持NFC功能的设备。

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

<activity android:name=".MainActivity"
            android:launchMode="singleTop"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustUnspecified|stateHidden"
            android:configChanges="orientation|keyboardHidden">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:mimeType="text/plain" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.TAG_DISCOVERED"/>
            </intent-filter>

            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED"/>
            </intent-filter>

            <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />
</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<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> 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<String>() {
                    @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<Throwable>() {
                    @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

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值