• 【uniapp】Dcloud的uni手机号一键登录,具体实现及踩过的坑,调用uniCloud.getPhoneNumber(),uni.login()等


    一键登录Dcloud官网请戳这里,感兴趣的可以看看官网,有很详细的示例,选择App一键登录,可以看到一些常用的概述
    比如:

    1、调用uni.login就能弹出一键登录的页面
    2、一键登录的流程,可以选择先预登录uni.prelogin()或直接登录uni.login()
    3、要先开通Dcloud一键登录服务,在Dcloud开发者中心登录账户开通一键登录服务,这个需要付费的,每调用一次是0.02元,充值多少是无限制的,够你测试用就行。
    4、设置uniCloud云函数,一键登录需要调用uniCloud.getPhoneNumber()
    5、HBuilderX 3.4.0及之后的版本上传云函数时如果没有指定使用uni-cloud-verify扩展库的云函数将无法调用uniCloud.getPhoneNumber接口,所以要在云函数的package.json内添加uni-cloud-verify的引用
    6、一键登录页面是配置出来的,如何配置,可以看univerifyStyle 数据结构
    7、关闭一键登录授权界面,调用uni.closeAuthView()
    8、用户点击一键登录自定义按钮
    9、一键登录成功后,根据自己的后端接口判断是直接进入app页面还是需要去注册的业务处理

    在这里插入图片描述

    uni一键登录概述请戳这里

    在这里插入图片描述
    Uni手机号一键登录,请戳这里

    在这里插入图片描述

    一键登录具体实现:

    首先得有Dcloud账号,申请好应用之后,申请开通一键登录服务,开通一键登录服务详细流程,请戳这里,在左侧选择一键登录,点击基础配置,取ApiKey和ApiSecret的值
    在这里插入图片描述
    1、mainfest.json中选择App模块配置,勾选一键登录
    在这里插入图片描述
    2、要实现一键登录,需要借助UniCloud 云函数的 API:uniCloud.getPhoneNumber
    创建uniCloud.getPhoneNumber云函数步骤如下

    1、在项目根目录uniCloud文件夹下找到 cloudfunctions 文件夹。如果没有该文件夹,可以手动创建
    2、在 cloudfunctions 文件夹中创建一个新的文件夹,作为你的云函数的名称,例如 getPhoneNumber。我这里名称是login
    3、进入 getPhoneNumber 文件夹,并创建一个 JavaScript 文件,例如 index.js。
    4、在 index.js 中编写云函数的代码,具体实现获取手机号码的逻辑。

    备注:这段代码在下面引起了一个报错,报错已解决,此段代码不要直接复制,用解决后的代码

    exports.main = async (event, context) => {
    //登录Dcloud账号,左侧选择一键登录,点击基础配置,取ApiKey和ApiSecret的值
    	const res = await uniCloud.getPhoneNumber({
    		provider: 'univerify',
    		apiKey: '对应的apiKey',
    		apiSecret: '对应的apiSecret',
    		access_token: event.access_token,
    		openid: event.openid
    	})
    
    	// 这里需要改成你们自己后端登录成功后的接口地址 ...
    	const url = event.serversUrl + '/user/login'
    
    	// md5加密方式:手机号 时间戳 私钥
    	const phone = res.phoneNumber
    	const timestamp = new Date().getTime()
    	const signKey = '对应的signKey '
    	const sign = crypto.createHash('md5').update(phone + timestamp + signKey).digest('hex')
    
    	const result = await uniCloud.httpclient.request(url, {
    		method: 'POST',
    		data: {
    			phone,
    			timestamp,
    			sign
    		},
    		contentType: 'json',
    		dataType: 'json',
    		// 是否在证书不受信任时返回错误
    		rejectUnauthorized: false
    	})
    	console.log('服务端返回结果=', result)
    
    	if (result.data.code == 200) {
    		return {
    			code: 0,
    			message: '获取手机号成功',
    			data: result.data.data
    		}
    	} else {
    		return {
    			code: result.data.code,
    			message: result.data.msg,
    			data: result.data.data
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    5、在项目根目录的uniCloud文件夹下,在云函数的package.json内添加uni-cloud-verify的引用即可为云函数启用此扩展,无需做其他调整
    在这里插入图片描述

    {
    	"name": "login",
    	  "dependencies": {},
    	"extensions": {
    	"uni-cloud-verify": {} // 启用一键登录扩展,值为空对象即可
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3、页面中具体使用
    关于如何使用,我自己踩了些坑
    1、首先一键登录页面类似于一个弹窗,在app刚打开的时候先弹出这个一键登录的页面
    如果不想选一键登录,点左上角的叉号,关闭弹窗。
    我遇到的第一个坑是,我对一键登录不了解,
    我自己按ui图画了一个一键登录的页面,在实现过程中一直很疑惑,如何获得加密的手机号和对应的供应商认证服务来渲染到页面上,误区在于一键登录页面是配置出来的。
    既然它是弹窗,关闭之后就得有一个展示的页面,我这里是关闭之后显示的是账号登录页面

    2、uniapp介绍中,左侧菜单栏点击uni一键登录
    在这里插入图片描述
    里面有张流程图,先预登录然后是一键登录

    在这里插入图片描述
    关于预登录,需要调用 uni.preLogin(), 主要是检查预登录环境
    然后紧接着就是调用uni.login(),
    这个地方就很疑惑,我一直觉得是点击一键登录按钮才会调用login方法
    误区就在于,uni.login()获取用户的登录凭证 code。然后将这个 code 发送给后端服务器,服务器使
    用这个凭证进行登录验证,并返回用户的身份信息或生成用户的会话凭证,直白的说就是调用
    uni.login()之后才能拿到手机号和对应的供应商认证服务
    ,一键登录页面上的手机号和对应的供应商认证服务才会显示出来
    紧接着是一键登录按钮,当点击按钮的时候会触发uniCloud.callFunction,就是去调用云函数,云函
    数返回的参数有用户的完整手机号,拿着这个手机号,去调我们自己后端的接口,根据后端给的标识
    判断是放行到主页还是需要用户去注册页

    function preLogin(isShowMsg = false) {
    		//预登陆检查是否符合一键登录的环境
    		uni.preLogin({
    			provider: "univerify",
    			success: (res) => {
    			//调用login方法,我是vue3,没有thi实例,vue2框架this.login()
    				login()
    			},
    			fail(err) {
    				// 如果手机没有插入有效的sim卡,或者手机蜂窝数据网络关闭,都有可能造成预登录校验失败。
    			
    				if (isShowMsg && err.errMsg != "login:ok") {
    					// 不同运营商 返回的报错字段不同
    					uni.showModal({
    						title: "当前设备环境不支持一键登录",
    						content:
    							err.errMsg ||
    							err.metastate.resultMsg ||
    							err.metastate.error_data ||
    							err.metastate.resultDesc ||
    							"请检查是否插入有效sim卡及开启蜂窝数据网络",
    						showCancel: false,
    					});
    				}
    				
    			},
    		});
    
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    function login() {
    		uni.login({
    			provider: 'univerify',
    			univerifyStyle: {
    				"fullScreen": true, // 是否全屏显示,true表示全屏模式,false表示非全屏模式,默认值为false。
    				"backgroundColor": "#ffffff", // 授权页面背景颜色,默认值:#ffffff  
    				"icon": {
    					"path": "static/images/logo.png",// 自定义显示在授权框中的logo,仅支持本地图片 默认显示App logo   
    					"width": "60px",  //图标宽度 默认值:60px
    					"height": "60px",//图标高度 默认值:60px,				
    				},
    				"phoneNum": {
    					"color": "#525252",// 手机号文字颜色 默认值:#202020  
    					"fontSize": "22",// 手机号字体大小 默认值:18
    				},
    				"slogan": {
    					"color": "#525252", //  slogan 字体颜色 默认值:#8a8b90
    					"fontSize": "14"
    				},
    				"authButton": {
    					"normalColor": "#FF9CAE", // 授权按钮正常状态背景颜色 默认值:#3479f5  
    					"highlightColor": "#FF9CAE", // 授权按钮按下状态背景颜色 默认值:#2861c5(仅ios支持)  
    					"disabledColor": "#73aaf5", // 授权按钮不可点击时背景颜色 默认值:#73aaf5(仅ios支持)  
    					"textColor": "#ffffff", // 授权按钮文字颜色 默认值:#ffffff  
    					"title": "一键登录/注册" // 授权按钮文案 默认值:“本机号码一键登录”  
    				},
    				"otherLoginButton": {
    					"visible": "true", // 是否显示其他登录按钮,默认值:true  
    					"normalColor": "", // 其他登录按钮正常状态背景颜色 默认值:透明 
    					"highlightColor": "", // 其他登录按钮按下状态背景颜色 默认值:透明 
    					"textColor": "#656565", // 其他登录按钮文字颜色 默认值:#656565  
    					"title": "验证码登录", // 其他登录方式按钮文字 默认值:“其他登录方式”  
    					"borderColor": "",  //边框颜色 默认值:透明(仅iOS支持)  
    					"borderRadius": "0px",// 其他登录按钮圆角 默认值:"24px" (按钮高度的一半)
    				},
    				"privacyTerms": {
    					"defaultCheckBoxState": false, // 条款勾选框初始状态 默认值: true
    					"uncheckedImage": "", // 可选 条款勾选框未选中状态图片(仅支持本地图片 建议尺寸 24x24px)(3.2.0+ 版本支持)   
    					"checkedImage": "", // 可选 条款勾选框选中状态图片(仅支持本地图片 建议尺寸24x24px)(3.2.0+ 版本支持)   
    					"checkBoxSize": 12, // 可选 条款勾选框大小,仅android支持
    					"textColor": "#BBBBBB", // 文字颜色 默认值:#BBBBBB  
    					"termsColor": "#5496E3", //  协议文字颜色 默认值: #5496E3  
    					"prefix": "请阅读并同意", // 条款前的文案 默认值:“我已阅读并同意”  
    					"suffix": "并使用本机号码登录", // 条款后的文案 默认值:“并使用本机号码登录”  
    					"privacyItems": [  // 自定义协议条款,最大支持2个,需要同时设置url和title. 否则不生效  
    						{
    							"url": "/pages/privacy/use", // 点击跳转的协议详情页面  
    							"title": "《xxx用户注册协议》" //用户注册协议名称  
    						},
    
    						{
    							"url": "/pages/privacy/privacy", // 点击跳转的协议详情页面  
    							"title": "《xx隐私政策》" // 隐私政策名称  
    						}
    					]
    
    				}
    
    			},
    			success: (res) => {
    				
    				uniCloud.callFunction({
    					name: 'login', // 你的云函数名称
    					data: {
    						access_token: res.authResult
    							.access_token, // 客户端一键登录接口返回的access_token
    						openid: res.authResult.openid // 客户端一键登录接口返回的openid
    					}
    				}).then(dataRes => {
    					console.log('云函数返回的参数', dataRes)
    					data.form.mobile = dataRes.result.data.phoneNumber
    					$Api.post("user/direct",data.form).then((res) => {
    						console.log(res,'调后端接口判断登录后操作');
    						if(res&&res.code==0){
    						if(res.id){
                        	uni.switchTab({
    					 url: "/pages/square/square",
    				});
                           }else{
                           uni.navigateTo({
    								url: "/pages/user/register?mobile=" + data.form.mobile,
    							});
                                           }
                                         }
    					});
    					
    				}).catch(err => {
    					console.log('云函数报错', err)
    				})
    				uni.showToast({
    					title: res.authResult,
    					icon: "none"
    				})
    				uni.closeAuthView() //关闭一键登录弹出窗口
    			},
    			fail(res) { // 登录失败			
    				uni.closeAuthView() //关闭一键登录弹出窗口
    				console.log('失败')
    			},
    		})
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101

    3、当uni.login()调用成功之后,一键登录页面就出现了,然后就是调整样式,大框架是没法改变的,只能调整一些类似于字体大小,颜色之类的,如何调整icon和phoneNumber之间的间距,我一直没有实现,有实现的可以给我留言,感谢感谢

    通过univerifyStyle 配置,官网是这样的,我自己的配置看上面的代码

    {  
        "fullScreen": false, // 是否全屏显示,默认值: false
        "backgroundColor": "#ffffff",  // 授权页面背景颜色,默认值:#ffffff
        "backgroundImage": "", // 全屏显示的背景图片,默认值:"" (仅支持本地图片,只有全屏显示时支持)  
        "icon": {  
            "path": "static/xxx.png", // 自定义显示在授权框中的logo,仅支持本地图片 默认显示App logo
            "width":  "60px",  //图标宽度 默认值:60px
            "height": "60px"   //图标高度 默认值:60px
        },  
        "closeIcon": {  
            "path": "static/xxx.png" // 自定义关闭按钮,仅支持本地图片。 HBuilderX3.3.7+版本支持
        },  
        "phoneNum": {  
            "color": "#202020"  // 手机号文字颜色 默认值:#202020  
        },  
        "slogan": {  
            "color": "#BBBBBB"  //  slogan 字体颜色 默认值:#BBBBBB  
        },  
        "authButton": {  
            "normalColor": "#3479f5", // 授权按钮正常状态背景颜色 默认值:#3479f5  
            "highlightColor": "#2861c5",  // 授权按钮按下状态背景颜色 默认值:#2861c5(仅ios支持)  
            "disabledColor": "#73aaf5",  // 授权按钮不可点击时背景颜色 默认值:#73aaf5(仅ios支持)  
            "textColor": "#ffffff",  // 授权按钮文字颜色 默认值:#ffffff  
            "title": "本机号码一键登录", // 授权按钮文案 默认值:“本机号码一键登录”  
            "borderRadius": "24px"	// 授权按钮圆角 默认值:"24px" (按钮高度的一半)
        },  
        "otherLoginButton": {  
            "visible": true, // 是否显示其他登录按钮,默认值:true  
            "normalColor": "", // 其他登录按钮正常状态背景颜色 默认值:透明 
            "highlightColor": "", // 其他登录按钮按下状态背景颜色 默认值:透明 
            "textColor": "#656565", // 其他登录按钮文字颜色 默认值:#656565  
            "title": "其他登录方式", // 其他登录方式按钮文字 默认值:“其他登录方式”  
            "borderColor": "",  //边框颜色 默认值:透明(仅iOS支持)  
            "borderRadius": "0px" // 其他登录按钮圆角 默认值:"24px" (按钮高度的一半)
        },  
        "privacyTerms": {  
            "defaultCheckBoxState":true, // 条款勾选框初始状态 默认值: true
            "isCenterHint":false, //未勾选服务条款时点击登录按钮的提示是否居中显示 默认值: false (3.7.13+ 版本支持)
            "uncheckedImage":"", // 可选 条款勾选框未选中状态图片(仅支持本地图片 建议尺寸 24x24px)(3.2.0+ 版本支持)   
            "checkedImage":"", // 可选 条款勾选框选中状态图片(仅支持本地图片 建议尺寸24x24px)(3.2.0+ 版本支持)   
            "checkBoxSize":12, // 可选 条款勾选框大小
            "textColor": "#BBBBBB", // 文字颜色 默认值:#BBBBBB  
            "termsColor": "#5496E3", //  协议文字颜色 默认值: #5496E3  
            "prefix": "我已阅读并同意", // 条款前的文案 默认值:“我已阅读并同意”  
            "suffix": "并使用本机号码登录", // 条款后的文案 默认值:“并使用本机号码登录”  
            "privacyItems": [  // 自定义协议条款,最大支持2个,需要同时设置url和title. 否则不生效  
                {  
                    "url": "https://", // 点击跳转的协议详情页面  
                    "title": "用户服务协议" // 协议名称  
                }  
            ]  
        },
        "buttons": {  // 自定义页面下方按钮仅全屏模式生效(3.1.14+ 版本支持)
            "iconWidth": "45px", // 图标宽度(高度等比例缩放) 默认值:45px
            "list": [
                {
                    "provider": "apple",
                    "iconPath": "/static/apple.png" // 图标路径仅支持本地图片
                }, 
                {
                    "provider": "weixin",
                    "iconPath": "/static/wechat.png" // 图标路径仅支持本地图片
                }
            ]
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    这里遇到一个报错,云函数中这个接口的前缀是underfiend,导致找不到,云函数index.js中的代码之前是其他人写的,我打印之后才发现,event只返回两个参数,access_token和openid,没有event.serversUrl这个参数,所以导致显示的是undefined
    在这里插入图片描述
    代码改为:

    exports.main = async (event, context) => {
    //登录Dcloud账号,左侧选择一键登录,点击基础配置,取ApiKey和ApiSecret的值
    	const res = await uniCloud.getPhoneNumber({
    	appid: '_xxxxA3', // 替换成自己开通一键登录的应用的DCloud appid
    		provider: 'univerify',
    		apiKey: '对应的apiKey',
    		apiSecret: '对应的apiSecret',
    		access_token: event.access_token,
    		openid: event.openid
    	})
    return {
    			code: 0,
    			message: '获取手机号成功',
    			data:res
    		}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    然后调用成功后会返回这样的数据格式

    在这里插入图片描述
    我们需要的就是完整的手机号
    在这里插入图片描述
    在自己的页面中调用uni.login,uniCloud.callFunction({}).then((dataRes=>{
    console.log(‘云函数返回的参数’, dataRes)
    })),打印之后就能拿到:

    {
        "result": {
            "code": 0,
            "message": "获取手机号成功",
            "data": {
                "code": 0,
                "success": true,
                "phoneNumber": "1510000xxxx"
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    再说个小细节点,如果你想在云函数中打印看结果的话,一定要右击云函数选择上传部署,不然的话云函数不会更新,我就是自己傻傻的等着看结果,试了好几次才反应过来
    在这里插入图片描述
    欢迎留言沟通或私信沟通~~~~

  • 相关阅读:
    C++:过滤中文字符
    Gillespie 随机模拟算法附matlab代码
    分类接口,淘宝分类详情 API
    MYSQL练习题:每篇文章同时刻最大在看人数
    使用Docker安装ElasticSearch和可视化界面Kibana【图文教学】
    竞赛选题 深度学习人体语义分割在弹幕防遮挡上的实现 - python
    分布式事务(Seata)原理 详解篇,建议收藏
    美团应届生面试第一问:Object o = new Object()占用多少字节?
    Java编程练习题Demo33-Demo40
    Angular依赖注入模式的应用和玩法案例
  • 原文地址:https://blog.csdn.net/weixin_49668076/article/details/132813065