You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Compose Multiplatform中实现iOS端Firebase谷歌认证

Compose Multiplatform(2023新方案)iOS端Firebase谷歌认证实现(Swift配合Kotlin)

前置准备

  • 完成iOS项目的Firebase基础配置:导入GoogleService-Info.plist,在Podfile中添加pod 'Firebase/Auth'和pod 'GoogleSignIn'并执行pod install
  • 确保Compose Multiplatform项目的iosMain模块已正确关联Xcode项目

1. Common层定义Expect接口

在commonMain目录下定义跨平台的认证抽象类,统一调用入口:

expect class FirebaseAuthManager {
    suspend fun signInWithGoogle(): Result<String> // 返回用户ID或错误信息
    fun signOut()
}

2. Xcode中编写Swift桥接逻辑

在Xcode项目中创建以下文件,处理iOS系统层的谷歌认证流程:

2.1 认证逻辑实现(FirebaseAuthBridge.swift)

import FirebaseAuth
import GoogleSignIn
import UIKit

@objc class FirebaseAuthBridge: NSObject {
    static let shared = FirebaseAuthBridge()
    
    private override init() {}
    
    func signInWithGoogle(completion: @escaping (String?, Error?) -> Void) {
        guard let clientID = FirebaseApp.app()?.options.clientID else {
            completion(nil, NSError(domain: "Firebase", code: -1, userInfo: [NSLocalizedDescriptionKey: "Firebase未完成配置"]))
            return
        }
        
        let config = GIDConfiguration(clientID: clientID)
        guard let rootVC = UIApplication.shared.windows.first?.rootViewController else {
            completion(nil, NSError(domain: "UI", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法获取根视图控制器"]))
            return
        }
        
        GIDSignIn.sharedInstance.signIn(with: config, presenting: rootVC) { user, error in
            if let error = error {
                completion(nil, error)
                return
            }
            
            guard let auth = user?.authentication, let idToken = auth.idToken else {
                completion(nil, NSError(domain: "GoogleSignIn", code: -1, userInfo: [NSLocalizedDescriptionKey: "无法获取ID Token"]))
                return
            }
            
            let credential = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: auth.accessToken)
            Auth.auth().signIn(with: credential) { authResult, error in
                completion(authResult?.user.uid, error)
            }
        }
    }
    
    func signOut() {
        do {
            try Auth.auth().signOut()
            GIDSignIn.sharedInstance.signOut()
        } catch {
            print("登出失败: \(error.localizedDescription)")
        }
    }
}

2.2 桥接头文件(FirebaseAuthBridge-Bridging-Header.h)

让Kotlin能识别Swift类的接口:

#import <Foundation/Foundation.h>

@interface FirebaseAuthBridge : NSObject
+ (instancetype)shared;
- (void)signInWithGoogleWithCompletion:(void (^)(NSString * _Nullable, NSError * _Nullable))completion;
- (void)signOut;
@end

然后在Xcode的Build Settings中,将Objective-C Bridging Header设置为该文件的路径(例如$(PROJECT_DIR)/FirebaseAuthBridge-Bridging-Header.h)


3. iOS层实现Actual类

在iosMain目录下编写Kotlin代码,通过Kotlin/Native interop调用Swift桥接类:

import kotlinx.coroutines.suspendCancellableCoroutine
import platform.Foundation.NSError
import platform.darwin.dispatch_async
import platform.darwin.dispatch_get_main_queue
import kotlin.coroutines.resume

actual class FirebaseAuthManager {
    private val authBridge = FirebaseAuthBridge.shared()
    
    actual suspend fun signInWithGoogle(): Result<String> = suspendCancellableCoroutine { continuation ->
        // 必须切换到主线程执行UI操作
        dispatch_async(dispatch_get_main_queue()) {
            authBridge.signInWithGoogleWithCompletion { userId, error ->
                when {
                    error != null -> continuation.resume(Result.failure(Exception(error.localizedDescription)))
                    userId != null -> continuation.resume(Result.success(userId))
                    else -> continuation.resume(Result.failure(Exception("登录失败,未获取到用户ID")))
                }
            }
        }
    }
    
    actual fun signOut() {
        dispatch_async(dispatch_get_main_queue()) {
            authBridge.signOut()
        }
    }
}

4. Common层Compose代码调用

在跨平台UI中直接调用认证逻辑,无需区分平台:

import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.lifecycle.viewmodel.compose.viewModel
import kotlinx.coroutines.launch

@Composable
fun AuthScreen() {
    val lifecycleScope = rememberCoroutineScope()
    
    Column {
        Button(onClick = {
            lifecycleScope.launch {
                val result = FirebaseAuthManager().signInWithGoogle()
                when (result) {
                    is Result.Success -> {
                        // 处理登录成功逻辑,如跳转主页、保存用户信息
                    }
                    is Result.Failure -> {
                        // 处理错误,如显示Toast
                    }
                }
            }
        }) {
            Text("谷歌登录")
        }
        
        Button(onClick = {
            FirebaseAuthManager().signOut()
        }) {
            Text("登出")
        }
    }
}

关键排坑点

  • 所有涉及iOS UI的操作必须在主线程执行,否则会崩溃,需用dispatch_async(dispatch_get_main_queue())切换
  • 确保iOS项目的Info.plist中添加了谷歌登录的URL Scheme,格式为com.googleusercontent.apps.${你的Firebase Client ID}
  • 检查Pod依赖版本是否匹配,避免因版本冲突导致的认证失败

内容的提问来源于stack exchange,提问作者Lucas Kim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 15:14:59