├── static └── logo.png ├── README.en.md ├── main.js ├── README.md ├── App.vue ├── pages.json ├── pages └── index │ └── index.vue ├── LICENSE ├── uni.scss ├── manifest.json └── utils └── hexiii-nfc.js /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cssmini/uniapp-hexiii-nfc-plugin/HEAD/static/logo.png -------------------------------------------------------------------------------- /README.en.md: -------------------------------------------------------------------------------- 1 | # uniapp-hexiii-nfc-plugin 2 | 3 | #### Description 4 | uniapp NFC 插件,代码个人整理自 uni-app 论坛及网络。 5 | 6 | 使用插件时,建议先查阅安卓 NFC api 相关文档。 7 | 8 | 如代码或注释有误,欢迎联系作者进行反馈。 9 | 10 | 如代码对你有帮助,欢迎 Star -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | 4 | Vue.config.productionTip = false 5 | 6 | App.mpType = 'app' 7 | 8 | const app = new Vue({ 9 | ...App 10 | }) 11 | app.$mount() 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # uniapp-hexiii-nfc-plugin 2 | 3 | #### 介绍 4 | uniapp NFC 插件,代码个人整理自 uni-app 论坛及网络。 5 | 6 | 使用插件时,建议先查阅安卓 NFC api 相关文档。 7 | 8 | 如代码或注释有误,欢迎联系我进行反馈。 9 | 10 | 如代码对你有帮助,欢迎 Star,这是对我的鼓励。 11 | 12 | 论坛消息、留言做不到及时回复,可邮件或QQ找到我。 13 | ``` 14 | 邮箱(base64): Y3NzbWluaUBxcS5jb20= 15 | 企鹅号(base64):MjQxNTIzMTQ5Nw== 16 | ``` -------------------------------------------------------------------------------- /App.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 18 | -------------------------------------------------------------------------------- /pages.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages 3 | { 4 | "path": "pages/index/index", 5 | "style": { 6 | "navigationBarTitleText": "uni-app" 7 | } 8 | } 9 | ], 10 | "globalStyle": { 11 | "navigationBarTextStyle": "black", 12 | "navigationBarTitleText": "uni-app", 13 | "navigationBarBackgroundColor": "#F8F8F8", 14 | "backgroundColor": "#F8F8F8" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /pages/index/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 38 | 39 | 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 乘风 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /uni.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * 这里是uni-app内置的常用样式变量 3 | * 4 | * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 5 | * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App 6 | * 7 | */ 8 | 9 | /** 10 | * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 11 | * 12 | * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 13 | */ 14 | 15 | /* 颜色变量 */ 16 | 17 | /* 行为相关颜色 */ 18 | $uni-color-primary: #007aff; 19 | $uni-color-success: #4cd964; 20 | $uni-color-warning: #f0ad4e; 21 | $uni-color-error: #dd524d; 22 | 23 | /* 文字基本颜色 */ 24 | $uni-text-color:#333;//基本色 25 | $uni-text-color-inverse:#fff;//反色 26 | $uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 27 | $uni-text-color-placeholder: #808080; 28 | $uni-text-color-disable:#c0c0c0; 29 | 30 | /* 背景颜色 */ 31 | $uni-bg-color:#ffffff; 32 | $uni-bg-color-grey:#f8f8f8; 33 | $uni-bg-color-hover:#f1f1f1;//点击状态颜色 34 | $uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 35 | 36 | /* 边框颜色 */ 37 | $uni-border-color:#c8c7cc; 38 | 39 | /* 尺寸变量 */ 40 | 41 | /* 文字尺寸 */ 42 | $uni-font-size-sm:24upx; 43 | $uni-font-size-base:28upx; 44 | $uni-font-size-lg:32upx; 45 | 46 | /* 图片尺寸 */ 47 | $uni-img-size-sm:40upx; 48 | $uni-img-size-base:52upx; 49 | $uni-img-size-lg:80upx; 50 | 51 | /* Border Radius */ 52 | $uni-border-radius-sm: 4upx; 53 | $uni-border-radius-base: 6upx; 54 | $uni-border-radius-lg: 12upx; 55 | $uni-border-radius-circle: 50%; 56 | 57 | /* 水平间距 */ 58 | $uni-spacing-row-sm: 10px; 59 | $uni-spacing-row-base: 20upx; 60 | $uni-spacing-row-lg: 30upx; 61 | 62 | /* 垂直间距 */ 63 | $uni-spacing-col-sm: 8upx; 64 | $uni-spacing-col-base: 16upx; 65 | $uni-spacing-col-lg: 24upx; 66 | 67 | /* 透明度 */ 68 | $uni-opacity-disabled: 0.3; // 组件禁用态的透明度 69 | 70 | /* 文章场景相关 */ 71 | $uni-color-title: #2C405A; // 文章标题颜色 72 | $uni-font-size-title:40upx; 73 | $uni-color-subtitle: #555555; // 二级标题颜色 74 | $uni-font-size-subtitle:36upx; 75 | $uni-color-paragraph: #3F536E; // 文章段落颜色 76 | $uni-font-size-paragraph:30upx; -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "NFC_DEMO", 3 | "appid" : "__UNI__3A733D9", 4 | "description": "", 5 | "versionName": "1.0.0", 6 | "versionCode": "100", 7 | "transformPx": false, 8 | /* 5+App特有相关 */ 9 | "app-plus": { 10 | "usingComponents": true, 11 | "nvueCompiler": "uni-app", 12 | "splashscreen": { 13 | "alwaysShowBeforeRender": true, 14 | "waiting": true, 15 | "autoclose": true, 16 | "delay": 0 17 | }, 18 | /* 模块配置 */ 19 | "modules": { 20 | 21 | }, 22 | /* 应用发布信息 */ 23 | "distribute": { 24 | /* android打包配置 */ 25 | "android": { 26 | "permissions": ["", 27 | "", 28 | "", 29 | "", 30 | "", 31 | "", 32 | "", 33 | "", 34 | "", 35 | "", 36 | "", 37 | "", 38 | "", 39 | "", 40 | "", 41 | "", 42 | "", 43 | "", 44 | "", 45 | "", 46 | "", 47 | "" 48 | ] 49 | }, 50 | /* ios打包配置 */ 51 | "ios": { 52 | 53 | }, 54 | /* SDK配置 */ 55 | "sdkConfigs": { 56 | 57 | } 58 | } 59 | }, 60 | /* 快应用特有相关 */ 61 | "quickapp": { 62 | 63 | }, 64 | /* 小程序特有相关 */ 65 | "mp-weixin": { 66 | "appid": "", 67 | "setting": { 68 | "urlCheck": false 69 | }, 70 | "usingComponents": true 71 | }, 72 | "mp-alipay" : { 73 | "usingComponents" : true 74 | }, 75 | "mp-baidu" : { 76 | "usingComponents" : true 77 | }, 78 | "mp-toutiao" : { 79 | "usingComponents" : true 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /utils/hexiii-nfc.js: -------------------------------------------------------------------------------- 1 | // 包路径 2 | const package_NdefRecord = 'android.nfc.NdefRecord'; 3 | const package_NdefMessage = 'android.nfc.NdefMessage'; 4 | const package_TECH_DISCOVERED = 'android.nfc.action.TECH_DISCOVERED'; 5 | const package_Intent = 'android.content.Intent'; 6 | const package_Activity = 'android.app.Activity'; 7 | const package_PendingIntent = 'android.app.PendingIntent'; 8 | const package_IntentFilter = 'android.content.IntentFilter'; 9 | const package_NfcAdapter = 'android.nfc.NfcAdapter'; 10 | const package_Ndef = 'android.nfc.tech.Ndef'; 11 | const package_NdefFormatable = 'android.nfc.tech.NdefFormatable'; 12 | const package_Parcelable = 'android.os.Parcelable'; 13 | const package_String = 'java.lang.String'; 14 | 15 | let NfcAdapter; 16 | let NdefRecord; 17 | let NdefMessage; 18 | let readyWriteData = false; 19 | let readyRead = false; 20 | let noNFC = false; 21 | let techListsArray = [ 22 | ['android.nfc.tech.IsoDep'], 23 | ['android.nfc.tech.NfcA'], 24 | ['android.nfc.tech.NfcB'], 25 | ['android.nfc.tech.NfcF'], 26 | ['android.nfc.tech.Nfcf'], 27 | ['android.nfc.tech.NfcV'], 28 | ['android.nfc.tech.NdefFormatable'], 29 | ['android.nfc.tech.MifareClassi'], 30 | ['android.nfc.tech.MifareUltralight'] 31 | ]; 32 | // 要写入的数据 33 | let text = '{id:123,name:nfc,stie:cssmini.com}'; 34 | let readResult = ''; 35 | 36 | export default { 37 | listenNFCStatus: function () { 38 | let that = this; 39 | try { 40 | let main = plus.android.runtimeMainActivity(); 41 | let Intent = plus.android.importClass('android.content.Intent'); 42 | let Activity = plus.android.importClass('android.app.Activity'); 43 | let PendingIntent = plus.android.importClass('android.app.PendingIntent'); 44 | let IntentFilter = plus.android.importClass('android.content.IntentFilter'); 45 | NfcAdapter = plus.android.importClass('android.nfc.NfcAdapter'); 46 | let nfcAdapter = NfcAdapter.getDefaultAdapter(main); 47 | 48 | if(nfcAdapter == null){ 49 | uni.showToast({ 50 | title: '设备不支持NFC!', 51 | icon: 'none' 52 | }) 53 | noNFC = true; 54 | return; 55 | } 56 | 57 | if (!nfcAdapter.isEnabled()) { 58 | uni.showToast({ 59 | title: '请在系统设置中先启用NFC功能!', 60 | icon: 'none' 61 | }); 62 | noNFC = true; 63 | return; 64 | }else{ 65 | noNFC = false; 66 | } 67 | 68 | let intent = new Intent(main, main.getClass()); 69 | intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); 70 | let pendingIntent = PendingIntent.getActivity(main, 0, intent, 0); 71 | let ndef = new IntentFilter("android.nfc.action.TECH_DISCOVERED"); 72 | ndef.addDataType("*/*"); 73 | let intentFiltersArray = [ndef]; 74 | 75 | plus.globalEvent.addEventListener('newintent',function() { 76 | console.log('newintent running'); 77 | // 监听 NFC 78 | setTimeout(that.nfcRuning(), 1000); 79 | }); 80 | plus.globalEvent.addEventListener('pause',function(e) { 81 | console.log('pause running'); 82 | if (nfcAdapter) { 83 | //关闭前台调度系统 84 | //恢复默认状态 85 | nfcAdapter.disableForegroundDispatch(main); 86 | } 87 | }); 88 | plus.globalEvent.addEventListener('resume',function(e) { 89 | console.log('resume running'); 90 | if (nfcAdapter) { 91 | //开启前台调度系统 92 | nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray); 93 | } 94 | }); 95 | nfcAdapter.enableForegroundDispatch(main, pendingIntent, intentFiltersArray, techListsArray); 96 | } catch (e) { 97 | console.error(e); 98 | } 99 | }, 100 | nfcRuning: function () { 101 | NdefRecord = plus.android.importClass("android.nfc.NdefRecord"); 102 | NdefMessage = plus.android.importClass("android.nfc.NdefMessage"); 103 | let main = plus.android.runtimeMainActivity(); 104 | let intent = main.getIntent(); 105 | let that = this; 106 | 107 | console.log("action type:" + intent.getAction()); 108 | 109 | if (package_TECH_DISCOVERED == intent.getAction()) { 110 | if (readyWriteData) { 111 | that.write(intent); 112 | readyWriteData = false; 113 | } else if (readyRead) { 114 | that.read(intent); 115 | readyRead = false; 116 | } 117 | } 118 | }, 119 | write(intent) { 120 | try { 121 | toast('请勿移开标签 正在写入...'); 122 | console.log("text=" + text); 123 | 124 | let textBytes = plus.android.invoke(text, "getBytes"); 125 | // image/jpeg text/plain 126 | let textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, 127 | plus.android.invoke("text/plain", "getBytes"), 128 | plus.android.invoke("", "getBytes"), textBytes); 129 | let message = new NdefMessage([textRecord]); 130 | let Ndef = plus.android.importClass('android.nfc.tech.Ndef'); 131 | let NdefFormatable = plus.android.importClass('android.nfc.tech.NdefFormatable'); 132 | let tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 133 | let ndef = Ndef.get(tag); 134 | if (ndef != null) { 135 | // 待写入的数据长度 136 | let size = message.toByteArray().length; 137 | ndef.connect(); 138 | if (!ndef.isWritable()) { 139 | toast('tag不允许写入!'); 140 | return; 141 | } 142 | if (ndef.getMaxSize() < size) { 143 | toast('文件大小超出容量!'); 144 | return; 145 | } 146 | ndef.writeNdefMessage(message); 147 | toast('写入数据成功!'); 148 | return; 149 | } else { 150 | let format = NdefFormatable.get(tag); 151 | if (format != null) { 152 | try { 153 | format.connect(); 154 | format.format(message); 155 | toast('格式化tag并且写入message'); 156 | return; 157 | } catch (e) { 158 | toast('格式化tag失败.'); 159 | return; 160 | } 161 | } else { 162 | toast('Tag不支持NDEF'); 163 | return; 164 | } 165 | } 166 | } catch (e) { 167 | toast('写入失败'); 168 | console.log("error=" + e); 169 | } 170 | 171 | }, 172 | read(intent) { 173 | toast('请勿移开标签正在读取数据'); 174 | let that = this; 175 | // NFC id 176 | let bytesId = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID); 177 | let nfc_id = that.byteArrayToHexString(bytesId); 178 | console.log('nfc_id:', nfc_id); 179 | let Parcelable = plus.android.importClass("android.os.Parcelable"); 180 | let rawmsgs = intent.getParcelableArrayExtra("android.nfc.extra.NDEF_MESSAGES"); 181 | //let rawmsgs = intent.getParcelableArrayExtra(); 182 | 183 | if(rawmsgs != null && rawmsgs.length > 0) { 184 | let records = rawmsgs[0].getRecords(); 185 | let result = records[0].getPayload(); 186 | let data = plus.android.newObject("java.lang.String", result); 187 | toast('NFC 数据:' + data); 188 | console.log('NFC 数据:',data); 189 | readResult = data; 190 | }else{ 191 | toast('没有读取到数据'); 192 | } 193 | }, 194 | byteArrayToHexString: function (inarray) { // converts byte arrays to string 195 | let i, j, inn; 196 | let hex = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"]; 197 | let out = ""; 198 | 199 | for(j = 0; j < inarray.length; ++j) { 200 | inn = inarray[j] & 0xff; 201 | i = (inn >>> 4) & 0x0f; 202 | out += hex[i]; 203 | i = inn & 0x0f; 204 | out += hex[i]; 205 | } 206 | return out; 207 | }, 208 | writeData: function () { 209 | if(noNFC){ 210 | toast('请检查设备是否支持并开启 NFC 功能!'); 211 | return; 212 | } 213 | // 监听事件,触发条件 214 | readyWriteData = true; 215 | toast('请将NFC标签靠近!'); 216 | }, 217 | readData: function () { 218 | if(noNFC){ 219 | toast('请检查设备是否支持并开启 NFC 功能!'); 220 | return; 221 | } 222 | // 监听事件,触发条件 223 | readyRead = true; 224 | toast('请将NFC标签靠近!'); 225 | } 226 | } 227 | function toast(content){ 228 | uni.showToast({ 229 | title: content, 230 | icon: 'none' 231 | }) 232 | } --------------------------------------------------------------------------------