导入 XuXuCheck 工程(iOS 干化学尿液试纸分析 App)
从桌面工程复制而来,作为本仓库的 Xuxucheck/ 子目录。 为控制仓库体积做了两处删减: - 移除 Frameworks/opencv2.xcframework 下的两个 visionOS 切片 (xros-arm64、xros-arm64-simulator,合计约 106 MB),并同步删掉该 xcframework 内 Info.plist 里对应的两条 AvailableLibraries 记录, 只保留 ios-arm64 与 ios-arm64_x86_64-simulator。 - 移除全部 .DS_Store 与 xcuserdata/。 已用 xcodebuild 从本目录完整编译验证:BUILD SUCCEEDED, ProcessXCFramework 以 --platform ios 成功选中框架,产物含 3699 个 cv:: 符号 (OpenCV 确实链入),嵌入 framework 3 个,与移除无用 pod 之后的状态一致。 仓库约 206 MB,其中 OpenCV 203 MB、其余源码与依赖约 3 MB。
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// API.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/6/18.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct API {
|
||||
//MARK: - Singleton
|
||||
static let instance = API()
|
||||
|
||||
|
||||
static let apiVersion = "/v1"
|
||||
static let baseUrl = "https://xuxucheck.com/api"
|
||||
static let imageUrl = "https://xuxucheck.com/image/"
|
||||
|
||||
|
||||
|
||||
|
||||
static let privacy_URL = "https://xuxucheck.com/web/about-us/privacy-policy"
|
||||
static let protocol_URL = "https://xuxucheck.com/web/about-us/user-agreement"
|
||||
static let webAboutUsUrl = "https://xuxucheck.com/web/about-us"
|
||||
static let webColorimetricCardUrl = "https://xuxucheck.com/web/colorimetric-card"
|
||||
static let webCourseUrl = "https://xuxucheck.com/web/tutorial"
|
||||
static let webManualUrl = "https://xuxucheck.com/web/manual"
|
||||
static let webLearning = "https://xuxucheck.com/web/information"
|
||||
static let webKefuUrl = "https://xuxucheck.com/web/question"
|
||||
static let webProductIntroductionUrl = "https://xuxucheck.com/web/product-introduction"
|
||||
|
||||
static let webrecordUrl = "https://xuxucheck.com/web/urinalysis-record/list"
|
||||
static let webrecordDetailUrl = "https://xuxucheck.com/web/urinalysis-record/detail"
|
||||
static let webMemberListUrl = "https://xuxucheck.com/web/member/list"
|
||||
static let webSettingUrl = "https://xuxucheck.com/web/setting"
|
||||
static let webUserQrcodeUrl = "https://xuxucheck.com/web/account/user-code"
|
||||
static let webMyAccountUrl = "https://xuxucheck.com/web/account/info"
|
||||
static let webCameraScanUrl = "https://xuxucheck.com/web/camera-scan"
|
||||
static let webQualityControlUrl = "https://xuxucheck.com/web/quality-control"
|
||||
|
||||
|
||||
static var interface_login = "user/login"
|
||||
static let interface_register = "user/register"
|
||||
static let interface_forgetpwd = "user/forgetpwd"
|
||||
static let interface_verified_code = "verification/send-code"
|
||||
static let interface_family_getself = "user/info"
|
||||
static let interface_result_addrecord = "urinalysis-record/create"
|
||||
static let interface_result_pic = "urinalysis-record/save-img"
|
||||
static let interface_result_longtest = "result/longtest"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
//
|
||||
// APIService.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/6/18.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
import AlamofireObjectMapper
|
||||
|
||||
|
||||
struct XuXuRespError: Error {
|
||||
var code: Int = 0
|
||||
var message: String?
|
||||
}
|
||||
|
||||
|
||||
struct APIService {
|
||||
|
||||
//MARK: - Singleton
|
||||
static let instance = APIService()
|
||||
|
||||
private init(){}
|
||||
|
||||
//MARK: - URL
|
||||
|
||||
|
||||
func userLogin(with username:String,with code:String,with password:String,completion:@escaping (MemberModel?, XuXuRespError?)->()){
|
||||
|
||||
Alamofire.request(Router.interface_login(username,code, password)).responseObject{ (response:DataResponse<MemberModel>) in
|
||||
debugPrint("Alamofire userLogin~~~~ ")
|
||||
|
||||
if let data = response.data{
|
||||
let rawString = String(decoding: data, as: UTF8.self)
|
||||
print(rawString)
|
||||
}
|
||||
|
||||
// dump(response.data)
|
||||
// debugPrint(response.data ?? "")
|
||||
//
|
||||
// print(response.data ?? "")
|
||||
|
||||
|
||||
if let error = response.error{
|
||||
debugPrint(error)
|
||||
|
||||
var err = XuXuRespError()
|
||||
err.code = 10086
|
||||
err.message = "Unknown error"
|
||||
completion(nil,err)
|
||||
|
||||
//completion(nil,error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if let model = response.result.value{
|
||||
//guard let setCookie = response.response?.allHeaderFields["Set-Cookie"] else {return}
|
||||
//Storage.shared.setCookie = setCookie as! String
|
||||
|
||||
if model.code > 0{
|
||||
var err = XuXuRespError()
|
||||
err.code = model.code
|
||||
err.message = model.message
|
||||
completion(nil,err)
|
||||
return
|
||||
}
|
||||
|
||||
completion(model,nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getVCode(with mobile:String,with check:String,with forW:String,completion:@escaping (MemberModel?, XuXuRespError?)->()){
|
||||
|
||||
Alamofire.request(Router.interface_verified_code(mobile, check, forW)).responseObject{ (response:DataResponse<MemberModel>) in
|
||||
debugPrint("Alamofire getVcode~~~~ ")
|
||||
|
||||
//dump(response.data)
|
||||
// if let data = response.data, let utf8Text = String(data: data, encoding: .utf8) {
|
||||
// print("Data: \(utf8Text)")
|
||||
// }
|
||||
|
||||
if let data = response.data{
|
||||
let rawString = String(decoding: data, as: UTF8.self)
|
||||
print(rawString)
|
||||
}
|
||||
|
||||
if let error = response.error{
|
||||
debugPrint(error)
|
||||
var err = XuXuRespError()
|
||||
err.code = 10086
|
||||
err.message = "Unknown error"
|
||||
completion(nil,err)
|
||||
//completion(nil,error)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func userRegister(with username:String,with code:String,with password:String,with confirm_password:String,completion:@escaping (MemberModel?, XuXuRespError?)->()){
|
||||
|
||||
Alamofire.request(Router.interface_register(username, code, password, confirm_password)).responseObject{ (response:DataResponse<MemberModel>) in
|
||||
debugPrint("Alamofire register~~~~ ")
|
||||
|
||||
// dump(response.data)
|
||||
// debugPrint(response.data ?? "")
|
||||
//
|
||||
// print(response.data ?? "")
|
||||
|
||||
if let data = response.data{
|
||||
let rawString = String(decoding: data, as: UTF8.self)
|
||||
print(rawString)
|
||||
}
|
||||
|
||||
if let error = response.error{
|
||||
debugPrint(error)
|
||||
var err = XuXuRespError()
|
||||
err.code = 10086
|
||||
err.message = "Unknown error"
|
||||
completion(nil,err)
|
||||
//completion(nil,error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if let model = response.result.value{
|
||||
//guard let setCookie = response.response?.allHeaderFields["Set-Cookie"] else {return}
|
||||
//Storage.shared.setCookie = setCookie as! String
|
||||
if model.code > 0{
|
||||
var err = XuXuRespError()
|
||||
err.code = model.code
|
||||
err.message = model.message
|
||||
completion(nil,err)
|
||||
return
|
||||
}
|
||||
|
||||
completion(model,nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
func userForgetpwd(with username:String,with code:String,with password:String,with confirm_password:String,completion:@escaping (MemberModel?, XuXuRespError?)->()){
|
||||
|
||||
Alamofire.request(Router.interface_forgetpwd(username, code, password, confirm_password)).responseObject{ (response:DataResponse<MemberModel>) in
|
||||
debugPrint("Alamofire forget~~~~ ")
|
||||
|
||||
// dump(response.data)
|
||||
// debugPrint(response.data ?? "")
|
||||
//
|
||||
// print(response.data ?? "")
|
||||
//
|
||||
if let data = response.data{
|
||||
let rawString = String(decoding: data, as: UTF8.self)
|
||||
print(rawString)
|
||||
}
|
||||
|
||||
if let error = response.error{
|
||||
debugPrint(error)
|
||||
var err = XuXuRespError()
|
||||
err.code = 10086
|
||||
err.message = "Unknown error"
|
||||
completion(nil,err)
|
||||
//completion(nil,error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if let model = response.result.value{
|
||||
//guard let setCookie = response.response?.allHeaderFields["Set-Cookie"] else {return}
|
||||
//Storage.shared.setCookie = setCookie as! String
|
||||
if model.code > 0{
|
||||
var err = XuXuRespError()
|
||||
err.code = model.code
|
||||
err.message = model.message
|
||||
completion(nil,err)
|
||||
return
|
||||
}
|
||||
|
||||
completion(model,nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getSelf(completion:@escaping (MemberModel?, XuXuRespError?)->()){
|
||||
|
||||
Alamofire.request(Router.interface_family_getself).responseObject{ (response:DataResponse<MemberModel>) in
|
||||
debugPrint("Alamofire getself~~~~ ")
|
||||
|
||||
// dump(response.data)
|
||||
// debugPrint(response.data ?? "")
|
||||
//
|
||||
// print(response.data ?? "")
|
||||
|
||||
if let data = response.data{
|
||||
let rawString = String(decoding: data, as: UTF8.self)
|
||||
print(rawString)
|
||||
}
|
||||
|
||||
if let error = response.error{
|
||||
debugPrint(error)
|
||||
var err = XuXuRespError()
|
||||
err.code = 10086
|
||||
err.message = "Unknown error"
|
||||
completion(nil,err)
|
||||
//completion(nil,error)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if let model = response.result.value{
|
||||
|
||||
if model.code > 0{
|
||||
var err = XuXuRespError()
|
||||
err.code = model.code
|
||||
err.message = model.message
|
||||
completion(nil,err)
|
||||
return
|
||||
}
|
||||
|
||||
completion(model,nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func addNewRecord(with paperDesc:[Int],with ResultData:[[[Double]]],completion:@escaping (RecordResultModel?, XuXuRespError?)->()){
|
||||
Alamofire.request(Router.interface_result_addrecord(paperDesc, ResultData)).responseObject{ (response:DataResponse<RecordResultModel>) in
|
||||
debugPrint("Alamofire addNewRecord~~~~ ")
|
||||
|
||||
if let data = response.data{
|
||||
let rawString = String(decoding: data, as: UTF8.self)
|
||||
print(rawString)
|
||||
}
|
||||
|
||||
// dump(response.data)
|
||||
// debugPrint(response.data ?? "")
|
||||
//
|
||||
// print(response.data ?? "")
|
||||
//
|
||||
|
||||
if let error = response.error{
|
||||
debugPrint(error)
|
||||
var err = XuXuRespError()
|
||||
err.code = 10086
|
||||
err.message = "Unknown error"
|
||||
completion(nil,err)
|
||||
//completion(nil,error)
|
||||
return
|
||||
}
|
||||
|
||||
if let model = response.result.value{
|
||||
//guard let setCookie = response.response?.allHeaderFields["Set-Cookie"] else {return}
|
||||
//Storage.shared.setCookie = setCookie as! String
|
||||
if model.code > 0{
|
||||
var err = XuXuRespError()
|
||||
err.code = model.code
|
||||
err.message = model.message
|
||||
completion(nil,err)
|
||||
return
|
||||
}
|
||||
|
||||
completion(model,nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
//
|
||||
// Router.swift
|
||||
// XuXuCheck
|
||||
//
|
||||
// Created by henseycai on 2025/6/18.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
import ObjectMapper
|
||||
|
||||
internal extension APIService{
|
||||
|
||||
enum Router: URLRequestConvertible {
|
||||
case interface_login(String,String,String)
|
||||
case interface_register(String,String,String,String)
|
||||
case interface_forgetpwd(String,String,String,String)
|
||||
case interface_verified_code(String,String,String)
|
||||
case interface_family_getself
|
||||
case interface_result_addrecord([Int],[[[Double]]])
|
||||
case interface_result_pic
|
||||
case interface_result_longtest
|
||||
|
||||
|
||||
var baseUrl: URL {
|
||||
return URL(string: API.baseUrl.appending(API.apiVersion))!
|
||||
}
|
||||
|
||||
var method: HTTPMethod {
|
||||
switch self {
|
||||
case .interface_login: return .post
|
||||
case .interface_register: return .post
|
||||
case .interface_forgetpwd: return .post
|
||||
case .interface_verified_code: return .post
|
||||
case .interface_family_getself: return .post
|
||||
case .interface_result_addrecord: return .post
|
||||
case .interface_result_pic: return .post
|
||||
case .interface_result_longtest: return .post
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var path: String {
|
||||
switch self {
|
||||
case .interface_login(_, _, _): return API.interface_login
|
||||
case .interface_register(_, _, _, _): return API.interface_register
|
||||
case .interface_forgetpwd(_, _, _, _): return API.interface_forgetpwd
|
||||
case .interface_verified_code(_, _, _): return API.interface_verified_code
|
||||
case .interface_family_getself: return API.interface_family_getself
|
||||
case .interface_result_addrecord(_, _): return API.interface_result_addrecord
|
||||
case .interface_result_pic: return API.interface_result_pic
|
||||
case .interface_result_longtest: return API.interface_result_longtest
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var params: [String: Any]? {
|
||||
switch self {
|
||||
case .interface_login(let username,let code, let password):
|
||||
return ["username":username,"code":code,"password":password,"app_version":"4.2.0.2025.0607","system":"iOS","system_version":brandName,"device_model":systemModel,"device_brand":brandName]
|
||||
case .interface_register(let username,let code,let password,let confirm_password):
|
||||
return ["username":username,"code":code,"password":password,"confirm_password":confirm_password,"system":"iOS","system_version":brandName,"device_model":systemModel,"device_brand":brandName]
|
||||
case .interface_forgetpwd(let username,let code,let password,let confirm_password):
|
||||
return ["username":username,"code":code,"password":password,"confirm_password":confirm_password,"system":"iOS","system_version":brandName,"device_model":systemModel,"device_brand":brandName]
|
||||
case .interface_verified_code(let mobile,let check,let forW):
|
||||
return ["keyword":mobile,"check":check,"for":forW]
|
||||
case .interface_family_getself: return ["usertoken":Storage.shared.usertoken]
|
||||
case .interface_result_addrecord(_, _): return nil
|
||||
case .interface_result_pic: return nil
|
||||
case .interface_result_longtest: return nil
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func asURLRequest() throws -> URLRequest {
|
||||
|
||||
let url = baseUrl.appendingPathComponent(path)
|
||||
var request = URLRequest(url: url)
|
||||
request.httpMethod = method.rawValue
|
||||
|
||||
//request.addValue(Storage.shared.$setCookie.wrappedValue, forHTTPHeaderField: "Cookie") //添加cookie
|
||||
//request.httpBody = try JSONSerialization.data(withJSONObject: params,options: [])
|
||||
if(Storage.shared.isLogin){
|
||||
// request.addValue("Authorization", forHTTPHeaderField: "Bearer ".appending(Storage.shared.usertoken))
|
||||
request.setValue("Bearer ".appending(Storage.shared.usertoken), forHTTPHeaderField: "Authorization")
|
||||
}
|
||||
|
||||
|
||||
request.setValue("1", forHTTPHeaderField: "X-Platform")
|
||||
request.setValue(channel, forHTTPHeaderField: "X-Channel")
|
||||
|
||||
let date = Date()
|
||||
let time = Int(date.timeIntervalSince1970)
|
||||
let sign = getSign(time: time)
|
||||
|
||||
request.setValue(String(time), forHTTPHeaderField: "X-Time")
|
||||
request.setValue(sign, forHTTPHeaderField: "X-Sign")
|
||||
request.setValue(TimeZone.autoupdatingCurrent.identifier, forHTTPHeaderField: "X-TimeZone")
|
||||
request.setValue(Locale.current.identifier, forHTTPHeaderField: "X-Locale")
|
||||
|
||||
|
||||
|
||||
switch self {
|
||||
case .interface_login(_, _, _),
|
||||
.interface_register,
|
||||
.interface_forgetpwd,
|
||||
.interface_verified_code,
|
||||
.interface_family_getself,
|
||||
.interface_result_pic,
|
||||
.interface_result_longtest:
|
||||
|
||||
//let encoding = JSONEncoding.default
|
||||
let encoding = URLEncoding.default
|
||||
|
||||
print(request.allHTTPHeaderFields ?? "")
|
||||
print(params ?? "")
|
||||
|
||||
return try encoding.encode(request, with: params)
|
||||
|
||||
case .interface_result_addrecord(let desc, let resData):
|
||||
var recordModel = RecordModel(usertoken: Storage.shared.usertoken, memberID: Storage.shared.member_id,
|
||||
sign: sign, time: time, userid: Storage.shared.userid, color: desc[0], items: desc[1], locator: desc[2], recordType: 0, channel: channel, data: [])
|
||||
|
||||
// var recordModel = RecordModel(usertoken: Storage.shared.usertoken, memberID: Storage.shared.member_id,
|
||||
// sign: sign, time: time, userid: Storage.shared.userid, color: 1, items: 14, locator: 2, recordType: 0, channel: channel, data: [])
|
||||
for i in 0..<resData.count {
|
||||
var data2D = [Datum]()
|
||||
|
||||
for j in 0..<resData[i].count {
|
||||
//let dataItem = Datam()
|
||||
var v = ""
|
||||
for k in 0..<resData[i][j].count {
|
||||
v.append(String(format: "%.1f",resData[i][j][k]))
|
||||
|
||||
if( (k + 1) < resData[i][j].count){
|
||||
v.append(",")
|
||||
}
|
||||
}
|
||||
data2D.append(Datum(i: j, v:v))
|
||||
}
|
||||
recordModel.data.append(data2D)
|
||||
}
|
||||
|
||||
var jsonParameters: Parameters!
|
||||
jsonParameters = try encodeJson(recordModel)
|
||||
let encoding = JSONEncoding.default
|
||||
|
||||
|
||||
return try encoding.encode(request, withJSONObject: jsonParameters)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func encodeJson<Body: Encodable>(_ body: Body) throws -> Parameters {
|
||||
var parameters: Parameters!
|
||||
let encoder = JSONEncoder()
|
||||
encoder.keyEncodingStrategy = .convertToSnakeCase
|
||||
|
||||
do {
|
||||
let data = try encoder.encode(body)
|
||||
parameters = try JSONSerialization.jsonObject(with: data) as? Parameters ?? Parameters()
|
||||
} catch {
|
||||
throw error
|
||||
}
|
||||
|
||||
return parameters
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user