diff --git a/Podfile b/Podfile
index c6c17cb..5d7c5d5 100644
--- a/Podfile
+++ b/Podfile
@@ -16,7 +16,7 @@ target 'yana' do
# pod 'NELocalConversationUIKit', '10.6.1' # 本地会话列表组件。
# Networks
- pod 'Alamofire'
+# pod 'Alamofire'
end
post_install do |installer|
diff --git a/Podfile.lock b/Podfile.lock
index 4dc3a44..31e689b 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -1,16 +1,3 @@
-PODS:
- - Alamofire (5.10.2)
-
-DEPENDENCIES:
- - Alamofire
-
-SPEC REPOS:
- trunk:
- - Alamofire
-
-SPEC CHECKSUMS:
- Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
-
-PODFILE CHECKSUM: 4ccb5fbbedd3dcb71c35d00e7bfd0d280d4ced88
+PODFILE CHECKSUM: 9817fb04504ebed48143ca78630f70d3b3402405
COCOAPODS: 1.16.2
diff --git a/yana.xcodeproj/project.pbxproj b/yana.xcodeproj/project.pbxproj
index 30fa9e7..c0215b5 100644
--- a/yana.xcodeproj/project.pbxproj
+++ b/yana.xcodeproj/project.pbxproj
@@ -145,7 +145,6 @@
4C3E651B2DB61F7A00E5A455 /* Sources */,
4C3E651C2DB61F7A00E5A455 /* Frameworks */,
4C3E651D2DB61F7A00E5A455 /* Resources */,
- A9AAC370C902C50E37521C40 /* [CP] Embed Pods Frameworks */,
);
buildRules = (
);
@@ -263,23 +262,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
- A9AAC370C902C50E37521C40 /* [CP] Embed Pods Frameworks */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-yana/Pods-yana-frameworks-${CONFIGURATION}-input-files.xcfilelist",
- );
- name = "[CP] Embed Pods Frameworks";
- outputFileListPaths = (
- "${PODS_ROOT}/Target Support Files/Pods-yana/Pods-yana-frameworks-${CONFIGURATION}-output-files.xcfilelist",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-yana/Pods-yana-frameworks.sh\"\n";
- showEnvVarsInLog = 0;
- };
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
diff --git a/yana.xcodeproj/xcuserdata/edwinqqq.xcuserdatad/xcschemes/xcschememanagement.plist b/yana.xcodeproj/xcuserdata/edwinqqq.xcuserdatad/xcschemes/xcschememanagement.plist
index 9674f9b..e5c6177 100644
--- a/yana.xcodeproj/xcuserdata/edwinqqq.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/yana.xcodeproj/xcuserdata/edwinqqq.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -7,7 +7,7 @@
yana.xcscheme_^#shared#^_
orderHint
- 3
+ 1
diff --git a/yana.xcworkspace/xcuserdata/edwinqqq.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/yana.xcworkspace/xcuserdata/edwinqqq.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
index 0f8d13c..3922ed9 100644
--- a/yana.xcworkspace/xcuserdata/edwinqqq.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+++ b/yana.xcworkspace/xcuserdata/edwinqqq.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -3,4 +3,38 @@
uuid = "A60FAB2A-3184-45B2-920F-A3D7A086CF95"
type = "0"
version = "2.0">
+
+
+
+
+
+
+
+
+
+
diff --git a/yana/APIs/API-README.md b/yana/APIs/API-README.md
new file mode 100644
index 0000000..4add884
--- /dev/null
+++ b/yana/APIs/API-README.md
@@ -0,0 +1,152 @@
+## 🔐 **自动认证 Header 机制**
+
+### 概述
+
+系统会自动检查用户的登录状态,并在所有API请求中自动添加认证相关的header。
+
+### 工作原理
+
+1. **检查认证状态**:每次发起API请求时,系统会检查`AccountModel`的有效性
+2. **自动添加Header**:如果用户已登录且认证信息有效,自动添加以下header:
+ - `pub_uid`: 用户唯一标识(来自`AccountModel.uid`)
+ - `pub_ticket`: 业务会话票据(来自`AccountModel.ticket`)
+
+### 实现细节
+
+```swift
+// 在 APIConfiguration.defaultHeaders 中实现
+static var defaultHeaders: [String: String] {
+ var headers = [
+ "Content-Type": "application/json",
+ "Accept": "application/json",
+ // ... 其他基础header
+ ]
+
+ // 检查用户认证状态并添加相关 headers
+ let authStatus = UserInfoManager.checkAuthenticationStatus()
+
+ if authStatus.canAutoLogin {
+ // 添加认证 headers(仅在 AccountModel 有效时)
+ if let userId = UserInfoManager.getCurrentUserId() {
+ headers["pub_uid"] = userId
+ }
+
+ if let userTicket = UserInfoManager.getCurrentUserTicket() {
+ headers["pub_ticket"] = userTicket
+ }
+ }
+
+ return headers
+}
+```
+
+### 认证状态检查
+
+系统使用`UserInfoManager.checkAuthenticationStatus()`检查认证状态:
+
+```swift
+enum AuthenticationStatus {
+ case valid // 认证有效,可以自动登录
+ case invalid // 认证信息不完整或无效
+ case notFound // 未找到认证信息
+}
+```
+
+**认证有效的条件**:
+- `AccountModel`存在
+- `uid`不为空
+- `ticket`不为空
+- `accessToken`不为空
+
+### 使用方式
+
+认证header的添加是**完全自动的**,开发者无需手动处理:
+
+```swift
+// 示例:发起API请求
+let request = ConfigRequest()
+let response = try await apiService.request(request)
+
+// 如果用户已登录,以上请求会自动包含:
+// Header: pub_uid = "12345"
+// Header: pub_ticket = "eyJhbGciOiJIUzI1NiJ9..."
+```
+
+### 测试功能
+
+在DEBUG模式下,可以使用测试方法验证功能:
+
+```swift
+#if DEBUG
+// 运行认证header测试
+UserInfoManager.testAuthenticationHeaders()
+#endif
+```
+
+测试包括:
+1. **未登录状态测试**:验证不会添加认证header
+2. **已登录状态测试**:验证正确添加认证header
+3. **清理测试**:验证测试数据正确清理
+
+### 调试日志
+
+在DEBUG模式下,系统会输出认证header的添加情况:
+
+```
+🔐 添加认证 header: pub_uid = 12345
+🔐 添加认证 header: pub_ticket = eyJhbGciOiJIUzI1NiJ9...
+```
+
+或者:
+
+```
+🔐 跳过认证 header 添加 - 认证状态: 未找到认证信息
+```
+
+### 最佳实践
+
+1. **登录成功后保存完整认证信息**:
+```swift
+UserInfoManager.saveCompleteAuthenticationData(
+ accessToken: loginResponse.accessToken,
+ ticket: ticketResponse.ticket,
+ uid: loginResponse.uid,
+ userInfo: loginResponse.userInfo
+)
+```
+
+2. **登出时清理认证信息**:
+```swift
+UserInfoManager.clearAllAuthenticationData()
+```
+
+3. **应用启动时检查认证状态**:
+```swift
+let authStatus = UserInfoManager.checkAuthenticationStatus()
+if authStatus.canAutoLogin {
+ // 可以直接进入主界面
+} else {
+ // 需要重新登录
+}
+```
+
+### 安全考虑
+
+- **内存安全**:ticket存储在内存中,应用重启需重新获取
+- **持久化安全**:uid和accessToken存储在Keychain中,确保安全性
+- **自动清理**:认证失效时系统会自动停止添加认证header
+
+### 故障排除
+
+1. **认证header未添加**:
+ - 检查用户是否已正确登录
+ - 验证AccountModel是否包含有效的uid和ticket
+ - 确认认证状态为valid
+
+2. **ticket为空**:
+ - 检查登录流程是否正确获取了ticket
+ - 验证ticket是否正确保存到AccountModel
+
+3. **调试模式下查看详细日志**:
+ - 启用DEBUG模式查看认证header添加日志
+ - 使用测试方法验证功能正确性
\ No newline at end of file
diff --git a/yana/APIs/APIEndpoints.swift b/yana/APIs/APIEndpoints.swift
index dc32c89..60b1611 100644
--- a/yana/APIs/APIEndpoints.swift
+++ b/yana/APIs/APIEndpoints.swift
@@ -94,13 +94,28 @@ struct APIConfiguration {
"User-Agent": "YuMi/20.20.61 (iPhone; iOS 16.4; Scale/2.00)"
]
- // 添加用户认证相关 headers(如果存在)
- if let userId = UserInfoManager.getCurrentUserId() {
- headers["pub_uid"] = userId
- }
+ // 检查用户认证状态并添加相关 headers
+ let authStatus = UserInfoManager.checkAuthenticationStatus()
- if let userTicket = UserInfoManager.getCurrentUserTicket() {
- headers["pub_ticket"] = userTicket
+ if authStatus.canAutoLogin {
+ // 添加用户认证相关 headers(仅在 AccountModel 有效时)
+ if let userId = UserInfoManager.getCurrentUserId() {
+ headers["pub_uid"] = userId
+ #if DEBUG
+ debugInfo("🔐 添加认证 header: pub_uid = \(userId)")
+ #endif
+ }
+
+ if let userTicket = UserInfoManager.getCurrentUserTicket() {
+ headers["pub_ticket"] = userTicket
+ #if DEBUG
+ debugInfo("🔐 添加认证 header: pub_ticket = \(userTicket.prefix(20))...")
+ #endif
+ }
+ } else {
+ #if DEBUG
+ debugInfo("🔐 跳过认证 header 添加 - 认证状态: \(authStatus.description)")
+ #endif
}
return headers
diff --git a/yana/APIs/APILogger.swift b/yana/APIs/APILogger.swift
index e2defa3..0921e76 100644
--- a/yana/APIs/APILogger.swift
+++ b/yana/APIs/APILogger.swift
@@ -22,7 +22,11 @@ class APILogger {
// MARK: - Request Logging
static func logRequest(_ request: T, url: URL, body: Data?, finalHeaders: [String: String]? = nil) {
+ #if DEBUG
guard logLevel != .none else { return }
+ #else
+ return
+ #endif
let timestamp = dateFormatter.string(from: Date())
@@ -107,7 +111,11 @@ class APILogger {
// MARK: - Response Logging
static func logResponse(data: Data, response: HTTPURLResponse, duration: TimeInterval) {
+ #if DEBUG
guard logLevel != .none else { return }
+ #else
+ return
+ #endif
let timestamp = dateFormatter.string(from: Date())
let statusEmoji = response.statusCode < 400 ? "✅" : "❌"
@@ -143,7 +151,11 @@ class APILogger {
// MARK: - Error Logging
static func logError(_ error: Error, url: URL?, duration: TimeInterval) {
+ #if DEBUG
guard logLevel != .none else { return }
+ #else
+ return
+ #endif
let timestamp = dateFormatter.string(from: Date())
@@ -186,7 +198,11 @@ class APILogger {
// MARK: - Decoded Response Logging
static func logDecodedResponse(_ response: T, type: T.Type) {
+ #if DEBUG
guard logLevel == .detailed else { return }
+ #else
+ return
+ #endif
let timestamp = dateFormatter.string(from: Date())
print("🎯 [Decoded Response] [\(timestamp)] Type: \(type)")
@@ -203,7 +219,11 @@ class APILogger {
// MARK: - Performance Logging
static func logPerformanceWarning(duration: TimeInterval, threshold: TimeInterval = 5.0) {
+ #if DEBUG
guard logLevel != .none && duration > threshold else { return }
+ #else
+ return
+ #endif
let timestamp = dateFormatter.string(from: Date())
print("\n⚠️ [Performance Warning] [\(timestamp)] ============")
diff --git a/yana/APIs/APIModels.swift b/yana/APIs/APIModels.swift
index f14de1d..ecfbaf9 100644
--- a/yana/APIs/APIModels.swift
+++ b/yana/APIs/APIModels.swift
@@ -260,21 +260,27 @@ struct UserInfoManager {
return getAccountModel()?.accessToken
}
- // MARK: - Ticket Management (内存存储)
+ // MARK: - Ticket Management (优先从 AccountModel 获取)
private static var currentTicket: String?
static func getCurrentUserTicket() -> String? {
+ // 优先从 AccountModel 获取 ticket(确保一致性)
+ if let accountTicket = getAccountModel()?.ticket, !accountTicket.isEmpty {
+ return accountTicket
+ }
+
+ // 备选:从内存获取(用于兼容性)
return currentTicket
}
static func saveTicket(_ ticket: String) {
currentTicket = ticket
- print("💾 保存 Ticket 到内存")
+ debugInfo("💾 保存 Ticket 到内存")
}
static func clearTicket() {
currentTicket = nil
- print("🗑️ 清除 Ticket")
+ debugInfo("🗑️ 清除 Ticket")
}
// MARK: - User Info Management
@@ -283,9 +289,9 @@ struct UserInfoManager {
do {
try keychain.store(userInfo, forKey: StorageKeys.userInfo)
userInfoCache = userInfo
- print("💾 保存用户信息成功")
+ debugInfo("💾 保存用户信息成功")
} catch {
- print("❌ 保存用户信息失败: \(error)")
+ debugError("❌ 保存用户信息失败: \(error)")
}
}
}
@@ -303,7 +309,7 @@ struct UserInfoManager {
userInfoCache = userInfo
return userInfo
} catch {
- print("❌ 读取用户信息失败: \(error)")
+ debugError("❌ 读取用户信息失败: \(error)")
return nil
}
}
@@ -337,7 +343,7 @@ struct UserInfoManager {
saveUserInfo(userInfo)
}
- print("✅ 完整认证信息保存成功")
+ debugInfo("✅ 完整认证信息保存成功")
}
/// 检查是否有有效的认证信息
@@ -351,7 +357,7 @@ struct UserInfoManager {
clearUserInfo()
clearTicket()
- print("🗑️ 清除所有认证信息")
+ debugInfo("🗑️ 清除所有认证信息")
}
/// 尝试恢复 Ticket(用于应用重启后)
@@ -361,7 +367,7 @@ struct UserInfoManager {
return false
}
- print("🔄 尝试使用 Access Token 恢复 Ticket...")
+ debugInfo("🔄 尝试使用 Access Token 恢复 Ticket...")
// 这里需要注入 APIService 依赖,暂时返回 false
// 实际实现中应该调用 TicketHelper.createTicketRequest
@@ -382,9 +388,9 @@ struct UserInfoManager {
saveTicket(ticket)
}
- print("💾 AccountModel 保存成功")
+ debugInfo("💾 AccountModel 保存成功")
} catch {
- print("❌ AccountModel 保存失败: \(error)")
+ debugError("❌ AccountModel 保存失败: \(error)")
}
}
}
@@ -404,7 +410,7 @@ struct UserInfoManager {
accountModelCache = accountModel
return accountModel
} catch {
- print("❌ 读取 AccountModel 失败: \(error)")
+ debugError("❌ 读取 AccountModel 失败: \(error)")
return nil
}
}
@@ -414,7 +420,7 @@ struct UserInfoManager {
/// - Parameter ticket: 新的票据
static func updateAccountModelTicket(_ ticket: String) {
guard var accountModel = getAccountModel() else {
- print("❌ 无法更新 ticket:AccountModel 不存在")
+ debugError("❌ 无法更新 ticket:AccountModel 不存在")
return
}
@@ -449,9 +455,9 @@ struct UserInfoManager {
do {
try keychain.delete(forKey: StorageKeys.accountModel)
accountModelCache = nil
- print("🗑️ AccountModel 已清除")
+ debugInfo("🗑️ AccountModel 已清除")
} catch {
- print("❌ 清除 AccountModel 失败: \(error)")
+ debugError("❌ 清除 AccountModel 失败: \(error)")
}
}
}
@@ -462,9 +468,9 @@ struct UserInfoManager {
do {
try keychain.delete(forKey: StorageKeys.userInfo)
userInfoCache = nil
- print("🗑️ UserInfo 已清除")
+ debugInfo("🗑️ UserInfo 已清除")
} catch {
- print("❌ 清除 UserInfo 失败: \(error)")
+ debugError("❌ 清除 UserInfo 失败: \(error)")
}
}
}
@@ -474,7 +480,7 @@ struct UserInfoManager {
cacheQueue.async(flags: .barrier) {
accountModelCache = nil
userInfoCache = nil
- print("🗑️ 清除所有内存缓存")
+ debugInfo("🗑️ 清除所有内存缓存")
}
}
@@ -485,7 +491,7 @@ struct UserInfoManager {
_ = getAccountModel()
// 预加载 UserInfo
_ = getUserInfo()
- print("🚀 缓存预加载完成")
+ debugInfo("🚀 缓存预加载完成")
}
}
@@ -496,29 +502,29 @@ struct UserInfoManager {
static func checkAuthenticationStatus() -> AuthenticationStatus {
return cacheQueue.sync {
guard let accountModel = getAccountModel() else {
- print("🔍 认证检查:未找到 AccountModel")
+ debugInfo("🔍 认证检查:未找到 AccountModel")
return .notFound
}
// 检查 uid 是否有效
guard let uid = accountModel.uid, !uid.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
- print("🔍 认证检查:uid 无效")
+ debugInfo("🔍 认证检查:uid 无效")
return .invalid
}
// 检查 ticket 是否有效
guard let ticket = accountModel.ticket, !ticket.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
- print("🔍 认证检查:ticket 无效")
+ debugInfo("🔍 认证检查:ticket 无效")
return .invalid
}
// 可选:检查 access token 是否有效
guard let accessToken = accountModel.accessToken, !accessToken.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
- print("🔍 认证检查:access token 无效")
+ debugInfo("🔍 认证检查:access token 无效")
return .invalid
}
- print("🔍 认证检查:认证有效 - uid: \(uid), ticket: \(ticket.prefix(10))...")
+ debugInfo("🔍 认证检查:认证有效 - uid: \(uid), ticket: \(ticket.prefix(10))...")
return .valid
}
}
@@ -545,6 +551,49 @@ struct UserInfoManager {
return self == .valid
}
}
+
+ // MARK: - Testing and Debugging
+
+ /// 测试认证 header 功能(仅用于调试)
+ /// 模拟用户登录状态并验证 header 添加逻辑
+ static func testAuthenticationHeaders() {
+ #if DEBUG
+ debugInfo("\n🧪 开始测试认证 header 功能")
+
+ // 测试1:未登录状态
+ debugInfo("📝 测试1:未登录状态")
+ clearAllAuthenticationData()
+ let headers1 = APIConfiguration.defaultHeaders
+ let hasAuthHeaders1 = headers1.keys.contains("pub_uid") || headers1.keys.contains("pub_ticket")
+ debugInfo(" 认证 headers 存在: \(hasAuthHeaders1) (应该为 false)")
+
+ // 测试2:模拟登录状态
+ debugInfo("📝 测试2:模拟登录状态")
+ let testAccount = AccountModel(
+ uid: "12345",
+ jti: "test-jti",
+ tokenType: "bearer",
+ refreshToken: nil,
+ netEaseToken: nil,
+ accessToken: "test-access-token",
+ expiresIn: 3600,
+ scope: "read write",
+ ticket: "test-ticket-12345678901234567890"
+ )
+ saveAccountModel(testAccount)
+
+ let headers2 = APIConfiguration.defaultHeaders
+ let hasUid = headers2["pub_uid"] == "12345"
+ let hasTicket = headers2["pub_ticket"] == "test-ticket-12345678901234567890"
+ debugInfo(" pub_uid 正确: \(hasUid) (应该为 true)")
+ debugInfo(" pub_ticket 正确: \(hasTicket) (应该为 true)")
+
+ // 测试3:清理测试数据
+ debugInfo("📝 测试3:清理测试数据")
+ clearAllAuthenticationData()
+ debugInfo("✅ 认证 header 测试完成\n")
+ #endif
+ }
}
// MARK: - API Request Protocol
diff --git a/yana/APIs/APIService.swift b/yana/APIs/APIService.swift
index 9e14d5b..3f92f6a 100644
--- a/yana/APIs/APIService.swift
+++ b/yana/APIs/APIService.swift
@@ -93,6 +93,7 @@ struct LiveAPIService: APIServiceProtocol {
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = request.method.rawValue
urlRequest.timeoutInterval = request.timeout
+ urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
// 设置请求头
var headers = APIConfiguration.defaultHeaders
@@ -113,18 +114,30 @@ struct LiveAPIService: APIServiceProtocol {
var requestBody: Data? = nil
if request.method != .GET, let bodyParams = request.bodyParameters {
do {
- // 如果需要包含基础参数,则合并
var finalBody = bodyParams
+
+ // 如果需要包含基础参数,则先合并所有参数,再统一生成签名
if request.includeBaseParameters {
+ // 第一步:创建基础参数实例(不包含签名)
var baseParams = BaseRequest()
- // 生成符合 API rule 的签名
+
+ // 第二步:基于所有参数(bodyParams + 基础参数)统一生成签名
baseParams.generateSignature(with: bodyParams)
+
+ // 第三步:将包含正确签名的基础参数合并到最终请求体
let baseDict = try baseParams.toDictionary()
- finalBody.merge(baseDict) { existing, _ in existing }
+ finalBody.merge(baseDict) { _, new in new } // 基础参数(包括签名)优先
+
+ debugInfo("🔐 签名生成完成 - 基于所有参数统一生成: \(baseParams.pubSign)")
}
requestBody = try JSONSerialization.data(withJSONObject: finalBody, options: [])
urlRequest.httpBody = requestBody
+// urlRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
+ if let httpBody = urlRequest.httpBody,
+ let bodyString = String(data: httpBody, encoding: .utf8) {
+ debugInfo("HTTP Body: \(bodyString)")
+ }
} catch {
let encodingError = APIError.decodingError("请求体编码失败: \(error.localizedDescription)")
APILoadingManager.shared.setError(loadingId, errorMessage: encodingError.localizedDescription)
@@ -133,7 +146,7 @@ struct LiveAPIService: APIServiceProtocol {
}
// 记录请求日志,传递完整的 headers 信息
-// APILogger.logRequest(request, url: url, body: requestBody, finalHeaders: headers)
+ APILogger.logRequest(request, url: url, body: requestBody, finalHeaders: headers)
do {
// 发起请求
@@ -226,16 +239,22 @@ struct LiveAPIService: APIServiceProtocol {
// 对于 GET 请求,将基础参数添加到查询参数中
if request.method == .GET && request.includeBaseParameters {
do {
+ // 第一步:创建基础参数实例(不包含签名)
var baseParams = BaseRequest()
- // 为 GET 请求生成签名(合并查询参数)
+
+ // 第二步:基于所有参数(queryParams + 基础参数)统一生成签名
let queryParamsDict = request.queryParameters ?? [:]
baseParams.generateSignature(with: queryParamsDict)
+
+ // 第三步:将包含正确签名的基础参数添加到查询参数
let baseDict = try baseParams.toDictionary()
for (key, value) in baseDict {
queryItems.append(URLQueryItem(name: key, value: "\(value)"))
}
+
+ debugInfo("🔐 GET请求签名生成完成 - 基于所有参数统一生成: \(baseParams.pubSign)")
} catch {
- print("警告:无法添加基础参数到查询字符串")
+ debugWarn("警告:无法添加基础参数到查询字符串")
}
}
diff --git a/yana/APIs/LoginModels.swift b/yana/APIs/LoginModels.swift
index aac54b8..af2b7dd 100644
--- a/yana/APIs/LoginModels.swift
+++ b/yana/APIs/LoginModels.swift
@@ -105,7 +105,7 @@ struct IDLoginAPIRequest: APIRequestProtocol {
// "version": version,
// "client_id": clientId,
// "grant_type": grantType
-// ]
+// ];
}
}
@@ -192,15 +192,15 @@ struct LoginHelper {
guard let encryptedID = DESEncrypt.encryptUseDES(userID, key: encryptionKey),
let encryptedPassword = DESEncrypt.encryptUseDES(password, key: encryptionKey) else {
- print("❌ DES加密失败")
+ debugError("❌ DES加密失败")
return nil
}
- print("🔐 DES加密成功")
- print(" 原始ID: \(userID)")
- print(" 加密后ID: \(encryptedID)")
- print(" 原始密码: \(password)")
- print(" 加密后密码: \(encryptedPassword)")
+ debugInfo("🔐 DES加密成功")
+ debugInfo(" 原始ID: \(userID)")
+ debugInfo(" 加密后ID: \(encryptedID)")
+ debugInfo(" 原始密码: \(password)")
+ debugInfo(" 加密后密码: \(encryptedPassword)")
return IDLoginAPIRequest(
phone: userID,
@@ -292,13 +292,13 @@ struct TicketHelper {
/// - accessToken: OAuth 访问令牌
/// - uid: 用户唯一标识
static func debugTicketRequest(accessToken: String, uid: Int?) {
- print("🎫 Ticket 请求调试信息")
- print(" AccessToken: \(accessToken)")
- print(" UID: \(uid?.description ?? "nil")")
- print(" Endpoint: /oauth/ticket")
- print(" Method: POST")
- print(" Headers: pub_uid = \(uid?.description ?? "nil")")
- print(" Parameters: access_token=\(accessToken), issue_type=multi")
+ debugInfo("🎫 Ticket 请求调试信息")
+ debugInfo(" AccessToken: \(accessToken)")
+ debugInfo(" UID: \(uid?.description ?? "nil")")
+ debugInfo(" Endpoint: /oauth/ticket")
+ debugInfo(" Method: POST")
+ debugInfo(" Headers: pub_uid = \(uid?.description ?? "nil")")
+ debugInfo(" Parameters: access_token=\(accessToken), issue_type=multi")
}
}
@@ -389,13 +389,13 @@ extension LoginHelper {
let encryptionKey = "1ea53d260ecf11e7b56e00163e046a26"
guard let encryptedEmail = DESEncrypt.encryptUseDES(email, key: encryptionKey) else {
- print("❌ 邮箱DES加密失败")
+ debugError("❌ 邮箱DES加密失败")
return nil
}
- print("🔐 邮箱DES加密成功")
- print(" 原始邮箱: \(email)")
- print(" 加密邮箱: \(encryptedEmail)")
+ debugInfo("🔐 邮箱DES加密成功")
+ debugInfo(" 原始邮箱: \(email)")
+ debugInfo(" 加密邮箱: \(encryptedEmail)")
return EmailGetCodeRequest(emailAddress: email, type: 1)
}
@@ -409,14 +409,14 @@ extension LoginHelper {
let encryptionKey = "1ea53d260ecf11e7b56e00163e046a26"
guard let encryptedEmail = DESEncrypt.encryptUseDES(email, key: encryptionKey) else {
- print("❌ 邮箱DES加密失败")
+ debugError("❌ 邮箱DES加密失败")
return nil
}
- print("🔐 邮箱验证码登录DES加密成功")
- print(" 原始邮箱: \(email)")
- print(" 加密邮箱: \(encryptedEmail)")
- print(" 验证码: \(code)")
+ debugInfo("🔐 邮箱验证码登录DES加密成功")
+ debugInfo(" 原始邮箱: \(email)")
+ debugInfo(" 加密邮箱: \(encryptedEmail)")
+ debugInfo(" 验证码: \(code)")
return EmailLoginRequest(email: encryptedEmail, code: code)
}
diff --git a/yana/Configs/ClientConfig.swift b/yana/Configs/ClientConfig.swift
index e7d77ce..e79f814 100644
--- a/yana/Configs/ClientConfig.swift
+++ b/yana/Configs/ClientConfig.swift
@@ -7,12 +7,12 @@ final class ClientConfig {
private init() {}
func initializeClient() {
- print("✅ 开始初始化客户端 - URL: \(AppConfig.baseURL)/client/init")
+ debugInfo("✅ 开始初始化客户端 - URL: \(AppConfig.baseURL)/client/init")
callClientInitAPI() // 调用新方法
}
func callClientInitAPI() {
- print("🆕 使用GET方法调用初始化接口")
+ debugInfo("🆕 使用GET方法调用初始化接口")
// let queryParams = [
// "debug": "1",
diff --git a/yana/Features/IDLoginFeature.swift b/yana/Features/IDLoginFeature.swift
index 1d617f6..2af51db 100644
--- a/yana/Features/IDLoginFeature.swift
+++ b/yana/Features/IDLoginFeature.swift
@@ -110,9 +110,9 @@ struct IDLoginFeature {
UserInfoManager.saveUserInfo(userInfo)
}
- print("✅ ID 登录 OAuth 认证成功")
- print("🔑 Access Token: \(accountModel.accessToken ?? "nil")")
- print("🆔 用户 UID: \(accountModel.uid ?? "nil")")
+ debugInfo("✅ ID 登录 OAuth 认证成功")
+ debugInfo("🔑 Access Token: \(accountModel.accessToken ?? "nil")")
+ debugInfo("🆔 用户 UID: \(accountModel.uid ?? "nil")")
// 自动获取 ticket
return .send(.requestTicket(accessToken: accountModel.accessToken!))
@@ -145,7 +145,7 @@ struct IDLoginFeature {
let response = try await apiService.request(ticketRequest)
await send(.ticketResponse(.success(response)))
} catch {
- print("❌ ID登录 Ticket 获取失败: \(error)")
+ debugError("❌ ID登录 Ticket 获取失败: \(error)")
await send(.ticketResponse(.failure(APIError.networkError(error.localizedDescription))))
}
}
@@ -156,8 +156,8 @@ struct IDLoginFeature {
state.ticketError = nil
state.loginStep = .completed
- print("✅ ID 登录完整流程成功")
- print("🎫 Ticket 获取成功: \(response.ticket ?? "nil")")
+ debugInfo("✅ ID 登录完整流程成功")
+ debugInfo("🎫 Ticket 获取成功: \(response.ticket ?? "nil")")
// 更新 AccountModel 中的 ticket 并保存
if let ticket = response.ticket {
@@ -171,7 +171,7 @@ struct IDLoginFeature {
// 发送 Ticket 获取成功通知,触发导航到主页面
NotificationCenter.default.post(name: .ticketSuccess, object: nil)
} else {
- print("❌ AccountModel 不存在,无法保存 ticket")
+ debugError("❌ AccountModel 不存在,无法保存 ticket")
state.ticketError = "内部错误:账户信息丢失"
state.loginStep = .failed
}
@@ -190,7 +190,7 @@ struct IDLoginFeature {
state.isTicketLoading = false
state.ticketError = error.localizedDescription
state.loginStep = .failed
- print("❌ ID 登录 Ticket 获取失败: \(error.localizedDescription)")
+ debugError("❌ ID 登录 Ticket 获取失败: \(error.localizedDescription)")
return .none
case .clearTicketError:
diff --git a/yana/Features/LoginFeature.swift b/yana/Features/LoginFeature.swift
index 3e530f3..23d74c4 100644
--- a/yana/Features/LoginFeature.swift
+++ b/yana/Features/LoginFeature.swift
@@ -109,9 +109,9 @@ struct LoginFeature {
let accountModel = AccountModel.from(loginData: loginData) {
state.accountModel = accountModel
- print("✅ OAuth 认证成功")
- print("🔑 Access Token: \(accountModel.accessToken ?? "nil")")
- print("🆔 用户 UID: \(accountModel.uid ?? "nil")")
+ debugInfo("✅ OAuth 认证成功")
+ debugInfo("🔑 Access Token: \(accountModel.accessToken ?? "nil")")
+ debugInfo("🆔 用户 UID: \(accountModel.uid ?? "nil")")
// 自动获取 ticket
return .send(.requestTicket(accessToken: accountModel.accessToken!))
@@ -144,7 +144,7 @@ struct LoginFeature {
let response = try await apiService.request(ticketRequest)
await send(.ticketResponse(.success(response)))
} catch {
- print("❌ Ticket 获取失败: \(error)")
+ debugError("❌ Ticket 获取失败: \(error)")
await send(.ticketResponse(.failure(APIError.networkError(error.localizedDescription))))
}
}
@@ -155,8 +155,8 @@ struct LoginFeature {
state.ticketError = nil
state.loginStep = .completed
- print("✅ 完整登录流程成功")
- print("🎫 Ticket 获取成功: \(response.ticket ?? "nil")")
+ debugInfo("✅ 完整登录流程成功")
+ debugInfo("🎫 Ticket 获取成功: \(response.ticket ?? "nil")")
// 更新 AccountModel 中的 ticket 并保存
if let ticket = response.ticket {
@@ -170,7 +170,7 @@ struct LoginFeature {
// 发送 Ticket 获取成功通知,触发导航到主页面
NotificationCenter.default.post(name: .ticketSuccess, object: nil)
} else {
- print("❌ AccountModel 不存在,无法保存 ticket")
+ debugError("❌ AccountModel 不存在,无法保存 ticket")
state.ticketError = "内部错误:账户信息丢失"
state.loginStep = .failed
}
@@ -189,7 +189,7 @@ struct LoginFeature {
state.isTicketLoading = false
state.ticketError = error.localizedDescription
state.loginStep = .failed
- print("❌ Ticket 获取失败: \(error.localizedDescription)")
+ debugError("❌ Ticket 获取失败: \(error.localizedDescription)")
return .none
case .clearTicketError:
diff --git a/yana/Features/RecoverPasswordFeature.swift b/yana/Features/RecoverPasswordFeature.swift
index 550a9ce..e2d7782 100644
--- a/yana/Features/RecoverPasswordFeature.swift
+++ b/yana/Features/RecoverPasswordFeature.swift
@@ -238,13 +238,13 @@ struct RecoverPasswordHelper {
let encryptionKey = "1ea53d260ecf11e7b56e00163e046a26"
guard let encryptedEmail = DESEncrypt.encryptUseDES(email, key: encryptionKey) else {
- print("❌ 邮箱DES加密失败")
+ debugError("❌ 邮箱DES加密失败")
return nil
}
- print("🔐 密码恢复邮箱DES加密成功")
- print(" 原始邮箱: \(email)")
- print(" 加密邮箱: \(encryptedEmail)")
+ debugInfo("🔐 密码恢复邮箱DES加密成功")
+ debugInfo(" 原始邮箱: \(email)")
+ debugInfo(" 加密邮箱: \(encryptedEmail)")
// 使用type=3表示密码重置验证码
return EmailGetCodeRequest(emailAddress: email, type: 3)
@@ -261,16 +261,16 @@ struct RecoverPasswordHelper {
guard let encryptedEmail = DESEncrypt.encryptUseDES(email, key: encryptionKey),
let encryptedPassword = DESEncrypt.encryptUseDES(newPassword, key: encryptionKey) else {
- print("❌ 密码重置DES加密失败")
+ debugError("❌ 密码重置DES加密失败")
return nil
}
- print("🔐 密码重置DES加密成功")
- print(" 原始邮箱: \(email)")
- print(" 加密邮箱: \(encryptedEmail)")
- print(" 验证码: \(code)")
- print(" 原始新密码: \(newPassword)")
- print(" 加密新密码: \(encryptedPassword)")
+ debugInfo("🔐 密码重置DES加密成功")
+ debugInfo(" 原始邮箱: \(email)")
+ debugInfo(" 加密邮箱: \(encryptedEmail)")
+ debugInfo(" 验证码: \(code)")
+ debugInfo(" 原始新密码: \(newPassword)")
+ debugInfo(" 加密新密码: \(encryptedPassword)")
return ResetPasswordRequest(
email: email,
diff --git a/yana/Features/SplashFeature.swift b/yana/Features/SplashFeature.swift
index 053961a..9c3c2d8 100644
--- a/yana/Features/SplashFeature.swift
+++ b/yana/Features/SplashFeature.swift
@@ -55,10 +55,10 @@ struct SplashFeature {
// 根据认证状态发送相应的导航通知
if status.canAutoLogin {
- print("🎉 自动登录成功,进入主页")
+ debugInfo("🎉 自动登录成功,进入主页")
NotificationCenter.default.post(name: .autoLoginSuccess, object: nil)
} else {
- print("🔑 需要手动登录")
+ debugInfo("🔑 需要手动登录")
NotificationCenter.default.post(name: .autoLoginFailed, object: nil)
}
diff --git a/yana/Managers/LogManager.swift b/yana/Managers/LogManager.swift
index 228f1cf..cd0ab9d 100644
--- a/yana/Managers/LogManager.swift
+++ b/yana/Managers/LogManager.swift
@@ -18,18 +18,33 @@ public class LogManager {
/// - Parameters:
/// - level: 日志等级
/// - message: 日志内容
- /// - onlyRelease: 是否仅在 Release 环境输出(默认 false,Debug 全部输出)
+ /// - onlyRelease: 是否仅在 Release 环境输出(已修复逻辑)
public func log(_ level: LogLevel, _ message: @autoclosure () -> String, onlyRelease: Bool = false) {
#if DEBUG
- if onlyRelease { return }
- print("[\(level)] \(message())")
+ // DEBUG 环境:如果 onlyRelease 为 true,则不输出;否则正常输出
+ if !onlyRelease {
+ print("[\(level)] \(message())")
+ }
#else
+ // RELEASE 环境:如果 onlyRelease 为 true,则输出;否则不输出
+ if onlyRelease {
+ print("[\(level)] \(message())")
+ }
+ #endif
+ }
+
+ /// 仅在 DEBUG 环境输出的日志(推荐使用)
+ /// - Parameters:
+ /// - level: 日志等级
+ /// - message: 日志内容
+ public func debugLog(_ level: LogLevel, _ message: @autoclosure () -> String) {
+ #if DEBUG
print("[\(level)] \(message())")
#endif
}
}
-// MARK: - 快捷方法
+// MARK: - 原有快捷方法(保持向后兼容)
public func logVerbose(_ message: @autoclosure () -> String, onlyRelease: Bool = false) {
LogManager.shared.log(.verbose, message(), onlyRelease: onlyRelease)
}
@@ -48,4 +63,25 @@ public func logWarn(_ message: @autoclosure () -> String, onlyRelease: Bool = fa
public func logError(_ message: @autoclosure () -> String, onlyRelease: Bool = false) {
LogManager.shared.log(.error, message(), onlyRelease: onlyRelease)
+}
+
+// MARK: - 新的DEBUG专用快捷方法(推荐使用)
+public func debugVerbose(_ message: @autoclosure () -> String) {
+ LogManager.shared.debugLog(.verbose, message())
+}
+
+public func debugLog(_ message: @autoclosure () -> String) {
+ LogManager.shared.debugLog(.debug, message())
+}
+
+public func debugInfo(_ message: @autoclosure () -> String) {
+ LogManager.shared.debugLog(.info, message())
+}
+
+public func debugWarn(_ message: @autoclosure () -> String) {
+ LogManager.shared.debugLog(.warn, message())
+}
+
+public func debugError(_ message: @autoclosure () -> String) {
+ LogManager.shared.debugLog(.error, message())
}
\ No newline at end of file
diff --git a/yana/Utils/APILoading/APILoadingEffectView.swift b/yana/Utils/APILoading/APILoadingEffectView.swift
index 56366e9..017a7e4 100644
--- a/yana/Utils/APILoading/APILoadingEffectView.swift
+++ b/yana/Utils/APILoading/APILoadingEffectView.swift
@@ -18,24 +18,24 @@ struct APILoadingEffectView: View {
if let firstItem = getFirstDisplayItem() {
SingleLoadingView(item: firstItem)
.onAppear {
- print("🔍 Loading item appeared: \(firstItem.id)")
+ debugInfo("🔍 Loading item appeared: \(firstItem.id)")
}
.onDisappear {
- print("🔍 Loading item disappeared: \(firstItem.id)")
+ debugInfo("🔍 Loading item disappeared: \(firstItem.id)")
}
}
}
.allowsHitTesting(false) // 不阻挡用户点击
.ignoresSafeArea(.all) // 覆盖整个屏幕
.onReceive(loadingManager.$loadingItems) { items in
- print("🔍 Loading items updated: \(items.count) items")
+ debugInfo("🔍 Loading items updated: \(items.count) items")
}
}
/// 安全地获取第一个需要显示的项目
private func getFirstDisplayItem() -> APILoadingItem? {
guard Thread.isMainThread else {
- print("⚠️ getFirstDisplayItem called from background thread")
+ debugWarn("⚠️ getFirstDisplayItem called from background thread")
return nil
}
@@ -151,7 +151,7 @@ struct APILoadingEffectView_Previews: PreviewProvider {
.font(.title)
Button("测试按钮") {
- print("按钮被点击了!")
+ debugInfo("按钮被点击了!")
}
.padding()
.background(Color.blue)
diff --git a/yana/Utils/Extensions/String+HashTest.swift b/yana/Utils/Extensions/String+HashTest.swift
index b1721cc..68f67ce 100644
--- a/yana/Utils/Extensions/String+HashTest.swift
+++ b/yana/Utils/Extensions/String+HashTest.swift
@@ -6,7 +6,7 @@ struct StringHashTest {
/// 测试哈希方法
static func runTests() {
- print("🧪 开始测试字符串哈希方法...")
+ debugInfo("🧪 开始测试字符串哈希方法...")
let testStrings = [
"hello world",
@@ -16,27 +16,27 @@ struct StringHashTest {
]
for testString in testStrings {
- print("\n📝 测试字符串: \"\(testString)\"")
+ debugInfo("\n📝 测试字符串: \"\(testString)\"")
// 测试 MD5
let md5Result = testString.md5()
- print(" MD5: \(md5Result)")
+ debugInfo(" MD5: \(md5Result)")
// 测试 SHA256 (iOS 13+)
if #available(iOS 13.0, *) {
let sha256Result = testString.sha256()
- print(" SHA256: \(sha256Result)")
+ debugInfo(" SHA256: \(sha256Result)")
} else {
- print(" SHA256: 不支持 (需要 iOS 13+)")
+ debugInfo(" SHA256: 不支持 (需要 iOS 13+)")
}
}
- print("\n✅ 哈希方法测试完成")
+ debugInfo("\n✅ 哈希方法测试完成")
}
/// 验证已知的哈希值
static func verifyKnownHashes() {
- print("\n🔍 验证已知哈希值...")
+ debugInfo("\n🔍 验证已知哈希值...")
// 验证 "hello world" 的 MD5 应该是 "5d41402abc4b2a76b9719d911017c592"
let testString = "hello world"
@@ -44,11 +44,11 @@ struct StringHashTest {
let actualMD5 = testString.md5()
if actualMD5 == expectedMD5 {
- print("✅ MD5 验证通过: \(actualMD5)")
+ debugInfo("✅ MD5 验证通过: \(actualMD5)")
} else {
- print("❌ MD5 验证失败:")
- print(" 期望: \(expectedMD5)")
- print(" 实际: \(actualMD5)")
+ debugError("❌ MD5 验证失败:")
+ debugError(" 期望: \(expectedMD5)")
+ debugError(" 实际: \(actualMD5)")
}
// 验证 SHA256
@@ -57,11 +57,11 @@ struct StringHashTest {
let actualSHA256 = testString.sha256()
if actualSHA256 == expectedSHA256 {
- print("✅ SHA256 验证通过: \(actualSHA256)")
+ debugInfo("✅ SHA256 验证通过: \(actualSHA256)")
} else {
- print("❌ SHA256 验证失败:")
- print(" 期望: \(expectedSHA256)")
- print(" 实际: \(actualSHA256)")
+ debugError("❌ SHA256 验证失败:")
+ debugError(" 期望: \(expectedSHA256)")
+ debugError(" 实际: \(actualSHA256)")
}
}
}
@@ -75,9 +75,9 @@ struct StringHashTest {
StringHashTest.verifyKnownHashes()
// 或者在开发时快速测试
- print("Test MD5:", "hello".md5())
+ debugInfo("Test MD5:", "hello".md5())
if #available(iOS 13.0, *) {
- print("Test SHA256:", "hello".sha256())
+ debugInfo("Test SHA256:", "hello".sha256())
}
*/
\ No newline at end of file
diff --git a/yana/Utils/FontManager.swift b/yana/Utils/FontManager.swift
index c290ea7..357032d 100644
--- a/yana/Utils/FontManager.swift
+++ b/yana/Utils/FontManager.swift
@@ -67,11 +67,11 @@ struct FontManager {
/// 打印所有可用字体(调试用)
static func printAllAvailableFonts() {
- print("=== 所有可用字体 ===")
+ debugInfo("=== 所有可用字体 ===")
for font in getAllAvailableFonts() {
- print(font)
+ debugInfo(font)
}
- print("==================")
+ debugInfo("==================")
}
}
diff --git a/yana/Utils/LocalizationManager.swift b/yana/Utils/LocalizationManager.swift
index e3736bd..464b618 100644
--- a/yana/Utils/LocalizationManager.swift
+++ b/yana/Utils/LocalizationManager.swift
@@ -42,9 +42,9 @@ class LocalizationManager: ObservableObject {
didSet {
do {
try KeychainManager.shared.storeString(currentLanguage.rawValue, forKey: "AppLanguage")
- } catch {
- print("❌ 保存语言设置失败: \(error)")
- }
+ } catch {
+ debugError("❌ 保存语言设置失败: \(error)")
+ }
// 通知视图更新
objectWillChange.send()
}
@@ -56,7 +56,7 @@ class LocalizationManager: ObservableObject {
do {
savedLanguage = try KeychainManager.shared.retrieveString(forKey: "AppLanguage")
} catch {
- print("❌ 读取语言设置失败: \(error)")
+ debugError("❌ 读取语言设置失败: \(error)")
savedLanguage = nil
}
diff --git a/yana/Utils/Security/DESEncryptOCTest.swift b/yana/Utils/Security/DESEncryptOCTest.swift
index 8d27e99..2f9341c 100644
--- a/yana/Utils/Security/DESEncryptOCTest.swift
+++ b/yana/Utils/Security/DESEncryptOCTest.swift
@@ -5,8 +5,8 @@ struct DESEncryptOCTest {
/// 测试 OC 版本的 DES 加密功能
static func testOCDESEncryption() {
- print("🧪 开始测试 OC 版本的 DES 加密...")
- print(String(repeating: "=", count: 50))
+ debugInfo("🧪 开始测试 OC 版本的 DES 加密...")
+ debugInfo(String(repeating: "=", count: 50))
let key = "1ea53d260ecf11e7b56e00163e046a26"
let testCases = [
@@ -19,25 +19,25 @@ struct DESEncryptOCTest {
for testCase in testCases {
if let encrypted = DESEncrypt.encryptUseDES(testCase, key: key) {
- print("✅ 加密成功:")
- print(" 原文: \"\(testCase)\"")
- print(" 密文: \(encrypted)")
+ debugInfo("✅ 加密成功:")
+ debugInfo(" 原文: \"\(testCase)\"")
+ debugInfo(" 密文: \(encrypted)")
// 测试解密
if let decrypted = DESEncrypt.decryptUseDES(encrypted, key: key) {
let isMatch = decrypted == testCase
- print(" 解密: \"\(decrypted)\" \(isMatch ? "✅" : "❌")")
+ debugInfo(" 解密: \"\(decrypted)\" \(isMatch ? "✅" : "❌")")
} else {
- print(" 解密: 失败 ❌")
+ debugError(" 解密: 失败 ❌")
}
} else {
- print("❌ 加密失败: \"\(testCase)\"")
+ debugError("❌ 加密失败: \"\(testCase)\"")
}
- print()
+ debugInfo("")
}
- print(String(repeating: "=", count: 50))
- print("🏁 OC版本DES加密测试完成")
+ debugInfo(String(repeating: "=", count: 50))
+ debugInfo("🏁 OC版本DES加密测试完成")
}
}
diff --git a/yana/Utils/Security/DataMigrationManager.swift b/yana/Utils/Security/DataMigrationManager.swift
index 3b4f390..2731633 100644
--- a/yana/Utils/Security/DataMigrationManager.swift
+++ b/yana/Utils/Security/DataMigrationManager.swift
@@ -54,23 +54,23 @@ final class DataMigrationManager {
/// 执行数据迁移
/// - Returns: 迁移结果
func performMigration() -> MigrationResult {
- print("🔄 开始检查数据迁移...")
+ debugInfo("🔄 开始检查数据迁移...")
// 检查是否已经迁移过
if isMigrationCompleted() {
- print("✅ 数据已经迁移过,跳过迁移")
+ debugInfo("✅ 数据已经迁移过,跳过迁移")
return .alreadyMigrated
}
// 检查是否有需要迁移的数据
let legacyData = collectLegacyData()
if legacyData.isEmpty {
- print("ℹ️ 没有发现需要迁移的数据")
+ debugInfo("ℹ️ 没有发现需要迁移的数据")
markMigrationCompleted()
return .noDataToMigrate
}
- print("📦 发现需要迁移的数据: \(legacyData.keys.joined(separator: ", "))")
+ debugInfo("📦 发现需要迁移的数据: \(legacyData.keys.joined(separator: ", "))")
do {
// 执行迁移
@@ -85,11 +85,11 @@ final class DataMigrationManager {
// 标记迁移完成
markMigrationCompleted()
- print("✅ 数据迁移完成")
+ debugInfo("✅ 数据迁移完成")
return .completed
} catch {
- print("❌ 数据迁移失败: \(error)")
+ debugError("❌ 数据迁移失败: \(error)")
return .failed(error)
}
}
@@ -157,9 +157,9 @@ final class DataMigrationManager {
do {
let accountModel = try JSONDecoder().decode(AccountModel.self, from: accountModelData)
try keychain.store(accountModel, forKey: "account_model")
- print("✅ AccountModel 迁移成功")
+ debugInfo("✅ AccountModel 迁移成功")
} catch {
- print("❌ AccountModel 迁移失败: \(error)")
+ debugError("❌ AccountModel 迁移失败: \(error)")
// 如果 AccountModel 迁移失败,尝试从独立字段重建
try migrateAccountModelFromIndependentFields(legacyData)
}
@@ -173,9 +173,9 @@ final class DataMigrationManager {
do {
let userInfo = try JSONDecoder().decode(UserInfo.self, from: userInfoData)
try keychain.store(userInfo, forKey: "user_info")
- print("✅ UserInfo 迁移成功")
+ debugInfo("✅ UserInfo 迁移成功")
} catch {
- print("❌ UserInfo 迁移失败: \(error)")
+ debugError("❌ UserInfo 迁移失败: \(error)")
throw error
}
}
@@ -183,7 +183,7 @@ final class DataMigrationManager {
// 迁移语言设置
if let appLanguage = legacyData[LegacyStorageKeys.appLanguage] as? String {
try keychain.storeString(appLanguage, forKey: "AppLanguage")
- print("✅ 语言设置迁移成功")
+ debugInfo("✅ 语言设置迁移成功")
}
}
@@ -191,7 +191,7 @@ final class DataMigrationManager {
private func migrateAccountModelFromIndependentFields(_ legacyData: [String: Any]) throws {
guard let userId = legacyData[LegacyStorageKeys.userId] as? String,
let accessToken = legacyData[LegacyStorageKeys.accessToken] as? String else {
- print("ℹ️ 没有足够的独立字段来重建 AccountModel")
+ debugInfo("ℹ️ 没有足够的独立字段来重建 AccountModel")
return
}
@@ -208,7 +208,7 @@ final class DataMigrationManager {
)
try KeychainManager.shared.store(accountModel, forKey: "account_model")
- print("✅ 从独立字段重建 AccountModel 成功")
+ debugInfo("✅ 从独立字段重建 AccountModel 成功")
}
/// 验证迁移结果
@@ -240,7 +240,7 @@ final class DataMigrationManager {
}
}
- print("✅ 迁移数据验证成功")
+ debugInfo("✅ 迁移数据验证成功")
}
/// 清理旧数据
@@ -249,11 +249,11 @@ final class DataMigrationManager {
for key in keys {
userDefaults.removeObject(forKey: key)
- print("🗑️ 清理旧数据: \(key)")
+ debugInfo("🗑️ 清理旧数据: \(key)")
}
userDefaults.synchronize()
- print("✅ 旧数据清理完成")
+ debugInfo("✅ 旧数据清理完成")
}
}
@@ -287,13 +287,13 @@ extension DataMigrationManager {
switch migrationResult {
case .completed:
- print("🎉 应用启动时数据迁移完成")
+ debugInfo("🎉 应用启动时数据迁移完成")
case .alreadyMigrated:
break // 静默处理
case .noDataToMigrate:
break // 静默处理
case .failed(let error):
- print("⚠️ 应用启动时数据迁移失败: \(error)")
+ debugError("⚠️ 应用启动时数据迁移失败: \(error)")
// 这里可以添加错误上报或降级策略
}
}
@@ -307,9 +307,9 @@ extension DataMigrationManager {
/// 调试:打印旧数据信息
func debugPrintLegacyData() {
let legacyData = collectLegacyData()
- print("🔍 旧版本数据:")
+ debugInfo("🔍 旧版本数据:")
for (key, value) in legacyData {
- print(" - \(key): \(type(of: value))")
+ debugInfo(" - \(key): \(type(of: value))")
}
}
@@ -322,7 +322,7 @@ extension DataMigrationManager {
userDefaults.set("zh-Hans", forKey: LegacyStorageKeys.appLanguage)
userDefaults.synchronize()
- print("🧪 已创建测试用的旧版本数据")
+ debugInfo("🧪 已创建测试用的旧版本数据")
}
/// 调试:清除所有迁移相关数据
@@ -331,7 +331,7 @@ extension DataMigrationManager {
do {
try KeychainManager.shared.clearAll()
} catch {
- print("❌ 清除 Keychain 数据失败: \(error)")
+ debugError("❌ 清除 Keychain 数据失败: \(error)")
}
// 清除 UserDefaults 数据
@@ -350,7 +350,7 @@ extension DataMigrationManager {
}
userDefaults.synchronize()
- print("🧪 已清除所有迁移相关数据")
+ debugInfo("🧪 已清除所有迁移相关数据")
}
}
#endif
\ No newline at end of file
diff --git a/yana/Utils/Security/KeychainManager.swift b/yana/Utils/Security/KeychainManager.swift
index 9ad3b17..9eedad7 100644
--- a/yana/Utils/Security/KeychainManager.swift
+++ b/yana/Utils/Security/KeychainManager.swift
@@ -108,7 +108,7 @@ final class KeychainManager {
throw KeychainError.keychainOperationFailed(status)
}
- print("🔐 Keychain 存储成功: \(key)")
+ debugInfo("🔐 Keychain 存储成功: \(key)")
}
/// 从 Keychain 检索 Codable 对象
@@ -137,7 +137,7 @@ final class KeychainManager {
// 4. 解码数据
do {
let object = try JSONDecoder().decode(type, from: data)
- print("🔐 Keychain 读取成功: \(key)")
+ debugInfo("🔐 Keychain 读取成功: \(key)")
return object
} catch {
throw KeychainError.decodingFailed(error)
@@ -176,7 +176,7 @@ final class KeychainManager {
switch status {
case errSecSuccess:
- print("🔐 Keychain 更新成功: \(key)")
+ debugInfo("🔐 Keychain 更新成功: \(key)")
case errSecItemNotFound:
// 如果项目不存在,则创建新项目
@@ -196,7 +196,7 @@ final class KeychainManager {
switch status {
case errSecSuccess:
- print("🔐 Keychain 删除成功: \(key)")
+ debugInfo("🔐 Keychain 删除成功: \(key)")
case errSecItemNotFound:
// 项目不存在,视为删除成功
@@ -231,7 +231,7 @@ final class KeychainManager {
switch status {
case errSecSuccess, errSecItemNotFound:
- print("🔐 Keychain 清除完成")
+ debugInfo("🔐 Keychain 清除完成")
default:
throw KeychainError.keychainOperationFailed(status)
@@ -353,9 +353,9 @@ extension KeychainManager {
/// 打印所有存储的键(仅用于调试)
func debugPrintAllKeys() {
let keys = debugListAllKeys()
- print("🔐 Keychain 中存储的键:")
+ debugInfo("🔐 Keychain 中存储的键:")
for key in keys {
- print(" - \(key)")
+ debugInfo(" - \(key)")
}
}
}
diff --git a/yana/Views/Components/UserAgreementView.swift b/yana/Views/Components/UserAgreementView.swift
index ddea471..0b1a341 100644
--- a/yana/Views/Components/UserAgreementView.swift
+++ b/yana/Views/Components/UserAgreementView.swift
@@ -66,20 +66,20 @@ struct UserAgreementView: View {
UserAgreementView(
isAgreed: .constant(true),
onUserServiceTapped: {
- print("User Service Agreement tapped")
+ debugInfo("User Service Agreement tapped")
},
onPrivacyPolicyTapped: {
- print("Privacy Policy tapped")
+ debugInfo("Privacy Policy tapped")
}
)
UserAgreementView(
isAgreed: .constant(true),
onUserServiceTapped: {
- print("User Service Agreement tapped")
+ debugInfo("User Service Agreement tapped")
},
onPrivacyPolicyTapped: {
- print("Privacy Policy tapped")
+ debugInfo("Privacy Policy tapped")
}
)
}
diff --git a/yana/Views/IDLoginView.swift b/yana/Views/IDLoginView.swift
index 16c1730..fcda328 100644
--- a/yana/Views/IDLoginView.swift
+++ b/yana/Views/IDLoginView.swift
@@ -207,7 +207,7 @@ struct IDLoginView: View {
#if DEBUG
// 移除测试用的硬编码凭据
- print("🐛 Debug模式: 已移除硬编码测试凭据")
+ debugInfo("🐛 Debug模式: 已移除硬编码测试凭据")
#endif
}
}
diff --git a/yana/Views/MeView.swift b/yana/Views/MeView.swift
index de8f57a..b194c89 100644
--- a/yana/Views/MeView.swift
+++ b/yana/Views/MeView.swift
@@ -1,6 +1,7 @@
import SwiftUI
struct MeView: View {
+ @State private var showLogoutConfirmation = false
var body: some View {
GeometryReader { geometry in
ScrollView {
@@ -48,7 +49,9 @@ struct MeView: View {
.padding(.top, 40)
// 退出登录按钮
- Button(action: {}) {
+ Button(action: {
+ showLogoutConfirmation = true
+ }) {
HStack {
Image(systemName: "rectangle.portrait.and.arrow.right")
.font(.system(size: 16))
@@ -72,6 +75,27 @@ struct MeView: View {
}
}
.ignoresSafeArea(.container, edges: .top)
+ .alert("确认退出", isPresented: $showLogoutConfirmation) {
+ Button("取消", role: .cancel) { }
+ Button("退出", role: .destructive) {
+ performLogout()
+ }
+ } message: {
+ Text("确定要退出登录吗?")
+ }
+ }
+
+ // MARK: - 退出登录方法
+ private func performLogout() {
+ debugInfo("🔓 开始执行退出登录...")
+
+ // 清除所有认证数据(包括 keychain 中的内容)
+ UserInfoManager.clearAllAuthenticationData()
+
+ // 发送通知重置 window root 为 login view
+ NotificationCenter.default.post(name: .homeLogout, object: nil)
+
+ debugInfo("✅ 退出登录完成")
}
}
@@ -111,4 +135,4 @@ struct MenuItemView: View {
#Preview {
MeView()
-}
\ No newline at end of file
+}
diff --git a/yana/Views/SettingView.swift b/yana/Views/SettingView.swift
index c332085..ac2d47f 100644
--- a/yana/Views/SettingView.swift
+++ b/yana/Views/SettingView.swift
@@ -188,12 +188,12 @@ struct SettingRowView: View {
}
}
-#Preview {
- SettingView(
- store: Store(
- initialState: SettingFeature.State()
- ) {
- SettingFeature()
- }
- )
-}
\ No newline at end of file
+//#Preview {
+// SettingView(
+// store: Store(
+// initialState: SettingFeature.State()
+// ) {
+// SettingFeature()
+// }
+// )
+//}
diff --git a/yana/yanaApp.swift b/yana/yanaApp.swift
index a38d1c4..890cca8 100644
--- a/yana/yanaApp.swift
+++ b/yana/yanaApp.swift
@@ -21,7 +21,7 @@ struct yanaApp: App {
}
#endif
- print("🛠 原生URLSession测试开始")
+ debugInfo("🛠 原生URLSession测试开始")
}
var body: some Scene {
diff --git a/yanaAPITests/yanaAPITests.swift b/yanaAPITests/yanaAPITests.swift
index 8a86ace..cb75126 100644
--- a/yanaAPITests/yanaAPITests.swift
+++ b/yanaAPITests/yanaAPITests.swift
@@ -163,10 +163,10 @@ final class yanaAPITests: XCTestCase {
XCTAssertEqual(accountModel?.uid, "3184", "真实API数据的UID应该正确")
XCTAssertTrue(accountModel?.hasValidAuthentication ?? false, "真实API数据应该有有效认证")
- print("✅ 真实API数据测试通过")
- print(" UID: \(accountModel?.uid ?? "nil")")
- print(" Access Token存在: \(accountModel?.accessToken != nil)")
- print(" Token类型: \(accountModel?.tokenType ?? "nil")")
+ debugInfo("✅ 真实API数据测试通过")
+ debugInfo(" UID: \(accountModel?.uid ?? "nil")")
+ debugInfo(" Access Token存在: \(accountModel?.accessToken != nil)")
+ debugInfo(" Token类型: \(accountModel?.tokenType ?? "nil")")
} catch {
XCTFail("解析真实API数据失败: \(error)")