chore(ios): 添加LoginView并修复TokenStore类型与线程调度问题
- 在Xcode项目中添加LoginView.swift文件引用 - 修复TokenStore中Keychain查询字典类型为CFString - 将DispatchQueue.main.async替换为MainActor.run,避免弱引用丢失 - 修复绑定设备信息时的线程安全与变量命名
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
FB0000000000000000000012 /* VideoRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0000000000000000000012 /* VideoRecorder.swift */; };
|
FB0000000000000000000012 /* VideoRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0000000000000000000012 /* VideoRecorder.swift */; };
|
||||||
FB0000000000000000000013 /* SetupPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0000000000000000000013 /* SetupPanelView.swift */; };
|
FB0000000000000000000013 /* SetupPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0000000000000000000013 /* SetupPanelView.swift */; };
|
||||||
FB0000000000000000000014 /* ControlPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0000000000000000000014 /* ControlPanelView.swift */; };
|
FB0000000000000000000014 /* ControlPanelView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0000000000000000000014 /* ControlPanelView.swift */; };
|
||||||
|
FB0000000000000000000017 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA0000000000000000000017 /* LoginView.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@@ -53,6 +54,7 @@
|
|||||||
FA0000000000000000000012 /* VideoRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRecorder.swift; sourceTree = "<group>"; };
|
FA0000000000000000000012 /* VideoRecorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoRecorder.swift; sourceTree = "<group>"; };
|
||||||
FA0000000000000000000013 /* SetupPanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupPanelView.swift; sourceTree = "<group>"; };
|
FA0000000000000000000013 /* SetupPanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetupPanelView.swift; sourceTree = "<group>"; };
|
||||||
FA0000000000000000000014 /* ControlPanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlPanelView.swift; sourceTree = "<group>"; };
|
FA0000000000000000000014 /* ControlPanelView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlPanelView.swift; sourceTree = "<group>"; };
|
||||||
|
FA0000000000000000000017 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -145,6 +147,7 @@
|
|||||||
FA0000000000000000000008 /* RemoteTouchView.swift */,
|
FA0000000000000000000008 /* RemoteTouchView.swift */,
|
||||||
FA0000000000000000000009 /* RemoteVideoView.swift */,
|
FA0000000000000000000009 /* RemoteVideoView.swift */,
|
||||||
FA000000000000000000000A /* SelfCodecDisplayView.swift */,
|
FA000000000000000000000A /* SelfCodecDisplayView.swift */,
|
||||||
|
FA0000000000000000000017 /* LoginView.swift */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -256,6 +259,7 @@
|
|||||||
FB0000000000000000000008 /* RemoteTouchView.swift in Sources */,
|
FB0000000000000000000008 /* RemoteTouchView.swift in Sources */,
|
||||||
FB0000000000000000000009 /* RemoteVideoView.swift in Sources */,
|
FB0000000000000000000009 /* RemoteVideoView.swift in Sources */,
|
||||||
FB000000000000000000000A /* SelfCodecDisplayView.swift in Sources */,
|
FB000000000000000000000A /* SelfCodecDisplayView.swift in Sources */,
|
||||||
|
FB0000000000000000000017 /* LoginView.swift in Sources */,
|
||||||
FB000000000000000000000B /* ContentView.swift in Sources */,
|
FB000000000000000000000B /* ContentView.swift in Sources */,
|
||||||
FB000000000000000000000C /* AuthSheetView.swift in Sources */,
|
FB000000000000000000000C /* AuthSheetView.swift in Sources */,
|
||||||
FB000000000000000000000D /* ControllerViewModel.swift in Sources */,
|
FB000000000000000000000D /* ControllerViewModel.swift in Sources */,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ enum TokenStore {
|
|||||||
|
|
||||||
static func clear() {
|
static func clear() {
|
||||||
for k in [accessKey, refreshKey, userKey] {
|
for k in [accessKey, refreshKey, userKey] {
|
||||||
let query: [String: Any] = [
|
let query: [CFString: Any] = [
|
||||||
kSecClass: kSecClassGenericPassword,
|
kSecClass: kSecClassGenericPassword,
|
||||||
kSecAttrService: service,
|
kSecAttrService: service,
|
||||||
kSecAttrAccount: k
|
kSecAttrAccount: k
|
||||||
@@ -55,7 +55,7 @@ enum TokenStore {
|
|||||||
|
|
||||||
private static func save(key: String, value: String) {
|
private static func save(key: String, value: String) {
|
||||||
// 先删后存,避免重复条目。
|
// 先删后存,避免重复条目。
|
||||||
let query: [String: Any] = [
|
let query: [CFString: Any] = [
|
||||||
kSecClass: kSecClassGenericPassword,
|
kSecClass: kSecClassGenericPassword,
|
||||||
kSecAttrService: service,
|
kSecAttrService: service,
|
||||||
kSecAttrAccount: key,
|
kSecAttrAccount: key,
|
||||||
@@ -66,7 +66,7 @@ enum TokenStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static func load(key: String) -> String? {
|
private static func load(key: String) -> String? {
|
||||||
let query: [String: Any] = [
|
let query: [CFString: Any] = [
|
||||||
kSecClass: kSecClassGenericPassword,
|
kSecClass: kSecClassGenericPassword,
|
||||||
kSecAttrService: service,
|
kSecAttrService: service,
|
||||||
kSecAttrAccount: key,
|
kSecAttrAccount: key,
|
||||||
|
|||||||
@@ -391,7 +391,8 @@ final class ControllerViewModel: NSObject, ObservableObject {
|
|||||||
do {
|
do {
|
||||||
let newAt = try await ensureAccessToken()
|
let newAt = try await ensureAccessToken()
|
||||||
accessToken = newAt
|
accessToken = newAt
|
||||||
DispatchQueue.main.async {
|
await MainActor.run { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
self.signalingClient?.disconnect()
|
self.signalingClient?.disconnect()
|
||||||
self.signalingClient = nil
|
self.signalingClient = nil
|
||||||
// 用新令牌重建连接(REGISTER_SUCCESS 会再次触发 startWebRTC)。
|
// 用新令牌重建连接(REGISTER_SUCCESS 会再次触发 startWebRTC)。
|
||||||
@@ -403,7 +404,8 @@ final class ControllerViewModel: NSObject, ObservableObject {
|
|||||||
signaling.connect()
|
signaling.connect()
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
DispatchQueue.main.async {
|
await MainActor.run { [weak self] in
|
||||||
|
guard let self else { return }
|
||||||
self.logout()
|
self.logout()
|
||||||
self.alertMessage = "令牌刷新失败,请重新登录"
|
self.alertMessage = "令牌刷新失败,请重新登录"
|
||||||
}
|
}
|
||||||
@@ -417,13 +419,14 @@ final class ControllerViewModel: NSObject, ObservableObject {
|
|||||||
do {
|
do {
|
||||||
let data = try await ApiClient.bindings(accessToken: at)
|
let data = try await ApiClient.bindings(accessToken: at)
|
||||||
guard let list = data["bindings"] as? [[String: Any]], !list.isEmpty else { return }
|
guard let list = data["bindings"] as? [[String: Any]], !list.isEmpty else { return }
|
||||||
let uids = list.compactMap { $ -> String? in
|
let uids = list.compactMap { entry -> String? in
|
||||||
if let u = $["deviceUid"] as? String, !u.isEmpty { return u }
|
if let u = entry["deviceUid"] as? String, !u.isEmpty { return u }
|
||||||
return $["deviceId"] as? String
|
return entry["deviceId"] as? String
|
||||||
}.filter { !$0.isEmpty }
|
}.filter { !$0.isEmpty }
|
||||||
if !uids.isEmpty {
|
if !uids.isEmpty {
|
||||||
DispatchQueue.main.async {
|
let message = "已绑定设备: " + uids.joined(separator: ", ")
|
||||||
self.alertMessage = "已绑定设备: " + uids.joined(separator: ", ")
|
Task { @MainActor [weak self] in
|
||||||
|
self?.alertMessage = message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch { /* 忽略 */ }
|
} catch { /* 忽略 */ }
|
||||||
@@ -470,7 +473,7 @@ final class ControllerViewModel: NSObject, ObservableObject {
|
|||||||
webRTCClient?.stats { [weak self] report in
|
webRTCClient?.stats { [weak self] report in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
let text = self.buildStatsText(report)
|
let text = self.buildStatsText(report)
|
||||||
DispatchQueue.main.async {
|
Task { @MainActor in
|
||||||
self.statsText = text
|
self.statsText = text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user