Android — Firebase Authentication Core / 原生登录 UI
选择模块与依赖
| 模块 | Maven 坐标 | 用途 |
|---|---|---|
auth-firebase | com.ronpad.sdk:ro-auth-firebase:0.1.0 | Firebase App/Auth、Session、ID Token、匿名登录、Provider 凭证、link/reauth、账号观察与登出 |
auth-firebase-ui | com.ronpad.sdk:ro-auth-firebase-ui:0.1.0 | 可选原生登录模态、已关联 Provider 身份卡、缓存倒计时、重试/换方式、四语言 |
Core 使用 Firebase Auth 22.1.2,最低 Android 23;UI 只依赖 Core,不强制安装 Google/Apple/Facebook 授权模块或 Egret。请在项目配置实际可用的 ROSDK 私有 Maven 仓库,并使用已固定、能从仓库下载的版本:
// 使用应用实际可访问的 ROSDK 私有 Maven 源。
implementation 'com.ronpad.sdk:ro-auth-firebase:0.1.0'
// 需要 ROSDK 统一原生登录窗口时再引入:
implementation 'com.ronpad.sdk:ro-auth-firebase-ui:0.1.0'宿主初始化与 Firebase Session
// 宿主已安全配置并初始化 FirebaseApp(或使用显式 FirebaseOptions)。
ROAuthFirebase core = ROAuthFirebase.forDefaultApp();
// Firebase currentUser/hasSession 不代表 Token 有效或游戏已登录。
core.getIdToken(false, new ROAuthFirebase.Completion() {
@Override public void onSuccess(ROAuthFirebase.Session session) {
// 将 session.idToken 经 HTTPS 给游戏服务器验签/兑换 account/token;不打印 ID Token。
}
@Override public void onFailure(String code, Exception error) {
// 可重试 Token 获取、网络失败或失效会话;只输出安全错误码。
}
});Core 还支持 initialize(context, FirebaseOptions, appName)、signInAnonymously、signInWithCredential、linkWithCredential、reauthenticate、getIdToken(forceRefresh)、observe 和 signOut(OperationCallback);本地退出必须通过回调把成功或异常返回给宿主。Google Credential Manager 的 Google ID Token 可由 ROAuthFirebase.googleCredential(idToken) 构造 Firebase 凭证;Google ID Token 与 Firebase ID Token 不同。Apple 在 Android 使用 Firebase 官方 OAuth 凭证入口;不要把游戏后端 Apple 一次性 code 当作 Firebase Credential。
可选 UI:匿名登录示例
ROFirebaseLoginUI.Options options = new ROFirebaseLoginUI.Options();
options.loginMethods = ROFirebaseLoginUI.ANONYMOUS;
options.showCachedAccount = true;
options.allowSwitchAccount = true;
options.autoContinueSeconds = 3; // 默认逐秒 3→2→1,设 0 禁止自动继续。
options.timeoutSeconds = 60; // 仅 UI 等待超时,不代表取消官方网络请求。
ROFirebaseLoginUI ui = new ROFirebaseLoginUI(activity, core, options);
ui.show(new ROFirebaseLoginUI.Completion() {
@Override public void onSuccess(ROAuthFirebase.Session session) {
// 只代表 Firebase 身份成功;宿主仍需通过游戏服务器验签与兑换。
}
@Override public void onCancel() {
// 只允许宿主生命周期主动结束;不能视为已登录游戏。
}
@Override public void onFailure(String code, Exception error) {
// 非终态、可恢复失败;UI 保留重试/选择其他方式,不直接放行游戏。
}
});
// Activity 销毁时 ui.dismiss(),不在用户必需登录面板上提供跳过按钮。Google/Apple 等需通过 registerProvider / registerSessionProvider 注册真实实现,且 loginMethods 允许才显示;不能因为 Firebase User 的 providerIDs 存在就假设已安装 Provider。Facebook 目前仅支持展示 Firebase 已关联身份,未实现独立 Facebook 登录模块。合规品牌图标由对应 Provider/宿主注入,缺失时用中性图标。缓存身份多 Provider 显示的是已关联方式而不是最近一次登录方式;不显示完整邮箱/UID/Token,不下载远程头像阻塞登录。
SDK 成功与游戏 sdk.login() 成功的边界
游戏 sdk.login() → Firebase UI/Session + ID Token
↓
宿主 Platform : SDKDelegate 调用游戏服务端 auth.Auth
├─ 有效游戏 account/token → 单次向游戏返回成功
└─ 拒绝/网络失败/无效账号 → 游戏仍未登录
→ 宿主可刷新 Token、重试服务器或再次打开 SDK UIFirebase 的会话可保留以免用户重复授权;游戏认证失败不必自动 Firebase signOut。真正换号涉及未绑定游客进度时,必须让用户确认;不能用 UI 成功直接解锁游戏。Firebase Core/UI 不负责游戏账号认证,也不需要额外的 loginFlush();业务最终状态由原有宿主管理。
宿主需要注意
- 按需注册可用 Provider Handler,未安装的登录方式不会显示;已有 Firebase providerData 只代表关联身份,不表示可直接授权。
- 账号缓存、Token 过期、Activity 销毁、网络失败和重复回调都应在现有宿主处理,不记录明文 Token 或完整账号资料。
- UI 支持
en/zh/th/id系统语言;具体字符串不跟随 Egret 游戏语言。 - 当前未提供独立 Facebook 原生登录 Provider;展示 Facebook 关联标记不等于支持 Facebook OAuth 登录。
API 全览:Firebase Auth Core(可不安装 UI)
Maven 候选:com.ronpad.sdk:ro-auth-firebase:0.1.0。Core 只管理 Firebase 身份/Token,不包含游戏后端 auth.Auth、游戏 account/token、Egret 协议,也不强制依赖 ROSDK Google/Apple Provider。
| 公开 Java 接口 | 参数、回调与用途 |
|---|---|
new ROAuthFirebase(FirebaseApp app) | 宿主已配置 FirebaseApp 时构造 |
ROAuthFirebase.forDefaultApp() | 获取已初始化的默认 Firebase App(缺配置抛错) |
ROAuthFirebase.initialize(context, FirebaseOptions, appName) | 不用 google-services 插件时显式创建/复用指定 Firebase App |
currentUser()、hasSession() | 当前本地身份快照和有无缓存用户,不保证 Token 仍有效 |
observe(StateListener) → Subscription | 观察 Firebase 身份,Subscription.remove() 在宿主销毁时解除监听 |
getIdToken(forceRefresh, Completion) | 本地会话刷新/获取 Token;forceRefresh=true 强制刷新 |
signInAnonymously(Completion) | Firebase 匿名用户,不等于业务游客登录 |
signInWithCredential(credential, Completion) | 使用独立 Provider 返回的 Firebase AuthCredential |
linkWithCredential(credential, Completion) | 将凭证关联到当前 Firebase 账号 |
reauthenticate(credential, Completion) | 对当前 Firebase 账号重新认证 |
googleCredential(googleIdToken) | Google ID Token 转为 Firebase AuthCredential(不应传 serverAuthCode) |
signInWithApple(activity, Completion) | Android Firebase 官方 Apple OAuth |
linkWithApple(activity, Completion)、reauthenticateWithApple(activity, Completion) | Apple 账号关联/重新认证 |
signOut(OperationCallback) | Firebase 会话登出;不会替宿主注销游戏服务器或 Credential Manager |
Completion.onSuccess(Session)、onFailure(code, Exception) | Firebase 层最终回调;成功仍需游戏服务器核验 |
StateListener.onChanged(UserSnapshot) | 只是身份变化,不意味着游戏登录成功 |
Session 有 user 和机密 idToken;UserSnapshot 有 uid、displayName、anonymous、providers,providers 只表示已关联的来源。公开错误常量:ERROR_NO_USER、ERROR_INVALID_CREDENTIAL、ERROR_CANCELLED、ERROR_STALE_SESSION、ERROR_FIREBASE;保留处理其他上游错误码的分支。
ROAuthFirebase core = ROAuthFirebase.initialize(
applicationContext, firebaseOptions, "game-auth");
// 如果宿主已配置 default FirebaseApp,亦可用 ROAuthFirebase.forDefaultApp()。
ROAuthFirebase.Subscription subscription = core.observe(user -> {
// user 可能为 null;不是游戏 sdk.login() 的完成事件
});
ROAuthFirebase.Completion callback = new ROAuthFirebase.Completion() {
@Override public void onSuccess(ROAuthFirebase.Session session) {
// 宿主把 session.idToken 通过 HTTPS 交给游戏服务器 auth.Auth 验签和兑换。
}
@Override public void onFailure(String code, Exception error) {
// Firebase 层失败,由宿主决定重试、选择方式等。
}
};
// 选用所需的 API,无需全部执行:
core.signInAnonymously(callback);
// core.signInWithCredential(firebaseCredential, callback);
// core.linkWithCredential(firebaseCredential, callback);
// core.reauthenticate(firebaseCredential, callback);
// core.signInWithApple(activity, callback);
// core.linkWithApple(activity, callback);
// core.reauthenticateWithApple(activity, callback);
// core.getIdToken(true, callback);
// AuthCredential google = ROAuthFirebase.googleCredential(googleIdToken);
// 观察不用时:subscription.remove();
// 主动退出 Firebase:core.signOut(error -> {
// error == null 表示 Firebase 本地退出成功;不代表游戏后端退出。
});API 全览:可选 Firebase 登录 UI
UI 候选:com.ronpad.sdk:ro-auth-firebase-ui:0.1.0,只依赖 Core,不会把所有 Google/Apple/Meta 库强制拉进应用。
生命周期建议:应用按需配置并复用 Core;每次宿主 sdk.login() 新的登录流程创建一次 UI 实例,在宿主 Activity 有效期间持有;注册已实际接入的 Provider,调用 show。UI 内部管理缓存账号卡、3→2→1 倒计时、方式列表、授权与 Core 调用、重试、关闭及迟到回调。宿主 Activity 的 onDestroy() 调用 dismiss(),但不应在服务器 auth.Auth 失败时让游戏误以为已登录;此时应在宿主层保持门控、重试服务器或重新开启登录流程。不是每次点击“继续”就 new UI。
| UI 公开接口 | 用法 |
|---|---|
new ROFirebaseLoginUI(activity, core, options) | 构建一个当前 Activity 所属的模态登录流程 |
show(Completion) | 展示一次登录窗口;已经显示时重复 show 拒绝 |
state() | 当前流程 State:IDLE、CHOOSING、CACHED_ACCOUNT、AUTHORIZING、FIREBASE_AUTHENTICATING、REFRESHING_TOKEN、SUCCEEDED、FAILED、CANCELLED |
registerProvider(method, Provider) | 注册获取 AuthCredential 的独立第三方授权实现 |
registerSessionProvider(method, SessionProvider) | 注册直接调用 Firebase Core 产生 Session 的方式(如 Android Apple OAuth) |
unregisterProvider(method) | 注销授权实现,两种 handler 类型一并移除 |
setProviderIcon(method, Drawable) | 注入有许可的品牌图标;未提供时使用中性素材 |
dismiss() | 宿主主动销毁窗口时关闭、清理定时与迟到响应,不供玩家跳过必需登录 |
Completion.onSuccess(Session) | 只表示 Firebase Session 成功;宿主仍须业务验签 |
Completion.onFailure(code,error) | 默认可选的非终态错误通知,SDK 留窗重试 |
Completion.onCancel() | 只表示宿主主动终止 UI,不是成功登录 |
Provider.authorize(Activity,CredentialCallback) / CredentialCallback.complete(credential,error,cancelled) | 独立 OAuth Provider 异步返回 Firebase 凭证 |
SessionProvider.authorize(Activity,Mode,ROAuthFirebase.Completion) | 自行实现 SIGN_IN/LINK/REAUTHENTICATE 的 Firebase 会话路径 |
Options 全字段:loginMethods(默认 GOOGLE|APPLE,但只显示真实已注册 Handler)、preferredOrder(按钮顺序)、showCachedAccount=true、autoContinueSeconds=3(设 0 关闭)、timeoutSeconds=60(设 0 不超时,超时不取消上游)、allowSwitchAccount=true、showAnonymousWarning=true、accentColor、mode=SIGN_IN。模式枚举为 SIGN_IN / LINK / REAUTHENTICATE。方式位:GOOGLE=1、FACEBOOK=2、GITHUB=4、TWITTER=8、MICROSOFT=16、YAHOO=32、APPLE=64、ANONYMOUS=512;仅位值存在不代表项目已有对应 SDK。
ROFirebaseLoginUI.Options options = new ROFirebaseLoginUI.Options();
options.loginMethods = ROFirebaseLoginUI.GOOGLE | ROFirebaseLoginUI.ANONYMOUS;
options.autoContinueSeconds = 3;
options.mode = ROFirebaseLoginUI.Mode.SIGN_IN;
ROFirebaseLoginUI ui = new ROFirebaseLoginUI(activity, core, options);
// 将 ui 作为当前宿主登录流程的成员保存,而非方法局部临时引用。
ui.registerProvider(ROFirebaseLoginUI.GOOGLE, (a, done) ->
ROLoginGoogle.signIn(a, webClientId, executor,
new ROLoginGoogle.Completion() {
@Override public void onSuccess(String token) {
done.complete(ROAuthFirebase.googleCredential(token), null, false);
}
@Override public void onFailure(Exception e, boolean cancelled) {
done.complete(null, e, cancelled);
}
}));
ui.show(new ROFirebaseLoginUI.Completion() {
@Override public void onSuccess(ROAuthFirebase.Session session) {
// Firebase 身份成功。游戏服务器 auth.Auth 成功并返回 account/token 后
// 宿主才按原有 SDKDelegate 协议结束游戏 sdk.login()。
}
@Override public void onFailure(String code, Exception error) {
// 此处非终态,SDK 登录弹窗会保留并提示重试/换方式。
}
@Override public void onCancel() {
// 宿主销毁登录 UI;仍不可把未认证游戏当已登录。
}
});
// 当前 Activity.onDestroy() 必须调用 ui.dismiss()。只需匿名的应用可设置 loginMethods=ANONYMOUS,不需要调用 registerProvider;Android Apple 可选用 registerSessionProvider(APPLE, (activity,mode,done) -> ...),按模式调用 Core 的 signInWithApple/linkWithApple/reauthenticateWithApple。没有真实 Provider 的按钮不显示。正式游戏不应出现重复初始化 Firebase 或再次从 UI 直接调用游戏业务 auth.Auth 的实现。
**验收状态:**上述 Core/UI 为已审查的 Draft 公开 API;最新源码构建/真实游戏 OAuth 和生产服务器仍须按仓库 HANDOFF 单独验收。
2026-10-28 登录与退出回调准则
ROAuthFirebase.signOut(OperationCallback)现在必须给出退出回调;同步 Firebase SDK 调用完成后在主线程返回onComplete(Exception error)。此接口只清除 Firebase 本地会话,游戏业务账号的退出仍需宿主调用自己的服务端。ROFirebaseLoginUI.Completion的onSuccess(Session)、onCancel()、onFailure(code,error)均需实现。UI 内部失败会保留重试/重新选择方式,不能将onFailure当成已获得游戏登录结果,更不能放行未认证的游戏会话。- 核心和 UI 是两个可选独立模块,登录 UI 持有 Core、自己调用 Firebase 并管理倒计时、窗口和状态;宿主在 Core 返回 Session 后仍须完成游戏服务器 ID Token 验证/账号兑换。