
新增Package.swift和Package.resolved文件以支持Swift Package管理,创建API相关文件(API.swift、APICaller.swift、APIConstants.swift、APIEndpoints.swift、APIService.swift、APILogger.swift、APIModels.swift、Integration-Guide.md)以实现API请求管理和网络交互功能,增强项目的功能性和可扩展性。同时更新.gitignore以排除构建文件和临时文件。
138 lines
4.0 KiB
Swift
138 lines
4.0 KiB
Swift
import Foundation
|
||
import ComposableArchitecture
|
||
|
||
// MARK: - HTTP Method
|
||
enum HTTPMethod: String, CaseIterable {
|
||
case GET = "GET"
|
||
case POST = "POST"
|
||
case PUT = "PUT"
|
||
case DELETE = "DELETE"
|
||
case PATCH = "PATCH"
|
||
}
|
||
|
||
// MARK: - API Error Types
|
||
enum APIError: Error, Equatable {
|
||
case invalidURL
|
||
case noData
|
||
case decodingError(String)
|
||
case networkError(String)
|
||
case httpError(statusCode: Int, message: String?)
|
||
case timeout
|
||
case resourceTooLarge
|
||
case unknown(String)
|
||
|
||
var localizedDescription: String {
|
||
switch self {
|
||
case .invalidURL:
|
||
return "无效的 URL"
|
||
case .noData:
|
||
return "没有收到数据"
|
||
case .decodingError(let message):
|
||
return "数据解析失败: \(message)"
|
||
case .networkError(let message):
|
||
return "网络错误: \(message)"
|
||
case .httpError(let statusCode, let message):
|
||
return "HTTP 错误 \(statusCode): \(message ?? "未知错误")"
|
||
case .timeout:
|
||
return "请求超时"
|
||
case .resourceTooLarge:
|
||
return "响应数据过大"
|
||
case .unknown(let message):
|
||
return "未知错误: \(message)"
|
||
}
|
||
}
|
||
}
|
||
|
||
// MARK: - Base Request Parameters
|
||
struct BaseRequest: Codable {
|
||
let acceptLanguage: String
|
||
let os: String = "iOS"
|
||
let osVersion: String
|
||
let ispType: String
|
||
let channel: String = "molistar_enterprise"
|
||
let model: String
|
||
let deviceId: String
|
||
let appVersion: String
|
||
let app: String = "youmi"
|
||
let mcc: String?
|
||
let spType: String?
|
||
let pubSign: String
|
||
|
||
enum CodingKeys: String, CodingKey {
|
||
case acceptLanguage = "Accept-Language"
|
||
case appVersion = "appVersion"
|
||
case os, osVersion, ispType, channel, model, deviceId
|
||
case app, mcc, spType
|
||
case pubSign = "pub_sign"
|
||
}
|
||
|
||
init() {
|
||
// 获取系统首选语言
|
||
self.acceptLanguage = Locale.current.languageCode ?? "en"
|
||
|
||
// 获取系统版本
|
||
self.osVersion = UIDevice.current.systemVersion
|
||
|
||
// 获取设备型号
|
||
self.model = UIDevice.current.model
|
||
|
||
// 生成设备ID (这里使用 identifierForVendor,实际项目中可能需要更稳定的方案)
|
||
self.deviceId = UIDevice.current.identifierForVendor?.uuidString ?? UUID().uuidString
|
||
|
||
// 获取应用版本
|
||
self.appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "1.0.0"
|
||
|
||
// 运营商相关信息(简化处理)
|
||
self.ispType = "65535"
|
||
self.mcc = nil
|
||
self.spType = nil
|
||
|
||
// 生成签名(这里使用时间戳的 MD5,实际项目中需要根据具体签名规则)
|
||
let timestamp = String(Int(Date().timeIntervalSince1970))
|
||
self.pubSign = timestamp.md5()
|
||
}
|
||
}
|
||
|
||
// MARK: - API Request Protocol
|
||
protocol APIRequestProtocol {
|
||
associatedtype Response: Codable
|
||
|
||
var endpoint: String { get }
|
||
var method: HTTPMethod { get }
|
||
var queryParameters: [String: String]? { get }
|
||
var bodyParameters: [String: Any]? { get }
|
||
var headers: [String: String]? { get }
|
||
var timeout: TimeInterval { get }
|
||
var includeBaseParameters: Bool { get }
|
||
}
|
||
|
||
extension APIRequestProtocol {
|
||
var timeout: TimeInterval { 30.0 }
|
||
var includeBaseParameters: Bool { true }
|
||
var headers: [String: String]? { nil }
|
||
}
|
||
|
||
// MARK: - Generic API Response
|
||
struct APIResponse<T: Codable>: Codable {
|
||
let data: T?
|
||
let status: String?
|
||
let message: String?
|
||
let code: Int?
|
||
}
|
||
|
||
// MARK: - String MD5 Extension
|
||
extension String {
|
||
func md5() -> String {
|
||
let data = Data(self.utf8)
|
||
let hash = data.withUnsafeBytes { bytes -> [UInt8] in
|
||
var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
|
||
CC_MD5(bytes.baseAddress, CC_LONG(data.count), &hash)
|
||
return hash
|
||
}
|
||
return hash.map { String(format: "%02x", $0) }.joined()
|
||
}
|
||
}
|
||
|
||
// 需要导入 CommonCrypto
|
||
import CommonCrypto
|