feat: 简化登录模型,移除 nickname/avatar/expiresAt
- XuqmSDK.login() 只保留 userId + userSig - 移除 UserSigRefresher 续签逻辑 - XuqmLoginSession 移除 nickname/avatar/expiresAt - ImSDK.login() 同步简化 - AuthRepository 适配新登录方式,移除过期检查与定时刷新 - README 示例同步更新
这个提交包含在:
父节点
595a91ae3d
当前提交
553427d44e
@ -68,11 +68,10 @@ val userSig = api.getUserSig(userId)
|
|||||||
XuqmSDK.login(
|
XuqmSDK.login(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
userSig = userSig,
|
userSig = userSig,
|
||||||
nickname = profile.nickname,
|
|
||||||
avatar = profile.avatar,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 如果工程里集成了 sdk-im,SDK 会自动完成 IM 登录
|
// 如果工程里集成了 sdk-im / sdk-push / sdk-update,
|
||||||
|
// SDK 会自动完成对应模块的登录与初始化
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 切换联调环境
|
### 3. 切换联调环境
|
||||||
|
|||||||
@ -30,9 +30,6 @@ import java.util.concurrent.atomic.AtomicBoolean
|
|||||||
class AuthRepository(context: Context) {
|
class AuthRepository(context: Context) {
|
||||||
|
|
||||||
private val appScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
private val appScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
private var refreshJob: Job? = null
|
|
||||||
private val refreshing = AtomicBoolean(false)
|
|
||||||
|
|
||||||
private val prefs = EncryptedSharedPreferences.create(
|
private val prefs = EncryptedSharedPreferences.create(
|
||||||
"xuqm_demo_auth",
|
"xuqm_demo_auth",
|
||||||
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
|
MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC),
|
||||||
@ -52,21 +49,17 @@ class AuthRepository(context: Context) {
|
|||||||
fun getCurrentNickname(): String? = prefs.getString("nickname", null)
|
fun getCurrentNickname(): String? = prefs.getString("nickname", null)
|
||||||
fun getCurrentAvatar(): String? = prefs.getString("avatar", null)
|
fun getCurrentAvatar(): String? = prefs.getString("avatar", null)
|
||||||
fun getCurrentUserSig(): String? = prefs.getString("user_sig", null)
|
fun getCurrentUserSig(): String? = prefs.getString("user_sig", null)
|
||||||
fun getCurrentUserSigExpiresAt(): Long = prefs.getLong("user_sig_expires_at", 0L)
|
|
||||||
fun isLoggedIn(): Boolean = hasUsableSession()
|
fun isLoggedIn(): Boolean = hasUsableSession()
|
||||||
|
|
||||||
private fun hasUsableSession(): Boolean {
|
private fun hasUsableSession(): Boolean {
|
||||||
val now = System.currentTimeMillis()
|
|
||||||
val demoToken = getDemoToken().orEmpty()
|
val demoToken = getDemoToken().orEmpty()
|
||||||
val userId = getCurrentUserId().orEmpty()
|
val userId = getCurrentUserId().orEmpty()
|
||||||
val userSig = getCurrentUserSig().orEmpty()
|
val userSig = getCurrentUserSig().orEmpty()
|
||||||
val demoTokenExpiresAt = prefs.getLong("demo_token_expires_at", 0L)
|
val demoTokenExpiresAt = prefs.getLong("demo_token_expires_at", 0L)
|
||||||
val userSigExpiresAt = getCurrentUserSigExpiresAt()
|
|
||||||
return demoToken.isNotBlank() &&
|
return demoToken.isNotBlank() &&
|
||||||
userId.isNotBlank() &&
|
userId.isNotBlank() &&
|
||||||
userSig.isNotBlank() &&
|
userSig.isNotBlank() &&
|
||||||
demoTokenExpiresAt > now &&
|
demoTokenExpiresAt > System.currentTimeMillis()
|
||||||
userSigExpiresAt > now
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveSession(result: AuthResult) {
|
private fun saveSession(result: AuthResult) {
|
||||||
@ -78,27 +71,7 @@ class AuthRepository(context: Context) {
|
|||||||
.putString("nickname", profile.nickname)
|
.putString("nickname", profile.nickname)
|
||||||
.putString("avatar", profile.avatar)
|
.putString("avatar", profile.avatar)
|
||||||
.putString("user_sig", result.userSig)
|
.putString("user_sig", result.userSig)
|
||||||
.putLong("user_sig_expires_at", result.imTokenExpiresAt ?: 0L)
|
|
||||||
.apply()
|
.apply()
|
||||||
scheduleImTokenRefresh(result.imTokenExpiresAt)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun saveImCredential(result: ImRefreshResult) {
|
|
||||||
prefs.edit()
|
|
||||||
.putString("user_sig", result.userSig)
|
|
||||||
.putLong("user_sig_expires_at", result.imTokenExpiresAt ?: 0L)
|
|
||||||
.apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun scheduleImTokenRefresh(expiresAt: Long?) {
|
|
||||||
refreshJob?.cancel()
|
|
||||||
val tokenExpiresAt = expiresAt ?: 0L
|
|
||||||
if (tokenExpiresAt <= 0L) return
|
|
||||||
val delayMs = (tokenExpiresAt - System.currentTimeMillis() - REFRESH_GRACE_MS).coerceAtLeast(0L)
|
|
||||||
refreshJob = appScope.launch {
|
|
||||||
delay(delayMs)
|
|
||||||
refreshImToken()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun login(userId: String, password: String): Result<UserData> =
|
suspend fun login(userId: String, password: String): Result<UserData> =
|
||||||
@ -113,8 +86,6 @@ class AuthRepository(context: Context) {
|
|||||||
XuqmSDK.login(
|
XuqmSDK.login(
|
||||||
userId = data.profile.userId,
|
userId = data.profile.userId,
|
||||||
userSig = userSig,
|
userSig = userSig,
|
||||||
nickname = data.profile.nickname,
|
|
||||||
avatar = data.profile.avatar,
|
|
||||||
)
|
)
|
||||||
UserData(data.profile.userId, data.profile.nickname, data.profile.avatar, data.profile.gender)
|
UserData(data.profile.userId, data.profile.nickname, data.profile.avatar, data.profile.gender)
|
||||||
}
|
}
|
||||||
@ -133,8 +104,6 @@ class AuthRepository(context: Context) {
|
|||||||
XuqmSDK.login(
|
XuqmSDK.login(
|
||||||
userId = data.profile.userId,
|
userId = data.profile.userId,
|
||||||
userSig = userSig,
|
userSig = userSig,
|
||||||
nickname = data.profile.nickname,
|
|
||||||
avatar = data.profile.avatar,
|
|
||||||
)
|
)
|
||||||
UserData(data.profile.userId, data.profile.nickname, data.profile.avatar, data.profile.gender)
|
UserData(data.profile.userId, data.profile.nickname, data.profile.avatar, data.profile.gender)
|
||||||
}
|
}
|
||||||
@ -177,86 +146,22 @@ class AuthRepository(context: Context) {
|
|||||||
val userSig = getCurrentUserSig()
|
val userSig = getCurrentUserSig()
|
||||||
val demoToken = getDemoToken()
|
val demoToken = getDemoToken()
|
||||||
if (userId.isNullOrBlank() || userSig.isNullOrBlank() || demoToken.isNullOrBlank()) {
|
if (userId.isNullOrBlank() || userSig.isNullOrBlank() || demoToken.isNullOrBlank()) {
|
||||||
clearSession()
|
logout()
|
||||||
throw IllegalStateException("No cached session")
|
throw IllegalStateException("No cached session")
|
||||||
}
|
}
|
||||||
val refreshed = if (shouldRefreshImToken()) {
|
|
||||||
refreshImTokenInternal()
|
|
||||||
} else {
|
|
||||||
null
|
|
||||||
}
|
|
||||||
if (shouldRefreshImToken() && refreshed == null) {
|
|
||||||
clearSession()
|
|
||||||
throw IllegalStateException("Cached session expired")
|
|
||||||
}
|
|
||||||
XuqmSDK.login(
|
XuqmSDK.login(
|
||||||
userId = userId,
|
userId = userId,
|
||||||
userSig = refreshed?.userSig ?: userSig,
|
userSig = userSig,
|
||||||
nickname = getCurrentNickname(),
|
|
||||||
avatar = getCurrentAvatar(),
|
|
||||||
)
|
)
|
||||||
if (refreshed != null) {
|
Unit
|
||||||
saveImCredential(refreshed)
|
|
||||||
scheduleImTokenRefresh(refreshed.imTokenExpiresAt)
|
|
||||||
} else {
|
|
||||||
scheduleImTokenRefresh(getCurrentUserSigExpiresAt().takeIf { it > 0L })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun logout() {
|
fun logout() {
|
||||||
refreshJob?.cancel()
|
|
||||||
refreshJob = null
|
|
||||||
XuqmSDK.logout()
|
XuqmSDK.logout()
|
||||||
prefs.edit().clear().apply()
|
prefs.edit().clear().apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun refreshImToken() {
|
|
||||||
if (!refreshing.compareAndSet(false, true)) return
|
|
||||||
try {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
val refreshed = refreshImTokenInternal() ?: run {
|
|
||||||
clearSession()
|
|
||||||
return@withContext
|
|
||||||
}
|
|
||||||
saveImCredential(refreshed)
|
|
||||||
XuqmSDK.login(
|
|
||||||
userId = getCurrentUserId() ?: return@withContext,
|
|
||||||
userSig = refreshed.userSig,
|
|
||||||
nickname = getCurrentNickname(),
|
|
||||||
avatar = getCurrentAvatar(),
|
|
||||||
)
|
|
||||||
scheduleImTokenRefresh(refreshed.imTokenExpiresAt)
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
refreshing.set(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearSession() {
|
|
||||||
refreshJob?.cancel()
|
|
||||||
refreshJob = null
|
|
||||||
XuqmSDK.logout()
|
|
||||||
prefs.edit().clear().apply()
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun refreshImTokenInternal(): ImRefreshResult? {
|
|
||||||
val appId = DEMO_APP_ID
|
|
||||||
return runCatching {
|
|
||||||
val response = api.refreshImToken(appId)
|
|
||||||
requireNotNull(response.data) { response.message ?: "Refresh IM token failed" }
|
|
||||||
}.getOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun shouldRefreshImToken(): Boolean {
|
|
||||||
val expiresAt = getCurrentUserSigExpiresAt()
|
|
||||||
return expiresAt <= 0L || expiresAt - System.currentTimeMillis() <= REFRESH_GRACE_MS
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val REFRESH_GRACE_MS = 5 * 60 * 1000L
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T> Result<T>.mapFailureMessage(transform: (Throwable) -> String): Result<T> =
|
private fun <T> Result<T>.mapFailureMessage(transform: (Throwable) -> String): Result<T> =
|
||||||
fold(
|
fold(
|
||||||
onSuccess = { Result.success(it) },
|
onSuccess = { Result.success(it) },
|
||||||
|
|||||||
@ -4,7 +4,4 @@ data class XuqmLoginSession(
|
|||||||
val appKey: String,
|
val appKey: String,
|
||||||
val userId: String,
|
val userId: String,
|
||||||
val userSig: String,
|
val userSig: String,
|
||||||
val nickname: String? = null,
|
|
||||||
val avatar: String? = null,
|
|
||||||
val expiresAt: Long? = null,
|
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package com.xuqm.sdk
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.xuqm.sdk.auth.TokenStore
|
import com.xuqm.sdk.auth.TokenStore
|
||||||
import com.xuqm.sdk.auth.UserSigRefresher
|
|
||||||
import com.xuqm.sdk.core.LogLevel
|
import com.xuqm.sdk.core.LogLevel
|
||||||
import com.xuqm.sdk.core.ServiceEndpointRegistry
|
import com.xuqm.sdk.core.ServiceEndpointRegistry
|
||||||
import com.xuqm.sdk.core.ServiceEndpoints
|
import com.xuqm.sdk.core.ServiceEndpoints
|
||||||
@ -26,8 +25,6 @@ object XuqmSDK {
|
|||||||
@Volatile
|
@Volatile
|
||||||
private var loginSession: XuqmLoginSession? = null
|
private var loginSession: XuqmLoginSession? = null
|
||||||
|
|
||||||
private val userSigRefresher = UserSigRefresher()
|
|
||||||
|
|
||||||
fun initialize(
|
fun initialize(
|
||||||
context: Context,
|
context: Context,
|
||||||
appKey: String,
|
appKey: String,
|
||||||
@ -63,31 +60,18 @@ object XuqmSDK {
|
|||||||
val currentLoginSession: XuqmLoginSession?
|
val currentLoginSession: XuqmLoginSession?
|
||||||
get() = loginSession
|
get() = loginSession
|
||||||
|
|
||||||
fun setUserSigRefreshListener(listener: UserSigRefresher.UserSigRefreshListener?) {
|
|
||||||
userSigRefresher.setRefreshListener(listener)
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun login(
|
suspend fun login(
|
||||||
userId: String,
|
userId: String,
|
||||||
userSig: String,
|
userSig: String,
|
||||||
nickname: String? = null,
|
|
||||||
avatar: String? = null,
|
|
||||||
userSigExpiresAt: Long? = null,
|
|
||||||
): XuqmLoginSession = withContext(Dispatchers.IO) {
|
): XuqmLoginSession = withContext(Dispatchers.IO) {
|
||||||
requireInit()
|
requireInit()
|
||||||
val session = XuqmLoginSession(
|
val session = XuqmLoginSession(
|
||||||
appKey = appKey,
|
appKey = appKey,
|
||||||
userId = userId,
|
userId = userId,
|
||||||
userSig = userSig,
|
userSig = userSig,
|
||||||
nickname = nickname,
|
|
||||||
avatar = avatar,
|
|
||||||
expiresAt = userSigExpiresAt,
|
|
||||||
)
|
)
|
||||||
loginSession = session
|
loginSession = session
|
||||||
tokenStore.saveToken(userSig)
|
tokenStore.saveToken(userSig)
|
||||||
userSigExpiresAt?.let {
|
|
||||||
userSigRefresher.start(it)
|
|
||||||
}
|
|
||||||
notifyOptionalModules("onSdkLogin", session)
|
notifyOptionalModules("onSdkLogin", session)
|
||||||
session
|
session
|
||||||
}
|
}
|
||||||
@ -96,7 +80,6 @@ object XuqmSDK {
|
|||||||
val session = loginSession
|
val session = loginSession
|
||||||
loginSession = null
|
loginSession = null
|
||||||
tokenStore.clear()
|
tokenStore.clear()
|
||||||
userSigRefresher.stop()
|
|
||||||
if (session != null) {
|
if (session != null) {
|
||||||
notifyOptionalModulesSync("onSdkLogout")
|
notifyOptionalModulesSync("onSdkLogout")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,28 +85,12 @@ object ImSDK {
|
|||||||
XuqmSDK.currentLoginSession?.let { onSdkLogin(it) }
|
XuqmSDK.currentLoginSession?.let { onSdkLogin(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun login(
|
suspend fun login(userId: String, userSig: String) = withContext(Dispatchers.IO) {
|
||||||
userId: String,
|
|
||||||
userSig: String,
|
|
||||||
nickname: String? = null,
|
|
||||||
avatar: String? = null,
|
|
||||||
) = withContext(Dispatchers.IO) {
|
|
||||||
XuqmSDK.requireInit()
|
XuqmSDK.requireInit()
|
||||||
currentUserId = userId
|
currentUserId = userId
|
||||||
connectWithToken(userSig)
|
connectWithToken(userSig)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun loginWithUserSig(userId: String, userSig: String) =
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
XuqmSDK.requireInit()
|
|
||||||
currentUserId = userId
|
|
||||||
connectWithToken(userSig)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated("Use loginWithUserSig(userId, userSig) instead.")
|
|
||||||
suspend fun loginWithToken(userId: String, token: String) =
|
|
||||||
loginWithUserSig(userId, token)
|
|
||||||
|
|
||||||
fun sendMessage(
|
fun sendMessage(
|
||||||
toId: String,
|
toId: String,
|
||||||
chatType: String,
|
chatType: String,
|
||||||
|
|||||||
正在加载...
在新工单中引用
屏蔽一个用户