Android NFC 简单实现

博主最近因为项目中要实现nfc读写功能,所以才接触这一方面,理论概念啥的请大家自行查询资料或百度。下面内容为博主自己demo实现的功能,为大家做参考(部分代码来源于其他博主,至于谁是第一个整理的,我也不知道,所以就不写转载谁了)。以下全是干货,大家看看看~~~

功能需求:将卡贴在有nfc功能的设备上,读取、写入数据。

博主查资料说这种属于读卡器模式,数据存储在有nfc芯片的卡中。so,如果大家想知道其他模式,百度去吧~~~

1.Manifest中配置

  //权限
  //要求当前设备具有nfc功能

权限 声明 配置...


    
        
        
        
    

这个是处理nfc的activity。Android提供两个系统来帮助你正确的识别一个NFC tag是否是你的Activity想要处理的:1.Intent发布系统和2.前台Activity发布系统。上面配置的是1。

2.下面贴上一个工具类NfcUtils

public class NfcUtils {

    //nfc
    public static NfcAdapter mNfcAdapter;
    public static IntentFilter[] mIntentFilter = null;
    public static PendingIntent mPendingIntent = null;
    public static String[][] mTechList = null;

    public NfcUtils(Activity activity) {
        mNfcAdapter = NfcCheck(activity);
        NfcInit(activity);
    }

    /**
     * 检查NFC是否打开
     */
    public static NfcAdapter NfcCheck(Activity activity) {
        NfcAdapter mNfcAdapter = NfcAdapter.getDefaultAdapter(activity);
        if (mNfcAdapter == null) {
            ToastUtils.showShort(activity, "设备不支持NFC功能!");
            return null;
        } else {
            if (!mNfcAdapter.isEnabled()) {
                IsToSet(activity);
            } else {
                ToastUtils.showShort(activity, "NFC功能已打开!");
            }
        }
        return mNfcAdapter;
    }

    /**
     * 初始化nfc设置
     */
    public static void NfcInit(Activity activity) {
        Intent intent = new Intent(activity, activity.getClass());
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
        mPendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
        //做一个IntentFilter过滤你想要的action 这里过滤的是ndef
        IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        //如果你对action的定义有更高的要求,比如data的要求,你可以使用如下的代码来定义intentFilter
        //        IntentFilter filter2 = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        //        try {
        //            filter.addDataType("*/*");
        //        } catch (IntentFilter.MalformedMimeTypeException e) {
        //            e.printStackTrace();
        //        }
        //        mIntentFilter = new IntentFilter[]{filter, filter2};
        //        mTechList = null;
        try {
            filter.addDataType("*/*");
        } catch (IntentFilter.MalformedMimeTypeException e) {
            e.printStackTrace();
        }
        mTechList = new String[][]{{MifareClassic.class.getName()},
                {NfcA.class.getName()}};
        //生成intentFilter
        mIntentFilter = new IntentFilter[]{filter};
    }


    /**
     * 读取NFC的数据
     */
    public static String readNFCFromTag(Intent intent) throws UnsupportedEncodingException {
        Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (rawArray != null) {
            NdefMessage mNdefMsg = (NdefMessage) rawArray[0];
            NdefRecord mNdefRecord = mNdefMsg.getRecords()[0];
            if (mNdefRecord != null) {
                return parseTextRecord(mNdefRecord);
            }
        }
        return "";
    }


    /**
     * 往nfc写入数据
     */
    public static void writeNFCToTag(Context context,String data, Intent intent) throws IOException, FormatException {
        NdefRecord ndefRecord = null;
        ndefRecord=createTextRecord(data);
        NdefRecord[] records = {ndefRecord};

        NdefMessage ndefMessage = new NdefMessage(records);

        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        Ndef ndef = Ndef.get(tag);
        if(ndef==null){
            NdefFormatable format = NdefFormatable.get(tag);
            format.connect();
            format.format(ndefMessage);
            if(format.isConnected()){
                format.close();
            }
            return;
        }

        ndef.connect();
        if(!ndef.isWritable()){
            LogUtils.e("当前设备不支持写入");
            return;
        }
        //判断大小
//        if(ndef.getMaxSize() < size)

        ndef.writeNdefMessage(ndefMessage);
        if(ndef.isConnected()){
            ndef.close();
        }
        ToastUtils.showShort(context,"读写完毕");
    }



    /**
     * 读取nfcID
     */
    public static String readNFCId(Intent intent) throws UnsupportedEncodingException {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        String id = ByteArrayToHexString(tag.getId());
        return id;
    }

    /**
     * 将字节数组转换为字符串
     */
    private static 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;
    }


    private static void IsToSet(final Activity activity) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("是否跳转到设置页面打开NFC功能");
//        builder.setTitle("提示");
        builder.setPositiveButton("确认", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                goToSet(activity);
                dialog.dismiss();
            }
        });
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        builder.create().show();
    }

    private static void goToSet(Activity activity) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BASE) {
            // 进入设置系统应用权限界面
            Intent intent = new Intent(Settings.ACTION_SETTINGS);
            activity.startActivity(intent);
            return;
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {// 运行系统在5.x环境使用
            // 进入设置系统应用权限界面
            Intent intent = new Intent(Settings.ACTION_SETTINGS);
            activity.startActivity(intent);
            return;
        }
    }


    /**
     * 创建NDEF文本数据
     * @param text
     * @return
     */
    public static NdefRecord createTextRecord(String text) {
        byte[] langBytes = Locale.CHINA.getLanguage().getBytes(Charset.forName("US-ASCII"));
        Charset utfEncoding = Charset.forName("UTF-8");
        //将文本转换为UTF-8格式
        byte[] textBytes = text.getBytes(utfEncoding);
        //设置状态字节编码最高位数为0
        int utfBit = 0;
        //定义状态字节
        char status = (char) (utfBit + langBytes.length);
        byte[] data = new byte[1 + langBytes.length + textBytes.length];
        //设置第一个状态字节,先将状态码转换成字节
        data[0] = (byte) status;
        //设置语言编码,使用数组拷贝方法,从0开始拷贝到data中,拷贝到data的1到langBytes.length的位置
        System.arraycopy(langBytes, 0, data, 1, langBytes.length);
        //设置文本字节,使用数组拷贝方法,从0开始拷贝到data中,拷贝到data的1 + langBytes.length
        //到textBytes.length的位置
        System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
        //通过字节传入NdefRecord对象
        //NdefRecord.RTD_TEXT:传入类型 读写
        NdefRecord ndefRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
                NdefRecord.RTD_TEXT, new byte[0], data);
        return ndefRecord;
    }



    /**
     * 解析NDEF文本数据,从第三个字节开始,后面的文本数据
     * @param ndefRecord
     * @return
     */
    public static String parseTextRecord(NdefRecord ndefRecord) {
        /**
         * 判断数据是否为NDEF格式
         */
        //判断TNF
        if (ndefRecord.getTnf() != NdefRecord.TNF_WELL_KNOWN) {
            return null;
        }
        //判断可变的长度的类型
        if (!Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {
            return null;
        }
        try {
            //获得字节数组,然后进行分析
            byte[] payload = ndefRecord.getPayload();
            //下面开始NDEF文本数据第一个字节,状态字节
            //判断文本是基于UTF-8还是UTF-16的,取第一个字节"位与"上16进制的80,16进制的80也就是最高位是1,
            //其他位都是0,所以进行"位与"运算后就会保留最高位
            String textEncoding = ((payload[0] & 0x80) == 0) ? "UTF-8" : "UTF-16";
            LogUtils.e("parseTextRecord() textEncoding="+textEncoding);
            //3f最高两位是0,第六位是1,所以进行"位与"运算后获得第六位
            int languageCodeLength = payload[0] & 0x3f;
            //下面开始NDEF文本数据第二个字节,语言编码
            //获得语言编码
            String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
            LogUtils.e("parseTextRecord() languageCode="+languageCode);
            //下面开始NDEF文本数据后面的字节,解析出文本
            String textRecord = new String(payload, languageCodeLength + 1,
                    payload.length - languageCodeLength - 1, textEncoding);
            LogUtils.e("parseTextRecord() text="+textRecord);
            return textRecord;
        } catch (Exception e) {
            throw new IllegalArgumentException();
        }
    }
}

3.Activity中的设置

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
      NfcUtils nfcUtils = new NfcUtils(this);
}

@Override
protected void onResume() {
      super.onResume();
      //设定intentfilter和tech-list。如果两个都为null就代表优先接收任何形式的TAG action。也就是说系统会主动发TAG intent。
      if (NfcUtils.mNfcAdapter != null) {
          NfcUtils.mNfcAdapter.enableForegroundDispatch(this, NfcUtils.mPendingIntent, NfcUtils.mIntentFilter, NfcUtils.mTechList);
      }
}

@Override
protected void onPause() {
      super.onPause();
      if (NfcUtils.mNfcAdapter != null) {
          NfcUtils.mNfcAdapter.disableForegroundDispatch(this);
      }
}

@Override
protected void onDestroy() {
      super.onDestroy();
      NfcUtils.mNfcAdapter = null;
}

@Override
protected void onNewIntent(Intent intent) {
      super.onNewIntent(intent);
      readWrite(intent);
}
//  这块的readWrite() 就是处理卡中数据的方法
public void readWrite(Intent intent) {
    try {
        // 检测卡的id
        String id = NfcUtils.readNFCId(intent);
        // NfcUtils中获取卡中数据的方法
        String result = NfcUtils.readNFCFromTag(intent);
        // 往卡中写数据
        String data = "1这是写入的数据2";
        NfcUtils.writeNFCToTag(this,data,intent);
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }  catch (IOException e) {
        e.printStackTrace();
    } catch (FormatException e) {
        e.printStackTrace();
    }
}

好了,就是这样。如果你想了解更多,那就好好查资料去吧。以上是博主从别的博主那参考过来,然后整理实践出来的demo,仅供大家参考,如有不对,欢迎指正。更多原理性知识,暂时没时间整理,如有时间,继续更上。

 

你可能感兴趣的:(Android)