2022-01-04 22:28:18 +08:00
|
|
|
|
//
|
|
|
|
|
// AppState.swift
|
|
|
|
|
// PushDeer
|
|
|
|
|
//
|
|
|
|
|
// Created by HEXT on 2022/1/4.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import Foundation
|
2022-01-10 00:26:29 +08:00
|
|
|
|
import AuthenticationServices
|
|
|
|
|
|
2022-01-04 22:28:18 +08:00
|
|
|
|
class AppState: ObservableObject {
|
2022-01-10 00:26:29 +08:00
|
|
|
|
/// 账号 token
|
2022-04-19 00:35:56 +08:00
|
|
|
|
@Published var token : String = "" {
|
2022-01-10 00:26:29 +08:00
|
|
|
|
didSet {
|
2022-04-19 00:35:56 +08:00
|
|
|
|
getUserDefaults().set(token, forKey: "PushDeer_token")
|
2022-01-10 00:26:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// 设备列表
|
2022-01-04 22:28:18 +08:00
|
|
|
|
@Published var devices: [DeviceItem] = []
|
2022-01-10 00:26:29 +08:00
|
|
|
|
/// key 列表
|
2022-01-04 22:28:18 +08:00
|
|
|
|
@Published var keys: [KeyItem] = []
|
2022-01-10 00:26:29 +08:00
|
|
|
|
/// 消息列表
|
2022-01-30 01:02:44 +08:00
|
|
|
|
// @Published var messages: [MessageItem] = []
|
2022-01-10 00:26:29 +08:00
|
|
|
|
/// 选中的 tab 下标
|
2022-04-19 00:35:56 +08:00
|
|
|
|
@Published var tabSelectedIndex: Int = 2 {
|
2022-01-10 00:26:29 +08:00
|
|
|
|
didSet {
|
2022-04-19 00:35:56 +08:00
|
|
|
|
getUserDefaults().set(tabSelectedIndex, forKey: "PushDeer_tabSelectedIndex")
|
2022-01-10 00:26:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// 设备推送 token
|
|
|
|
|
@Published var deviceToken: String = ""
|
|
|
|
|
/// 用户信息
|
|
|
|
|
@Published var userInfo: UserInfoContent?
|
|
|
|
|
/// 是否显示测试发推送的 UI
|
2022-04-19 00:35:56 +08:00
|
|
|
|
@Published var isShowTestPush: Bool = true {
|
2022-01-10 00:26:29 +08:00
|
|
|
|
didSet {
|
2022-04-19 00:35:56 +08:00
|
|
|
|
getUserDefaults().set(isShowTestPush, forKey: "PushDeer_isShowTestPush")
|
2022-01-10 00:26:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-27 23:02:58 +08:00
|
|
|
|
/// 是否使用内置浏览器打开链接
|
2022-04-19 00:35:56 +08:00
|
|
|
|
@Published var isUseBuiltInBrowser: Bool = true {
|
2022-02-27 23:02:58 +08:00
|
|
|
|
didSet {
|
2022-04-19 00:35:56 +08:00
|
|
|
|
getUserDefaults().set(isUseBuiltInBrowser, forKey: "PushDeer_isUseBuiltInBrowser")
|
2022-02-27 23:02:58 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-30 01:45:02 +08:00
|
|
|
|
/// MarkDown BaseURL
|
|
|
|
|
@Published var markDownBaseURL: String? {
|
|
|
|
|
didSet {
|
2022-04-19 00:35:56 +08:00
|
|
|
|
getUserDefaults().set(markDownBaseURL, forKey: "PushDeer_markDownBaseURL")
|
2022-03-30 01:45:02 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-01-10 00:26:29 +08:00
|
|
|
|
|
2022-02-14 01:13:26 +08:00
|
|
|
|
/// API endpoint
|
2022-04-19 00:35:56 +08:00
|
|
|
|
@Published var api_endpoint : String = "" {
|
2022-02-14 01:13:26 +08:00
|
|
|
|
didSet {
|
2022-04-19 00:35:56 +08:00
|
|
|
|
getUserDefaults().set(api_endpoint, forKey: "PushDeer_api_endpoint")
|
2022-02-14 01:13:26 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-10 00:26:29 +08:00
|
|
|
|
var isAppClip: Bool {
|
|
|
|
|
#if APPCLIP
|
|
|
|
|
return true
|
|
|
|
|
#else
|
|
|
|
|
return false
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 22:28:18 +08:00
|
|
|
|
|
|
|
|
|
static let shared = AppState()
|
2022-01-10 00:26:29 +08:00
|
|
|
|
private init() {
|
2022-04-19 00:35:56 +08:00
|
|
|
|
reloadUserDefaults()
|
|
|
|
|
moveOldUserDefaults()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func getUserDefaults() -> UserDefaults {
|
|
|
|
|
let ud = UserDefaults(suiteName: Env.appGroupId)
|
|
|
|
|
if let ud = ud {
|
|
|
|
|
return ud
|
|
|
|
|
} else {
|
|
|
|
|
return UserDefaults.standard
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func reloadUserDefaults() -> Void {
|
|
|
|
|
let _token = getUserDefaults().string(forKey: "PushDeer_token")
|
|
|
|
|
let _tabSelectedIndex = getUserDefaults().integer(forKey: "PushDeer_tabSelectedIndex")
|
|
|
|
|
let _isShowTestPush = getUserDefaults().object(forKey: "PushDeer_isShowTestPush")
|
|
|
|
|
let _isUseBuiltInBrowser = getUserDefaults().object(forKey: "PushDeer_isUseBuiltInBrowser")
|
|
|
|
|
let _markDownBaseURL = getUserDefaults().string(forKey: "PushDeer_markDownBaseURL")
|
|
|
|
|
let _api_endpoint = getUserDefaults().string(forKey: "PushDeer_api_endpoint")
|
2022-01-10 00:26:29 +08:00
|
|
|
|
token = _token ?? ""
|
|
|
|
|
tabSelectedIndex = _tabSelectedIndex
|
|
|
|
|
isShowTestPush = _isShowTestPush as? Bool ?? true
|
2022-02-27 23:02:58 +08:00
|
|
|
|
isUseBuiltInBrowser = _isUseBuiltInBrowser as? Bool ?? true
|
2022-03-30 01:45:02 +08:00
|
|
|
|
markDownBaseURL = _markDownBaseURL
|
2022-02-14 01:13:26 +08:00
|
|
|
|
api_endpoint = _api_endpoint ?? ""
|
2022-01-10 00:26:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-04-19 00:35:56 +08:00
|
|
|
|
/// 迁移老版本数据, 老版本不是存在共享组中, 需要迁移到共享组
|
|
|
|
|
func moveOldUserDefaults() -> Void {
|
|
|
|
|
let oldUserDefaults = UserDefaults.standard
|
|
|
|
|
if let _token = oldUserDefaults.string(forKey: "PushDeer_token") {
|
|
|
|
|
oldUserDefaults.removeObject(forKey: "PushDeer_token")
|
|
|
|
|
token = _token
|
|
|
|
|
}
|
|
|
|
|
if let _tabSelectedIndex = oldUserDefaults.object(forKey: "PushDeer_tabSelectedIndex") as? Int {
|
|
|
|
|
oldUserDefaults.removeObject(forKey: "PushDeer_tabSelectedIndex")
|
|
|
|
|
tabSelectedIndex = _tabSelectedIndex
|
|
|
|
|
}
|
|
|
|
|
if let _isShowTestPush = oldUserDefaults.object(forKey: "PushDeer_isShowTestPush") as? Bool {
|
|
|
|
|
oldUserDefaults.removeObject(forKey: "PushDeer_isShowTestPush")
|
|
|
|
|
isShowTestPush = _isShowTestPush
|
|
|
|
|
}
|
|
|
|
|
if let _isUseBuiltInBrowser = oldUserDefaults.object(forKey: "PushDeer_isUseBuiltInBrowser") as? Bool {
|
|
|
|
|
oldUserDefaults.removeObject(forKey: "PushDeer_isUseBuiltInBrowser")
|
|
|
|
|
isUseBuiltInBrowser = _isUseBuiltInBrowser
|
|
|
|
|
}
|
|
|
|
|
if let _markDownBaseURL = oldUserDefaults.string(forKey: "PushDeer_markDownBaseURL") {
|
|
|
|
|
oldUserDefaults.removeObject(forKey: "PushDeer_markDownBaseURL")
|
|
|
|
|
markDownBaseURL = _markDownBaseURL
|
|
|
|
|
}
|
|
|
|
|
if let _api_endpoint = oldUserDefaults.string(forKey: "PushDeer_api_endpoint") {
|
|
|
|
|
oldUserDefaults.removeObject(forKey: "PushDeer_api_endpoint")
|
|
|
|
|
api_endpoint = _api_endpoint
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-14 00:14:19 +08:00
|
|
|
|
func loginAfter() {
|
|
|
|
|
Task {
|
|
|
|
|
// 查询 UserInfo
|
|
|
|
|
self.userInfo = try await HttpRequest.getUserInfo()
|
|
|
|
|
var stoken = self.userInfo?.simple_token
|
|
|
|
|
if isEmpty(stoken) {
|
|
|
|
|
// UserInfo 中的 stoken 为空, 就重新生成一个
|
|
|
|
|
stoken = try await HttpRequest.stokenRegen().stoken
|
|
|
|
|
}
|
|
|
|
|
if isNotEmpty(stoken) {
|
|
|
|
|
// 最后 stoken 不为空, 就保存到本地
|
|
|
|
|
self.saveSTokenToLocal(stoken: stoken)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func saveSTokenToLocal(stoken: String?) -> Void {
|
|
|
|
|
let key = "stoken_\(self.api_endpoint)"
|
|
|
|
|
getUserDefaults().set(stoken, forKey: key)
|
|
|
|
|
}
|
|
|
|
|
func getLocalSToken() -> String? {
|
|
|
|
|
let key = "stoken_\(self.api_endpoint)"
|
|
|
|
|
return getUserDefaults().string(forKey: key)
|
|
|
|
|
}
|
|
|
|
|
func deleteLocalSToken() -> Void {
|
|
|
|
|
let key = "stoken_\(self.api_endpoint)"
|
|
|
|
|
getUserDefaults().removeObject(forKey: key)
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-10 00:26:29 +08:00
|
|
|
|
func appleIdLogin(_ result: Result<ASAuthorization, Error>) async throws -> TokenContent {
|
|
|
|
|
switch result {
|
|
|
|
|
case let .success(authorization):
|
|
|
|
|
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
|
|
|
|
|
// 用户唯一ID,在一个开发者账号下的APP获取到的是一样的
|
|
|
|
|
print(appleIDCredential.user) // 000791.7a323f1326dd4674bc16d32fd6339875.1424
|
|
|
|
|
// 注意:当第一次认证成功之后,将不会再返回email,fullName等信息,可以在设置->Apple ID->密码与安全性->使用您AppleID的App 中删除对应的APP。
|
|
|
|
|
print(appleIDCredential.email as Any) // easychen@qq.com
|
|
|
|
|
print(appleIDCredential.fullName as Any) // givenName: lijie familyName: chen
|
|
|
|
|
// 「JWT」格式的token,用于验证信息合法性。其值用.分割成3段, 中间一段base64后会看到包含了 用户唯一标识 和 邮箱 等字段
|
|
|
|
|
let idToken = String(data:appleIDCredential.identityToken!, encoding: .utf8)
|
|
|
|
|
print(idToken as Any)
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
// 请求接口
|
|
|
|
|
let result = try await HttpRequest.login(idToken: idToken!)
|
|
|
|
|
print(result)
|
|
|
|
|
// 登录成功
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
} catch {
|
|
|
|
|
print(error)
|
2022-01-30 01:02:44 +08:00
|
|
|
|
// 后端登录失败
|
|
|
|
|
throw NSError(domain: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示") + "\n\(error.localizedDescription)", code: -4, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示") + "(-4)\n\(error.localizedDescription)"])
|
2022-01-10 00:26:29 +08:00
|
|
|
|
}
|
2022-01-30 01:02:44 +08:00
|
|
|
|
} else {
|
|
|
|
|
// 非 Apple 登录凭证
|
|
|
|
|
throw NSError(domain: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示"), code: -3, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示") + "(-3)"])
|
2022-01-10 00:26:29 +08:00
|
|
|
|
}
|
|
|
|
|
case let .failure(error):
|
|
|
|
|
print(error)
|
2022-02-27 23:02:58 +08:00
|
|
|
|
if (error as NSError).code == 1001 {
|
|
|
|
|
// Apple 登录取消
|
|
|
|
|
throw NSError(domain: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示") + "\n\(error.localizedDescription)", code: 1001, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("你已取消授权", comment: "")])
|
|
|
|
|
}
|
2022-01-30 01:02:44 +08:00
|
|
|
|
// Apple 登录失败
|
|
|
|
|
throw NSError(domain: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示") + "\n\(error.localizedDescription)", code: -2, userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("登录失败", comment: "AppleId登录失败时提示") + "(-2)\n\(error.localizedDescription)"])
|
2022-01-10 00:26:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-04 22:28:18 +08:00
|
|
|
|
}
|