对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();
}
}以上就是此项目的全部核心代码,以下是一些非核心类以及配置信息:

微信扫一扫打赏
支付宝扫一扫打赏

