广播扫码监听功能

手持 PDA 是 Android 平台,其扫码的解决方案也有摄像头和激光扫描等多种解决方案,这里结合 uni-app 的开发特性,记录一下具体的实现方案。

扫码方案

现阶段来说,读取一段 Barcode(也可能是 QRcode,以下我都用 Barcode 代替表述)的方式无非两种主要方式和一种附加方式,主要方式包含摄像头和激光,附加方式则需要将 Barcode 转为RFID方式,后者不再此赘述。

摄像头

摄像头扫码兼容性最高,也是一种软解的解决方案,理论上只要带有光学摄像头的终端设备都可以实现解码过程,但是其解码过程很依赖终端性能,有些低端设备搭载的摄像头在对焦上需要花费更多的时候,这对一些高度依赖效率的工作内容产生一定的阻碍,比如大批量的工单扫码。
因此,使用摄像头扫码方案也是可以达到可以使用的层级,如果需要应付一些追求效率的内容就显得相对困难。
uni-app 自带的调用摄像头方法

uni.scanCode({
  //成功回调
  success: function (res) {
    //条码类型
    console.log(res.scanType);
    //条码的值
    console.log(res.result);
  },
  //失败回调
  fail: function (res) {},
  //完成回调
  complete: function (res) {},
});

缺点: UNI官方为考虑多平台使用,兼容太多,导致组件使用会存在扫码功能出现误差 或者 卡死现象
建议: 使用支付宝扫码插件

激光

这是硬解的方案,扫码的速度远高于需要唤醒过程的摄像头扫码方式,激光扫码几乎可以实时返回结果。不过其依赖Android 8以上的版本才可以通过广播的方式被应用监听,因此在开发的过程中会造成一些阻碍。无论是原生的Android开发方式,还是像uni-app的跨平台解决方案,都需要在激光扫描模块获取到结果后向系统发出一条广播,接着可以通过应用监听广播的方式来获取扫码结果。
uni-app 内如何使用
在SUPOIN设备上,需要手动设置广播:

设置 ==> 自定义广播 √
		 广播字段名称 com.android.server.scannerservice.broadcast
		 数据字段名称 scannerdata
		 扫码服务设置 ==> 使能所有条码类型 √
		 				 使能一维条码类型 √
		 				 使能二维条码类型 √

在另一些设备上,系统是没有广播设置的,不过一般厂家都会带上自己的硬解扫码工具供用户配置,具体的细节可以咨询对应的厂家。

然后,我们需要确定 2 个变量的值:
广播动作和广播标签,你可以简单的将这两个变量理解为key-value,这两者都可以在设备上进行自定义设置,如果没有设置项,需要向厂家了解。

封装组件

创建一个激光扫码的组件,我们在这里是/components/scan/scan.vue,并写入以下代码:

<template>
	<view class="content"></view>
</template>

<script>
// #ifdef APP-PLUS
var main, receiver, filter;
var _codeQueryTag = false;
export default {
	data() {
		return {
		};
	},
	created: function(option) {
		this.initScan();
		this.startScan();
	},
	onHide: function() {
		this.stopScan();
	},
	destroyed: function() {
		/*页面退出时一定要卸载监听,否则下次进来时会重复,造成扫一次出2个以上的结果*/
		this.stopScan();
	},
	methods: {
		initScan() {
			let _this = this;
			main = plus.android.runtimeMainActivity(); //获取activity
			var IntentFilter = plus.android.importClass('android.content.IntentFilter');
			filter = new IntentFilter();
			filter.addAction('com.android.server.scannerservice.broadcast'); // 广播动作 supoin X8AT 扫码服务设置 广播字段名称
			receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {
				onReceive: function(context, intent) {
					plus.android.importClass(intent);
					let code = intent.getStringExtra('scannerdata'); // 广播标签 supoin X8AT 扫码服务设置 数据字段名称
					_this.queryCode(code);
				}
			});
		},
		startScan() {
			main.registerReceiver(receiver, filter);
		},
		stopScan() {
			main.unregisterReceiver(receiver);
		},
		queryCode: function(code) {
			//防重复
			if (_codeQueryTag) return false;
			_codeQueryTag = true;
			setTimeout(function() {
				_codeQueryTag = false;
			}, 150);
			const value = code;
			uni.$emit('scancodedate', { code: value });
		}
	}
};
// #endif
</script>
<style></style>

处理完组件后,在需要使用激光扫码的页面中引入该组件进行使用,在这里我以index.vue页面为例:

<template>
	<view>
		<scan></scan>
		<view class="">{{ code }}</view>
	</view>
</template>

<script>
import scan from '@/components/scan/scan.vue';

export default {
	components: {
		scan
	},
	data() {
		return {
			code: ''
		};
	},
	//获取到扫码的结果,进行后续的处理
	onShow: function() {
		var _this = this;
		uni.$off('scancodedate'); // 每次进来先 移除全局自定义事件监听器
		uni.$on('scancodedate', function(data) {
			console.log('你想要的code:', data);
			console.log('你想要的code:', data.code);
			_this.code = data.code;
		});
	}
};
</script>

<style></style>

重要!通过软件调用激光
在之前,我无法使用软件的方式调用激光扫描模块,只能使用物理键来打开扫描头,现在已经有了解决方案。

<template>
	<view>
		<button class="bind">已绑定工号{{ userCode }}<tton>
	<iew>
</template>

<script>
export default {
	data() {
		return {
			userCode: '131313',
			main: '',
			receiver: '',
			filter: ''
		};
	},
	created: function(option) {
		this.bindUserCode();
	},
	methods: {
		//打开扫描头的方法
		bindUserCode() {
			this.initScan();
			this.startScan();
		},
		initScan() {
			let that = this;
			//获取Android主Activity
			that.main = plus.android.runtimeMainActivity();
			//获取Android意图类
			let Intent = plus.android.importClass('android.content.Intent');
			//实例化意图
			let intent = new Intent();
			//定义意图,模拟按下L键,L键实际上是打开激光的物理键映射,由厂商提供
			intent.setAction('com.android.action.keyevent.KEYCODE_KEYCODE_SCAN_L_DOWN');
			//广播这个意图
			that.main.sendBroadcast(intent);
			//获取Android意图过滤类
			let IntentFilter = plus.android.importClass('android.content.IntentFilter');
			//实例化意图过滤
			that.filter = new IntentFilter();
			//获取扫码成功的意图广播
			that.filter.addAction('com.android.server.scannerservice.broadcast');
			that.receiver = plus.android.implements('io.dcloud.feature.internal.reflect.BroadcastReceiver', {
				onReceive: function(context, intent) {
					plus.android.importClass(intent);
					let code = intent.getStringExtra('scannerdata');
					//成功输出扫码内容
					console.log(code);
					that.userCode =  code 
				}
			});
		},
		startScan() {
			this.main.registerReceiver(this.receiver, this.filter);
		}
	}
};
</script>

uni-app 主动唤醒激光
同样以index.vue页面为例(这里我出于方便用单页面举例,把所有的扫描相关方法写在一起)。

流程说明
首先,我们模拟 Android 的按键事件,因为 L 键是物理扫描键的映射,所以当我们按下 L 键(虚拟的)时,就是按下了物理的扫描键。

接着,我们同样通过监听广播的方式,来获取扫描结果。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐