Skip to content

登入與注冊

最後更新:2026-04-09


功能說明

提供使用者帳號密碼登入、手機驗證碼登入、新用戶注冊、忘記密碼找回、Face ID 生物辨識快速登入等功能。未登入狀態下可以「隨便逛逛」進入 App 瀏覽,也可直接聯繫客服。登入後自動恢復上次的個人設定(賠率偏好、推播設定等)。

使用者流程

登入流程

  1. 進入 App,若 token 過期或手動登出,自動彈出登入頁(全螢幕覆蓋)
  2. 頁面頂部顯示背景圖,底部有帳號/密碼輸入區(LoginView
  3. 使用者可切換「帳號密碼」或「手機驗證碼」登入方式(STTabSelectView
  4. 帳號密碼登入:輸入帳號 + 密碼,點擊登入
  5. 手機驗證碼登入:輸入手機號,點擊取得驗證碼,輸入驗證碼
  6. 登入成功 → IFLoginService.setUpChangeWindows() 刷新主視窗
  7. 若曾開啟 Face ID,3小時內未操作則改用 Face ID 驗證

自動登入邏輯

  • 條件:已勾選「記住密碼」+ 非手機登入 + 有本地帳號密碼
  • 在 3 小時內:直接使用本地帳密靜默重新登入
  • 超過 3 小時:觸發 Face ID 驗證(若已開啟),否則彈出登入頁

注冊流程

  1. 登入頁點擊「立即注冊」→ 跳轉至 RegisterViewController
  2. 填寫使用者名稱 + 密碼
  3. 可選填設置暱稱、頭像
  4. 注冊成功後可開啟 Face ID 設定(BBSetFaceIDViewController

找回密碼

  1. 點擊「忘記密碼」或底部「聯繫客服 > 自助找回密碼」
  2. FindPasswordViewController → 輸入手機號 → SendMessageViewController 發送驗證碼
  3. 驗證通過後進入 ChangePaawordViewController 設置新密碼

訪客模式(隨便逛逛)

  • 登入頁底部左側顯示「隨便逛逛」按鈕(guangGuangBtn),帶有圖示 troll_around
  • 點擊後直接呼叫 IFLoginService.setUpChangeWindows() 關閉登入頁,進入主畫面
  • 訪客狀態下 IFUserModel.isLoginThisPlatform = false,可瀏覽 App 但無法進行需登入的操作(投注、充值等)
  • 關閉登入頁時若非已登入狀態,isManualLoginOut 設為 true

頁面跳轉

  • 登入頁底部「立即注冊」→ RegisterViewController
  • 登入頁底部「忘記密碼」→ FindPasswordViewController
  • FindPasswordViewControllerSendMessageViewControllerChangePaawordViewController
  • 注冊成功 → BBSetFaceIDViewController(Face ID 設定)
  • 登入成功 → 主視窗刷新(IFLoginService.setUpChangeWindows()
  • 「隨便逛逛」→ 關閉登入頁進入主視窗

技術視角(開發看這裡)

相關檔案

類型檔案路徑
ViewController(登入)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Login/C/STLoginViewController.swift
ViewController(注冊)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Register/C/RegisterViewController.swift
ViewController(找回密碼)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/FindPassword/C/FindPasswordViewController.swift
ViewController(修改密碼)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/FindPassword/C/ChangePaawordViewController.swift
ViewController(發送驗證碼)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/FindPassword/C/SendMessageViewController.swift
ViewController(綁定帳號)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Login/C/BindingAccountViewController.swift
ViewController(設定帳號)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Login/C/SetAccountViewController.swift
ViewController(Face ID 設定)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Register/C/BBSetFaceIDViewController.swift
Service(登入管理)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/STLoginManager.swift
Service(登入 UI)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/STNewLoginUIManager.swift
Service(客服)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/CustomerChatManager.swift
Service(OC 登入核心)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/IFLoginService.m
Service(OC 模組路由)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/ModuleApi.m
Service(HTTP 請求橋接)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Helpers/HttpService.swift
Helper(帳號儲存)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/SavedAccountManager.swift
Helper(常數定義)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/BBNewCommonConstant.swift
View(登入主視圖)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Login/V/LoginView.swift
View(帳號密碼輸入)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Login/V/LoginUserNameView.swift
View(手機驗證碼輸入)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Login/V/LoginPhoneCodeView.swift
View(帳號列表)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Login/V/MLAllUserNameView.swift
ViewController(維護模式)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/BBMaintain/BBMaintainViewController.swift
API(帳密登入)/Users/user/Work/bbsport-new/BBSport/API/STAPI/User/Login/STAPI+UsernameLoginRequest.swift
API(登入二次驗證)/Users/user/Work/bbsport-new/BBSport/API/STAPI/User/Login/STAPI+LoginCheckRequest.swift
API(心跳)/Users/user/Work/bbsport-new/BBSport/API/STAPI/User/Login/STAPI+LoginHeartbeatRequest.swift
API(驗證碼 ID)/Users/user/Work/bbsport-new/BBSport/API/STAPI/User/Login/STAPI+LoginCaptchaIdRequest.swift
API(體驗金)/Users/user/Work/bbsport-new/BBSport/API/STAPI/User/Login/STAPI+ExperienceCashRequest.swift
API(更新登入紀錄)/Users/user/Work/bbsport-new/BBSport/API/STAPI/User/Login/STAPI+UpdateLoginRecordRequest.swift
API(重發二次驗證碼)/Users/user/Work/bbsport-new/BBSport/API/STAPI/STAPI+ResendLoginRequest.swift
路由註冊 Header(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/ModuleApi.h
View(登入基礎視圖)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Login/V/LoginBaseView.swift
View(帳號 Cell)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Login/V/MLUsernameTableViewCell.swift
View(登入背景播放器)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Login/V/BBLoginAvPlayer.swift
ViewController(找回密碼基類)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/FindPassword/C/BaseRegisterViewController.swift
ViewController(設定暱稱)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Register/C/RegSetNickNameViewController.swift
View(注冊主視圖)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Register/V/RegisterView.swift
View(帳號密碼注冊)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Register/V/RegisterByUserNameView.swift
View(設定帳密視圖)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Register/V/SetUserNameAndPasswordView.swift
View(設定頭像暱稱)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Register/V/SetHeadImageAndNickNameView.swift
View(注冊成功基礎)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Register/V/RegSuccessSetBaseView.swift
View(頭像選擇器)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/BBInfoAvatarPicker.swift
ViewModel(頭像選擇器)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/BBInfoAvatarPickerViewModel.swift
Model(頭像 Cell)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/BBLoginInfoAvatarImageCellModel.swift
View(Tab 切換)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/STTabSelectView.swift
View(倒計時按鈕)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/STNewTimeButton.swift
View(訊息提示)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/BBShowMessageView.swift
View(裝置資訊)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/DeviceInformationView.swift
WebView(登入內嵌)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/BBNewBackWebViewController.swift
網路偵測 Header(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/ErrorInternetVC/InternetManager.h
網路偵測實作(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/ErrorInternetVC/InternetManager.m
網路錯誤頁 Header(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/ErrorInternetVC/NetErrorViewController.h
網路錯誤頁實作(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/ErrorInternetVC/NetErrorViewController.m
網路可達性 Header(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/ErrorInternetVC/Reachability.h
網路可達性實作(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/ErrorInternetVC/Reachability.m
UI 工廠 Header(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/BBLoginUIFactory.h
UI 工廠實作(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/BBLoginUIFactory.m
UI 工廠基類 Header(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/BBUIFactory.h
UI 工廠基類實作(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/BBUIFactory.m
手勢擴展 Header(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/UITapGestureRecognizer+Extand.h
手勢擴展實作(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Manager/UITapGestureRecognizer+Extand.m
Model(版本資訊 Header)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Model/STVersionInfoModel.h
Model(版本資訊實作)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Model/STVersionInfoModel.m
Protocol(主頁)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Protocol/BBMaindProtocol.swift
Protocol(域名探測)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Protocol/FindFastProtocol.swift
Protocol(狀態列樣式)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Protocol/STStatusBarStyleProtocol.swift
LiveChat VC Header(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/ChatLiveViewController.h
LiveChat VC 實作(OC)/Users/user/Work/bbsport-new/BBSport/Tab/我的/Mine/Login_Register/登录注册/Maind/ChatLiveViewController.m
Config(API 路徑映射)/Users/user/Work/bbsport-new/BBSport/STUIKit/STFoundation/Network/Basebusinesscomponent/Classes/URL/ThisPlatformRequestAction.swift

API

登入 / 注冊 / 驗證碼 API(本平台)

功能說明來源EndpointMethod主要參數
帳號密碼登入(v2)STAPI UsernameLoginRequestapi/forehead/user/login/username/v2POST urlFormusername, password, lotNumber, captchaOutput, passToken, genTime
手機驗證碼登入OC ThisPlatformRequestAction.loginMobileGlapi/forehead/user/login/submit/validate/mobile/code/v2POSTmobile, telArea, code, (滑動驗證參數)
登入二次驗證(異常設備)STAPI LoginCheckRequestapi/forehead/user/login/abnormal/device/login/checkPOST urlFormaccessToken, code
重發二次驗證碼STAPI ResendLoginRequestapi/forehead/user/login/abnormal/device/login/resendPOST urlFormaccessToken
登入心跳(60s 輪詢)STAPI LoginHeartbeatRequestapi/forehead/user/login/heartbeatPOST urlForm無(使用本地 KEY_TOKEN)
取得驗證碼 IDSTAPI LoginCaptchaIdRequestapi/forehead/user/login/captchaOutput/idPOST urlFormtelArea, mobile
手機登入取得驗證碼(含滑動驗證)OC ThisPlatformRequestAction.loginCodeGlapi/forehead/user/login/code/v2POSTmobile, telArea, lotNumber, captchaOutput, passToken, genTime
取得手機驗證碼(通用)OC ThisPlatformRequestAction.mobileCodeapi/forehead/user/mobile/codePOSTmobile, telArea, type
用戶名注冊(v2)OC ThisPlatformRequestAction.registerUserNameGlapi/forehead/user/register/username/v2POSTusername, password, inviterCode, (滑動驗證參數)
手機號注冊OC ThisPlatformRequestAction.registerMobileapi/forehead/user/register/mobilePOSTmobile, telArea, code, username, password
注冊取得驗證碼(v2)OC ThisPlatformRequestAction.registerCodeapi/forehead/user/register/code/v2POSTmobile, telArea, (滑動驗證參數)
驗證注冊用戶名OC ThisPlatformRequestAction.registerUserNameValidateapi/forehead/user/register/username/validatePOSTusername, telArea
驗證手機驗證碼OC ThisPlatformRequestAction.registerCodeValidateapi/forehead/user/register/code/validatePOSTmobile, telArea, code
綁定帳號OC ThisPlatformRequestAction.bindingAccountapi/forehead/user/login/submit/bind/or/createPOSTtelArea, mobile, accessToken, operationType, password, username
忘記密碼取得綁定資訊(v2)OC ThisPlatformRequestAction.forgetInfoGlapi/forehead/user/forget/info/v2POSTusername, (滑動驗證參數)
忘記密碼發送驗證碼OC ThisPlatformRequestAction.forgetCodeOldapi/forehead/user/forget/get/validate/codePOSTaccessToken, type
忘記密碼重設密碼OC ThisPlatformRequestAction.forgetResetPasswordGlapi/forehead/user/forget/submit/reset/passwordPOSTaccessToken, code, type, password

其他相關 API

功能說明來源EndpointMethod主要參數
取得使用者識別碼STAPIapi/forehead/user/security/get/user/valid/codePOST json
重置使用者識別碼STAPIapi/forehead/user/security/submit/reset/user/valid/codePOST json
取得使用者安全資訊STAPIapi/forehead/user/security/load/infoPOST
取得體驗金STAPIapi/forehead/activity/welfare/experienceCash/listPOST
取得賠率設定OC ThisPlatformRequestAction.gl_cfg_getapi/forehead/system/cfg/get?collect=UserConfigGET

GameJump API(game/jumpgame/jump/preCheck)已移至 場館登入

Token / Session 管理機制

存儲位置

Key說明儲存方式
KEY_TOKEN登入 Token,用於心跳保活及 API 認證UserDefaults
KEY_UID使用者 IDUserDefaults
TOKENTIMEToken 過期時間(由伺服器下發 tokenExpireTimeUserDefaults
KEY_USERNAME帳號名稱UserDefaults(OC #define)及 Swift 常數
KEY_PASSWORD密碼UserDefaults(OC #define)及 Swift 常數
KEY_REMEMBER / isRememberPassword是否記住密碼UserDefaults
loginTime上次登入成功的時間戳(毫秒)UserDefaults
isManualLoginOut是否手動登出UserDefaults
phoneNumberLogin / isPhoneLogin是否使用手機驗證碼登入UserDefaults
isOpenFaceId + username該帳號是否開啟 Face IDUserDefaults(key 包含帳號名)
loginFirst是否首次登入(用於 Face ID 引導彈窗)UserDefaults
Accounts已儲存帳號列表UserDefaults@UserDefaultCodableSavedAccountManager
Caches/UserInfo.plist完整登入回應快取(NSKeyedArchiver 序列化)檔案(Caches 目錄)

Token 生命週期

  1. 登入成功logonDataProcessing 解析伺服器回應,呼叫 IFUserModel.refreshUserInfotoken 存入 KEY_TOKENId 存入 KEY_UIDtokenExpireTime 存入 TOKENTIME
  2. 心跳保活:登入成功後啟動 NSTimer,每 60 秒呼叫一次 loginHeartBeat,帶 KEY_TOKEN 請求 api/forehead/user/login/heartbeat,成功後 refreshUserInfo 更新使用者資料
  3. 自動登入判斷STLoginManager.canAutoLoginAuto() 檢查 isRememberPassword=true + isPhoneLogin=false + KEY_USERNAME/KEY_PASSWORD 非空;再用 loginTime 判斷距離上次登入是否小於 3 小時(3 * 60 * 60 * 1000 毫秒)
  4. 登出清除userKillOut() 移除 KEY_TOKENKEY_UIDKEY_WITHDRAW_TIP,清空 IFUserModel

Refresh Token 機制

本專案無獨立的 refresh token 流程。取而代之的是:

  • 心跳每 60 秒 call 一次保持 token 有效
  • 本平台 token 失效時(收到 STNotify.logoutThisPlantForm 通知),STLoginManager.setupLoginOut 使用本地帳密自動重新登入
  • 各體育平台 token 失效時,由 GameJump 機制重新登入(詳見 場館登入

資料模型

IFUserModel(全局使用者 Singleton)

欄位說明
isLoginThisPlatform是否已登入本平台
isShowingLoginVC是否正在展示登入頁(防止重複彈出)
isThisPlatformLogining是否正在登入流程中
token登入 Token
Id使用者 ID
oddsOBID / oddsSTID / oddsUPID各平台賠率類型偏好
nearGameID上次進入的遊戲類型
headUrl頭像 URL

SavedAccountManager(帳號管理 Singleton)

欄位說明
accounts: [Account]已儲存帳號列表(@UserDefaultCodable("Accounts")
Account.username帳號名稱
Account.password密碼(若未勾選「記住密碼」則為空字串)
  • 登入成功時 append 新帳號(自動去重)
  • MLAllUserNameView 以 TableView 展示已儲存帳號列表,最多顯示 5 個(超出可滾動)
  • 選中帳號自動填入帳號密碼欄位;可滑動刪除帳號

STAPI.UserSecurityInfoRequest.Response

欄位說明
mobile手機號(脫敏)
cardCount已綁銀行卡數量
usdtCountUSDT 地址數量
withdrawVal提款驗證是否已完成

錯誤場景處理

API 回應碼判斷

IFLoginService.vailtedDataWithResponse: 統一檢查回應:

  • code == 1:成功
  • code != 1:失敗,顯示 message(除「您所在地區訪問受限制」外,均以 BBShowMessageView 提示)
  • code == 500001:特殊登入失敗碼,回傳 response["data"] 供上層處理

滑動驗證碼觸發

  • code == 20003code == 200025:伺服器要求滑動驗證,LoginUserNameView / LoginPhoneCodeView 記錄 self.code,下次登入時先啟動 VerifyCodeManager.shared.start 取得滑動驗證結果(lotNumbercaptchaOutputpassTokengenTime),再帶入登入 API

異常設備二次驗證

  • 帳密登入成功後,若回應包含 accessToken + areaCode + mobile,代表偵測到異常設備
  • 彈出 BBSendMsgCodeView 讓使用者輸入簡訊驗證碼
  • 呼叫 IFLoginService.loginCheck(accessToken, code:) 完成二次驗證
  • 可透過 STAPI.ResendLoginRequest 重發驗證碼

帳號密碼為空

  • userName.length <= 0passWord.length <= 0:直接 STLoading.stop() 返回,不發送請求
  • 前端額外檢查:LoginUserNameViewSTHud.showTopToast 提示「請輸入帳號」/「請輸入密碼」

維護 / 強更

  • logonDataProcessing 中檢查 userModel.isMainUpdateGameMaintenanceManager.shared.app.isGameMaintenance
  • 若正在維護或強更,設定 isManualLoginOut = true 並直接 return,不完成登入

網路錯誤

  • IFLoginService.commonRequestWithActionType 的 failure callback:呼叫 setupError:BBShowMessageView 顯示錯誤訊息 + STLoading.stop()
  • 登入頁有網路偵測功能(listenNetWorkingStatus),無網路時顯示紅色提示條 redNetView,點擊跳轉 NetErrorViewController

手機驗證碼錯誤

  • 區號為空:BBShowMessageView 提示「區號不能為空」
  • 驗證碼為空:BBShowMessageView 提示「請輸入驗證碼」
  • 手機號格式不正確:由 IFCheckUtil.checkPhoneNumber:region: / ylCheckPhoneNumber:region: 檢查

實作重點

  1. 自動登入判斷邏輯(STLoginManagercanAutoLoginAuto() 檢查本地是否有帳密 + 勾選記住密碼;3小時門檻以 loginTime UserDefaults 記錄;Face ID 路徑:BBFaceIdLoginService.login 成功後才重新調用 loginService

  2. 登出流程(userKillOut:若為橫屏狀態先強制退出全螢幕;清除 IFUserModel 資料;發送 STNotify.clearWindowMaskView 清除浮層;發送 STNotify.specifiedTab 切換至預設 Tab;清除 TOKEN / UID UserDefaults

  3. 登入成功資料處理(logonDataProcessing

    • 將整個 response 用 NSKeyedArchiver 序列化存入 Caches/UserInfo.plist(供 TOKEN 登入使用)
    • IFUserModel.refreshUserInfo 更新使用者資訊並存 KEY_TOKEN / KEY_UID / TOKENTIME
    • 觸發版本更新檢查
    • 儲存 gameJumpConfigIFMainSwitch(場館登入用,詳見 場館登入
    • 啟動心跳 Timer(60 秒)
  4. TOKEN 登入(冷啟動)ModuleApi.load 註冊 LoginByToken 路由 → 從 Caches/UserInfo.plist 讀取快取登入回應 → 直接呼叫 logonDataProcessing + loginHeartBeat + uploadLoginCount

  5. 手機驗證碼登入後處理:不儲存密碼(removeObject(forKey: PassWord)),不記住密碼(removeObject(forKey: isRememberPassword)),isPhoneLogin = true;若回應為字串(新用戶),跳轉 SetAccountViewController 設定帳號

  6. 維護模式BBMaintainViewController / BBMaintainView — 後台設定維護時展示

  7. 客服整合:登入頁底部「聯繫客服」按鈕,呼叫 CustomerChatManager.shared.openChat 開啟客服選單,含多線路選項(自助找回密碼、主線客服、次線客服)

  8. 多帳號切換SavedAccountManager@UserDefaultCodable("Accounts") 儲存帳號密碼列表;MLAllUserNameView 以下拉列表展示;選中自動填入、可刪除;新帳號自動去重追加

  9. Face ID 引導:登入成功後若 loginFirst = false 且未開啟 Face ID 且已記住密碼,STLoginManager.presentFaceIdOverlayIfNeeded 彈出 STFaceIdOverlay 引導開啟


API 呼叫流程

App 啟動自動登入流程請見 App 啟動

帳號密碼登入

用戶點擊登入按鈕 (LoginUserNameView.loginBtnClick)
  ├─ 驗證: 帳號密碼已填寫?

  ├─ VerifyCodeManager.shared.start() → 滑動驗證碼 (CAPTCHA v4)
  │  └─ 回傳: lotNumber, captchaOutput, passToken, genTime

  └─ [API 1] POST api/forehead/user/login/username/v2
     │  Body: username, password, lotNumber, captchaOutput, passToken, genTime

     ├─ code 20003/200025 → 重試驗證碼

     ├─ 含 accessToken+areaCode+mobile (異常設備)
     │  ├─ [API 2] POST api/forehead/user/login/abnormal/device/login/resend → 發送簡訊
     │  └─ 用戶輸入驗證碼
     │     └─ [API 3] POST api/forehead/user/login/abnormal/device/login/check

     └─ 直接成功
        ├─ [API 4] readUserSaveInfo() → 取得用戶賠率設定
        ├─ [API 5] getTitleId() → 取得用戶稱號
        ├─ [API 6] POST api/forehead/user/setting/auto/login/record → 更新登入紀錄
        └─ setupTimer() → 每 60 秒心跳
           └─ [API 7] POST api/forehead/user/login/heartbeat (持續)

註冊新帳號

用戶點擊註冊 (RegisterByUserNameView.registerBtnClick)
  ├─ 驗證: 帳號(6-16字) + 密碼(8-20字)
  ├─ VerifyCodeManager.shared.start() → 滑動驗證碼

  └─ [API] IFLoginService.glUserNameRegister
     │  Body: username, password, inviterCode(選填), proxyHost(選填),
     │        lotNumber, captchaOutput, passToken, genTime

     └─ 成功 → 儲存帳密 → readUserSaveInfo() + getTitleId()
              → setUpChangeWindows() → 進入主畫面

Token 刷新 (心跳)

登入成功後啟動 Timer (每 60 秒)
  └─ [API] POST api/forehead/user/login/heartbeat
     │  Headers: token, uid (由 STRequestTokenAdapter 自動附加)
     └─ 成功 → refreshUserInfo() 更新用戶資訊