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
    评论
以下是一个简单的 Android NFC enableReaderMode 的示例代码: ``` public class MainActivity extends AppCompatActivity implements NfcAdapter.ReaderCallback { private NfcAdapter nfcAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); nfcAdapter = NfcAdapter.getDefaultAdapter(this); if (nfcAdapter == null) { Toast.makeText(this, "该设备不支持NFC功能", Toast.LENGTH_SHORT).show(); finish(); return; } } @Override protected void onResume() { super.onResume(); Bundle options = new Bundle(); options.putInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY, 1000); nfcAdapter.enableReaderMode(this, this, NfcAdapter.FLAG_READER_NFC_A | NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, options); } @Override protected void onPause() { super.onPause(); nfcAdapter.disableReaderMode(this); } @Override public void onTagDiscovered(Tag tag) { // 处理读取到的标签信息 } } ``` 在此示例代码中,我们首先获取默认的 NFC 适配器,并检查设备是否支持 NFC 功能。然后,在 onResume() 方法中,我们调用 enableReaderMode() 方法来启用读卡器模式。其中,第一个参数为当前 Activity,第二个参数为实现了 ReaderCallback 接口的对象,第三个参数为标志位,表示读卡器模式的相关设置。最后,我们在 onPause() 方法中调用 disableReaderMode() 方法来关闭读卡器模式。在实现 ReaderCallback 接口的 onTagDiscovered() 方法中,我们可以处理读取到的标签信息。 需要注意的是,enableReaderMode() 方法必须在 onResume() 方法中调用,而 disableReaderMode() 方法必须在 onPause() 方法中调用。此外,enableReaderMode() 方法调用后,应用程序将成为系统中的前台应用程序,并在用户确认后获得 NFC 读取标签的权限。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值