07.Taro框架获取用户手机号解决方案
流程图
核心代码
PhoneAuth 组件
import Taro from '[@tarojs](/user/tarojs)/taro';
import React, { useCallback, useEffect, useState } from 'react';
import { View, Button } from '[@tarojs](/user/tarojs)/components';
import { PLATFORM_TYPE } from '@/constant/index';
import tools from '@/utils/tools';
import './index.less';
// 工具方法
const PhoneManager: TaroMiniApp.IUtilsPhoneManager = {
// 老版本: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/deprecatedGetPhoneNumber.html
async oldVersionGetPhoneNumber(evt: TaroMiniApp.TGetPhoneNumberEvtDetail): Promise<TaroMiniApp.TaroApiResult> {
return Taro.login()
.then((codeRes: Taro.login.SuccessCallbackResult) => {
// console.log(codeRes, evt);
return this.getPhoneNumber(evt, codeRes.code)
})
},
// 新版本: https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
async newVersionGetPhoneNumber(evt: TaroMiniApp.TGetPhoneNumberEvtDetail): Promise<any> {
console.log(evt);
return this.getPhoneNumber(evt);
},
// 获取支付宝绑定的手机号
async handleGetAliPayPhoneNumber(): Promise<TaroMiniApp.TaroApiResult> {
try {
const res = await (Taro as any).getPhoneNumber();
const data = JSON.parse(res.response);
if (data.response.code !== 0) {
return Promise.reject({
code: data.response.code,
errMsg: 'getPhoneNumber:fail',
data: {
error: data.response
},
})
}
// TODO: 支付宝
return this.getPhoneNumber(data);
} catch (error) {
return Promise.reject({
code: 10,
errMsg: 'getPhoneNumber:fail',
data: {
error: error
},
})
}
},
// TODO: 对接后端服务 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
getPhoneNumber(evtDetail: TaroMiniApp.TGetPhoneNumberEvtDetail, code?: string): Promise<TaroMiniApp.TaroApiResult> {
// console.log(evtDetail, code);
return Promise.resolve({
code: 0,
errMsg: evtDetail?.detail?.errMsg,
data: {
phone: `121212-${code}`
},
})
},
// 处理获取手机号事件
async handleGetPhoneNumberEvt(evt?: TaroMiniApp.TGetPhoneNumberEvtDetail): Promise<TaroMiniApp.TGetPhoneNumberResult> {
if (PLATFORM_TYPE === 'WEAPP') {
if (evt?.detail?.errMsg.indexOf('deny') !== -1) {
return Promise.reject({
errMsg: evt?.detail.errMsg,
code: 10,
})
}
// 获取系统信息
const { SDKVersion } = tools.getSystemInfo();
// console.log(SDKVersion, tools.compareVersion(SDKVersion, '2.21.2'));
// 版本号对比
if (tools.compareVersion(SDKVersion, '2.21.2') === -1) {
return this.oldVersionGetPhoneNumber(evt);
}
// new version
return this.newVersionGetPhoneNumber(evt);
}
if (PLATFORM_TYPE === 'ALIPAY') {
return this.handleGetAliPayPhoneNumber();
}
const res = {
code: 10,
errMsg: 'getPhoneNumber: noSupport',
data: {},
};
return Promise.resolve(res);
},
}
const PhoneAuth = (props: TaroMiniApp.IComponentsPhoneAuthProps) => {
const [phoneNumberAuth, setPhoneNumber] = useState(false);
useEffect(() => {
if (PLATFORM_TYPE === 'ALIPAY') {
Taro.getSetting()
.then((res: Taro.getSetting.SuccessCallbackResult) => {
setPhoneNumber((res.authSetting as any).phoneNumber);
});
}
}, []);
const handleGetPhoneNumber = useCallback(async (evt) => {
if (PLATFORM_TYPE === 'WEAPP') {
PhoneManager.handleGetPhoneNumberEvt(evt).then((res) => {
props.onSuccess(res)
}).catch((err) => {
props.onFail(err)
})
return;
}
if (PLATFORM_TYPE === 'ALIPAY') {
PhoneManager.handleGetPhoneNumberEvt().then((res) => {
props.onSuccess(res)
}).catch((err) => {
props.onFail(err)
})
}
}, []);
const getManualPhoneNumber = useCallback(async () => {
PhoneManager.handleGetPhoneNumberEvt().then((res) => {
props.onSuccess(res)
}).catch((err) => {
props.onFail(err)
})
}, []);
const onAuthError = useCallback((err) => {
props.onFail({
code: 11,
errMsg: 'getPhoneNumber: deny',
data: err.detail
})
}, []);
const btnTxt = props.children || props.btnText || '手机号登录';
if (PLATFORM_TYPE !== 'ALIPAY' && PLATFORM_TYPE !== 'WEAPP') {
return <View>不支持</View>
}
return (
<View className="phoneAuthContainer">
{
PLATFORM_TYPE === 'WEAPP' && (
<Button
style={`${props.btnStyle}`}
className={`${props.uesSlot ? 'resetBtn' : ''}`}
openType="getPhoneNumber"
onGetPhoneNumber={handleGetPhoneNumber}
>{btnTxt}</Button>
)
}
{/* 支付宝已授权用户 */}
{
PLATFORM_TYPE === 'ALIPAY' && !phoneNumberAuth && (
<Button
style={`${props.btnStyle}`}
className={`${props.uesSlot ? 'resetBtn' : ''}`}
openType="getAuthorize"
scope='phoneNumber'
onGetAuthorize={handleGetPhoneNumber}
onError={onAuthError}
>{btnTxt}</Button>
)
}
{/* 支付宝未授权用户 */}
{
PLATFORM_TYPE === 'ALIPAY' && phoneNumberAuth && (
<Button
style={`${props.btnStyle}`}
className={`${props.uesSlot ? 'resetBtn' : ''}`}
onClick={getManualPhoneNumber}
>{btnTxt}</Button>
)
}
</View>
);
}
export default PhoneAuth;
如何使用
import React, { useCallback } from 'react';
import { View, } from '[@tarojs](/user/tarojs)/components';
// 引入的 PhoneAuth 组件
import { PhoneAuth } from '@/components/index';
import './index.less';
export default function PhoneAuthDemo() {
const handleSuccess = useCallback((res) => {
console.log('success:', res);
}, []);
const handleFail = useCallback((err) => {
console.log('fail:', err);
}, []);
const resetBtnStyle = "display: flex; background: #eee";
return (
<View className="page">
<View className='wrap'>
<PhoneAuth onSuccess={handleSuccess} onFail={handleFail} />
</View>
<View className='wrap'>
<PhoneAuth onSuccess={handleSuccess} onFail={handleFail} btnText="自定义文本" />
</View>
<View className='wrap'>
<PhoneAuth onSuccess={handleSuccess} onFail={handleFail} btnStyle={resetBtnStyle} uesSlot>
<View>我是自定义 slot</View>
</PhoneAuth>
</View>
</View>
)
}