WeChatLoginBridge.swift 2.34 KB
import Foundation
import UIKit

/// Delivers the native WeChat authorization callback to Flutter's login flow.
final class WeChatLoginBridge: NSObject, WeChatHostApi, WXApiDelegate {
  static let shared = WeChatLoginBridge()

  private let appId = "wx42b603acf3dd68f5"
  private var pendingCompletion: ((Result<String, Error>) -> Void)?

  private override init() {}

  func registerApp() {
    WXApi.registerApp(appId, universalLink: "")
  }

  func requestAuthorizationCode(completion: @escaping (Result<String, Error>) -> Void) {
    DispatchQueue.main.async {
      guard self.pendingCompletion == nil else {
        completion(.failure(PigeonError(
          code: "wechat_authorization_in_progress",
          message: "WeChat authorization is already in progress.",
          details: nil
        )))
        return
      }
      guard WXApi.isWXAppInstalled() else {
        completion(.failure(PigeonError(
          code: "wechat_not_installed",
          message: "WeChat is not installed.",
          details: nil
        )))
        return
      }

      let request = SendAuthReq()
      request.scope = "snsapi_userinfo"
      request.state = UUID().uuidString
      self.pendingCompletion = completion
      WXApi.send(request) { success in
        if !success {
          self.finish(.failure(PigeonError(
            code: "wechat_request_failed",
            message: "Unable to open WeChat.",
            details: nil
          )))
        }
      }
    }
  }

  func handleOpenURL(_ url: URL) -> Bool {
    WXApi.handleOpen(url, delegate: self)
  }

  func handleUniversalLink(_ userActivity: NSUserActivity) -> Bool {
    WXApi.handleOpenUniversalLink(userActivity, delegate: self)
  }

  func onReq(_ req: BaseReq) {}

  func onResp(_ resp: BaseResp) {
    guard let authResponse = resp as? SendAuthResp else { return }
    if authResponse.errCode == 0,
       let code = authResponse.code,
       !code.isEmpty {
      finish(.success(code))
      return
    }
    let message = authResponse.errStr.isEmpty
      ? "WeChat authorization was cancelled or failed."
      : authResponse.errStr
    finish(.failure(PigeonError(
      code: "wechat_authorization_failed",
      message: message,
      details: nil
    )))
  }

  private func finish(_ result: Result<String, Error>) {
    let completion = pendingCompletion
    pendingCompletion = nil
    completion?(result)
  }
}