导入 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:
2026-09-23 14:17:31 +08:00
commit d6aeede2bc
901 changed files with 327267 additions and 0 deletions
+59
View File
@@ -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"
}
+282
View File
@@ -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
}
}
}
}
+175
View File
@@ -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
}
}
}