最近在自己用 uniapp 写应用玩,想实现一个软件锁的效果,折腾了不少时间,折腾出来了。

软件锁的界面一般是一个遮罩盖住整个页面,然后进行人脸或指纹验证,验证通过就关闭遮罩这么个逻辑。

我一开始使用 fixed 进行全屏覆盖,但是显然没这么简单:

这个遮罩无法覆盖原生的头部与底部栏。

此方法作罢,继续寻找尝试,最后发现 nvue 页面可以实现全屏幕的覆盖而不受影响原生控件的影响。

为什么呢,因为用这种方式实现的遮罩其实并不是在软件首页,而是跳转至了一个专门用来做遮罩的二级页面,这个二级页面什么也没有(当然要有其他你也可以自己加),没有原生的头部,二级页面自然也没有底部的导航栏。上面这个特点普通的 vue 页面就能做到,但是 nvue 页面还有一个特点是可以将页面的背景图片设置为透明,这是普通页面无法做到的。uniapp 的多级页面显示其实就是一层一层往上叠加页面,把下面的遮盖住,但是如果上面的页面是透明的,那么下面的页面自然就显示出来了。

当然如果没有透明度要求那直接用普通页面做也可以满足。

下面来说下实现过程:

首先新建一个页面,我命名为 mask.nvue (注意扩展名是 nvue)

<template>
  <!-- blurEffect 是 nvue 中的 view 标签独有的属性,可选值有:dark/extralight/light/none,用于背景高斯模糊 -->
  <!-- nvue 中 css 的使用限制很大,无法使用 filter 等属性 -->
    <view class="mask" blurEffect="dark"></view>
</template>
<script>
    export default {
        onLoad() {
              // 进入页面就开启验证
            uni.startSoterAuthentication({
                requestAuthModes: ['facial', 'fingerPrint'],
                success: res => {
                      // 因为识别有动画效果,所以延迟一秒等动画完成再返回
                    setTimeout(() => {
                        uni.navigateBack({})
                    }, 1000)
                }
            })
        }
    }
</script>
<style scoped>
    .mask {
        position: fixed;
        left: 0;
        top: 0;
        right: 0;
        bottom: 0;
    }
</style>

然后在 pages.json 中添加路由:

{
  "path": "pages/mask/mask",
  "style": {
    "navigationStyle": "custom",
    "app-plus": {
            "animationType": "none", // 不使用页面切换动画,否则就会被发现是页面切换
      "background": "transparent", //页面设置透明背景
      "popGesture": "none" //禁用侧滑返回,防止用户取消验证使用侧滑返回而绕过检验
    }
  }
}

这样就完成了,使用的话你只要直接在应用进入首页的时候,把页面跳转至验证页面就可以了,验证成功自动返回首页。

// /pages/index/index
onLoad(){
  uni.navigateTo({
    url: '/pages/mask/mask'
  })
}

当然,在跳转前你需要使用 uni.checkIsSoterEnrolledInDevice(OBJECT) 判断当前设置是否已经录入了指纹或者 Face ID并且在软件设置中打开了启用软件锁的开关(如果有的话),否则就不需要验证。

这是触发的效果:

GitHub 仓库地址