zoukankan      html  css  js  c++  java
  • 简单实现通过NFC标签打开固定应用功能

    一.功能需求

    当手机检测到NFC标签后,可打开相应应用,不管应用是在后台还是不在后台都可打开,当NFC标签离开手机时,会有相应的提示。

    二.开发环境

    Android studio

    具有NFC功能的手机

    NFC标签纸或NFC卡

    三.实现步骤

    1.首先在AndroidManifest.xml文件中添加如下配置,分别指定安卓SDK版本,NFC权限,要求当前设备必须要有NFC芯片

     <uses-sdk android:minSdkVersion="10" />
    
     <uses-permission android:name="android.permission.NFC" />
    
     <uses-feature
           android:name="android.hardware.nfc"
           android:required="true" />

    2.使用intent-filter过滤NFC标签,有三种过滤方式ACTION_NDEF_DISCOVERED,ACTION_TECH_DISCOVERED,ACTION_TAG_DISCOVERED

      可同时配置。如下

     <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.DEFUALT" />
                    <data android:mimeType="text/plain" />
                </intent-filter>
                <intent-filter>
                    <action android:name="android.nfc.action.TECH_DISCOVERED" />
                    <category android:name="android.intent.category.DEFUALT" />
                    <data android:resource="@xml/nfc_tech_filter" />
                </intent-filter>
                <intent-filter>
                    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <data android:scheme="vnd.android.nfc"
                        android:host="ext"
                        android:pathPrefix="/com.example.nfc_test"/>
                </intent-filter>
    
                <intent-filter>
                    <action android:name="android.nfc.action.TAG_DISCOVERED"/>
                </intent-filter>

    其中ACTION_TECH_DISCOVERED需要自己新建过滤器nfc_tech_filter.xml,过滤NFC卡的类型如下:

    <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
        <!-- 可以处理所有Android支持的NFC类型 -->
        <tech-list>
            <tech>android.nfc.tech.IsoDep</tech>
        </tech-list>
        <tech-list>
            <tech>android.nfc.tech.NfcA</tech>
        </tech-list>
        <tech-list>
            <tech>android.nfc.tech.NfcB</tech>
        </tech-list>
        <tech-list>
            <tech>android.nfc.tech.NfcF</tech>
        </tech-list>
        <tech-list>
            <tech>android.nfc.tech.NfcV</tech>
        </tech-list>
        <tech-list>
            <tech>android.nfc.tech.Ndef</tech>
        </tech-list>
        <tech-list>
            <tech>android.nfc.tech.NdefFormatable</tech>
        </tech-list>
        <tech-list>
            <tech>android.nfc.tech.MifareUltralight</tech>
        </tech-list>
        <tech-list>
            <tech>android.nfc.tech.MifareClassic</tech>
        </tech-list>
    </resources>
    View Code

    完整AndroidManifest.xml如下:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.nfc_test">
    
        <uses-sdk android:minSdkVersion="10" />
    
        <uses-permission android:name="android.permission.NFC" />
    
        <uses-feature
            android:name="android.hardware.nfc"
            android:required="true" />
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.NFC_TEST">
            <meta-data
                android:name="com.google.android.actions"
                android:resource="@xml/nfc_tech_filter" />
    
            <activity
                android:name=".MainActivity"
                android:launchMode="singleTop">
                <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.DEFUALT" />
                    <data android:mimeType="text/plain" />
                </intent-filter>
                <intent-filter>
                    <action android:name="android.nfc.action.TECH_DISCOVERED" />
                    <category android:name="android.intent.category.DEFUALT" />
                    <data android:resource="@xml/nfc_tech_filter" />
                </intent-filter>
                <intent-filter>
                    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <data android:scheme="vnd.android.nfc"
                        android:host="ext"
                        android:pathPrefix="/com.example.nfc_test"/>
                </intent-filter>
    
                <intent-filter>
                    <action android:name="android.nfc.action.TAG_DISCOVERED"/>
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    View Code

    3.创建一个基类BaseNfcActivity

    package com.example.nfc_test;
    
    import android.app.PendingIntent;
    import android.content.Intent;
    import android.nfc.NfcAdapter;
    import android.provider.Settings;
    import android.util.Log;
    import android.widget.Toast;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    public class BaseNfcActivity extends AppCompatActivity {
        public NfcAdapter mNfcAdapter;
        public PendingIntent mPendingIntent;
    
        private String TAG = "Android";
        @Override
        protected void onStart() {
            super.onStart();
            mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
    
            if(mNfcAdapter == null){
                //to to sth..
                return;
            }
            else{
                if(!mNfcAdapter.isEnabled()){
                    Intent nfcSet = new Intent(Settings.ACTION_NFC_SETTINGS);
                    startActivity(nfcSet);
                }
            }
            // 用于感应到NFC时启动该Activity
            // 这里建议将处理NFC的子类的launchMode设置成singleTop模式,这样感应到标签时就会回调onNewIntent,而不会重复打开页面
            mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0);
        }
        /**
         * 获得焦点,按钮可以点击
         */
       /* @Override
        public void onResume() {
            super.onResume();
            Log.d(TAG, "bbbbbbbbbbbbbbbbbbbbbbb");
            // 设置当该页面处于前台时,NFC标签会直接交给该页面处理
            if (mNfcAdapter != null) {
             //   Toast.makeText(getApplicationContext(),"NFC标签已离开",Toast.LENGTH_SHORT).show();
                mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
            }
    
        }*/
        /**
         * 暂停Activity,界面获取焦点,按钮可以点击
         */
        @Override
        public void onPause() {
            super.onPause();
            // 当页面不可见时,NFC标签不交给当前页面处理
            if (mNfcAdapter != null) {
                mNfcAdapter.disableForegroundDispatch(this);
            }
        }
    }
    View Code

    4.创建主活动窗口类MainActivity继承BaseNfcActivity

    package com.example.nfc_test;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.app.Activity;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.pm.PackageManager;
    import android.nfc.FormatException;
    import android.os.Bundle;
    
    import android.content.Intent;
    import android.nfc.NdefMessage;
    import android.nfc.NdefRecord;
    import android.nfc.NfcAdapter;
    import android.nfc.Tag;
    import android.nfc.tech.Ndef;
    import android.nfc.tech.NdefFormatable;
    import android.os.Bundle;
    import android.os.Looper;
    import android.util.Log;
    import android.widget.Toast;
    
    import java.io.IOException;
    import java.util.Timer;
    import java.util.TimerTask;
    
    /*
    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    }*/
    
    public class MainActivity extends BaseNfcActivity {
    
        private String TAG = "Debug";
        public boolean flag = false;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }
    
        // 将Activity的launchMode设置成singleTop,这样当感应到NFC标签时不会重复打开页面,而是回调该方法
        @Override
        public void onNewIntent(Intent intent) {
            super.onNewIntent(intent);
            setIntent(intent);
            String action = intent.getAction();
            if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)// NDEF类型
                    || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)// 其他类型
                    || NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) {
                // get tag
                Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
                String CardId = ByteArrayToHexString(detectedTag.getId());
                Log.d(TAG, "ID:" + CardId);
                writeTag(detectedTag);
            } else {
                //...
            }
    
    
            //write tag
            //  writeTag(detectedTag);
        }
    
        /**
         * 写标
         *
         * @param tag
         */
        public void writeTag(Tag tag) {
            if (tag == null) {
                return;
            }
    
            // 利用应用包名创建待写入的数据
            String mPackageName = "com.example.nfc_test";
            NdefMessage ndefMessage = null;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                ndefMessage = new NdefMessage(new NdefRecord[]{NdefRecord
                        .createApplicationRecord(mPackageName)});
            }
    
    //        NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{NdefRecord
    //                .createUri(Uri.parse("http://www.baidu.com"))});
    
            // 获取内容字节大小
            int size = ndefMessage.toByteArray().length;
            try {
                // 获取Nedf
                Ndef ndef = Ndef.get(tag);
                // 不为空表示该标签为Nedf格式
                if (ndef != null && (!ndef.isConnected())) {
                    ndef.connect();
    
                    // 是否可写
                    if (!ndef.isWritable()) {
                        Toast.makeText(this, "标签不支持写入", Toast.LENGTH_SHORT).show();
                        return;
                    }
                    // 判断写入内容大小是否超出允许写入的最大值
                    if (ndef.getMaxSize() < size) {
                        Toast.makeText(this, "写入内容过大", Toast.LENGTH_SHORT).show();
                        return;
                    }
                    // 写入数据
                    ndef.writeNdefMessage(ndefMessage);
                    ndef.close();
                    Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show();
                } else { // 标签非Nedf格式的情况
                    NdefFormatable format = NdefFormatable.get(tag);
                    // 不为空表示该标签允许格式化成Ndef格式
                    if (format != null) {
                        format.connect();
                        // 格式化并写入Nedf内容
                        format.format(ndefMessage);
                        Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(this, "标签不支持Nedf格式", Toast.LENGTH_SHORT).show();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        private 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;
        }
    
        @Override
        public void onResume() {
            super.onResume();
            // 设置当该页面处于前台时,NFC标签会直接交给该页面处理
            if (mNfcAdapter != null) {
                //   Toast.makeText(getApplicationContext(),"NFC标签已离开",Toast.LENGTH_SHORT).show();
                mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
                LoopCheckNfc();
            }
        }
    
        public void LoopCheckNfc() {
            Intent intent = getIntent();
            Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    
            if (detectedTag != null) {
                Ndef ndef = Ndef.get(detectedTag);
                new Thread(new Runnable() {
                    public void run() {
                        try {
                            while (true) {
                                try {
                                    Thread.sleep(1000);
                                    if (ndef != null && (!ndef.isConnected())) {
                                        ndef.connect();
                                        NdefMessage msg = ndef.getNdefMessage();
                                        // TODO: do something
                                    }
    
                                } catch (IOException e) {
                                    // if the tag is gone we might want to end the thread:
                                    Looper.prepare();
                                    Toast.makeText(getApplicationContext(), "NFC标签已不存在,请确认!", Toast.LENGTH_SHORT).show();
                                    Looper.loop();
                                    break;
                                } catch (FormatException e) {
                                    e.printStackTrace();
                                } finally {
                                    try {
                                        ndef.close();
                                    } catch (Exception e) {
                                    }
                                }
                            }
                        } catch (InterruptedException e) {
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
            else
            {
                Log.d(TAG, "invalid pointer!");
            }
        }
        
    
    }
    View Code

    综上就是NFC功能打开指定应用的实现。以上只为简单记录,如有错误之处望指出。

  • 相关阅读:
    Kali学习笔记38:文件上传漏洞
    Kali学习笔记37:APPSCAN
    Kali学习笔记36:AVWS10的使用
    Kali学习笔记35:使用VBScript、PowerShell、DEBUG传输文件
    Kali学习笔记34:配置TFTP和FTP服务
    《day13--异常的进阶和包的使用》
    《java作业》
    《day12---异常》
    《AppletButtonEvent.java》
    《CheckboxDemo.java》
  • 原文地址:https://www.cnblogs.com/zhangfengfly/p/14577437.html
Copyright © 2011-2022 走看看