07.Taro框架获取用户手机号解决方案
发布于 3 年前 作者 yongmeng 2426 次浏览 来自 分享

流程图

核心代码

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>
  )
}
1 回复

挖藕挖藕 你好棒棒哦

回到顶部