使用uniapp开发app时,需要实现三种登录:1.本机号码一键登录 2.手机号验证码登录 3.邮箱验证码登录。
由于手机号/邮箱的验证码配置流程类似,且都是后端与运维同学操作配置,我只需要将手机号/邮箱进行匹配后告知后端就可以了,所以本篇详细记录如何接入本机号码一键登录。

首先在插件市场找到阿里云号码认证SDK,由于我是使用离线打包的,所以我直接下载了压缩包,解压后得到名为AliCloud-NirvanaPns的文件夹,里面四个项目

阿里云官方给出了uni-app接入的文档与步骤,uni-app接入文档根据文档“在项目中引入插件”的步骤走就好了


走完“d.单击确定即可引入”即本地插件引入完成。接下来要浏览一下文档,了解开放出来的方法API要如何去使用。

根据文档可以得到setAuthSDKInfo必调,目的是为了设置密钥,而密钥又是与Bundle ID或包名匹配的,所以后端同学会给我一组密钥(安卓、iOS的密钥不同,需根据当前手机型号动态设置),密钥只需设置一次(意味着仅需调用setAuthSDKInfo一次)。
那么就要思考,这个setAuthSDKInfo方法调用要写在哪里?若写在pages/login/index.vue中的话岂不是每次都要设置么,所以我就放在了App.vue的onLaunch中,意味着只有app首次打开时会触发设置。参考文档:uniapp全局文件 - App.vue/uvue的应用生命周期
App.vue代码实现
<script>
//初始化
const aLiSDKModule = uni.requireNativePlugin('AliCloud-NirvanaPns');
export default {
setup() {
return {}
},
onLaunch: async function() {
// 获取手机系统信息
const systemInfo = uni.getSystemInfoSync();
let sdkInfo = '';
// 判断手机机型 安卓/iOS
if (systemInfo.osName == 'android') {
//开启SDK日志打印
aLiSDKModule.setLoggerEnable(true);
aLiSDKModule.expandAuthPageCheckedScope(true);
//开启区分界面返回及物理返回功能,自动控制后续返回事件
aLiSDKModule.userControlAuthPageCancel();
//是否跟随系统深色模式(由于我们开发时未做深色模式版UI样式,所以设置为false)
aLiSDKModule.setAuthPageUseDayLight(false);
sdkInfo = "这里是安卓的密钥";
} else if (systemInfo.osName == 'ios') {
sdkInfo = "这里是iOS的密钥";
}
//设置密钥
aLiSDKModule.setAuthSDKInfo(sdkInfo);
}
}
app首次打开时,设置好了号码认证SDK的密钥,后进入首页,当用户点击功能入口时会检测当前用户是否登录,没有token时会跳转至login页面。
交互要点:
1.在login/index页面onMounted时就要使用checkEnvAvailable方法去检测当前用户的环境是否支持唤起本机号码一键登录的功能,若支持则唤起;否则显示手机号验证码登录页面
2.环境要素:测试该功能的手机要有SIM卡,且该SIM卡有费可正常使用网络(蜂窝数据)。 ⚠️仅Wi-Fi是无法唤起的
3.aLiSDKModule.getLoginToken方法的第二个参数config为授权页UI配置,详情参考修改授权页主题配置。demo中我只定义了一个字段示意
4.实际使用本机号码一键登录时,唤起页面需要时间,所以加一个loading动画过渡一下
5.注意💡:demo中有很多quitLoginPage调用

login参考代码如下
<template>
<layout class="popup-content flex-column">
<!-- 手机号 + 验证码 -->
<phoneLog v-if="loginType === 1"></phoneLog>
<!-- 邮箱 + 验证码 -->
<emailLogin v-if="loginType === 3"></emailLogin>
<!-- loading动画 -->
<view v-if="loginType === 0" class="loadpopup flex align-center justify-center">
<image src="/static/app/gif/load.gif"></image>
</view>
</layout>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted } from 'vue'
import phoneLog from './phoneLogin.vue'
import emailLogin from './emailLogin.vue';
import { login } from '@/api/index.ts'
import { userStore } from '@/store/index'
const store = userStore()
const loginType = ref(0) // 1-手机号验证码登录 2-本机号码一键登录 3-email登录
const aLiSDKModule = uni.requireNativePlugin('AliCloud-NirvanaPns'); //引入
const systemInfo = uni.getSystemInfoSync(); //获取手机系统信息
let config = {} //授权页UI配置,详情参见。
// 唤起一键登录
const loginFun = () => {
aLiSDKModule.getLoginToken(5000, config, tokenResult => {
if ("600001" == tokenResult.resultCode) {
loginType.value = 2
// console.log("授权页拉起成功");
} else if ("600000" == tokenResult.resultCode) {
// console.log("获取Token成功,接下来拿着结果里面的Token去服务端换取手机号码,SDK服务到此结束");
formSubmit(tokenResult.token)
//手动关闭授权页
aLiSDKModule.quitLoginPage();
} else {
//其他失败情况,手动关闭授权页,并切换其他登录方式
}
}, clickResult => {
switch (clickResult.resultCode) {
case "700000":
console.log("用户点击返回按钮");
uni.navigateBack({ delta: 1 })
//手动关闭授权页
aLiSDKModule.quitLoginPage();
break;
case "700001":
console.log("用户切换其他登录方式");
//手动关闭授权页,并切换其他登录方式
break;
case "700002":
console.log("用户点击登录按钮");
//通过isChecked字段可以得到checkbox是否勾选,未勾选可以用自定义Toast进行提示
if (!clickResult.result.isChecked && systemInfo.osName === 'ios') {
return
}
break;
case "700003":
console.log("用户点击checkBox");
break;
case "700004":
console.log("用户点击协议");
break;
case "700010":
//调用userControlAuthPageCancel后方可使用
console.log("用户点击返回按钮,Android专用");
uni.navigateBack({ delta: 1 })
//手动关闭授权页
aLiSDKModule.quitLoginPage();
break;
case "700011":
//调用userControlAuthPageCancel后方可使用
console.log("用户使用物理返回键,Android专用");
uni.navigateBack({ delta: 1 })
//手动关闭授权页
aLiSDKModule.quitLoginPage();
break;
}
})
}
// 本机号码一键登录 - 提交换token
const formSubmit = (token) => {
let loginData = {
username: token,
loginType: 'spToken'
}
login(loginData).then((res) => {
// 登录成功后,记录用户token
store.setToken(res.token)
uni.setStorage({ key: 'token', data: res.token })
uni.setStorage({ key: 'refreshToken', data: res.refreshToken })
// 登录成功后,获取用户信息
getUserInfo()
// 登录成功,关闭弹窗,toast告知用户,并跳转页面
uni.navigateBack({ delta: 1 })
}).catch ((err) => {
console.log('err', err)
// 登录失败,toast告知用户并切换至其他登录方式
})
}
onMounted(async () => {
try {
aLiSDKModule.checkEnvAvailable(2, result => {
if (result.resultCode === '600000') {
aLiSDKModule.accelerateLoginPage(5000, (result) => {
if ("600000" == result.resultCode) {
loginFun()
} else { // 切换其他登录方式 }
});
} else { // 切换其他登录方式 }
})
} catch (error) {
console.error('Initialization failed:', error)
// 切换为其他登录方式
}
})
onUnmounted(() => {
aLiSDKModule.quitLoginPage();
})
</script>