Skip to content

iOS — Firebase Authentication Core / 原生登录 UI ​

独立模块与安装 ​

Pod用途
ROAuthFirebaseFirebaseApp/Auth、User/Session、ID Token 获取刷新、匿名、Firebase 凭证、link/reauth、状态监听/登出
ROAuthFirebaseUI选装 UIKit 缓存身份卡、Provider 方法选择、动态倒计时、错误重试、四语言资源

同装限制

iOS 12、FirebaseAuth/FirebaseCore 10.29.0 与 ROLoginGoogle 的 GoogleSignIn 9.2.0 当前存在官方依赖约束冲突。需要同一项目使用两者时,请先选取已验证的兼容依赖方案,不要强行覆盖官方版本。

下面是从本地源码按需集成的示例。游戏正式安装应选择实际可解析、已固定版本的 Pod 来源。UI 依赖 Firebase Core,二者需在同一消费者环境内正确解析:

ruby
platform :ios, '12.0'
target 'GameApp' do
  use_frameworks! :linkage => :static
  pod 'ROAuthFirebase',   :path => '<本机roios-sdk>/Modules/ROAuthFirebase'
  pod 'ROAuthFirebaseUI', :path => '<本机roios-sdk>/Modules/ROAuthFirebaseUI'
end

初始化和 Firebase 身份取得 ​

由宿主按 Firebase 官方步骤正确配置命名 FIRApp 或默认 FIRApp、合法 Bundle ID、GoogleService-Info.plist。资源属于消费宿主,不进入通用 SDK 的发布源码或公开文档。

objc
ROAuthFirebase *core = [ROAuthFirebase forDefaultApp];
// 如果应用没有默认 FirebaseApp,则使用宿主明确的 FIROptions 初始化对应 App。
[core getIDTokenForceRefresh:NO completion:^(ROAuthFirebaseSession *session, NSError *error) {
    if (session && session.idToken.length) {
        // 交给宿主经 HTTPS 向可信游戏后端验证;不要打印 Token。
    } else {
        // 按 error.code 做安全错误提示或重试,不返回游戏成功。
    }
}];

现有 ROLoginApple 在 Firebase OAuth 流程中必须正确使用不可预测 rawNonce 与 SHA256(rawNonce),Apple identityToken 不等于 authorizationCode:

objc
NSString *rawNonce = [ROAuthFirebase generateRawNonce];
NSString *hashedNonce = [ROAuthFirebase SHA256OfRawNonce:rawNonce];
[[ROLoginApple shared] authorizeFromWindow:window nonce:hashedNonce state:state
    completion:^(ROLoginAppleResult *result, NSError *error, BOOL cancelled) {
        if (!result) return; // 错误/取消留在可恢复的认证流程。
        FIRAuthCredential *credential =
            [ROAuthFirebase appleCredentialWithIDToken:result.identityToken
                                              rawNonce:rawNonce
                                              fullName:result.fullName];
        [core signInWithCredential:credential completion:^(ROAuthFirebaseSession *session, NSError *error) {
            // Firebase Session 成功后,游戏宿主再做 auth.Auth;并非游戏直接登录成功。
        }];
    }];

宿主为 Apple 的 state 独立生成并校验安全随机值;需要保护首次授权的姓名/邮箱只返回一次的情况。现有 ROLoginGoogle 另提供 signInForFirebaseFromController:completion: 返回 Google ID Token + Access Token;旧 serverAuthCode 不可替代 Access Token。正式 Google9.2 + Firebase10.29 的同装阻塞解除前,不把此桥接视为生产可用组合。

可选 ROSDK 登录 UI ​

objc
ROFirebaseUIOptions *options = [ROFirebaseUIOptions new];
options.loginMethods = ROFirebaseLoginMethodAnonymous; // 如需游客登录
options.showCachedAccount = YES;
options.allowSwitchAccount = YES;
options.autoContinueSeconds = 3; // 默认 3→2→1,设置 0 关闭
options.timeoutSeconds = 60;     // SDK 局部等待,不是取消官方请求
ROAuthFirebaseUI *ui = [[ROAuthFirebaseUI alloc] initWithCore:core options:options];
[ui presentFromController:presenter completion:^(ROAuthFirebaseSession *session, BOOL cancelled, NSError *error) {
    if (error) {
        // 可重试错误,窗口仍打开;不要完成游戏 sdk.login()。
    } else if (session) {
        // 只代表 Firebase 身份认证成功;游戏账号依赖服务端 account/token。
    } else {
        // 主窗口仅允许宿主生命周期主动 dismiss;不视为游戏登录成功。
    }
}];
// 宿主需持有 ui 实例,窗口/Scene 销毁时调用 [ui dismiss]。

completion 的 error 参数 是非终态、可恢复错误通知,会保留登录窗口;Provider 自身取消返回登录方式列表,不能解锁必需登录。多 Provider 身份卡仅表示 Firebase 已关联方式,不代表最近登录方式;无名称或品牌素材时退回中性头像,无需远程请求。Google/Apple 等入口只在宿主实际注册可执行 Provider Handler 后显示。系统语言为 en/zh-Hans/th/id,不是 Egret 游戏语言。

选择其他认证方式时可以绕过旧缓存卡并停止倒计时,但不需要默认登出 Firebase;切换已有游客身份时需由用户确认,避免丢失尚未绑定的进度。

SDK 成功与游戏 sdk.login() 成功 ​

Firebase currentUser 或 SDK UI 的 session 只代表 Firebase 身份。真实 Platform : SDKDelegate 使用 Firebase ID Token 发起游戏服务器 auth.Auth,服务器验签并兑换有效 account/token 后,才能按固定 JS↔Native 协议单次向游戏返回成功。业务网络错误、拒绝和空账号不能放行游戏;Firebase 缓存可保留并刷新,不需要额外的 Firebase loginFlush()。

宿主配置与错误处理 ​

  • 使用宿主自己的 GoogleService-Info.plist、Bundle ID 和安全配置初始化 Firebase,不要把真实账号或机密硬编码进模块。
  • completion 的 error 参数 属于可恢复错误通知;Provider 取消返回方式选择,窗口销毁应调用 dismiss。宿主应防止迟到回调和重复游戏登录完成。
  • 不含独立 Facebook 原生 OAuth 实现;关联身份标识并非可用登录按钮。
  • UI 的四语言资源由 Pod 内的资源 Bundle 提供,系统语言为 en/zh-Hans/th/id。

API 全览:Firebase Auth Core(独立 Pod) ​

ROAuthFirebase 独立处理 Firebase App/User、ID Token、凭证和观察者;不包含 Egret、游戏服务器 auth.Auth、账号转换或 UI。iOS 12 候选 FirebaseAuth/FirebaseCore 10.29.0。

Objective-C 公开接口参数、结果与用途
[[ROAuthFirebase alloc] initWithApp:FIRApp]宿主已有 FIRApp 时创建 Core
[ROAuthFirebase forDefaultApp]取得已配置的默认 FirebaseApp 对应 Core
[ROAuthFirebase configureWithName:options:error:]使用 FIROptions 配置指定 Firebase App
core.currentUser当前身份快照,不意味着 ID Token 或游戏 Session 有效
addStateListener: → handle、removeStateListener:订阅/解除 Firebase 身份变化
getIDTokenForceRefresh:completion:获取/强制刷新 Firebase ID Token
signInAnonymously:Firebase 匿名登录,与游戏后端游客账号不同
signInWithCredential:completion:Provider 返回的 FIRAuthCredential 登录
linkWithCredential:completion:绑定至当前 Firebase 用户
reauthenticateWithCredential:completion:当前用户重新认证
signOut:error:清理 Firebase 当前会话,不替游戏后端注销
googleCredentialWithIDToken:accessToken:Google Firebase Credential,注意 accessToken 不是 serverAuthCode
appleCredentialWithIDToken:rawNonce:、含 fullName: 的重载Apple 身份凭证及首次姓名,可选全名
generateRawNonce、SHA256OfRawNonce:Apple 授权请求 nonce 生成与 SHA256 编码
ROAuthFirebaseCompletion(session,error)Firebase 认证成功/失败;成功仍需服务器认证
ROAuthFirebaseStateChanged(user)当前本地身份变化,不是游戏登录结果

ROAuthFirebaseUser 公开 uid、displayName、anonymous、providerIDs;ROAuthFirebaseSession 公开 user 与敏感 idToken。ROAuthFirebaseErrorDomain 为错误域。ProviderIDs 只代表当前已关联方式,不推断最新登录来源。

objc
ROAuthFirebase *core = [ROAuthFirebase forDefaultApp];
// 或:core = [ROAuthFirebase configureWithName:@"game-auth" options:firebaseOptions error:&error];
id observer = [core addStateListener:^(ROAuthFirebaseUser *user) {
    // user 可能为 nil;不可据此报告游戏账号登录成功。
}];
[core signInAnonymously:^(ROAuthFirebaseSession *session, NSError *error) {
    if (session) {
        // 将 session.idToken 安全交游戏服务器验签/兑换 account + token。
    }
}];
// 任选:已有 Firebase 用户可续登刷新:
// [core getIDTokenForceRefresh:YES completion:completion];
// [core signInWithCredential:credential completion:completion];
// [core linkWithCredential:credential completion:completion];
// [core reauthenticateWithCredential:credential completion:completion];
// FIRAuthCredential *apple = [ROAuthFirebase appleCredentialWithIDToken:idToken rawNonce:rawNonce];
// NSString *nonce = [ROAuthFirebase generateRawNonce];
// NSString *sha = [ROAuthFirebase SHA256OfRawNonce:nonce];
// 用完监听:[core removeStateListener:observer];
// 退出:[core signOut:&error];

API 全览:独立选装登录 UI Pod ​

ROAuthFirebaseUI 需要 Core,不会强制依赖 Google/Apple 登录模块。宿主保持 Core 生命周期,在每次独立游戏登录流程中创建 UI 对象,保存至宿主属性;presentFromController:completion: 是一次窗口展示入口。UI 自己管理遮罩卡、账号信息、倒计时、方式列表、Core 调用、失败重试与关闭;宿主在控制器销毁前 dismiss。不是每次按钮点击都需要重新 new 一个 UI。

Objective-C UI 公开接口用法
[[ROAuthFirebaseUI alloc] initWithCore:options:]创建当前宿主登录流程的 UI
presentFromController:completion:在前台 ViewController 上展示一次模态卡片;获取 Firebase Session 才成功回调
registerMethod:handler:注册实际实现的 Provider,接收 FIRAuthCredential
unregisterMethod:移除指定 Provider handler
ui.state只读 Idle/Choosing/CachedAccount/Authorizing/FirebaseAuthenticating/RefreshingToken/Succeeded/Failed/Cancelled 阶段
ROFirebaseUICompletion(session,cancelled,error)同一回调接收 Firebase Session、主动关闭和可重试错误;错误事件不关闭 UI
dismiss宿主生命周期关闭模态并使迟到结果失效,不能作为给玩家的“跳过登录”按钮
ROFirebaseUIProviderHandler(presenter, completion)Provider 授权并调用 completion(credential,error,cancelled)
ROFirebaseUICompletion(session,cancelled,error)Firebase 成功或宿主主动取消,游戏仍须后端认证

ROFirebaseUIOptions 全部字段:loginMethods(方式位)、showCachedAccount、autoContinueSeconds(默认 3、0 关闭)、timeoutSeconds(默认 60)、allowSwitchAccount、showAnonymousWarning、accentColor(UIColor)、mode(SignIn/Link/Reauthenticate)、preferredOrder、methodIcons(按 NSNumber 位值注入合规 UIImage)。方式位:Google=1、Facebook=2、GitHub=4、Twitter=8、Microsoft=16、Yahoo=32、Apple=64、Anonymous=512。默认按钮按已注册 handler 与位掩码交集显示;匿名不需要外部 handler。关联 Provider 列表仅表示历史关联,不代表对应授权器已安装。

objc
ROFirebaseUIOptions *options = [ROFirebaseUIOptions new];
options.loginMethods = ROFirebaseLoginMethodAnonymous;
options.autoContinueSeconds = 3;
options.allowSwitchAccount = YES;
options.mode = ROFirebaseLoginModeSignIn;
ROAuthFirebaseUI *ui = [[ROAuthFirebaseUI alloc] initWithCore:core options:options];
// 宿主将 ui 保存在属性中,直至当前登录流程结束/控制器销毁。
[ui presentFromController:presenter
    completion:^(ROAuthFirebaseSession *session, BOOL cancelled, NSError *error) {
        if (error) {
            // 非终态错误:登录窗口仍打开,等待重试/选择其他登录方式。
        } else if (session) {
            // Firebase ID Token 交宿主游戏服务端 auth.Auth 兑换 account/token。
            // 只有成功兑换后才完成原有 sdk.login()。
        } else if (cancelled) {
            // 只表示宿主主动销毁;游戏仍未登录。
        }
    }];
// 如果项目引入真实 Google 等独立授权模块,可选注册:
// [ui registerMethod:ROFirebaseLoginMethodGoogle handler:
//   ^(UIViewController *vc, ROFirebaseUICredentialCompletion done) {
//       ... 获取 Google ID Token + Access Token,创建 FIRAuthCredential ...;
//       done(credential, nil, NO);
//   }];
// 在 presenter 销毁前:[ui dismiss];

**CocoaPods 依赖解析:**消费者目前必须同时提供 ROAuthFirebase 与 ROAuthFirebaseUI 两个具体来源(例如同时使用本地 :path,或经验证的两个固定 git split Tag),UI Podspec 的 s.dependency 不会自动推导 Core 的 Git URL。iOS12 + GoogleSignIn9.2 + FirebaseAuth10.29 官方依赖冲突仍 BLOCKED,不能声称真实 Google/Firebase 混装成功。

**验收状态:**UI/Core 最终代码与测试证据按当前源码 SHA 判断,XCTest build-for-testing 不等于执行;真实 OAuth/游戏服务器和固定 Egret 端到端仍需测试。

按需接入独立 SDK 模块,按真实宿主配置原生接口。