jsdw_ios/QuickLocation/Manager/App/ApiManager.swift

264 lines
9.8 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// ApiManager.swift
// SHECommunity
//
// Created by on 2024/11/26.
//
import SwiftyUserDefaults
import Moya
import SwiftyJSON
import RxSwift
import CommonCrypto
class ApiManager: NSObject {
public static let shared = ApiManager()
let disposeBag = DisposeBag()
var ignoreCheck: Bool = false
/// firebase
var fcmToken: String?
}
// MARK: - NetworkConfig
extension ApiManager {
///
func setup() {
setupNetworkConfig()
}
///
func setupNetworkConfig() {
AppNetworkConfig.shared.baseURL = URLManager.shared.apiServerURL
AppNetworkConfig.shared.httpHeader = { [weak self] in self?.httpHeader() ?? [:] }
AppNetworkConfig.shared.handleRespone = { [weak self] (result, isShowErrorToast) in
guard let this = self else { return nil }
return this.handleResult(result, handle: isShowErrorToast)
}
}
/// HttpHeader
func httpHeader() -> [String: String] {
var headers: [String : String] = [:]
headers["Accept"] = "application/json"
headers["Content-Type"] = "application/json"
headers["x-package"] = Bundle.main.bundleIdentifier
headers["x-platform"] = "ios"
headers["x-channel"] = "ios"
headers["x-mobile-brand"] = "ios"
headers["x-app-id"] = "10057"
headers["x-version"] = kAppShortVersion
headers["x-device-id"] = ApiManager.getMD5ID()
//
var systemInfo = utsname()
uname(&systemInfo)
let platform = withUnsafePointer(to: &systemInfo.machine.0) { ptr in
return String(cString: ptr)
}
headers["x-mobile-model"] = platform
if let loginToken = Defaults[\.loginToken] {
headers["x-token"] = loginToken
}
return headers
}
// MARK: -
private func handleResult(_ result: Result<Response, MoyaError>, handle: Bool) -> Result<Response, MoyaError>? {
DLToast.dismiss()
switch result {
case let .success(response):
//
let decryptedData = ApiManager.decryptIfNeeded(response.data)
// responsejson
let json = JSON(decryptedData ?? response.data)
print("============== decrypt ====================")
print(json)
let code = json["code"].int
let message = json["message"].string
let combineMessage = message ?? "请检查网络连接"
// code
switch code {
case GatewayStatusCode.success.rawValue:
// Response
if let decrypted = decryptedData {
let decryptedResponse = Response(statusCode: response.statusCode,
data: decrypted,
request: response.request, response: response.response)
return .success(decryptedResponse)
}
return result
// case GatewayStatusCode.outdateVersion.rawValue: //
// handleOutdateVersion(message)
case GatewayStatusCode.userLoginExpair.rawValue: // token
handleTokenExpired(msg: message)
case GatewayStatusCode.noAuthority.rawValue: // 退
handlePopView(message)
default:
///
let code = GatewayStatusCode(rawValue: code ?? -9999) ?? .unknownError
if code == .unknownError, handle {
DLToast.show(text: combineMessage)
}
}
return .failure(handleError(with: code, domain: "Data Error", message: combineMessage, data: response))
case let .failure(error):
let message = error.gatewayMessage ?? "请检查网络连接"
if error.innerError?.code == NSURLErrorCancelled {
//
LogInfo("cancel response: error: \(error.localizedDescription)")
} else if handle {
DLToast.show(text: message)
}
let innerError = error.innerError ?? error as NSError
return .failure(handleError(with: innerError.code, domain: innerError.domain, message: message))
}
}
private func handleError(with code: Int?,
domain: String,
message: String,
isShowTip: Bool = true,
data: Response? = nil) -> MoyaError {
//
let responseError = NSError(domain: domain,
code: code ?? -999999,
userInfo: [NSLocalizedDescriptionKey: message,
"isShowTip": isShowTip])
let error = MoyaError.underlying(responseError, data)
return error
}
// MARK: - Token
private func handleTokenExpired(msg: String?) {
MainAsync {
AppContextManager.shared.deleteAccount()
// IMServiceManager.shared.logout()
DLToast.showError(text: msg ?? "登录失效,请重新登录!") {
// AppDelegate.shared.showMainViewController()
}
}
}
// MARK: - (退)
private func handlePopView(_ msg: String?) {
MainAsync {
DLToast.showInfo(text: msg ?? "Error...") {
guard let viewController = UIViewController.currentViewController() else { return }
viewController.navigationController?.popViewController(animated: true)
}
}
}
}
extension ApiManager {
// MARK: - AES-256-CBC
private static let jieMiKey = "0b0d7962d67a76f00cf9fe0eec0061c2"
private static let jieMiIV = String(jieMiKey.prefix(16))
/// encrypt == 1 data JSON Data
class func decryptIfNeeded(_ responseData: Data) -> Data? {
guard let json = try? JSONSerialization.jsonObject(with: responseData) as? [String: Any],
let encrypt = json["encrypt"] as? Int,
encrypt == 1,
let encryptedString = json["data"] as? String,
let decryptedString = aes256CBCDecrypt(encryptedString, key: jieMiKey, iv: jieMiIV),
let decryptedData = decryptedString.data(using: .utf8),
let decryptedJSON = try? JSONSerialization.jsonObject(with: decryptedData) as? [String: Any]
else { return nil }
return try? JSONSerialization.data(withJSONObject: decryptedJSON)
}
private class func aes256CBCDecrypt(_ base64String: String, key: String, iv: String) -> String? {
guard let data = Data(base64Encoded: base64String),
let keyData = key.data(using: .utf8),
let ivData = iv.data(using: .utf8) else { return nil }
let bufferSize = data.count + kCCBlockSizeAES128
var buffer = [UInt8](repeating: 0, count: bufferSize)
var numBytesDecrypted = 0
let status = keyData.withUnsafeBytes { keyBytes in
ivData.withUnsafeBytes { ivBytes in
data.withUnsafeBytes { dataBytes in
CCCrypt(
CCOperation(kCCDecrypt),
CCAlgorithm(kCCAlgorithmAES),
CCOptions(kCCOptionPKCS7Padding),
keyBytes.baseAddress, kCCKeySizeAES256,
ivBytes.baseAddress,
dataBytes.baseAddress, data.count,
&buffer, bufferSize,
&numBytesDecrypted
)
}
}
}
guard status == kCCSuccess else { return nil }
return String(data: Data(bytes: buffer, count: numBytesDecrypted), encoding: .utf8)
}
class func getMD5ID() -> String {
var strback = ""
strback = "\(getFileTime())-\(getSysU())"
if strback.count < 6 {
strback = UIDevice.current.identifierForVendor?.uuidString ?? ""
}
return getMd5_32Bit_String(strback, isUppercase: false)
}
class func getMd5_32Bit_String(_ srcString: String, isUppercase: Bool) -> String {
let cStr = srcString.cString(using: .utf8)
let length = CC_LONG(strlen(cStr!))
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
CC_MD5(cStr, length, &digest)
var result = ""
for i in 0..<Int(CC_MD5_DIGEST_LENGTH) {
result += String(format: "%02x", digest[i])
}
return isUppercase ? result.uppercased() : result
}
class func getFileTime() -> String {
var info = stat()
let result = stat("/var/mobile", &info)
guard result == 0 else {
return ""
}
let time = info.st_birthtimespec
return String(format: "%ld.%09ld", time.tv_sec, time.tv_nsec)
}
class func getSysU() -> String? {
let information = "L3Zhci9tb2JpbGUvTGlicmFyeS9Vc2VyQ29uZmlndXJhdGlvblByb2ZpbGVzL1B1YmxpY0luZm8vTUNNZXRhLnBsaXN0"
guard let data = Data(base64Encoded: information),
let dataString = String(data: data, encoding: .utf8) else {
return nil
}
do {
let fileAttributes = try FileManager.default.attributesOfItem(atPath: dataString)
if let date = fileAttributes[.creationDate] as? Date {
return String(format: "%.6f", date.timeIntervalSince1970)
}
} catch {
print("获取文件属性失败:\(error)")
}
return nil
}
}