一、前言
遇到个最近需求,要求使用uniapp写app端,并且实现一个类似人脸认证的功能。因为第三方活体认证的对接费用有点贵,这时候就到了折磨时刻了。因为之前写过小程序类似的功能,想着<camera>标签梭哈一下,完事。结果大家都知道,当你以为👌的时候,那就很不ok了。在uniapp中写app,是使用不了<camera>标签的。
这该怎么办呢?于是查询资料,开始了骚操作之旅·····
二、需求
1、这个需求呢主要是为了实现用户到达某一个地点区域内,进行打卡,进行验证是否为本人打卡和是否在打卡区域内。
2、由于uniapp在开发app中,不能够使用像小程序直接使用camera标签来直接获取摄像头的影像将其展示在页面上供使用者查看。所以这里采用了另一种方式来解决这个问题。
3、这里这个需求所采用的方式是:前端进行摄像头的获取,并把实时影像放在页面中展示给使用者,利用切片的方式,将切片图传的给后端。后端采用阿里的人脸识别API进行切片的对比。 返回给前端此时是否为本人打卡,并返回打卡是否成功的信息。
三、需要解决的核心问题
1、前端如何将用户的前摄像头内容进行展示在页面中给使用者查看?(本篇也是主要为要这个点进行讲解)。
2、活体的识别交给前端做还是后端做?(这个点上边有说,主要是后端进行阿里的API进行人脸识别和活体的识别)
3、当你觉得一切完美的时候,常常事情就不完美了。还有一个比较要注意的点,当我们写这个认证组件的时候,通常我们使用的是 .vue 的文件,但是在这里我们的这个组件我们要建成 .nvue 的,原因下面会解释的。
四、前端如何进行摄像头内容的获取并展示给用户
由于需求是使用uniapp进行开发app端,无法使用设备的摄像头。不能够像uniapp写小程序一样可以直接使用camera标签进行将摄像头的内容进行获取展示。
思路:
1、既然无法像小程序一样直接使用camera标签,那我们可以采用直播推流的方式,进行获取摄像头的内容,然后在上面覆盖一层遮罩进行将不需要的部分进行遮挡,可见区域内就会形成一个我们想要的摄像头区域。
2、直播推流 组件 <live-pusher>,由使用的是<live-pusher>组件,普通的view盒子是无法再其上面进行遮挡的,所以需要使用到<cover-image>组件进行作为遮罩层来使用。
3、至于我们这个认证组件为什么要写成.nvue的文件,原因呢也很简单。其实在<live-pusher>的使用文档上也有说明,.vue中使用<live-pusher>组件需要vue版本3.4.1+上的版本,在其以下的版本想使用只能把文件建成.nvue。
4、说明:
组件的使用说明在这里就不多说了,详细可以直接点击下面的官方文档链接进行查看。
<live-pusher>组件说明文档
<cover-image>组件说明文档
5、具体代码来啦!!!
<!-- HTML大致结构,可根据自己需求进行配置 -->
<!-- 例:style配置,按照自己的项目情况自行配置即可 -->
<live-pusher
id='livePusher'
ref="livePusher"
class="livePusher"
url=""
mode="SD"
:muted="true"
:enable-camera="true"
:auto-focus="true"
:beauty="1"
whiteness="2"
aspect="9:16"
local-mirror="disable"
@error = "error"
:style="[{
height: '700rpx',
'margin-top': '200rpx' ,
width:'750rpx',
}]"
></live-pusher>
<cover-image
class="cover-image"
style="
width: 750rpx;
height: 698rpx;
transform: scale(1.2);
"
src="@/static/xxxx/camera_bg.png"
/>
js逻辑部分
data() {
return {
livePusher: '', // livePusher实例
snapshotInfo: '', // 快照信息
showCountDown: false, // 拍摄倒计时
timeOut: 3, // 签到倒计时
timeFlag: null, // 定时器
isPass: null, // 是否通过人脸认证
passMsg: '', // 提示信息
}
},
onReady() { // 初始化
// 创建 live-pusher 上下文 livePusherContext 对象
this.livePusher = uni.createLivePusherContext("livePusher", this);
},
mounted() {
const that_ = this
setTimeout(function() { // 进入页面1秒后开启预览
that_.startPreview()
}, 1000)
},
destroyed() { // 注销页面时清楚定时器
clearInterval(this.timeFlag)
uni.hideLoading();
},
methods: {
// 开始预览
startPreview() {
const _that = this
this.livePusher.startPreview({
success: (res)=> {
this.showCountDown = true
_that.handleSetTime()
}
})
},
// 开始预览后开始倒计时并拉取接口并进行对比
handleSetTime () {
this.timeFlag = setInterval(async () => {
// 倒计时
if (this.timeOut > 0) {
this.timeOut--
}
// 取得快照
if (this.timeOut == 1) {
this.livePusher.snapshot({
success: (res) => {
this.snapshotInfo = res.message
}
})
}
// 进行快照人脸认证
if (this.timeOut <= 0) {
uni.showLoading({
title: '验证中...'
})
try{
// 拉取后端接口(后端通过阿里API封装的接口)
// 参数1:接口地址 参数2:请求人的id 参数3:快照信息
const res = await file_request("/xxx/xxxx", { xx: this.xxx }, this.snapshotInfo.tempImagePath)
const { status, msg } = JSON.parse(res)
status == 200 ?this.isPass = 1 ? this.isPass = 2
this.passMsg = msg
} catch (e) {
this.$refs.uToast.show({
type: 'error',
message: err,
duration: 1500,
});
uni.redirectTo({ // 认证接口出错时返回的页面
url: `/pages/xxx/xxxxx`
})
}
uni.hideLoading()
// 验证成功后返回上一层,并把是否通过、提示信息、快照信息给上层页面,
uni.redirectTo({
url: `/pages/xxx/xxxxx?isPass=${this.isPass}&passMsg=${this.passMsg}&snapshotInfoHerder=${this.isPass == 1 ? this.snapshotInfo.tempImagePath : ''}`
})
}
}, 1000)
}
}
致敬
如果按照步骤成功完成自己手撸的人脸认证,就给本文章点个赞吧!😁😁😁