wechat_bind_handler.dart 6.15 KB
import 'dart:async';

import 'package:appframe/config/locator.dart';
import 'package:appframe/data/repositories/user_auth_repository.dart';
import 'package:appframe/data/repositories/wechat_auth_repository.dart';
import 'package:appframe/services/dispatcher.dart';
import 'package:appframe/utils/login_util.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:fluwx/fluwx.dart';
import 'package:shared_preferences/shared_preferences.dart';

class WechatBindHandler extends MessageHandler {
  late final Fluwx _fluwx;
  late final FluwxCancelable _fluwxCancelable;
  late final WechatAuthRepository _wechatAuthRepository;
  late final UserAuthRepository _userAuthRepository;

  // 是否正在等待微信授权回调
  bool _waitingWechatAuth = false;
  // 总超时定时器
  Timer? _wechatAuthTimeoutTimer;
  // App 回到前台后的短延时定时器
  Timer? _wechatAuthResumeTimer;

  WechatBindHandler() {
    _fluwx = getIt.get<Fluwx>();
    _wechatAuthRepository = getIt.get<WechatAuthRepository>();
    _userAuthRepository = getIt.get<UserAuthRepository>();
  }

  @override
  Future<dynamic> handleMessage(params) async {
    if (!await _fluwx.isWeChatInstalled) {
      // throw Exception('设备上未安装微信App,不支持微信绑定');
      Fluttertoast.showToast(msg: '设备上未安装微信App,不支持微信绑定', gravity: ToastGravity.TOP, backgroundColor: Colors.red);
      return null;
    }

    _fluwxCancelable = _fluwx.addSubscriber(_responseListener);

    var authResult = await _fluwx.authBy(
      which: NormalAuth(scope: 'snsapi_userinfo', state: 'wechat_bind'),
    );

    if (!authResult) {
      _fluwxCancelable.cancel();
      // throw Exception('微信授权处理失败');
      Fluttertoast.showToast(msg: '微信授权处理失败', gravity: ToastGravity.TOP, backgroundColor: Colors.red);
      return null;
    }

    // 启动等待微信授权回调的兜底机制
    _startWechatAuthWaiting();

    // 微信授权为异步回调,不返回结果给H5
    return null;
  }

  void _responseListener(WeChatResponse response) async {
    if (response is WeChatAuthResponse) {
      // 收到正式回调,结束等待状态
      _finishWechatAuthWaiting();

      if (response.code == null || response.code == '') {
        Fluttertoast.showToast(msg: '微信授权取消', gravity: ToastGravity.TOP);
        _cleanup();
        return;
      }

      try {
        // 1. 用code换取会话信息
        var resultData = await _wechatAuthRepository.codeToSk(response.code!) as Map<String, dynamic>?;

        // 请求接口异常
        if (resultData == null) {
          Fluttertoast.showToast(msg: '绑定请求处理失败', gravity: ToastGravity.TOP);
          _cleanup();
          return;
        }

        // 状态码错误
        if (resultData['resultCode'] != '001') {
          Fluttertoast.showToast(msg: '绑定请求状态失败', gravity: ToastGravity.TOP);
          _cleanup();
          return;
        }

        var data = resultData['data'] as Map<String, dynamic>;
        var wechatUserCode = data['userCode'] as String;

        // 2. 从SharedPreferences获取当前用户信息
        var sharedPreferences = getIt.get<SharedPreferences>();
        var visitorId = sharedPreferences.getString('auth_visitor_id') ?? '';
        var visitorType = sharedPreferences.getString('auth_visitor_type') ?? '';

        if (visitorId.isEmpty || visitorType.isEmpty) {
          Fluttertoast.showToast(msg: '用户信息获取失败,请重新登录', gravity: ToastGravity.TOP);
          _cleanup();
          return;
        }

        if (visitorType != 'apple' && visitorType != 'phone') {
          Fluttertoast.showToast(msg: '用户信息错误,请重新登录', gravity: ToastGravity.TOP);
          _cleanup();
          return;
        }

        // 3. 调用绑定接口
        var bindResult = await _userAuthRepository.newBinding(
          visitorId,
          wechatUserCode,
          visitorType
        ) as Map<String, dynamic>?;

        if (bindResult != null && bindResult['code'] == 0) {
          // Fluttertoast.showToast(msg: '微信绑定成功', gravity: ToastGravity.TOP);
          LoginUtil.handleLoginSuccess(data, 0, 'reload');
        } else {
          var errorMsg = bindResult?['error'] ?? '微信绑定失败';
          Fluttertoast.showToast(msg: errorMsg, gravity: ToastGravity.TOP);
        }
      } catch (e) {
        debugPrint('wechatBind error: $e');
        Fluttertoast.showToast(msg: '微信绑定异常', gravity: ToastGravity.TOP);
      } finally {
        _cleanup();
      }
    }
  }

  // 标记进入"等待微信授权回调"状态,并启动总超时
  void _startWechatAuthWaiting() {
    _waitingWechatAuth = true;
    _wechatAuthTimeoutTimer?.cancel();
    _wechatAuthTimeoutTimer = Timer(const Duration(seconds: 30), () {
      if (_waitingWechatAuth) {
        _finishWechatAuthWaiting(reason: _WechatBindFinishReason.timeout);
      }
    });
  }

  // 结束等待,按场景给出提示
  void _finishWechatAuthWaiting({
    _WechatBindFinishReason reason = _WechatBindFinishReason.response,
  }) {
    if (!_waitingWechatAuth) return;
    _waitingWechatAuth = false;
    _wechatAuthTimeoutTimer?.cancel();
    _wechatAuthResumeTimer?.cancel();
    _wechatAuthTimeoutTimer = null;
    _wechatAuthResumeTimer = null;
    switch (reason) {
      case _WechatBindFinishReason.cancel:
        Fluttertoast.showToast(msg: '已取消微信授权', gravity: ToastGravity.TOP);
        _cleanup();
        break;
      case _WechatBindFinishReason.timeout:
        Fluttertoast.showToast(msg: '微信授权超时,请重试', gravity: ToastGravity.TOP);
        _cleanup();
        break;
      case _WechatBindFinishReason.response:
        // 正常收到回调时不弹提示
        break;
    }
  }

  // 清理资源
  void _cleanup() {
    _fluwxCancelable.cancel();
    _wechatAuthTimeoutTimer?.cancel();
    _wechatAuthResumeTimer?.cancel();
  }
}

enum _WechatBindFinishReason {
  // 收到了正式的 WeChatAuthResponse
  response,
  // App 已回到前台但仍无回调,判定为取消
  cancel,
  // 总超时
  timeout,
}