对M1卡指定区块的读写,通过阅读nfc官方文档,对m1任意位置的读写需求如下图(实现对图中区块的指定位置读写)
本文涉及知识点:1,android,java 2,javascript 3,html
首先上网页代码,如下:
[HTML] 纯文本查看 复制代码
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/> <title>手机H5测试</title> <style> *{ text-align: center; } nav li{ display: inline; width: 24%; text-decoration: none; padding: 15px; } li:hover{ background-color: blue; } section{ height: 100%; } body{ /*font-size: 50px;*/ padding: 5px 0; } textarea,#content{ width: 100%; height: 400px; /*font-size: 50px;*/ background-color: blue; } button,#import{ width: 100%; height: 100px; font-size: 50px; margin-top: 30px; } input,#shuru{ width:20%; height:30px; font-size:20px; margin-top:5px; } </style> <script type="text/javascript"> var cardtype="员工卡"; window.onload=function () { //获取 li 也就是选项卡选项tab var nav=document.getElementById('nav'); var oNav=nav.getElementsByTagName('li'); //获取 包裹在container里面的section(内容) var container=document.getElementById('container'); var oDiv=container.getElementsByClassName('tab'); //使用 循环依次得到li for(var i=0;i<oNav.length;i++){ oNav[i].index=i; //每一次得到li后执行鼠标点击操作则触发函数function oNav[i].onclick=function () { //此处除了可以使用onclick,还可以使用onmouseover //在li的个数内依次展示内容 for(var i=0;i<oNav.length;i++){ oNav[i].className=''; oDiv[i].style.display="none"; } this.className='act'; cardtype=this.innerHTML; oDiv[this.index].style.display="block" } for(var m=1;m<oNav.length;m++){ oNav[m].className=''; oDiv[m].style.display="none"; } } } function backdata(arg){ document.getElementById("shownfcinfo").innerHTML=(arg); } function pargs(){ var card1_str=""; if(cardtype=="员工卡"){ for(var m=0;m<3;m++){ card1_str=card1_str+document.getElementById('str'+m).value+","; } }else{ var n=3; for(var m=0;m<11;m++){ card1_str=card1_str+document.getElementById('str'+n).value+","; n++; } } return card1_str; } </script> </head> <body> <nav id="nav"> <ul id="test"> <li class="act">员工卡</li> <li>生产卡</li> </ul> </nav> <div id="container" style="color:#00FF00"> <section class="tab" style="background-color: tomato">卡类型<input id="str0" type="text" name="a" value="byte[1]">员工编号<input id="str1" type="text" name="a" value="byte[2]">员工名称<input id="str2" type="text" value="byte[12]"style="width:76%;"></section> <section class="tab" style="background-color: cyan">卡类型<input id="str3" type="text" name="a" value="[1]" style="width:5%;">ID<input id="str4" type="text" value="[4]" style="width:15%;">总经长<input id="str5" type="text" name="a" value="[4]" style="width:15%;"><br>经密<input id="str6" type="text" name="a" value="[2]" style="width:10%;">纬密<input id="str7" type="text" name="a" value="[2]" style="width:10%;">织缩<input id="str8" type="text" name="a" value="[2]" style="width:10%;">产品编号<input id="str9" type="text" name="a" value="[24]" style="width:90%;"><br>扣号<input id="str10" type="text" name="a" value="[8]" style="width:30%;">经轴编号<input id="str11" type="text" name="a" value="[16]" style="width:60%;">批号<input id="str12" type="text" name="a" value="[2]" style="width:10%;">备注<input id="str13" type="text" name="a" value="byte[30]" style="width:90%;"></section> <button id="bt1" type="button">写入信息</button> <button id="bt2" type="button">读取信息</button> <p id="shownfcinfo">这里显示读<br>取到的信息</p> </div> </body> </html>
android读写卡代码,如下:
[Java] 纯文本查看 复制代码
package com.example.androidjs.NFCUtil; import android.content.Intent; import android.nfc.NfcAdapter; import android.nfc.Tag; import android.nfc.tech.MifareClassic; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; public class NFCUtil { private Tag tag; private static NFCUtil helper; private byte[] bytes = {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}; private NFCUtil.NFCCallback callback; public NFCUtil(Intent intent) { this.tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); } /** * 单例初始化 * * [url=home.php?mod=space&uid=952169]@Param[/url] intent * @return */ public static NFCUtil getInstence(Intent intent) { if (helper == null) { helper = new NFCUtil(intent); } return helper; } /** * 写卡 * * @param str 书写内容,16个字节 * @param a 书写的扇区 (从0开始数) * @param b 书写的块(从0开始数) * @param callback 返回监听 */ public void writeblock(byte[] str, int a, int b, NFCUtil.NFCCallback callback) { MifareClassic mfc = MifareClassic.get(tag); if (null != mfc) { try { //连接NFC mfc.connect(); //范围外不可写 if ((a==0&&b==0)||(b > 3 || b < 0)||(a > 15 || a < 0)){ callback.WriteSuccess(false); return; } //验证扇区密码 int bIndex = mfc.sectorToBlock(a); //写卡,str.length=16 mfc.writeBlock(bIndex + b, str); callback.WriteSuccess(true); } catch (Exception e) { e.printStackTrace(); callback.WriteSuccess(false); } finally { } } } public void writeSixblock(byte[] str, final NFCUtil.NFCCallback callback) { new Thread(new Runnable() { @Override public void run() { MifareClassic mfc = MifareClassic.get(tag); if (null != mfc) { try { mfc.connect(); byte[] backByte=new byte[96]; int n=0; for (int j=0;j<2;j++){ boolean isOpen = mfc.authenticateSectorWithKeyA(4+j, bytes); if (isOpen) { for (int i=0;i<3;i++){ int bIndex = mfc.sectorToBlock(4+j); byte[] data = mfc.readBlock(bIndex + i); System.arraycopy(data,0,backByte,n*16,16); n++; } }else { callback.error(); } } callback.callBack(backByte); } catch (Exception e) { callback.error(); e.printStackTrace(); } finally { try { mfc.close(); } catch (IOException e) { e.printStackTrace(); } } } } }).start(); } /**20190701 * @param str * @param sector 扇区号 * @param block 块号 * @param start * @param end * @param callback */ public void writeBytes(final byte[] str, final int sector, final int block, final int start, final int end, final NFCUtil.NFCCallback callback){ } /** * 读取NFC卡的全部信息 * * @param callback */ public void readAll(final NFCCallback callback) { new Thread(new Runnable() { @Override public void run() { Map<String, List<String>> map = new HashMap<>(); MifareClassic mfc = MifareClassic.get(tag); if (null != mfc) { try { //链接NFC mfc.connect(); //用于判断时候有内容读取出来 boolean flag = false; for (int i = 0; i <16; i++) { List<String> list = new ArrayList<>(); //验证扇区密码,否则会报错(链接失败错误) boolean isOpen = mfc.authenticateSectorWithKeyA(i, bytes); if (isOpen) { //获取扇区第一个块对应芯片存储器的位置(我是这样理解的,因为第0扇区的这个值是4而不是0) int bIndex = mfc.sectorToBlock(i); //String data1 = ""; for (int j = 0; j < 4; j++) { //读取数据 byte[] data = mfc.readBlock(bIndex); bIndex++; list.add(stringUtils.bytesToString(data)); } flag = true; } map.put(i + "", list); } if (flag) { callback.callBack(map); } else { callback.error(); } } catch (Exception e) { callback.error(); e.printStackTrace(); } finally { try { mfc.close(); } catch (IOException e) { e.printStackTrace(); } } } } }).start(); } /** * 读取NFC卡的特定扇区信息 * * @param a 扇区 * @param b 块 * @param callback */ public void readblock(final int a, final int b, final NFCCallback callback) { new Thread(new Runnable() { @Override public void run() { MifareClassic mfc = MifareClassic.get(tag); if (null != mfc) { try { mfc.connect(); if ((a < 0 || a > 15)||(b < 0 || b > 3)) { callback.error(); return; } boolean isOpen = mfc.authenticateSectorWithKeyA(a, bytes); if (isOpen) { int bIndex = mfc.sectorToBlock(a); byte[] data = mfc.readBlock(bIndex + b); callback.callBack(data); } else { callback.error(); } } catch (Exception e) { callback.error(); e.printStackTrace(); } finally { try { mfc.close(); } catch (IOException e) { e.printStackTrace(); } } } } }).start(); } public void readSixblock(final NFCCallback callback) { new Thread(new Runnable() { @Override public void run() { MifareClassic mfc = MifareClassic.get(tag); if (null != mfc) { try { mfc.connect(); byte[] backByte=new byte[96]; int n=0; for (int j=0;j<2;j++){ boolean isOpen = mfc.authenticateSectorWithKeyA(4+j, bytes); if (isOpen) { for (int i=0;i<3;i++){ int bIndex = mfc.sectorToBlock(4+j); byte[] data = mfc.readBlock(bIndex + i); System.arraycopy(data,0,backByte,n*16,16); n++; } }else { callback.error(); } } callback.callBack(backByte); } catch (Exception e) { callback.error(); e.printStackTrace(); } finally { try { mfc.close(); } catch (IOException e) { e.printStackTrace(); } } } } }).start(); } public interface NFCCallback { /** * 返回是否成功 * * @param flag */ void WriteSuccess(boolean flag); void callBack(Map<String, List<String>> data); void callBack(byte[] data); void error(); } }
与JS交互代码,如下
[ava] 纯文本查看 复制代码
package com.example.androidjs; import android.annotation.SuppressLint; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.net.http.SslError; import android.nfc.NfcAdapter; import android.nfc.NfcManager; import android.os.Build; import android.os.Handler; import android.os.Message; import android.support.v4.widget.SwipeRefreshLayout; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.webkit.JavascriptInterface; import android.webkit.SslErrorHandler; import android.webkit.WebChromeClient; import android.webkit.WebResourceRequest; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; import com.example.androidjs.NFCUtil.Employee; import com.example.androidjs.NFCUtil.NFCUtil; import com.example.androidjs.NFCUtil.Producing; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import static com.example.androidjs.NFCUtil.stringUtils.Authoriz; /** * */ public class MainActivity extends AppCompatActivity { private SwipeRefreshLayout mRefresh; private WebView h5; private byte[] byteTowrite;//待写入数据 private Map<String, List<byte[]>> map = new HashMap<>(); private List<byte[]> list = new ArrayList<>(); private SharedPreferences sp1; private SharedPreferences.Editor ed; private int flag=4; private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 1) { Toast.makeText(MainActivity.this, msg.getData().getString("data"), Toast.LENGTH_SHORT).show(); } else if (msg.what == 2) { Toast.makeText(MainActivity.this, "读取成功!", Toast.LENGTH_SHORT).show(); result(msg.getData().getString("data")); }else if (msg.what == 3){ Toast.makeText(MainActivity.this, msg.getData().getString("data"), Toast.LENGTH_SHORT).show(); //拼接字串,分行显示 } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sp1=getSharedPreferences("address",MODE_PRIVATE); ed=sp1.edit(); String uri=sp1.getString("adr","www.baidu.com"); if (hasNfc(this)==false){ Toast.makeText(MainActivity.this, "本手机不支持NFC功能,否则请打开NFC!", Toast.LENGTH_SHORT).show(); } mRefresh=findViewById(R.id.sRefresh); mRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { showdialog(); mRefresh.setRefreshing(false); } }); h5=findViewById(R.id.h5); WebSettings webSettings = h5.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setPluginState(WebSettings.PluginState.ON);//没有这个会导致诸如淘宝,知乎等网页显示不全 webSettings.setBlockNetworkImage(false); webSettings.setDomStorageEnabled(true); webSettings.setSupportMultipleWindows(true); webSettings.setLoadWithOverviewMode(true); //webSettings.setUseWideViewPort(true); if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){ webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); } h5.setWebViewClient(new WebViewClient()); h5.loadUrl(uri); h5.addJavascriptInterface(this,"justTest"); h5.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { return super.shouldOverrideUrlLoading(view, request); } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); result("I AM READY!"); } @Override public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { //super.onReceivedSslError(view, handler, error); handler.proceed(); //Toast.makeText(MainActivity.this, "加载网页异常", Toast.LENGTH_SHORT).show(); } }); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { finish(); return super.onKeyDown(keyCode, event); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); switch (flag){ case 0: write(intent); break;//写员工卡 case 1: write(intent); break;//写生产卡 case 2: read(intent); break;//读员工卡 case 3: read(intent); break;//读生产卡 } } /** * @param msg 接受待写入信息 * @param card 卡片类型 */ @JavascriptInterface public void writeNfc(String msg,String card) { //Toast.makeText(this, msg+card, Toast.LENGTH_SHORT).show(); String str=msg.substring(0,msg.length()-1); String[] strArray=str.split(","); int length=strArray.length; if (card.equals("员工卡")){ byteTowrite=new Employee(Integer.parseInt(strArray[0]),Integer.parseInt(strArray[1]),strArray[2]).getBytes(); Toast.makeText(this, "写员工卡,请确保NFC功能打开,并把卡靠近手机", Toast.LENGTH_SHORT).show(); flag=0; }else { byteTowrite=new Producing(Integer.parseInt(strArray[0]),Integer.parseInt(strArray[1]),Integer.parseInt(strArray[2]), Integer.parseInt(strArray[3]),Integer.parseInt(strArray[4]),Integer.parseInt(strArray[5]),strArray[6], strArray[7],strArray[8],Integer.parseInt(strArray[9]),strArray[10]).getBytes(); Toast.makeText(this, "写生产卡,请确保NFC功能打开,并把卡靠近手机", Toast.LENGTH_SHORT).show(); flag=1; return; } } /** * @param card 卡片类型 */ @JavascriptInterface public void readNfc(String card) { Toast.makeText(this,"读"+card+",请把卡片靠近手机", Toast.LENGTH_SHORT).show(); if (card.equals("员工卡")){ flag=2; }else { flag=3; } } /**返回 * @param data */ @SuppressLint("SetJavaScriptEnabled") public void result(String data) { h5.loadUrl("javascript:backdata(\""+data+"\")"); } /**CORE*/ private void write(Intent intent){ Message message = new Message(); final Bundle bundle = new Bundle(); if (flag==0){ NFCUtil.getInstence(intent).writeblock(byteTowrite,4,0,new NFCUtil.NFCCallback(){ @Override public void callBack(Map<String, List<String>> data) { } @Override public void error() { } @Override public void callBack(byte[] data) { } @Override public void WriteSuccess(boolean flag) { if (flag) { bundle.putString("data", "写入成功"); } else { bundle.putString("data", "写入失败"); } } }); }else if (flag==1){ NFCUtil.getInstence(intent).writeSixblock(byteTowrite, new NFCUtil.NFCCallback() { @Override public void WriteSuccess(boolean flag) { if (flag) { bundle.putString("data", "写入成功"); } else { bundle.putString("data", "写入失败"); } } @Override public void callBack(Map<String, List<String>> data) { } @Override public void callBack(byte[] data) { } @Override public void error() { } }); } message.setData(bundle); message.what = 1; handler.sendMessage(message); } private void read(Intent intent){ final Bundle bundle = new Bundle(); if (flag==2){ NFCUtil.getInstence(intent).readblock(4, 0, new NFCUtil.NFCCallback() { @Override public void WriteSuccess(boolean flag) { } @Override public void callBack(Map<String, List<String>> data) { } @Override public void callBack(byte[] data) { Message message = new Message(); Employee employee=Employee.getInstance(data); bundle.putString("data", "卡类型是:"+ employee.getType()+";员工编号是:"+employee.getNumber()+";员工姓名是:"+employee.getName()); message.setData(bundle); message.what = 2; handler.sendMessage(message); } @Override public void error() { Message message = new Message(); bundle.putString("data", "读取失败"); message.setData(bundle); message.what = 1; handler.sendMessage(message); } }); }else if (flag==3){ NFCUtil.getInstence(intent).readSixblock(new NFCUtil.NFCCallback() { @Override public void WriteSuccess(boolean flag) { } @Override public void callBack(Map<String, List<String>> data) { } @Override public void callBack(byte[] data) { Producing proCard=Producing.getInstance(data); bundle.putString("data", "卡类型是:"+proCard.getType()+";ID是:"+proCard.getID()+";总经长是:"+proCard.getZjc()+";经密是:" +proCard.getJm()+";纬密是:"+proCard.getWm()+";织缩是:"+proCard.getZs()+";产品编号是:"+proCard.getProductNo() +";扣号是:"+proCard.getQQ()+";经轴编号是:"+proCard.getJzbh()+";批号是:"+proCard.getBatch()+";备注是:"+proCard.getInfo()); Message message = new Message(); message.setData(bundle); message.what = 2; handler.sendMessage(message); } @Override public void error() { Message message = new Message(); bundle.putString("data", "读取失败"); message.setData(bundle); message.what = 1; handler.sendMessage(message); } }); } } public static boolean hasNfc(Context context){ boolean bRet=false; if(context==null) return bRet; NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE); NfcAdapter adapter = manager.getDefaultAdapter(); if (adapter != null && adapter.isEnabled()) { // adapter存在,能启用 bRet=true; } return bRet; } private void showdialog(){ //创建对话框 AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); //设置图标 builder.setIcon(R.mipmap.warning); //设置标题 builder.setTitle("是否确定删除当前配置?").setMessage("如确定,请点击“确定”,退出软件后请重新配置网址。否则请点“取消”"); //设置确定按钮 builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { ed.putString("adr",""); ed.commit(); Toast.makeText(MainActivity.this, "清除已配置网址!重启后重新配置。", Toast.LENGTH_SHORT).show(); finish(); } }); //设置取消按钮 如果只是要取消对话框 点击事件可以传NULL builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { //Toast.makeText(MainActivity.this, "点击了取消", Toast.LENGTH_LONG).show(); } }); //显示对话框 builder.show(); } }
以上就是此项目的全部核心代码,以下是一些非核心类以及配置信息: