培森的Blog Java android与网页交互实现对NFC指定区块的读写

android与网页交互实现对NFC指定区块的读写

对M1卡指定区块的读写,通过阅读nfc官方文档,对m1任意位置的读写需求如下图(实现对图中区块的指定位置读写)…

对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();
 
    }
}



以上就是此项目的全部核心代码,以下是一些非核心类以及配置信息:

本文来自网络,不代表培森的Blog立场,转载请注明出处:https://blog.xupeisen.com/archives/110

作者: 培森

联系我们

联系我们

13262951234

在线咨询: QQ交谈

邮箱: admin@xupeisen.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部