qingqiu chegngong
This commit is contained in:
4
Podfile
4
Podfile
@@ -15,6 +15,10 @@ target 'yinmeng-ios' do
|
||||
pod 'Reusable'
|
||||
#约束
|
||||
pod 'SnapKit', '~> 5.6.0'
|
||||
#获取设备信息
|
||||
pod 'DeviceKit', '~> 4.0'
|
||||
|
||||
pod "NSObject+Rx"
|
||||
# Pods for yinmeng-ios
|
||||
|
||||
end
|
||||
|
15
Podfile.lock
15
Podfile.lock
@@ -1,5 +1,6 @@
|
||||
PODS:
|
||||
- Alamofire (5.7.1)
|
||||
- Alamofire (5.8.1)
|
||||
- DeviceKit (4.9.0)
|
||||
- HandyJSON (5.0.2)
|
||||
- Kingfisher (7.10.2)
|
||||
- MBProgressHUD (1.2.0)
|
||||
@@ -7,6 +8,8 @@ PODS:
|
||||
- Moya/Core (= 15.0.0)
|
||||
- Moya/Core (15.0.0):
|
||||
- Alamofire (~> 5.0)
|
||||
- "NSObject+Rx (5.2.2)":
|
||||
- RxSwift (~> 6.2)
|
||||
- Reusable (4.1.2):
|
||||
- Reusable/Storyboard (= 4.1.2)
|
||||
- Reusable/View (= 4.1.2)
|
||||
@@ -21,10 +24,12 @@ PODS:
|
||||
- SnapKit (5.6.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- DeviceKit (~> 4.0)
|
||||
- HandyJSON
|
||||
- Kingfisher
|
||||
- MBProgressHUD
|
||||
- Moya
|
||||
- "NSObject+Rx"
|
||||
- Reusable
|
||||
- RxCocoa
|
||||
- RxSwift
|
||||
@@ -33,10 +38,12 @@ DEPENDENCIES:
|
||||
SPEC REPOS:
|
||||
https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git:
|
||||
- Alamofire
|
||||
- DeviceKit
|
||||
- HandyJSON
|
||||
- Kingfisher
|
||||
- MBProgressHUD
|
||||
- Moya
|
||||
- "NSObject+Rx"
|
||||
- Reusable
|
||||
- RxCocoa
|
||||
- RxRelay
|
||||
@@ -44,17 +51,19 @@ SPEC REPOS:
|
||||
- SnapKit
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: 0123a34370cb170936ae79a8df46cc62b2edeb88
|
||||
Alamofire: 3ca42e259043ee0dc5c0cdd76c4bc568b8e42af7
|
||||
DeviceKit: 847709bf70b78fd9ab765bd571fb9f5f815c3fc1
|
||||
HandyJSON: 9e4e236f5d2dbefad5155a77417bbea438201c03
|
||||
Kingfisher: 99edc495d3b7607e6425f0d6f6847b2abd6d716d
|
||||
MBProgressHUD: 3ee5efcc380f6a79a7cc9b363dd669c5e1ae7406
|
||||
Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
|
||||
"NSObject+Rx": 61cf1f7306a73dcef8b36649198af0813ec18dfd
|
||||
Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136
|
||||
RxCocoa: 94f817b71c07517321eb4f9ad299112ca8af743b
|
||||
RxRelay: 1de1523e604c72b6c68feadedd1af3b1b4d0ecbd
|
||||
RxSwift: 5710a9e6b17f3c3d6e40d6e559b9fa1e813b2ef8
|
||||
SnapKit: e01d52ebb8ddbc333eefe2132acf85c8227d9c25
|
||||
|
||||
PODFILE CHECKSUM: e291658151a1fcada5c9dd297587942ae9475225
|
||||
PODFILE CHECKSUM: c70d2998947e71f4b799d573fbe428797987a5b9
|
||||
|
||||
COCOAPODS: 1.12.1
|
||||
|
45
Pods/Alamofire/README.md
generated
45
Pods/Alamofire/README.md
generated
@@ -1,11 +1,10 @@
|
||||

|
||||
|
||||
[](https://img.shields.io/badge/Swift-5.5_5.6_5.7_5.8-Orange?style=flat-square)
|
||||
[](https://img.shields.io/badge/Platforms-macOS_iOS_tvOS_watchOS_Linux_Windows-Green?style=flat-square)
|
||||
[](https://img.shields.io/badge/Swift-5.6_5.7_5.8_5.9-Orange?style=flat-square)
|
||||
[](https://img.shields.io/badge/Platforms-macOS_iOS_tvOS_watchOS_vision_OS_Linux_Windows_Android-Green?style=flat-square)
|
||||
[](https://img.shields.io/cocoapods/v/Alamofire.svg)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](https://img.shields.io/badge/Swift_Package_Manager-compatible-orange?style=flat-square)
|
||||
[](https://twitter.com/AlamofireSF)
|
||||
[](https://forums.swift.org/c/related-projects/alamofire/37)
|
||||
|
||||
Alamofire is an HTTP networking library written in Swift.
|
||||
@@ -52,6 +51,33 @@ Alamofire is an HTTP networking library written in Swift.
|
||||
- [x] Comprehensive Unit and Integration Test Coverage
|
||||
- [x] [Complete Documentation](https://alamofire.github.io/Alamofire)
|
||||
|
||||
## Write Requests Fast!
|
||||
|
||||
Alamofire's compact syntax and extensive feature set allow requests with powerful features like automatic retry to be written in just a few lines of code.
|
||||
|
||||
```swift
|
||||
// Automatic String to URL conversion, Swift concurrency support, and automatic retry.
|
||||
let response = await AF.request("https://httpbin.org/get", interceptor: .retryPolicy)
|
||||
// Automatic HTTP Basic Auth.
|
||||
.authenticate(username: "user", password: "pass")
|
||||
// Caching customization.
|
||||
.cacheResponse(using: .cache)
|
||||
// Redirect customization.
|
||||
.redirect(using: .follow)
|
||||
// Validate response code and Content-Type.
|
||||
.validate()
|
||||
// Produce a cURL command for the request.
|
||||
.cURLDescription { description in
|
||||
print(description)
|
||||
}
|
||||
// Automatic Decodable support with background parsing.
|
||||
.serializingDecodable(DecodableType.self)
|
||||
// Await the full response with metrics and a parsed body.
|
||||
.response
|
||||
// Detailed response description for easy debugging.
|
||||
debugPrint(response)
|
||||
```
|
||||
|
||||
## Component Libraries
|
||||
|
||||
In order to keep Alamofire focused specifically on core networking implementations, additional component libraries have been created by the [Alamofire Software Foundation](https://github.com/Alamofire/Foundation) to bring additional functionality to the Alamofire ecosystem.
|
||||
@@ -62,20 +88,22 @@ In order to keep Alamofire focused specifically on core networking implementatio
|
||||
## Requirements
|
||||
|
||||
| Platform | Minimum Swift Version | Installation | Status |
|
||||
| --- | --- | --- | --- |
|
||||
| iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ | 5.5 | [CocoaPods](#cocoapods), [Carthage](#carthage), [Swift Package Manager](#swift-package-manager), [Manual](#manually) | Fully Tested |
|
||||
| ---------------------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------ |
|
||||
| iOS 10.0+ / macOS 10.12+ / tvOS 10.0+ / watchOS 3.0+ | 5.6 | [CocoaPods](#cocoapods), [Carthage](#carthage), [Swift Package Manager](#swift-package-manager), [Manual](#manually) | Fully Tested |
|
||||
| Linux | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported |
|
||||
| Windows | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported |
|
||||
| Android | Latest Only | [Swift Package Manager](#swift-package-manager) | Building But Unsupported |
|
||||
|
||||
#### Known Issues on Linux and Windows
|
||||
|
||||
Alamofire builds on Linux and Windows but there are missing features and many issues in the underlying `swift-corelibs-foundation` that prevent full functionality and may cause crashes. These include:
|
||||
Alamofire builds on Linux, Windows, and Android but there are missing features and many issues in the underlying `swift-corelibs-foundation` that prevent full functionality and may cause crashes. These include:
|
||||
|
||||
- `ServerTrustManager` and associated certificate functionality is unavailable, so there is no certificate pinning and no client certificate support.
|
||||
- Various methods of HTTP authentication may crash, including HTTP Basic and HTTP Digest. Crashes may occur if responses contain server challenges.
|
||||
- Cache control through `CachedResponseHandler` and associated APIs is unavailable, as the underlying delegate methods aren't called.
|
||||
- `URLSessionTaskMetrics` are never gathered.
|
||||
|
||||
Due to these issues, Alamofire is unsupported on Linux and Windows. Please report any crashes to the [Swift bug reporter](https://bugs.swift.org).
|
||||
Due to these issues, Alamofire is unsupported on Linux, Windows, and Android. Please report any crashes to the [Swift bug reporter](https://bugs.swift.org).
|
||||
|
||||
## Migration Guides
|
||||
|
||||
@@ -85,6 +113,7 @@ Due to these issues, Alamofire is unsupported on Linux and Windows. Please repor
|
||||
- [Alamofire 2.0 Migration Guide](https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%202.0%20Migration%20Guide.md)
|
||||
|
||||
## Communication
|
||||
|
||||
- If you **need help with making network requests** using Alamofire, use [Stack Overflow](https://stackoverflow.com/questions/tagged/alamofire) and tag `alamofire`.
|
||||
- If you need to **find or understand an API**, check [our documentation](http://alamofire.github.io/Alamofire/) or [Apple's documentation for `URLSession`](https://developer.apple.com/documentation/foundation/url_loading_system), on top of which Alamofire is built.
|
||||
- If you need **help with an Alamofire feature**, use [our forum on swift.org](https://forums.swift.org/c/related-projects/alamofire).
|
||||
@@ -118,7 +147,7 @@ Once you have your Swift package set up, adding Alamofire as a dependency is as
|
||||
|
||||
```swift
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.6.4"))
|
||||
.package(url: "https://github.com/Alamofire/Alamofire.git", .upToNextMajor(from: "5.8.1"))
|
||||
]
|
||||
```
|
||||
|
||||
|
20
Pods/Alamofire/Source/AFError.swift
generated
20
Pods/Alamofire/Source/AFError.swift
generated
@@ -24,6 +24,10 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
#if canImport(Security)
|
||||
import Security
|
||||
#endif
|
||||
|
||||
/// `AFError` is the error type returned by Alamofire. It encompasses a few different types of errors, each with
|
||||
/// their own associated reasons.
|
||||
public enum AFError: Error {
|
||||
@@ -129,7 +133,7 @@ public enum AFError: Error {
|
||||
case invalidEmptyResponse(type: String)
|
||||
}
|
||||
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
/// Underlying reason a server trust evaluation error occurred.
|
||||
public enum ServerTrustFailureReason {
|
||||
/// The output of a server trust evaluation.
|
||||
@@ -211,7 +215,7 @@ public enum AFError: Error {
|
||||
case responseValidationFailed(reason: ResponseValidationFailureReason)
|
||||
/// Response serialization failed.
|
||||
case responseSerializationFailed(reason: ResponseSerializationFailureReason)
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
/// `ServerTrustEvaluating` instance threw an error during trust evaluation.
|
||||
case serverTrustEvaluationFailed(reason: ServerTrustFailureReason)
|
||||
#endif
|
||||
@@ -314,7 +318,7 @@ extension AFError {
|
||||
return false
|
||||
}
|
||||
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
/// Returns whether the instance is `.serverTrustEvaluationFailed`. When `true`, the `underlyingError` property will
|
||||
/// contain the associated value.
|
||||
public var isServerTrustEvaluationError: Bool {
|
||||
@@ -393,7 +397,7 @@ extension AFError {
|
||||
return reason.underlyingError
|
||||
case let .responseSerializationFailed(reason):
|
||||
return reason.underlyingError
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
case let .serverTrustEvaluationFailed(reason):
|
||||
return reason.underlyingError
|
||||
#endif
|
||||
@@ -451,7 +455,7 @@ extension AFError {
|
||||
return destination
|
||||
}
|
||||
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
/// The download resume data of any underlying network error. Only produced by `DownloadRequest`s.
|
||||
public var downloadResumeData: Data? {
|
||||
(underlyingError as? URLError)?.userInfo[NSURLSessionDownloadTaskResumeData] as? Data
|
||||
@@ -610,7 +614,7 @@ extension AFError.ResponseSerializationFailureReason {
|
||||
}
|
||||
}
|
||||
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
extension AFError.ServerTrustFailureReason {
|
||||
var output: AFError.ServerTrustFailureReason.Output? {
|
||||
switch self {
|
||||
@@ -688,7 +692,7 @@ extension AFError: LocalizedError {
|
||||
"""
|
||||
case let .sessionInvalidated(error):
|
||||
return "Session was invalidated with error: \(error?.localizedDescription ?? "No description.")"
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
case let .serverTrustEvaluationFailed(reason):
|
||||
return "Server trust evaluation failed due to reason: \(reason.localizedDescription)"
|
||||
#endif
|
||||
@@ -822,7 +826,7 @@ extension AFError.ResponseValidationFailureReason {
|
||||
}
|
||||
}
|
||||
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
extension AFError.ServerTrustFailureReason {
|
||||
var localizedDescription: String {
|
||||
switch self {
|
||||
|
2
Pods/Alamofire/Source/Alamofire.swift
generated
2
Pods/Alamofire/Source/Alamofire.swift
generated
@@ -37,4 +37,4 @@ import Foundation
|
||||
public let AF = Session.default
|
||||
|
||||
/// Current Alamofire version. Necessary since SPM doesn't use dynamic libraries. Plus this will be more accurate.
|
||||
let version = "5.7.1"
|
||||
let version = "5.8.0"
|
||||
|
@@ -217,15 +217,14 @@ public class AuthenticationInterceptor<AuthenticatorType>: RequestInterceptor wh
|
||||
|
||||
/// The `Credential` used to authenticate requests.
|
||||
public var credential: Credential? {
|
||||
get { $mutableState.credential }
|
||||
set { $mutableState.credential = newValue }
|
||||
get { mutableState.credential }
|
||||
set { mutableState.credential = newValue }
|
||||
}
|
||||
|
||||
let authenticator: AuthenticatorType
|
||||
let queue = DispatchQueue(label: "org.alamofire.authentication.inspector")
|
||||
|
||||
@Protected
|
||||
private var mutableState: MutableState
|
||||
private let mutableState: Protected<MutableState>
|
||||
|
||||
// MARK: Initialization
|
||||
|
||||
@@ -242,13 +241,13 @@ public class AuthenticationInterceptor<AuthenticatorType>: RequestInterceptor wh
|
||||
credential: Credential? = nil,
|
||||
refreshWindow: RefreshWindow? = RefreshWindow()) {
|
||||
self.authenticator = authenticator
|
||||
mutableState = MutableState(credential: credential, refreshWindow: refreshWindow)
|
||||
mutableState = Protected(MutableState(credential: credential, refreshWindow: refreshWindow))
|
||||
}
|
||||
|
||||
// MARK: Adapt
|
||||
|
||||
public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
|
||||
let adaptResult: AdaptResult = $mutableState.write { mutableState in
|
||||
let adaptResult: AdaptResult = mutableState.write { mutableState in
|
||||
// Queue the adapt operation if a refresh is already in place.
|
||||
guard !mutableState.isRefreshing else {
|
||||
let operation = AdaptOperation(urlRequest: urlRequest, session: session, completion: completion)
|
||||
@@ -316,7 +315,7 @@ public class AuthenticationInterceptor<AuthenticatorType>: RequestInterceptor wh
|
||||
return
|
||||
}
|
||||
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
mutableState.requestsToRetry.append(completion)
|
||||
|
||||
guard !mutableState.isRefreshing else { return }
|
||||
@@ -340,7 +339,7 @@ public class AuthenticationInterceptor<AuthenticatorType>: RequestInterceptor wh
|
||||
// Dispatch to queue to hop out of the lock in case authenticator.refresh is implemented synchronously.
|
||||
queue.async {
|
||||
self.authenticator.refresh(credential, for: session) { result in
|
||||
self.$mutableState.write { mutableState in
|
||||
self.mutableState.write { mutableState in
|
||||
switch result {
|
||||
case let .success(credential):
|
||||
self.handleRefreshSuccess(credential, insideLock: &mutableState)
|
||||
|
35
Pods/Alamofire/Source/Combine.swift
generated
35
Pods/Alamofire/Source/Combine.swift
generated
@@ -22,7 +22,7 @@
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if !((os(iOS) && (arch(i386) || arch(arm))) || os(Windows) || os(Linux))
|
||||
#if !((os(iOS) && (arch(i386) || arch(arm))) || os(Windows) || os(Linux) || os(Android))
|
||||
|
||||
import Combine
|
||||
import Dispatch
|
||||
@@ -91,23 +91,22 @@ public struct DataResponsePublisher<Value>: Publisher {
|
||||
where Downstream.Input == Output {
|
||||
typealias Failure = Downstream.Failure
|
||||
|
||||
@Protected
|
||||
private var downstream: Downstream?
|
||||
private let downstream: Protected<Downstream?>
|
||||
private let request: DataRequest
|
||||
private let responseHandler: Handler
|
||||
|
||||
init(request: DataRequest, responseHandler: @escaping Handler, downstream: Downstream) {
|
||||
self.request = request
|
||||
self.responseHandler = responseHandler
|
||||
self.downstream = downstream
|
||||
self.downstream = Protected(downstream)
|
||||
}
|
||||
|
||||
func request(_ demand: Subscribers.Demand) {
|
||||
assert(demand > 0)
|
||||
|
||||
guard let downstream = downstream else { return }
|
||||
guard let downstream = downstream.read({ $0 }) else { return }
|
||||
|
||||
self.downstream = nil
|
||||
self.downstream.write(nil)
|
||||
responseHandler { response in
|
||||
_ = downstream.receive(response)
|
||||
downstream.receive(completion: .finished)
|
||||
@@ -116,7 +115,7 @@ public struct DataResponsePublisher<Value>: Publisher {
|
||||
|
||||
func cancel() {
|
||||
request.cancel()
|
||||
downstream = nil
|
||||
downstream.write(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,23 +311,22 @@ public struct DataStreamPublisher<Value>: Publisher {
|
||||
where Downstream.Input == Output {
|
||||
typealias Failure = Downstream.Failure
|
||||
|
||||
@Protected
|
||||
private var downstream: Downstream?
|
||||
private let downstream: Protected<Downstream?>
|
||||
private let request: DataStreamRequest
|
||||
private let streamHandler: Handler
|
||||
|
||||
init(request: DataStreamRequest, streamHandler: @escaping Handler, downstream: Downstream) {
|
||||
self.request = request
|
||||
self.streamHandler = streamHandler
|
||||
self.downstream = downstream
|
||||
self.downstream = Protected(downstream)
|
||||
}
|
||||
|
||||
func request(_ demand: Subscribers.Demand) {
|
||||
assert(demand > 0)
|
||||
|
||||
guard let downstream = downstream else { return }
|
||||
guard let downstream = downstream.read({ $0 }) else { return }
|
||||
|
||||
self.downstream = nil
|
||||
self.downstream.write(nil)
|
||||
streamHandler { stream in
|
||||
_ = downstream.receive(stream)
|
||||
if case .complete = stream.event {
|
||||
@@ -339,7 +337,7 @@ public struct DataStreamPublisher<Value>: Publisher {
|
||||
|
||||
func cancel() {
|
||||
request.cancel()
|
||||
downstream = nil
|
||||
downstream.write(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -462,23 +460,22 @@ public struct DownloadResponsePublisher<Value>: Publisher {
|
||||
where Downstream.Input == Output {
|
||||
typealias Failure = Downstream.Failure
|
||||
|
||||
@Protected
|
||||
private var downstream: Downstream?
|
||||
private let downstream: Protected<Downstream?>
|
||||
private let request: DownloadRequest
|
||||
private let responseHandler: Handler
|
||||
|
||||
init(request: DownloadRequest, responseHandler: @escaping Handler, downstream: Downstream) {
|
||||
self.request = request
|
||||
self.responseHandler = responseHandler
|
||||
self.downstream = downstream
|
||||
self.downstream = Protected(downstream)
|
||||
}
|
||||
|
||||
func request(_ demand: Subscribers.Demand) {
|
||||
assert(demand > 0)
|
||||
|
||||
guard let downstream = downstream else { return }
|
||||
guard let downstream = downstream.read({ $0 }) else { return }
|
||||
|
||||
self.downstream = nil
|
||||
self.downstream.write(nil)
|
||||
responseHandler { response in
|
||||
_ = downstream.receive(response)
|
||||
downstream.receive(completion: .finished)
|
||||
@@ -487,7 +484,7 @@ public struct DownloadResponsePublisher<Value>: Publisher {
|
||||
|
||||
func cancel() {
|
||||
request.cancel()
|
||||
downstream = nil
|
||||
downstream.write(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
200
Pods/Alamofire/Source/Concurrency.swift
generated
200
Pods/Alamofire/Source/Concurrency.swift
generated
@@ -37,7 +37,7 @@ extension Request {
|
||||
/// - Returns: The `StreamOf<Progress>`.
|
||||
public func uploadProgress(bufferingPolicy: StreamOf<Progress>.BufferingPolicy = .unbounded) -> StreamOf<Progress> {
|
||||
stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
|
||||
uploadProgress(queue: .singleEventQueue) { progress in
|
||||
uploadProgress(queue: underlyingQueue) { progress in
|
||||
continuation.yield(progress)
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ extension Request {
|
||||
/// - Returns: The `StreamOf<Progress>`.
|
||||
public func downloadProgress(bufferingPolicy: StreamOf<Progress>.BufferingPolicy = .unbounded) -> StreamOf<Progress> {
|
||||
stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
|
||||
downloadProgress(queue: .singleEventQueue) { progress in
|
||||
downloadProgress(queue: underlyingQueue) { progress in
|
||||
continuation.yield(progress)
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,7 @@ extension Request {
|
||||
/// - Returns: The `StreamOf<URLRequest>`.
|
||||
public func urlRequests(bufferingPolicy: StreamOf<URLRequest>.BufferingPolicy = .unbounded) -> StreamOf<URLRequest> {
|
||||
stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
|
||||
onURLRequestCreation(on: .singleEventQueue) { request in
|
||||
onURLRequestCreation(on: underlyingQueue) { request in
|
||||
continuation.yield(request)
|
||||
}
|
||||
}
|
||||
@@ -76,7 +76,7 @@ extension Request {
|
||||
/// - Returns: The `StreamOf<URLSessionTask>`.
|
||||
public func urlSessionTasks(bufferingPolicy: StreamOf<URLSessionTask>.BufferingPolicy = .unbounded) -> StreamOf<URLSessionTask> {
|
||||
stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
|
||||
onURLSessionTaskCreation(on: .singleEventQueue) { task in
|
||||
onURLSessionTaskCreation(on: underlyingQueue) { task in
|
||||
continuation.yield(task)
|
||||
}
|
||||
}
|
||||
@@ -89,13 +89,13 @@ extension Request {
|
||||
/// - Returns: The `StreamOf<String>`.
|
||||
public func cURLDescriptions(bufferingPolicy: StreamOf<String>.BufferingPolicy = .unbounded) -> StreamOf<String> {
|
||||
stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
|
||||
cURLDescription(on: .singleEventQueue) { description in
|
||||
cURLDescription(on: underlyingQueue) { description in
|
||||
continuation.yield(description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func stream<T>(of type: T.Type = T.self,
|
||||
fileprivate func stream<T>(of type: T.Type = T.self,
|
||||
bufferingPolicy: StreamOf<T>.BufferingPolicy = .unbounded,
|
||||
yielder: @escaping (StreamOf<T>.Continuation) -> Void) -> StreamOf<T> {
|
||||
StreamOf<T>(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
|
||||
@@ -168,18 +168,83 @@ public struct DataTask<Value> {
|
||||
|
||||
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||
extension DataRequest {
|
||||
/// Creates a `StreamOf<HTTPURLResponse>` for the instance's responses.
|
||||
///
|
||||
/// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
|
||||
///
|
||||
/// - Returns: The `StreamOf<HTTPURLResponse>`.
|
||||
public func httpResponses(bufferingPolicy: StreamOf<HTTPURLResponse>.BufferingPolicy = .unbounded) -> StreamOf<HTTPURLResponse> {
|
||||
stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
|
||||
onHTTPResponse(on: underlyingQueue) { response in
|
||||
continuation.yield(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=5.7)
|
||||
/// Sets an async closure returning a `Request.ResponseDisposition`, called whenever the `DataRequest` produces an
|
||||
/// `HTTPURLResponse`.
|
||||
///
|
||||
/// - Note: Most requests will only produce a single response for each outgoing attempt (initial + retries).
|
||||
/// However, some types of response may trigger multiple `HTTPURLResponse`s, such as multipart streams,
|
||||
/// where responses after the first will contain the part headers.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - handler: Async closure executed when a new `HTTPURLResponse` is received and returning a
|
||||
/// `ResponseDisposition` value. This value determines whether to continue the request or cancel it as
|
||||
/// if `cancel()` had been called on the instance. Note, this closure is called on an arbitrary thread,
|
||||
/// so any synchronous calls in it will execute in that context.
|
||||
///
|
||||
/// - Returns: The instance.
|
||||
@_disfavoredOverload
|
||||
@discardableResult
|
||||
public func onHTTPResponse(
|
||||
perform handler: @escaping @Sendable (_ response: HTTPURLResponse) async -> ResponseDisposition
|
||||
) -> Self {
|
||||
onHTTPResponse(on: underlyingQueue) { response, completionHandler in
|
||||
Task {
|
||||
let disposition = await handler(response)
|
||||
completionHandler(disposition)
|
||||
}
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
/// Sets an async closure called whenever the `DataRequest` produces an `HTTPURLResponse`.
|
||||
///
|
||||
/// - Note: Most requests will only produce a single response for each outgoing attempt (initial + retries).
|
||||
/// However, some types of response may trigger multiple `HTTPURLResponse`s, such as multipart streams,
|
||||
/// where responses after the first will contain the part headers.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - handler: Async closure executed when a new `HTTPURLResponse` is received. Note, this closure is called on an
|
||||
/// arbitrary thread, so any synchronous calls in it will execute in that context.
|
||||
///
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func onHTTPResponse(perform handler: @escaping @Sendable (_ response: HTTPURLResponse) async -> Void) -> Self {
|
||||
onHTTPResponse { response in
|
||||
await handler(response)
|
||||
return .allow
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Creates a `DataTask` to `await` a `Data` value.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DataTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
/// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before completion.
|
||||
/// - emptyResponseCodes: HTTP response codes for which empty responses are allowed. `[204, 205]` by default.
|
||||
/// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default.
|
||||
///
|
||||
/// - Returns: The `DataTask`.
|
||||
public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
|
||||
public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = true,
|
||||
dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
|
||||
emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
|
||||
emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods) -> DataTask<Data> {
|
||||
@@ -195,7 +260,7 @@ extension DataRequest {
|
||||
/// - type: `Decodable` type to decode from response data.
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DataTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
/// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer.
|
||||
/// `PassthroughPreprocessor()` by default.
|
||||
/// - decoder: `DataDecoder` to use to decode the response. `JSONDecoder()` by default.
|
||||
@@ -204,7 +269,7 @@ extension DataRequest {
|
||||
///
|
||||
/// - Returns: The `DataTask`.
|
||||
public func serializingDecodable<Value: Decodable>(_ type: Value.Type = Value.self,
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = true,
|
||||
dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<Value>.defaultDataPreprocessor,
|
||||
decoder: DataDecoder = JSONDecoder(),
|
||||
emptyResponseCodes: Set<Int> = DecodableResponseSerializer<Value>.defaultEmptyResponseCodes,
|
||||
@@ -221,7 +286,7 @@ extension DataRequest {
|
||||
/// - Parameters:
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DataTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
/// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer.
|
||||
/// `PassthroughPreprocessor()` by default.
|
||||
/// - encoding: `String.Encoding` to use during serialization. Defaults to `nil`, in which case
|
||||
@@ -231,7 +296,7 @@ extension DataRequest {
|
||||
/// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default.
|
||||
///
|
||||
/// - Returns: The `DataTask`.
|
||||
public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
|
||||
public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = true,
|
||||
dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
|
||||
encoding: String.Encoding? = nil,
|
||||
emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
|
||||
@@ -249,14 +314,14 @@ extension DataRequest {
|
||||
/// - serializer: `ResponseSerializer` responsible for serializing the request, response, and data.
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DataTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
///
|
||||
/// - Returns: The `DataTask`.
|
||||
public func serializingResponse<Serializer: ResponseSerializer>(using serializer: Serializer,
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = false)
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = true)
|
||||
-> DataTask<Serializer.SerializedObject> {
|
||||
dataTask(automaticallyCancelling: shouldAutomaticallyCancel) {
|
||||
self.response(queue: .singleEventQueue,
|
||||
dataTask(automaticallyCancelling: shouldAutomaticallyCancel) { [self] in
|
||||
response(queue: underlyingQueue,
|
||||
responseSerializer: serializer,
|
||||
completionHandler: $0)
|
||||
}
|
||||
@@ -269,14 +334,14 @@ extension DataRequest {
|
||||
/// response, and data.
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DataTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
///
|
||||
/// - Returns: The `DataTask`.
|
||||
public func serializingResponse<Serializer: DataResponseSerializerProtocol>(using serializer: Serializer,
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = false)
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = true)
|
||||
-> DataTask<Serializer.SerializedObject> {
|
||||
dataTask(automaticallyCancelling: shouldAutomaticallyCancel) {
|
||||
self.response(queue: .singleEventQueue,
|
||||
dataTask(automaticallyCancelling: shouldAutomaticallyCancel) { [self] in
|
||||
response(queue: underlyingQueue,
|
||||
responseSerializer: serializer,
|
||||
completionHandler: $0)
|
||||
}
|
||||
@@ -366,13 +431,13 @@ extension DownloadRequest {
|
||||
/// - Parameters:
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
/// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before completion.
|
||||
/// - emptyResponseCodes: HTTP response codes for which empty responses are allowed. `[204, 205]` by default.
|
||||
/// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default.
|
||||
///
|
||||
/// - Returns: The `DownloadTask`.
|
||||
public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
|
||||
public func serializingData(automaticallyCancelling shouldAutomaticallyCancel: Bool = true,
|
||||
dataPreprocessor: DataPreprocessor = DataResponseSerializer.defaultDataPreprocessor,
|
||||
emptyResponseCodes: Set<Int> = DataResponseSerializer.defaultEmptyResponseCodes,
|
||||
emptyRequestMethods: Set<HTTPMethod> = DataResponseSerializer.defaultEmptyRequestMethods) -> DownloadTask<Data> {
|
||||
@@ -390,7 +455,7 @@ extension DownloadRequest {
|
||||
/// - type: `Decodable` type to decode from response data.
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
/// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the serializer.
|
||||
/// `PassthroughPreprocessor()` by default.
|
||||
/// - decoder: `DataDecoder` to use to decode the response. `JSONDecoder()` by default.
|
||||
@@ -399,7 +464,7 @@ extension DownloadRequest {
|
||||
///
|
||||
/// - Returns: The `DownloadTask`.
|
||||
public func serializingDecodable<Value: Decodable>(_ type: Value.Type = Value.self,
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = true,
|
||||
dataPreprocessor: DataPreprocessor = DecodableResponseSerializer<Value>.defaultDataPreprocessor,
|
||||
decoder: DataDecoder = JSONDecoder(),
|
||||
emptyResponseCodes: Set<Int> = DecodableResponseSerializer<Value>.defaultEmptyResponseCodes,
|
||||
@@ -416,10 +481,10 @@ extension DownloadRequest {
|
||||
/// - Parameters:
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
///
|
||||
/// - Returns: The `DownloadTask`.
|
||||
public func serializingDownloadedFileURL(automaticallyCancelling shouldAutomaticallyCancel: Bool = false) -> DownloadTask<URL> {
|
||||
public func serializingDownloadedFileURL(automaticallyCancelling shouldAutomaticallyCancel: Bool = true) -> DownloadTask<URL> {
|
||||
serializingDownload(using: URLResponseSerializer(),
|
||||
automaticallyCancelling: shouldAutomaticallyCancel)
|
||||
}
|
||||
@@ -429,7 +494,7 @@ extension DownloadRequest {
|
||||
/// - Parameters:
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
/// - dataPreprocessor: `DataPreprocessor` which processes the received `Data` before calling the
|
||||
/// serializer. `PassthroughPreprocessor()` by default.
|
||||
/// - encoding: `String.Encoding` to use during serialization. Defaults to `nil`, in which case
|
||||
@@ -439,7 +504,7 @@ extension DownloadRequest {
|
||||
/// - emptyRequestMethods: `HTTPMethod`s for which empty responses are always valid. `[.head]` by default.
|
||||
///
|
||||
/// - Returns: The `DownloadTask`.
|
||||
public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = false,
|
||||
public func serializingString(automaticallyCancelling shouldAutomaticallyCancel: Bool = true,
|
||||
dataPreprocessor: DataPreprocessor = StringResponseSerializer.defaultDataPreprocessor,
|
||||
encoding: String.Encoding? = nil,
|
||||
emptyResponseCodes: Set<Int> = StringResponseSerializer.defaultEmptyResponseCodes,
|
||||
@@ -457,14 +522,14 @@ extension DownloadRequest {
|
||||
/// - serializer: `ResponseSerializer` responsible for serializing the request, response, and data.
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
///
|
||||
/// - Returns: The `DownloadTask`.
|
||||
public func serializingDownload<Serializer: ResponseSerializer>(using serializer: Serializer,
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = false)
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = true)
|
||||
-> DownloadTask<Serializer.SerializedObject> {
|
||||
downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) {
|
||||
self.response(queue: .singleEventQueue,
|
||||
downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) { [self] in
|
||||
response(queue: underlyingQueue,
|
||||
responseSerializer: serializer,
|
||||
completionHandler: $0)
|
||||
}
|
||||
@@ -478,14 +543,14 @@ extension DownloadRequest {
|
||||
/// response, and data.
|
||||
/// - shouldAutomaticallyCancel: `Bool` determining whether or not the request should be cancelled when the
|
||||
/// enclosing async context is cancelled. Only applies to `DownloadTask`'s async
|
||||
/// properties. `false` by default.
|
||||
/// properties. `true` by default.
|
||||
///
|
||||
/// - Returns: The `DownloadTask`.
|
||||
public func serializingDownload<Serializer: DownloadResponseSerializerProtocol>(using serializer: Serializer,
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = false)
|
||||
automaticallyCancelling shouldAutomaticallyCancel: Bool = true)
|
||||
-> DownloadTask<Serializer.SerializedObject> {
|
||||
downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) {
|
||||
self.response(queue: .singleEventQueue,
|
||||
downloadTask(automaticallyCancelling: shouldAutomaticallyCancel) { [self] in
|
||||
response(queue: underlyingQueue,
|
||||
responseSerializer: serializer,
|
||||
completionHandler: $0)
|
||||
}
|
||||
@@ -625,6 +690,69 @@ public struct DataStreamTask {
|
||||
|
||||
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
|
||||
extension DataStreamRequest {
|
||||
/// Creates a `StreamOf<HTTPURLResponse>` for the instance's responses.
|
||||
///
|
||||
/// - Parameter bufferingPolicy: `BufferingPolicy` that determines the stream's buffering behavior.`.unbounded` by default.
|
||||
///
|
||||
/// - Returns: The `StreamOf<HTTPURLResponse>`.
|
||||
public func httpResponses(bufferingPolicy: StreamOf<HTTPURLResponse>.BufferingPolicy = .unbounded) -> StreamOf<HTTPURLResponse> {
|
||||
stream(bufferingPolicy: bufferingPolicy) { [unowned self] continuation in
|
||||
onHTTPResponse(on: underlyingQueue) { response in
|
||||
continuation.yield(response)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=5.7)
|
||||
/// Sets an async closure returning a `Request.ResponseDisposition`, called whenever the `DataStreamRequest`
|
||||
/// produces an `HTTPURLResponse`.
|
||||
///
|
||||
/// - Note: Most requests will only produce a single response for each outgoing attempt (initial + retries).
|
||||
/// However, some types of response may trigger multiple `HTTPURLResponse`s, such as multipart streams,
|
||||
/// where responses after the first will contain the part headers.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - handler: Async closure executed when a new `HTTPURLResponse` is received and returning a
|
||||
/// `ResponseDisposition` value. This value determines whether to continue the request or cancel it as
|
||||
/// if `cancel()` had been called on the instance. Note, this closure is called on an arbitrary thread,
|
||||
/// so any synchronous calls in it will execute in that context.
|
||||
///
|
||||
/// - Returns: The instance.
|
||||
@_disfavoredOverload
|
||||
@discardableResult
|
||||
public func onHTTPResponse(perform handler: @escaping @Sendable (HTTPURLResponse) async -> ResponseDisposition) -> Self {
|
||||
onHTTPResponse(on: underlyingQueue) { response, completionHandler in
|
||||
Task {
|
||||
let disposition = await handler(response)
|
||||
completionHandler(disposition)
|
||||
}
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
/// Sets an async closure called whenever the `DataStreamRequest` produces an `HTTPURLResponse`.
|
||||
///
|
||||
/// - Note: Most requests will only produce a single response for each outgoing attempt (initial + retries).
|
||||
/// However, some types of response may trigger multiple `HTTPURLResponse`s, such as multipart streams,
|
||||
/// where responses after the first will contain the part headers.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - handler: Async closure executed when a new `HTTPURLResponse` is received. Note, this closure is called on an
|
||||
/// arbitrary thread, so any synchronous calls in it will execute in that context.
|
||||
///
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func onHTTPResponse(perform handler: @escaping @Sendable (HTTPURLResponse) async -> Void) -> Self {
|
||||
onHTTPResponse { response in
|
||||
await handler(response)
|
||||
return .allow
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Creates a `DataStreamTask` used to `await` streams of serialized values.
|
||||
///
|
||||
/// - Returns: The `DataStreamTask`.
|
||||
|
15
Pods/Alamofire/Source/EventMonitor.swift
generated
15
Pods/Alamofire/Source/EventMonitor.swift
generated
@@ -69,6 +69,9 @@ public protocol EventMonitor {
|
||||
|
||||
// MARK: URLSessionDataDelegate Events
|
||||
|
||||
/// Event called during `URLSessionDataDelegate`'s `urlSession(_:dataTask:didReceive:completionHandler:)` method.
|
||||
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse)
|
||||
|
||||
/// Event called during `URLSessionDataDelegate`'s `urlSession(_:dataTask:didReceive:)` method.
|
||||
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
|
||||
|
||||
@@ -244,6 +247,7 @@ extension EventMonitor {
|
||||
didFinishCollecting metrics: URLSessionTaskMetrics) {}
|
||||
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {}
|
||||
public func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) {}
|
||||
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse) {}
|
||||
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {}
|
||||
public func urlSession(_ session: URLSession,
|
||||
dataTask: URLSessionDataTask,
|
||||
@@ -380,6 +384,10 @@ public final class CompositeEventMonitor: EventMonitor {
|
||||
performEvent { $0.urlSession(session, taskIsWaitingForConnectivity: task) }
|
||||
}
|
||||
|
||||
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse) {
|
||||
performEvent { $0.urlSession(session, dataTask: dataTask, didReceive: response) }
|
||||
}
|
||||
|
||||
public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
|
||||
performEvent { $0.urlSession(session, dataTask: dataTask, didReceive: data) }
|
||||
}
|
||||
@@ -593,6 +601,9 @@ open class ClosureEventMonitor: EventMonitor {
|
||||
/// Closure called on the `urlSession(_:taskIsWaitingForConnectivity:)` event.
|
||||
open var taskIsWaitingForConnectivity: ((URLSession, URLSessionTask) -> Void)?
|
||||
|
||||
/// Closure called on the `urlSession(_:dataTask:didReceive:completionHandler:)` event.
|
||||
open var dataTaskDidReceiveResponse: ((URLSession, URLSessionDataTask, URLResponse) -> Void)?
|
||||
|
||||
/// Closure that receives the `urlSession(_:dataTask:didReceive:)` event.
|
||||
open var dataTaskDidReceiveData: ((URLSession, URLSessionDataTask, Data) -> Void)?
|
||||
|
||||
@@ -741,6 +752,10 @@ open class ClosureEventMonitor: EventMonitor {
|
||||
taskIsWaitingForConnectivity?(session, task)
|
||||
}
|
||||
|
||||
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse) {
|
||||
dataTaskDidReceiveResponse?(session, dataTask, response)
|
||||
}
|
||||
|
||||
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
|
||||
dataTaskDidReceiveData?(session, dataTask, data)
|
||||
}
|
||||
|
8
Pods/Alamofire/Source/HTTPHeaders.swift
generated
8
Pods/Alamofire/Source/HTTPHeaders.swift
generated
@@ -34,16 +34,12 @@ public struct HTTPHeaders {
|
||||
/// Creates an instance from an array of `HTTPHeader`s. Duplicate case-insensitive names are collapsed into the last
|
||||
/// name and value encountered.
|
||||
public init(_ headers: [HTTPHeader]) {
|
||||
self.init()
|
||||
|
||||
headers.forEach { update($0) }
|
||||
}
|
||||
|
||||
/// Creates an instance from a `[String: String]`. Duplicate case-insensitive names are collapsed into the last name
|
||||
/// and value encountered.
|
||||
public init(_ dictionary: [String: String]) {
|
||||
self.init()
|
||||
|
||||
dictionary.forEach { update(HTTPHeader(name: $0.key, value: $0.value)) }
|
||||
}
|
||||
|
||||
@@ -145,8 +141,6 @@ public struct HTTPHeaders {
|
||||
|
||||
extension HTTPHeaders: ExpressibleByDictionaryLiteral {
|
||||
public init(dictionaryLiteral elements: (String, String)...) {
|
||||
self.init()
|
||||
|
||||
elements.forEach { update(name: $0.0, value: $0.1) }
|
||||
}
|
||||
}
|
||||
@@ -405,6 +399,8 @@ extension HTTPHeader {
|
||||
return "Linux"
|
||||
#elseif os(Windows)
|
||||
return "Windows"
|
||||
#elseif os(Android)
|
||||
return "Android"
|
||||
#else
|
||||
return "Unknown"
|
||||
#endif
|
||||
|
31
Pods/Alamofire/Source/MultipartFormData.swift
generated
31
Pods/Alamofire/Source/MultipartFormData.swift
generated
@@ -24,9 +24,9 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
#if os(iOS) || os(watchOS) || os(tvOS)
|
||||
#if canImport(MobileCoreServices)
|
||||
import MobileCoreServices
|
||||
#elseif os(macOS)
|
||||
#elseif canImport(CoreServices)
|
||||
import CoreServices
|
||||
#endif
|
||||
|
||||
@@ -213,7 +213,7 @@ open class MultipartFormData {
|
||||
// Check 2 - is file URL reachable?
|
||||
//============================================================
|
||||
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if !(os(Linux) || os(Windows) || os(Android))
|
||||
do {
|
||||
let isReachable = try fileURL.checkPromisedItemIsReachable()
|
||||
guard isReachable else {
|
||||
@@ -455,9 +455,11 @@ open class MultipartFormData {
|
||||
inputStream.open()
|
||||
defer { inputStream.close() }
|
||||
|
||||
while inputStream.hasBytesAvailable {
|
||||
var buffer = [UInt8](repeating: 0, count: streamBufferSize)
|
||||
let bytesRead = inputStream.read(&buffer, maxLength: streamBufferSize)
|
||||
var bytesLeftToRead = bodyPart.bodyContentLength
|
||||
while inputStream.hasBytesAvailable && bytesLeftToRead > 0 {
|
||||
let bufferSize = min(streamBufferSize, Int(bytesLeftToRead))
|
||||
var buffer = [UInt8](repeating: 0, count: bufferSize)
|
||||
let bytesRead = inputStream.read(&buffer, maxLength: bufferSize)
|
||||
|
||||
if let streamError = inputStream.streamError {
|
||||
throw AFError.multipartEncodingFailed(reason: .inputStreamReadFailed(error: streamError))
|
||||
@@ -469,6 +471,7 @@ open class MultipartFormData {
|
||||
}
|
||||
|
||||
try write(&buffer, to: outputStream)
|
||||
bytesLeftToRead -= UInt64(bytesRead)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
@@ -549,6 +552,19 @@ extension MultipartFormData {
|
||||
// MARK: - Private - Mime Type
|
||||
|
||||
private func mimeType(forPathExtension pathExtension: String) -> String {
|
||||
#if swift(>=5.9)
|
||||
if #available(iOS 14, macOS 11, tvOS 14, watchOS 7, visionOS 1, *) {
|
||||
return UTType(filenameExtension: pathExtension)?.preferredMIMEType ?? "application/octet-stream"
|
||||
} else {
|
||||
if
|
||||
let id = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(),
|
||||
let contentType = UTTypeCopyPreferredTagWithClass(id, kUTTagClassMIMEType)?.takeRetainedValue() {
|
||||
return contentType as String
|
||||
}
|
||||
|
||||
return "application/octet-stream"
|
||||
}
|
||||
#else
|
||||
if #available(iOS 14, macOS 11, tvOS 14, watchOS 7, *) {
|
||||
return UTType(filenameExtension: pathExtension)?.preferredMIMEType ?? "application/octet-stream"
|
||||
} else {
|
||||
@@ -560,6 +576,7 @@ extension MultipartFormData {
|
||||
|
||||
return "application/octet-stream"
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,7 +586,7 @@ extension MultipartFormData {
|
||||
// MARK: - Private - Mime Type
|
||||
|
||||
private func mimeType(forPathExtension pathExtension: String) -> String {
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(CoreServices) || canImport(MobileCoreServices)
|
||||
if
|
||||
let id = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, pathExtension as CFString, nil)?.takeRetainedValue(),
|
||||
let contentType = UTTypeCopyPreferredTagWithClass(id, kUTTagClassMIMEType)?.takeRetainedValue() {
|
||||
|
14
Pods/Alamofire/Source/MultipartUpload.swift
generated
14
Pods/Alamofire/Source/MultipartUpload.swift
generated
@@ -28,8 +28,8 @@ import Foundation
|
||||
final class MultipartUpload {
|
||||
lazy var result = Result { try build() }
|
||||
|
||||
@Protected
|
||||
private(set) var multipartFormData: MultipartFormData
|
||||
private let multipartFormData: Protected<MultipartFormData>
|
||||
|
||||
let encodingMemoryThreshold: UInt64
|
||||
let request: URLRequestConvertible
|
||||
let fileManager: FileManager
|
||||
@@ -40,13 +40,13 @@ final class MultipartUpload {
|
||||
self.encodingMemoryThreshold = encodingMemoryThreshold
|
||||
self.request = request
|
||||
fileManager = multipartFormData.fileManager
|
||||
self.multipartFormData = multipartFormData
|
||||
self.multipartFormData = Protected(multipartFormData)
|
||||
}
|
||||
|
||||
func build() throws -> UploadRequest.Uploadable {
|
||||
let uploadable: UploadRequest.Uploadable
|
||||
if $multipartFormData.contentLength < encodingMemoryThreshold {
|
||||
let data = try $multipartFormData.read { try $0.encode() }
|
||||
if multipartFormData.contentLength < encodingMemoryThreshold {
|
||||
let data = try multipartFormData.read { try $0.encode() }
|
||||
|
||||
uploadable = .data(data)
|
||||
} else {
|
||||
@@ -58,7 +58,7 @@ final class MultipartUpload {
|
||||
try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
|
||||
|
||||
do {
|
||||
try $multipartFormData.read { try $0.writeEncodedData(to: fileURL) }
|
||||
try multipartFormData.read { try $0.writeEncodedData(to: fileURL) }
|
||||
} catch {
|
||||
// Cleanup after attempted write if it fails.
|
||||
try? fileManager.removeItem(at: fileURL)
|
||||
@@ -76,7 +76,7 @@ extension MultipartUpload: UploadConvertible {
|
||||
func asURLRequest() throws -> URLRequest {
|
||||
var urlRequest = try request.asURLRequest()
|
||||
|
||||
$multipartFormData.read { multipartFormData in
|
||||
multipartFormData.read { multipartFormData in
|
||||
urlRequest.headers.add(.contentType(multipartFormData.contentType))
|
||||
}
|
||||
|
||||
|
@@ -22,7 +22,7 @@
|
||||
// THE SOFTWARE.
|
||||
//
|
||||
|
||||
#if !(os(watchOS) || os(Linux) || os(Windows))
|
||||
#if canImport(SystemConfiguration)
|
||||
|
||||
import Foundation
|
||||
import SystemConfiguration
|
||||
@@ -113,8 +113,7 @@ open class NetworkReachabilityManager {
|
||||
private let reachability: SCNetworkReachability
|
||||
|
||||
/// Protected storage for mutable state.
|
||||
@Protected
|
||||
private var mutableState = MutableState()
|
||||
private let mutableState = Protected(MutableState())
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
@@ -168,7 +167,7 @@ open class NetworkReachabilityManager {
|
||||
onUpdatePerforming listener: @escaping Listener) -> Bool {
|
||||
stopListening()
|
||||
|
||||
$mutableState.write { state in
|
||||
mutableState.write { state in
|
||||
state.listenerQueue = queue
|
||||
state.listener = listener
|
||||
}
|
||||
@@ -194,7 +193,8 @@ open class NetworkReachabilityManager {
|
||||
let description = weakManager.manager?.flags?.readableDescription ?? "nil"
|
||||
|
||||
return Unmanaged.passRetained(description as CFString)
|
||||
})
|
||||
}
|
||||
)
|
||||
let callback: SCNetworkReachabilityCallBack = { _, flags, info in
|
||||
guard let info = info else { return }
|
||||
|
||||
@@ -219,7 +219,7 @@ open class NetworkReachabilityManager {
|
||||
open func stopListening() {
|
||||
SCNetworkReachabilitySetCallback(reachability, nil, nil)
|
||||
SCNetworkReachabilitySetDispatchQueue(reachability, nil)
|
||||
$mutableState.write { state in
|
||||
mutableState.write { state in
|
||||
state.listener = nil
|
||||
state.listenerQueue = nil
|
||||
state.previousStatus = nil
|
||||
@@ -236,7 +236,7 @@ open class NetworkReachabilityManager {
|
||||
func notifyListener(_ flags: SCNetworkReachabilityFlags) {
|
||||
let newStatus = NetworkReachabilityStatus(flags)
|
||||
|
||||
$mutableState.write { state in
|
||||
mutableState.write { state in
|
||||
guard state.previousStatus != newStatus else { return }
|
||||
|
||||
state.previousStatus = newStatus
|
||||
@@ -266,7 +266,7 @@ extension SCNetworkReachabilityFlags {
|
||||
var canConnectWithoutUserInteraction: Bool { canConnectAutomatically && !contains(.interventionRequired) }
|
||||
var isActuallyReachable: Bool { isReachable && (!isConnectionRequired || canConnectWithoutUserInteraction) }
|
||||
var isCellular: Bool {
|
||||
#if os(iOS) || os(tvOS)
|
||||
#if os(iOS) || os(tvOS) || (swift(>=5.9) && os(visionOS))
|
||||
return contains(.isWWAN)
|
||||
#else
|
||||
return false
|
||||
|
67
Pods/Alamofire/Source/Protected.swift
generated
67
Pods/Alamofire/Source/Protected.swift
generated
@@ -49,13 +49,7 @@ extension Lock {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(Linux) || os(Windows)
|
||||
|
||||
extension NSLock: Lock {}
|
||||
|
||||
#endif
|
||||
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
#if canImport(Darwin)
|
||||
/// An `os_unfair_lock` wrapper.
|
||||
final class UnfairLock: Lock {
|
||||
private let unfairLock: os_unfair_lock_t
|
||||
@@ -78,41 +72,35 @@ final class UnfairLock: Lock {
|
||||
os_unfair_lock_unlock(unfairLock)
|
||||
}
|
||||
}
|
||||
|
||||
#elseif canImport(Foundation)
|
||||
extension NSLock: Lock {}
|
||||
#else
|
||||
#error("This platform needs a Lock-conforming type without Foundation.")
|
||||
#endif
|
||||
|
||||
/// A thread-safe wrapper around a value.
|
||||
@propertyWrapper
|
||||
@dynamicMemberLookup
|
||||
final class Protected<T> {
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
final class Protected<Value> {
|
||||
#if canImport(Darwin)
|
||||
private let lock = UnfairLock()
|
||||
#elseif os(Linux) || os(Windows)
|
||||
#elseif canImport(Foundation)
|
||||
private let lock = NSLock()
|
||||
#else
|
||||
#error("This platform needs a Lock-conforming type without Foundation.")
|
||||
#endif
|
||||
private var value: T
|
||||
private var value: Value
|
||||
|
||||
init(_ value: T) {
|
||||
init(_ value: Value) {
|
||||
self.value = value
|
||||
}
|
||||
|
||||
/// The contained value. Unsafe for anything more than direct read or write.
|
||||
var wrappedValue: T {
|
||||
get { lock.around { value } }
|
||||
set { lock.around { value = newValue } }
|
||||
}
|
||||
|
||||
var projectedValue: Protected<T> { self }
|
||||
|
||||
init(wrappedValue: T) {
|
||||
value = wrappedValue
|
||||
}
|
||||
|
||||
/// Synchronously read or transform the contained value.
|
||||
///
|
||||
/// - Parameter closure: The closure to execute.
|
||||
///
|
||||
/// - Returns: The return value of the closure passed.
|
||||
func read<U>(_ closure: (T) throws -> U) rethrows -> U {
|
||||
func read<U>(_ closure: (Value) throws -> U) rethrows -> U {
|
||||
try lock.around { try closure(self.value) }
|
||||
}
|
||||
|
||||
@@ -122,21 +110,28 @@ final class Protected<T> {
|
||||
///
|
||||
/// - Returns: The modified value.
|
||||
@discardableResult
|
||||
func write<U>(_ closure: (inout T) throws -> U) rethrows -> U {
|
||||
func write<U>(_ closure: (inout Value) throws -> U) rethrows -> U {
|
||||
try lock.around { try closure(&self.value) }
|
||||
}
|
||||
|
||||
subscript<Property>(dynamicMember keyPath: WritableKeyPath<T, Property>) -> Property {
|
||||
/// Synchronously update the protected value.
|
||||
///
|
||||
/// - Parameter value: The `Value`.
|
||||
func write(_ value: Value) {
|
||||
write { $0 = value }
|
||||
}
|
||||
|
||||
subscript<Property>(dynamicMember keyPath: WritableKeyPath<Value, Property>) -> Property {
|
||||
get { lock.around { value[keyPath: keyPath] } }
|
||||
set { lock.around { value[keyPath: keyPath] = newValue } }
|
||||
}
|
||||
|
||||
subscript<Property>(dynamicMember keyPath: KeyPath<T, Property>) -> Property {
|
||||
subscript<Property>(dynamicMember keyPath: KeyPath<Value, Property>) -> Property {
|
||||
lock.around { value[keyPath: keyPath] }
|
||||
}
|
||||
}
|
||||
|
||||
extension Protected where T == Request.MutableState {
|
||||
extension Protected where Value == Request.MutableState {
|
||||
/// Attempts to transition to the passed `State`.
|
||||
///
|
||||
/// - Parameter state: The `State` to attempt transition to.
|
||||
@@ -159,3 +154,15 @@ extension Protected where T == Request.MutableState {
|
||||
lock.around { perform(value.state) }
|
||||
}
|
||||
}
|
||||
|
||||
extension Protected: Equatable where Value: Equatable {
|
||||
static func ==(lhs: Protected<Value>, rhs: Protected<Value>) -> Bool {
|
||||
lhs.read { left in rhs.read { right in left == right }}
|
||||
}
|
||||
}
|
||||
|
||||
extension Protected: Hashable where Value: Hashable {
|
||||
func hash(into hasher: inout Hasher) {
|
||||
read { hasher.combine($0) }
|
||||
}
|
||||
}
|
||||
|
332
Pods/Alamofire/Source/Request.swift
generated
332
Pods/Alamofire/Source/Request.swift
generated
@@ -125,11 +125,10 @@ public class Request {
|
||||
}
|
||||
|
||||
/// Protected `MutableState` value that provides thread-safe access to state values.
|
||||
@Protected
|
||||
fileprivate var mutableState = MutableState()
|
||||
fileprivate let mutableState = Protected(MutableState())
|
||||
|
||||
/// `State` of the `Request`.
|
||||
public var state: State { $mutableState.state }
|
||||
public var state: State { mutableState.state }
|
||||
/// Returns whether `state` is `.initialized`.
|
||||
public var isInitialized: Bool { state == .initialized }
|
||||
/// Returns whether `state is `.resumed`.
|
||||
@@ -152,50 +151,49 @@ public class Request {
|
||||
public let downloadProgress = Progress(totalUnitCount: 0)
|
||||
/// `ProgressHandler` called when `uploadProgress` is updated, on the provided `DispatchQueue`.
|
||||
private var uploadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)? {
|
||||
get { $mutableState.uploadProgressHandler }
|
||||
set { $mutableState.uploadProgressHandler = newValue }
|
||||
get { mutableState.uploadProgressHandler }
|
||||
set { mutableState.uploadProgressHandler = newValue }
|
||||
}
|
||||
|
||||
/// `ProgressHandler` called when `downloadProgress` is updated, on the provided `DispatchQueue`.
|
||||
fileprivate var downloadProgressHandler: (handler: ProgressHandler, queue: DispatchQueue)? {
|
||||
get { $mutableState.downloadProgressHandler }
|
||||
set { $mutableState.downloadProgressHandler = newValue }
|
||||
get { mutableState.downloadProgressHandler }
|
||||
set { mutableState.downloadProgressHandler = newValue }
|
||||
}
|
||||
|
||||
// MARK: Redirect Handling
|
||||
|
||||
/// `RedirectHandler` set on the instance.
|
||||
public private(set) var redirectHandler: RedirectHandler? {
|
||||
get { $mutableState.redirectHandler }
|
||||
set { $mutableState.redirectHandler = newValue }
|
||||
get { mutableState.redirectHandler }
|
||||
set { mutableState.redirectHandler = newValue }
|
||||
}
|
||||
|
||||
// MARK: Cached Response Handling
|
||||
|
||||
/// `CachedResponseHandler` set on the instance.
|
||||
public private(set) var cachedResponseHandler: CachedResponseHandler? {
|
||||
get { $mutableState.cachedResponseHandler }
|
||||
set { $mutableState.cachedResponseHandler = newValue }
|
||||
get { mutableState.cachedResponseHandler }
|
||||
set { mutableState.cachedResponseHandler = newValue }
|
||||
}
|
||||
|
||||
// MARK: URLCredential
|
||||
|
||||
/// `URLCredential` used for authentication challenges. Created by calling one of the `authenticate` methods.
|
||||
public private(set) var credential: URLCredential? {
|
||||
get { $mutableState.credential }
|
||||
set { $mutableState.credential = newValue }
|
||||
get { mutableState.credential }
|
||||
set { mutableState.credential = newValue }
|
||||
}
|
||||
|
||||
// MARK: Validators
|
||||
|
||||
/// `Validator` callback closures that store the validation calls enqueued.
|
||||
@Protected
|
||||
fileprivate var validators: [() -> Void] = []
|
||||
fileprivate let validators = Protected<[() -> Void]>([])
|
||||
|
||||
// MARK: URLRequests
|
||||
|
||||
/// All `URLRequests` created on behalf of the `Request`, including original and adapted requests.
|
||||
public var requests: [URLRequest] { $mutableState.requests }
|
||||
public var requests: [URLRequest] { mutableState.requests }
|
||||
/// First `URLRequest` created on behalf of the `Request`. May not be the first one actually executed.
|
||||
public var firstRequest: URLRequest? { requests.first }
|
||||
/// Last `URLRequest` created on behalf of the `Request`.
|
||||
@@ -205,7 +203,7 @@ public class Request {
|
||||
|
||||
/// `URLRequest`s from all of the `URLSessionTask`s executed on behalf of the `Request`. May be different from
|
||||
/// `requests` due to `URLSession` manipulation.
|
||||
public var performedRequests: [URLRequest] { $mutableState.read { $0.tasks.compactMap(\.currentRequest) } }
|
||||
public var performedRequests: [URLRequest] { mutableState.read { $0.tasks.compactMap(\.currentRequest) } }
|
||||
|
||||
// MARK: HTTPURLResponse
|
||||
|
||||
@@ -216,7 +214,7 @@ public class Request {
|
||||
// MARK: Tasks
|
||||
|
||||
/// All `URLSessionTask`s created on behalf of the `Request`.
|
||||
public var tasks: [URLSessionTask] { $mutableState.tasks }
|
||||
public var tasks: [URLSessionTask] { mutableState.tasks }
|
||||
/// First `URLSessionTask` created on behalf of the `Request`.
|
||||
public var firstTask: URLSessionTask? { tasks.first }
|
||||
/// Last `URLSessionTask` created on behalf of the `Request`.
|
||||
@@ -227,7 +225,7 @@ public class Request {
|
||||
// MARK: Metrics
|
||||
|
||||
/// All `URLSessionTaskMetrics` gathered on behalf of the `Request`. Should correspond to the `tasks` created.
|
||||
public var allMetrics: [URLSessionTaskMetrics] { $mutableState.metrics }
|
||||
public var allMetrics: [URLSessionTaskMetrics] { mutableState.metrics }
|
||||
/// First `URLSessionTaskMetrics` gathered on behalf of the `Request`.
|
||||
public var firstMetrics: URLSessionTaskMetrics? { allMetrics.first }
|
||||
/// Last `URLSessionTaskMetrics` gathered on behalf of the `Request`.
|
||||
@@ -238,14 +236,14 @@ public class Request {
|
||||
// MARK: Retry Count
|
||||
|
||||
/// Number of times the `Request` has been retried.
|
||||
public var retryCount: Int { $mutableState.retryCount }
|
||||
public var retryCount: Int { mutableState.retryCount }
|
||||
|
||||
// MARK: Error
|
||||
|
||||
/// `Error` returned from Alamofire internally, from the network request directly, or any validators executed.
|
||||
public fileprivate(set) var error: AFError? {
|
||||
get { $mutableState.error }
|
||||
set { $mutableState.error = newValue }
|
||||
get { mutableState.error }
|
||||
set { mutableState.error = newValue }
|
||||
}
|
||||
|
||||
/// Default initializer for the `Request` superclass.
|
||||
@@ -283,7 +281,7 @@ public class Request {
|
||||
func didCreateInitialURLRequest(_ request: URLRequest) {
|
||||
dispatchPrecondition(condition: .onQueue(underlyingQueue))
|
||||
|
||||
$mutableState.write { $0.requests.append(request) }
|
||||
mutableState.write { $0.requests.append(request) }
|
||||
|
||||
eventMonitor?.request(self, didCreateInitialURLRequest: request)
|
||||
}
|
||||
@@ -313,7 +311,7 @@ public class Request {
|
||||
func didAdaptInitialRequest(_ initialRequest: URLRequest, to adaptedRequest: URLRequest) {
|
||||
dispatchPrecondition(condition: .onQueue(underlyingQueue))
|
||||
|
||||
$mutableState.write { $0.requests.append(adaptedRequest) }
|
||||
mutableState.write { $0.requests.append(adaptedRequest) }
|
||||
|
||||
eventMonitor?.request(self, didAdaptInitialRequest: initialRequest, to: adaptedRequest)
|
||||
}
|
||||
@@ -343,7 +341,7 @@ public class Request {
|
||||
func didCreateURLRequest(_ request: URLRequest) {
|
||||
dispatchPrecondition(condition: .onQueue(underlyingQueue))
|
||||
|
||||
$mutableState.read { state in
|
||||
mutableState.read { state in
|
||||
state.urlRequestHandler?.queue.async { state.urlRequestHandler?.handler(request) }
|
||||
}
|
||||
|
||||
@@ -354,7 +352,7 @@ public class Request {
|
||||
|
||||
/// Asynchronously calls any stored `cURLHandler` and then removes it from `mutableState`.
|
||||
private func callCURLHandlerIfNecessary() {
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
guard let cURLHandler = mutableState.cURLHandler else { return }
|
||||
|
||||
cURLHandler.queue.async { cURLHandler.handler(self.cURLDescription()) }
|
||||
@@ -369,7 +367,7 @@ public class Request {
|
||||
func didCreateTask(_ task: URLSessionTask) {
|
||||
dispatchPrecondition(condition: .onQueue(underlyingQueue))
|
||||
|
||||
$mutableState.write { state in
|
||||
mutableState.write { state in
|
||||
state.tasks.append(task)
|
||||
|
||||
guard let urlSessionTaskHandler = state.urlSessionTaskHandler else { return }
|
||||
@@ -416,7 +414,9 @@ public class Request {
|
||||
func didCancel() {
|
||||
dispatchPrecondition(condition: .onQueue(underlyingQueue))
|
||||
|
||||
error = error ?? AFError.explicitlyCancelled
|
||||
mutableState.write { mutableState in
|
||||
mutableState.error = mutableState.error ?? AFError.explicitlyCancelled
|
||||
}
|
||||
|
||||
eventMonitor?.requestDidCancel(self)
|
||||
}
|
||||
@@ -436,7 +436,7 @@ public class Request {
|
||||
func didGatherMetrics(_ metrics: URLSessionTaskMetrics) {
|
||||
dispatchPrecondition(condition: .onQueue(underlyingQueue))
|
||||
|
||||
$mutableState.write { $0.metrics.append(metrics) }
|
||||
mutableState.write { $0.metrics.append(metrics) }
|
||||
|
||||
eventMonitor?.request(self, didGatherMetrics: metrics)
|
||||
}
|
||||
@@ -468,6 +468,7 @@ public class Request {
|
||||
|
||||
self.error = self.error ?? error
|
||||
|
||||
let validators = validators.read { $0 }
|
||||
validators.forEach { $0() }
|
||||
|
||||
eventMonitor?.request(self, didCompleteTask: task, with: error)
|
||||
@@ -479,7 +480,7 @@ public class Request {
|
||||
func prepareForRetry() {
|
||||
dispatchPrecondition(condition: .onQueue(underlyingQueue))
|
||||
|
||||
$mutableState.write { $0.retryCount += 1 }
|
||||
mutableState.write { $0.retryCount += 1 }
|
||||
|
||||
reset()
|
||||
|
||||
@@ -513,9 +514,9 @@ public class Request {
|
||||
func finish(error: AFError? = nil) {
|
||||
dispatchPrecondition(condition: .onQueue(underlyingQueue))
|
||||
|
||||
guard !$mutableState.isFinishing else { return }
|
||||
guard !mutableState.isFinishing else { return }
|
||||
|
||||
$mutableState.isFinishing = true
|
||||
mutableState.isFinishing = true
|
||||
|
||||
if let error = error { self.error = error }
|
||||
|
||||
@@ -531,7 +532,7 @@ public class Request {
|
||||
///
|
||||
/// - Parameter closure: The closure containing the response serialization call.
|
||||
func appendResponseSerializer(_ closure: @escaping () -> Void) {
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
mutableState.responseSerializers.append(closure)
|
||||
|
||||
if mutableState.state == .finished {
|
||||
@@ -554,7 +555,7 @@ public class Request {
|
||||
func nextResponseSerializer() -> (() -> Void)? {
|
||||
var responseSerializer: (() -> Void)?
|
||||
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
let responseSerializerIndex = mutableState.responseSerializerCompletions.count
|
||||
|
||||
if responseSerializerIndex < mutableState.responseSerializers.count {
|
||||
@@ -571,7 +572,7 @@ public class Request {
|
||||
// Execute all response serializer completions and clear them
|
||||
var completions: [() -> Void] = []
|
||||
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
completions = mutableState.responseSerializerCompletions
|
||||
|
||||
// Clear out all response serializers and response serializer completions in mutable state since the
|
||||
@@ -605,7 +606,7 @@ public class Request {
|
||||
/// - Parameter completion: The completion handler provided with the response serializer, called when all serializers
|
||||
/// are complete.
|
||||
func responseSerializerDidComplete(completion: @escaping () -> Void) {
|
||||
$mutableState.write { $0.responseSerializerCompletions.append(completion) }
|
||||
mutableState.write { $0.responseSerializerCompletions.append(completion) }
|
||||
processNextResponseSerializer()
|
||||
}
|
||||
|
||||
@@ -618,7 +619,7 @@ public class Request {
|
||||
downloadProgress.totalUnitCount = 0
|
||||
downloadProgress.completedUnitCount = 0
|
||||
|
||||
$mutableState.write { state in
|
||||
mutableState.write { state in
|
||||
state.isFinishing = false
|
||||
state.responseSerializerCompletions = []
|
||||
}
|
||||
@@ -640,7 +641,7 @@ public class Request {
|
||||
///
|
||||
/// - Parameter perform: The closure to perform.
|
||||
func withState(perform: (State) -> Void) {
|
||||
$mutableState.withState(perform: perform)
|
||||
mutableState.withState(perform: perform)
|
||||
}
|
||||
|
||||
// MARK: Task Creation
|
||||
@@ -667,7 +668,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func cancel() -> Self {
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
guard mutableState.state.canTransitionTo(.cancelled) else { return }
|
||||
|
||||
mutableState.state = .cancelled
|
||||
@@ -693,7 +694,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func suspend() -> Self {
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
guard mutableState.state.canTransitionTo(.suspended) else { return }
|
||||
|
||||
mutableState.state = .suspended
|
||||
@@ -714,7 +715,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func resume() -> Self {
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
guard mutableState.state.canTransitionTo(.resumed) else { return }
|
||||
|
||||
mutableState.state = .resumed
|
||||
@@ -754,7 +755,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func authenticate(with credential: URLCredential) -> Self {
|
||||
$mutableState.credential = credential
|
||||
mutableState.credential = credential
|
||||
|
||||
return self
|
||||
}
|
||||
@@ -770,7 +771,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func downloadProgress(queue: DispatchQueue = .main, closure: @escaping ProgressHandler) -> Self {
|
||||
$mutableState.downloadProgressHandler = (handler: closure, queue: queue)
|
||||
mutableState.downloadProgressHandler = (handler: closure, queue: queue)
|
||||
|
||||
return self
|
||||
}
|
||||
@@ -786,7 +787,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func uploadProgress(queue: DispatchQueue = .main, closure: @escaping ProgressHandler) -> Self {
|
||||
$mutableState.uploadProgressHandler = (handler: closure, queue: queue)
|
||||
mutableState.uploadProgressHandler = (handler: closure, queue: queue)
|
||||
|
||||
return self
|
||||
}
|
||||
@@ -802,7 +803,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func redirect(using handler: RedirectHandler) -> Self {
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
precondition(mutableState.redirectHandler == nil, "Redirect handler has already been set.")
|
||||
mutableState.redirectHandler = handler
|
||||
}
|
||||
@@ -821,7 +822,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func cacheResponse(using handler: CachedResponseHandler) -> Self {
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
precondition(mutableState.cachedResponseHandler == nil, "Cached response handler has already been set.")
|
||||
mutableState.cachedResponseHandler = handler
|
||||
}
|
||||
@@ -842,7 +843,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func cURLDescription(on queue: DispatchQueue, calling handler: @escaping (String) -> Void) -> Self {
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
if mutableState.requests.last != nil {
|
||||
queue.async { handler(self.cURLDescription()) }
|
||||
} else {
|
||||
@@ -863,13 +864,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func cURLDescription(calling handler: @escaping (String) -> Void) -> Self {
|
||||
$mutableState.write { mutableState in
|
||||
if mutableState.requests.last != nil {
|
||||
underlyingQueue.async { handler(self.cURLDescription()) }
|
||||
} else {
|
||||
mutableState.cURLHandler = (underlyingQueue, handler)
|
||||
}
|
||||
}
|
||||
cURLDescription(on: underlyingQueue, calling: handler)
|
||||
|
||||
return self
|
||||
}
|
||||
@@ -885,7 +880,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func onURLRequestCreation(on queue: DispatchQueue = .main, perform handler: @escaping (URLRequest) -> Void) -> Self {
|
||||
$mutableState.write { state in
|
||||
mutableState.write { state in
|
||||
if let request = state.requests.last {
|
||||
queue.async { handler(request) }
|
||||
}
|
||||
@@ -909,7 +904,7 @@ public class Request {
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func onURLSessionTaskCreation(on queue: DispatchQueue = .main, perform handler: @escaping (URLSessionTask) -> Void) -> Self {
|
||||
$mutableState.write { state in
|
||||
mutableState.write { state in
|
||||
if let task = state.tasks.last {
|
||||
queue.async { handler(task) }
|
||||
}
|
||||
@@ -928,19 +923,37 @@ public class Request {
|
||||
func onFinish(perform finishHandler: @escaping () -> Void) {
|
||||
guard !isFinished else { finishHandler(); return }
|
||||
|
||||
$mutableState.write { state in
|
||||
mutableState.write { state in
|
||||
state.finishHandlers.append(finishHandler)
|
||||
}
|
||||
}
|
||||
|
||||
/// Final cleanup step executed when the instance finishes response serialization.
|
||||
func cleanup() {
|
||||
delegate?.cleanup(after: self)
|
||||
let handlers = $mutableState.finishHandlers
|
||||
let handlers = mutableState.finishHandlers
|
||||
handlers.forEach { $0() }
|
||||
$mutableState.write { state in
|
||||
mutableState.write { state in
|
||||
state.finishHandlers.removeAll()
|
||||
}
|
||||
|
||||
delegate?.cleanup(after: self)
|
||||
}
|
||||
}
|
||||
|
||||
extension Request {
|
||||
/// Type indicating how a `DataRequest` or `DataStreamRequest` should proceed after receiving an `HTTPURLResponse`.
|
||||
public enum ResponseDisposition {
|
||||
/// Allow the request to continue normally.
|
||||
case allow
|
||||
/// Cancel the request, similar to calling `cancel()`.
|
||||
case cancel
|
||||
|
||||
var sessionDisposition: URLSession.ResponseDisposition {
|
||||
switch self {
|
||||
case .allow: return .allow
|
||||
case .cancel: return .cancel
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1085,11 +1098,16 @@ public class DataRequest: Request {
|
||||
/// `URLRequestConvertible` value used to create `URLRequest`s for this instance.
|
||||
public let convertible: URLRequestConvertible
|
||||
/// `Data` read from the server so far.
|
||||
public var data: Data? { mutableData }
|
||||
public var data: Data? { dataMutableState.data }
|
||||
|
||||
/// Protected storage for the `Data` read by the instance.
|
||||
@Protected
|
||||
private var mutableData: Data? = nil
|
||||
private struct DataMutableState {
|
||||
var data: Data?
|
||||
var httpResponseHandler: (queue: DispatchQueue,
|
||||
handler: (_ response: HTTPURLResponse,
|
||||
_ completionHandler: @escaping (ResponseDisposition) -> Void) -> Void)?
|
||||
}
|
||||
|
||||
private let dataMutableState = Protected(DataMutableState())
|
||||
|
||||
/// Creates a `DataRequest` using the provided parameters.
|
||||
///
|
||||
@@ -1122,7 +1140,9 @@ public class DataRequest: Request {
|
||||
override func reset() {
|
||||
super.reset()
|
||||
|
||||
mutableData = nil
|
||||
dataMutableState.write { mutableState in
|
||||
mutableState.data = nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Called when `Data` is received by this instance.
|
||||
@@ -1131,15 +1151,41 @@ public class DataRequest: Request {
|
||||
///
|
||||
/// - Parameter data: The `Data` received.
|
||||
func didReceive(data: Data) {
|
||||
if self.data == nil {
|
||||
mutableData = data
|
||||
dataMutableState.write { mutableState in
|
||||
if mutableState.data == nil {
|
||||
mutableState.data = data
|
||||
} else {
|
||||
$mutableData.write { $0?.append(data) }
|
||||
mutableState.data?.append(data)
|
||||
}
|
||||
}
|
||||
|
||||
updateDownloadProgress()
|
||||
}
|
||||
|
||||
func didReceiveResponse(_ response: HTTPURLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
|
||||
dataMutableState.read { dataMutableState in
|
||||
guard let httpResponseHandler = dataMutableState.httpResponseHandler else {
|
||||
underlyingQueue.async { completionHandler(.allow) }
|
||||
return
|
||||
}
|
||||
|
||||
httpResponseHandler.queue.async {
|
||||
httpResponseHandler.handler(response) { disposition in
|
||||
if disposition == .cancel {
|
||||
self.mutableState.write { mutableState in
|
||||
mutableState.state = .cancelled
|
||||
mutableState.error = mutableState.error ?? AFError.explicitlyCancelled
|
||||
}
|
||||
}
|
||||
|
||||
self.underlyingQueue.async {
|
||||
completionHandler(disposition.sessionDisposition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func task(for request: URLRequest, using session: URLSession) -> URLSessionTask {
|
||||
let copiedRequest = request
|
||||
return session.dataTask(with: copiedRequest)
|
||||
@@ -1179,7 +1225,48 @@ public class DataRequest: Request {
|
||||
withResult: result)
|
||||
}
|
||||
|
||||
$validators.write { $0.append(validator) }
|
||||
validators.write { $0.append(validator) }
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
/// Sets a closure called whenever the `DataRequest` produces an `HTTPURLResponse` and providing a completion
|
||||
/// handler to return a `ResponseDisposition` value.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - queue: `DispatchQueue` on which the closure will be called. `.main` by default.
|
||||
/// - handler: Closure called when the instance produces an `HTTPURLResponse`. The `completionHandler` provided
|
||||
/// MUST be called, otherwise the request will never complete.
|
||||
///
|
||||
/// - Returns: The instance.
|
||||
@_disfavoredOverload
|
||||
@discardableResult
|
||||
public func onHTTPResponse(
|
||||
on queue: DispatchQueue = .main,
|
||||
perform handler: @escaping (_ response: HTTPURLResponse,
|
||||
_ completionHandler: @escaping (ResponseDisposition) -> Void) -> Void
|
||||
) -> Self {
|
||||
dataMutableState.write { mutableState in
|
||||
mutableState.httpResponseHandler = (queue, handler)
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
/// Sets a closure called whenever the `DataRequest` produces an `HTTPURLResponse`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - queue: `DispatchQueue` on which the closure will be called. `.main` by default.
|
||||
/// - handler: Closure called when the instance produces an `HTTPURLResponse`.
|
||||
///
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func onHTTPResponse(on queue: DispatchQueue = .main,
|
||||
perform handler: @escaping (HTTPURLResponse) -> Void) -> Self {
|
||||
onHTTPResponse(on: queue) { response, completionHandler in
|
||||
handler(response)
|
||||
completionHandler(.allow)
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
@@ -1259,10 +1346,13 @@ public final class DataStreamRequest: Request {
|
||||
var numberOfExecutingStreams = 0
|
||||
/// Completion calls enqueued while streams are still executing.
|
||||
var enqueuedCompletionEvents: [() -> Void] = []
|
||||
/// Handler for any `HTTPURLResponse`s received.
|
||||
var httpResponseHandler: (queue: DispatchQueue,
|
||||
handler: (_ response: HTTPURLResponse,
|
||||
_ completionHandler: @escaping (ResponseDisposition) -> Void) -> Void)?
|
||||
}
|
||||
|
||||
@Protected
|
||||
var streamMutableState = StreamMutableState()
|
||||
let streamMutableState = Protected(StreamMutableState())
|
||||
|
||||
/// Creates a `DataStreamRequest` using the provided parameters.
|
||||
///
|
||||
@@ -1306,7 +1396,7 @@ public final class DataStreamRequest: Request {
|
||||
}
|
||||
|
||||
override func finish(error: AFError? = nil) {
|
||||
$streamMutableState.write { state in
|
||||
streamMutableState.write { state in
|
||||
state.outputStream?.close()
|
||||
}
|
||||
|
||||
@@ -1314,8 +1404,8 @@ public final class DataStreamRequest: Request {
|
||||
}
|
||||
|
||||
func didReceive(data: Data) {
|
||||
$streamMutableState.write { state in
|
||||
#if !(os(Linux) || os(Windows))
|
||||
streamMutableState.write { state in
|
||||
#if !canImport(FoundationNetworking) // If we not using swift-corelibs-foundation.
|
||||
if let stream = state.outputStream {
|
||||
underlyingQueue.async {
|
||||
var bytes = Array(data)
|
||||
@@ -1329,6 +1419,30 @@ public final class DataStreamRequest: Request {
|
||||
}
|
||||
}
|
||||
|
||||
func didReceiveResponse(_ response: HTTPURLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
|
||||
streamMutableState.read { dataMutableState in
|
||||
guard let httpResponseHandler = dataMutableState.httpResponseHandler else {
|
||||
underlyingQueue.async { completionHandler(.allow) }
|
||||
return
|
||||
}
|
||||
|
||||
httpResponseHandler.queue.async {
|
||||
httpResponseHandler.handler(response) { disposition in
|
||||
if disposition == .cancel {
|
||||
self.mutableState.write { mutableState in
|
||||
mutableState.state = .cancelled
|
||||
mutableState.error = mutableState.error ?? AFError.explicitlyCancelled
|
||||
}
|
||||
}
|
||||
|
||||
self.underlyingQueue.async {
|
||||
completionHandler(disposition.sessionDisposition)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Validates the `URLRequest` and `HTTPURLResponse` received for the instance using the provided `Validation` closure.
|
||||
///
|
||||
/// - Parameter validation: `Validation` closure used to validate the request and response.
|
||||
@@ -1351,12 +1465,12 @@ public final class DataStreamRequest: Request {
|
||||
withResult: result)
|
||||
}
|
||||
|
||||
$validators.write { $0.append(validator) }
|
||||
validators.write { $0.append(validator) }
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if !canImport(FoundationNetworking) // If we not using swift-corelibs-foundation.
|
||||
/// Produces an `InputStream` that receives the `Data` received by the instance.
|
||||
///
|
||||
/// - Note: The `InputStream` produced by this method must have `open()` called before being able to read `Data`.
|
||||
@@ -1370,7 +1484,7 @@ public final class DataStreamRequest: Request {
|
||||
defer { resume() }
|
||||
|
||||
var inputStream: InputStream?
|
||||
$streamMutableState.write { state in
|
||||
streamMutableState.write { state in
|
||||
Foundation.Stream.getBoundStreams(withBufferSize: bufferSize,
|
||||
inputStream: &inputStream,
|
||||
outputStream: &state.outputStream)
|
||||
@@ -1381,6 +1495,47 @@ public final class DataStreamRequest: Request {
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Sets a closure called whenever the `DataRequest` produces an `HTTPURLResponse` and providing a completion
|
||||
/// handler to return a `ResponseDisposition` value.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - queue: `DispatchQueue` on which the closure will be called. `.main` by default.
|
||||
/// - handler: Closure called when the instance produces an `HTTPURLResponse`. The `completionHandler` provided
|
||||
/// MUST be called, otherwise the request will never complete.
|
||||
///
|
||||
/// - Returns: The instance.
|
||||
@_disfavoredOverload
|
||||
@discardableResult
|
||||
public func onHTTPResponse(
|
||||
on queue: DispatchQueue = .main,
|
||||
perform handler: @escaping (_ response: HTTPURLResponse,
|
||||
_ completionHandler: @escaping (ResponseDisposition) -> Void) -> Void
|
||||
) -> Self {
|
||||
streamMutableState.write { mutableState in
|
||||
mutableState.httpResponseHandler = (queue, handler)
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
/// Sets a closure called whenever the `DataRequest` produces an `HTTPURLResponse`.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - queue: `DispatchQueue` on which the closure will be called. `.main` by default.
|
||||
/// - handler: Closure called when the instance produces an `HTTPURLResponse`.
|
||||
///
|
||||
/// - Returns: The instance.
|
||||
@discardableResult
|
||||
public func onHTTPResponse(on queue: DispatchQueue = .main,
|
||||
perform handler: @escaping (HTTPURLResponse) -> Void) -> Self {
|
||||
onHTTPResponse(on: queue) { response, completionHandler in
|
||||
handler(response)
|
||||
completionHandler(.allow)
|
||||
}
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func capturingError(from closure: () throws -> Void) {
|
||||
do {
|
||||
try closure()
|
||||
@@ -1395,7 +1550,7 @@ public final class DataStreamRequest: Request {
|
||||
appendResponseSerializer {
|
||||
self.underlyingQueue.async {
|
||||
self.responseSerializerDidComplete {
|
||||
self.$streamMutableState.write { state in
|
||||
self.streamMutableState.write { state in
|
||||
guard state.numberOfExecutingStreams == 0 else {
|
||||
state.enqueuedCompletionEvents.append {
|
||||
self.enqueueCompletion(on: queue, stream: stream)
|
||||
@@ -1546,23 +1701,22 @@ public class DownloadRequest: Request {
|
||||
}
|
||||
|
||||
/// Protected mutable state specific to `DownloadRequest`.
|
||||
@Protected
|
||||
private var mutableDownloadState = DownloadRequestMutableState()
|
||||
private let mutableDownloadState = Protected(DownloadRequestMutableState())
|
||||
|
||||
/// If the download is resumable and is eventually cancelled or fails, this value may be used to resume the download
|
||||
/// using the `download(resumingWith data:)` API.
|
||||
///
|
||||
/// - Note: For more information about `resumeData`, see [Apple's documentation](https://developer.apple.com/documentation/foundation/urlsessiondownloadtask/1411634-cancel).
|
||||
public var resumeData: Data? {
|
||||
#if !(os(Linux) || os(Windows))
|
||||
return $mutableDownloadState.resumeData ?? error?.downloadResumeData
|
||||
#if !canImport(FoundationNetworking) // If we not using swift-corelibs-foundation.
|
||||
return mutableDownloadState.resumeData ?? error?.downloadResumeData
|
||||
#else
|
||||
return $mutableDownloadState.resumeData
|
||||
return mutableDownloadState.resumeData
|
||||
#endif
|
||||
}
|
||||
|
||||
/// If the download is successful, the `URL` where the file was downloaded.
|
||||
public var fileURL: URL? { $mutableDownloadState.fileURL }
|
||||
public var fileURL: URL? { mutableDownloadState.fileURL }
|
||||
|
||||
// MARK: Initial State
|
||||
|
||||
@@ -1605,7 +1759,7 @@ public class DownloadRequest: Request {
|
||||
override func reset() {
|
||||
super.reset()
|
||||
|
||||
$mutableDownloadState.write {
|
||||
mutableDownloadState.write {
|
||||
$0.resumeData = nil
|
||||
$0.fileURL = nil
|
||||
}
|
||||
@@ -1620,7 +1774,7 @@ public class DownloadRequest: Request {
|
||||
eventMonitor?.request(self, didFinishDownloadingUsing: task, with: result)
|
||||
|
||||
switch result {
|
||||
case let .success(url): $mutableDownloadState.fileURL = url
|
||||
case let .success(url): mutableDownloadState.fileURL = url
|
||||
case let .failure(error): self.error = error
|
||||
}
|
||||
}
|
||||
@@ -1698,7 +1852,7 @@ public class DownloadRequest: Request {
|
||||
///
|
||||
/// - Returns: The instance.
|
||||
private func cancel(optionallyProducingResumeData completionHandler: ((_ resumeData: Data?) -> Void)?) -> Self {
|
||||
$mutableState.write { mutableState in
|
||||
mutableState.write { mutableState in
|
||||
guard mutableState.state.canTransitionTo(.cancelled) else { return }
|
||||
|
||||
mutableState.state = .cancelled
|
||||
@@ -1714,7 +1868,7 @@ public class DownloadRequest: Request {
|
||||
// Resume to ensure metrics are gathered.
|
||||
task.resume()
|
||||
task.cancel { resumeData in
|
||||
self.$mutableDownloadState.resumeData = resumeData
|
||||
self.mutableDownloadState.resumeData = resumeData
|
||||
self.underlyingQueue.async { self.didCancelTask(task) }
|
||||
completionHandler(resumeData)
|
||||
}
|
||||
@@ -1754,7 +1908,7 @@ public class DownloadRequest: Request {
|
||||
withResult: result)
|
||||
}
|
||||
|
||||
$validators.write { $0.append(validator) }
|
||||
validators.write { $0.append(validator) }
|
||||
|
||||
return self
|
||||
}
|
||||
|
2
Pods/Alamofire/Source/RequestTaskMap.swift
generated
2
Pods/Alamofire/Source/RequestTaskMap.swift
generated
@@ -131,7 +131,7 @@ struct RequestTaskMap {
|
||||
|
||||
switch (events.completed, events.metricsGathered) {
|
||||
case (true, _): fatalError("RequestTaskMap consistency error: duplicate completionReceivedForTask call.")
|
||||
#if os(Linux) // Linux doesn't gather metrics, so unconditionally remove the reference and return true.
|
||||
#if os(Linux) || os(Android) // Linux doesn't gather metrics, so unconditionally remove the reference and return true.
|
||||
default: self[task] = nil; return true
|
||||
#else
|
||||
case (false, false):
|
||||
|
@@ -1153,7 +1153,7 @@ extension DataStreamRequest {
|
||||
}
|
||||
}
|
||||
|
||||
$streamMutableState.write { $0.streams.append(parser) }
|
||||
streamMutableState.write { $0.streams.append(parser) }
|
||||
appendStreamCompletion(on: queue, stream: stream)
|
||||
|
||||
return self
|
||||
@@ -1195,7 +1195,7 @@ extension DataStreamRequest {
|
||||
}
|
||||
}
|
||||
|
||||
$streamMutableState.write { $0.streams.append(parser) }
|
||||
streamMutableState.write { $0.streams.append(parser) }
|
||||
appendStreamCompletion(on: queue, stream: stream)
|
||||
|
||||
return self
|
||||
@@ -1230,14 +1230,14 @@ extension DataStreamRequest {
|
||||
}
|
||||
}
|
||||
|
||||
$streamMutableState.write { $0.streams.append(parser) }
|
||||
streamMutableState.write { $0.streams.append(parser) }
|
||||
appendStreamCompletion(on: queue, stream: stream)
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
private func updateAndCompleteIfPossible() {
|
||||
$streamMutableState.write { state in
|
||||
streamMutableState.write { state in
|
||||
state.numberOfExecutingStreams -= 1
|
||||
|
||||
guard state.numberOfExecutingStreams == 0, !state.enqueuedCompletionEvents.isEmpty else { return }
|
||||
|
64
Pods/Alamofire/Source/ServerTrustEvaluation.swift
generated
64
Pods/Alamofire/Source/ServerTrustEvaluation.swift
generated
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// ServerTrustPolicy.swift
|
||||
// ServerTrustEvaluation.swift
|
||||
//
|
||||
// Copyright (c) 2014-2016 Alamofire Software Foundation (http://alamofire.org/)
|
||||
//
|
||||
@@ -48,7 +48,7 @@ open class ServerTrustManager {
|
||||
self.evaluators = evaluators
|
||||
}
|
||||
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
/// Returns the `ServerTrustEvaluating` value for the given host, if one is set.
|
||||
///
|
||||
/// By default, this method will return the policy that perfectly matches the given host. Subclasses could override
|
||||
@@ -75,8 +75,8 @@ open class ServerTrustManager {
|
||||
|
||||
/// A protocol describing the API used to evaluate server trusts.
|
||||
public protocol ServerTrustEvaluating {
|
||||
#if os(Linux) || os(Windows)
|
||||
// Implement this once Linux/Windows has API for evaluating server trusts.
|
||||
#if !canImport(Security)
|
||||
// Implement this once other platforms have API for evaluating server trusts.
|
||||
#else
|
||||
/// Evaluates the given `SecTrust` value for the given `host`.
|
||||
///
|
||||
@@ -91,7 +91,7 @@ public protocol ServerTrustEvaluating {
|
||||
|
||||
// MARK: - Server Trust Evaluators
|
||||
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
/// An evaluator which uses the default server trust evaluation while allowing you to control whether to validate the
|
||||
/// host provided by the challenge. Applications are encouraged to always validate the host in production environments
|
||||
/// to guarantee the validity of the server's certificate chain.
|
||||
@@ -181,6 +181,15 @@ public final class RevocationTrustEvaluator: ServerTrustEvaluating {
|
||||
try trust.af.performValidation(forHost: host)
|
||||
}
|
||||
|
||||
#if swift(>=5.9)
|
||||
if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, visionOS 1, *) {
|
||||
try trust.af.evaluate(afterApplying: SecPolicy.af.revocation(options: options))
|
||||
} else {
|
||||
try trust.af.validate(policy: SecPolicy.af.revocation(options: options)) { status, result in
|
||||
AFError.serverTrustEvaluationFailed(reason: .revocationCheckFailed(output: .init(host, trust, status, result), options: options))
|
||||
}
|
||||
}
|
||||
#else
|
||||
if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, *) {
|
||||
try trust.af.evaluate(afterApplying: SecPolicy.af.revocation(options: options))
|
||||
} else {
|
||||
@@ -188,6 +197,7 @@ public final class RevocationTrustEvaluator: ServerTrustEvaluating {
|
||||
AFError.serverTrustEvaluationFailed(reason: .revocationCheckFailed(output: .init(host, trust, status, result), options: options))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,12 +365,10 @@ public final class PublicKeysTrustEvaluator: ServerTrustEvaluating {
|
||||
|
||||
let pinnedKeysInServerKeys: Bool = {
|
||||
for serverPublicKey in trust.af.publicKeys {
|
||||
for pinnedPublicKey in keys {
|
||||
if serverPublicKey == pinnedPublicKey {
|
||||
if keys.contains(serverPublicKey) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}()
|
||||
|
||||
@@ -449,7 +457,7 @@ public final class DisabledTrustEvaluator: ServerTrustEvaluating {
|
||||
// MARK: - Extensions
|
||||
|
||||
extension Array where Element == ServerTrustEvaluating {
|
||||
#if os(Linux) || os(Windows)
|
||||
#if os(Linux) || os(Windows) || os(Android)
|
||||
// Add this same convenience method for Linux/Windows.
|
||||
#else
|
||||
/// Evaluates the given `SecTrust` value for the given `host`.
|
||||
@@ -598,7 +606,15 @@ extension AlamofireExtension where ExtendedType == SecTrust {
|
||||
|
||||
/// The `SecCertificate`s contained in `self`.
|
||||
public var certificates: [SecCertificate] {
|
||||
#if swift(>=5.5.1) // Xcode 13.1 / 2021 SDKs.
|
||||
#if swift(>=5.9)
|
||||
if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, visionOS 1, *) {
|
||||
return (SecTrustCopyCertificateChain(type) as? [SecCertificate]) ?? []
|
||||
} else {
|
||||
return (0..<SecTrustGetCertificateCount(type)).compactMap { index in
|
||||
SecTrustGetCertificateAtIndex(type, index)
|
||||
}
|
||||
}
|
||||
#elseif swift(>=5.5.1) // Xcode 13.1 / 2021 SDKs.
|
||||
if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) {
|
||||
return (SecTrustCopyCertificateChain(type) as? [SecCertificate]) ?? []
|
||||
} else {
|
||||
@@ -623,6 +639,15 @@ extension AlamofireExtension where ExtendedType == SecTrust {
|
||||
/// - Parameter host: The hostname, used only in the error output if validation fails.
|
||||
/// - Throws: An `AFError.serverTrustEvaluationFailed` instance with a `.defaultEvaluationFailed` reason.
|
||||
public func performDefaultValidation(forHost host: String) throws {
|
||||
#if swift(>=5.9)
|
||||
if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, visionOS 1, *) {
|
||||
try evaluate(afterApplying: SecPolicy.af.default)
|
||||
} else {
|
||||
try validate(policy: SecPolicy.af.default) { status, result in
|
||||
AFError.serverTrustEvaluationFailed(reason: .defaultEvaluationFailed(output: .init(host, type, status, result)))
|
||||
}
|
||||
}
|
||||
#else
|
||||
if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, *) {
|
||||
try evaluate(afterApplying: SecPolicy.af.default)
|
||||
} else {
|
||||
@@ -630,6 +655,7 @@ extension AlamofireExtension where ExtendedType == SecTrust {
|
||||
AFError.serverTrustEvaluationFailed(reason: .defaultEvaluationFailed(output: .init(host, type, status, result)))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Validates `self` after applying `SecPolicy.af.hostname(host)`, which performs the default validation as well as
|
||||
@@ -638,6 +664,15 @@ extension AlamofireExtension where ExtendedType == SecTrust {
|
||||
/// - Parameter host: The hostname to use in the validation.
|
||||
/// - Throws: An `AFError.serverTrustEvaluationFailed` instance with a `.defaultEvaluationFailed` reason.
|
||||
public func performValidation(forHost host: String) throws {
|
||||
#if swift(>=5.9)
|
||||
if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, visionOS 1, *) {
|
||||
try evaluate(afterApplying: SecPolicy.af.hostname(host))
|
||||
} else {
|
||||
try validate(policy: SecPolicy.af.hostname(host)) { status, result in
|
||||
AFError.serverTrustEvaluationFailed(reason: .hostValidationFailed(output: .init(host, type, status, result)))
|
||||
}
|
||||
}
|
||||
#else
|
||||
if #available(iOS 12, macOS 10.14, tvOS 12, watchOS 5, *) {
|
||||
try evaluate(afterApplying: SecPolicy.af.hostname(host))
|
||||
} else {
|
||||
@@ -645,6 +680,7 @@ extension AlamofireExtension where ExtendedType == SecTrust {
|
||||
AFError.serverTrustEvaluationFailed(reason: .hostValidationFailed(output: .init(host, type, status, result)))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -704,11 +740,19 @@ extension AlamofireExtension where ExtendedType == SecCertificate {
|
||||
|
||||
guard let createdTrust = trust, trustCreationStatus == errSecSuccess else { return nil }
|
||||
|
||||
#if swift(>=5.9)
|
||||
if #available(iOS 14, macOS 11, tvOS 14, watchOS 7, visionOS 1, *) {
|
||||
return SecTrustCopyKey(createdTrust)
|
||||
} else {
|
||||
return SecTrustCopyPublicKey(createdTrust)
|
||||
}
|
||||
#else
|
||||
if #available(iOS 14, macOS 11, tvOS 14, watchOS 7, *) {
|
||||
return SecTrustCopyKey(createdTrust)
|
||||
} else {
|
||||
return SecTrustCopyPublicKey(createdTrust)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
25
Pods/Alamofire/Source/SessionDelegate.swift
generated
25
Pods/Alamofire/Source/SessionDelegate.swift
generated
@@ -94,7 +94,7 @@ extension SessionDelegate: URLSessionTaskDelegate {
|
||||
case NSURLAuthenticationMethodHTTPBasic, NSURLAuthenticationMethodHTTPDigest, NSURLAuthenticationMethodNTLM,
|
||||
NSURLAuthenticationMethodNegotiate:
|
||||
evaluation = attemptCredentialAuthentication(for: challenge, belongingTo: task)
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
case NSURLAuthenticationMethodServerTrust:
|
||||
evaluation = attemptServerTrustAuthentication(with: challenge)
|
||||
case NSURLAuthenticationMethodClientCertificate:
|
||||
@@ -111,7 +111,7 @@ extension SessionDelegate: URLSessionTaskDelegate {
|
||||
completionHandler(evaluation.disposition, evaluation.credential)
|
||||
}
|
||||
|
||||
#if !(os(Linux) || os(Windows))
|
||||
#if canImport(Security)
|
||||
/// Evaluates the server trust `URLAuthenticationChallenge` received.
|
||||
///
|
||||
/// - Parameter challenge: The `URLAuthenticationChallenge`.
|
||||
@@ -230,6 +230,25 @@ extension SessionDelegate: URLSessionTaskDelegate {
|
||||
// MARK: URLSessionDataDelegate
|
||||
|
||||
extension SessionDelegate: URLSessionDataDelegate {
|
||||
open func urlSession(_ session: URLSession,
|
||||
dataTask: URLSessionDataTask,
|
||||
didReceive response: URLResponse,
|
||||
completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
|
||||
eventMonitor?.urlSession(session, dataTask: dataTask, didReceive: response)
|
||||
|
||||
guard let response = response as? HTTPURLResponse else { completionHandler(.allow); return }
|
||||
|
||||
if let request = request(for: dataTask, as: DataRequest.self) {
|
||||
request.didReceiveResponse(response, completionHandler: completionHandler)
|
||||
} else if let request = request(for: dataTask, as: DataStreamRequest.self) {
|
||||
request.didReceiveResponse(response, completionHandler: completionHandler)
|
||||
} else {
|
||||
assertionFailure("dataTask did not find DataRequest or DataStreamRequest in didReceive response")
|
||||
completionHandler(.allow)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
|
||||
eventMonitor?.urlSession(session, dataTask: dataTask, didReceive: data)
|
||||
|
||||
@@ -238,7 +257,7 @@ extension SessionDelegate: URLSessionDataDelegate {
|
||||
} else if let request = request(for: dataTask, as: DataStreamRequest.self) {
|
||||
request.didReceive(data: data)
|
||||
} else {
|
||||
assertionFailure("dataTask did not find DataRequest or DataStreamRequest in didReceive")
|
||||
assertionFailure("dataTask did not find DataRequest or DataStreamRequest in didReceive data")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
68
Pods/Alamofire/Source/URLEncodedFormEncoder.swift
generated
68
Pods/Alamofire/Source/URLEncodedFormEncoder.swift
generated
@@ -695,6 +695,74 @@ extension _URLEncodedFormEncoder.KeyedContainer: KeyedEncodingContainerProtocol
|
||||
try encode(nilValue, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Bool?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: String?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Double?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Float?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Int?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Int8?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Int16?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Int32?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: Int64?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: UInt?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: UInt8?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: UInt16?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: UInt32?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent(_ value: UInt64?, forKey key: Key) throws {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func encodeIfPresent<Value>(_ value: Value?, forKey key: Key) throws where Value: Encodable {
|
||||
try _encodeIfPresent(value, forKey: key)
|
||||
}
|
||||
|
||||
func _encodeIfPresent<Value>(_ value: Value?, forKey key: Key) throws where Value: Encodable {
|
||||
if let value = value {
|
||||
try encode(value, forKey: key)
|
||||
} else {
|
||||
try encodeNil(forKey: key)
|
||||
}
|
||||
}
|
||||
|
||||
func encode<T>(_ value: T, forKey key: Key) throws where T: Encodable {
|
||||
var container = nestedSingleValueEncoder(for: key)
|
||||
try container.encode(value)
|
||||
|
15
Pods/Manifest.lock
generated
15
Pods/Manifest.lock
generated
@@ -1,5 +1,6 @@
|
||||
PODS:
|
||||
- Alamofire (5.7.1)
|
||||
- Alamofire (5.8.1)
|
||||
- DeviceKit (4.9.0)
|
||||
- HandyJSON (5.0.2)
|
||||
- Kingfisher (7.10.2)
|
||||
- MBProgressHUD (1.2.0)
|
||||
@@ -7,6 +8,8 @@ PODS:
|
||||
- Moya/Core (= 15.0.0)
|
||||
- Moya/Core (15.0.0):
|
||||
- Alamofire (~> 5.0)
|
||||
- "NSObject+Rx (5.2.2)":
|
||||
- RxSwift (~> 6.2)
|
||||
- Reusable (4.1.2):
|
||||
- Reusable/Storyboard (= 4.1.2)
|
||||
- Reusable/View (= 4.1.2)
|
||||
@@ -21,10 +24,12 @@ PODS:
|
||||
- SnapKit (5.6.0)
|
||||
|
||||
DEPENDENCIES:
|
||||
- DeviceKit (~> 4.0)
|
||||
- HandyJSON
|
||||
- Kingfisher
|
||||
- MBProgressHUD
|
||||
- Moya
|
||||
- "NSObject+Rx"
|
||||
- Reusable
|
||||
- RxCocoa
|
||||
- RxSwift
|
||||
@@ -33,10 +38,12 @@ DEPENDENCIES:
|
||||
SPEC REPOS:
|
||||
https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git:
|
||||
- Alamofire
|
||||
- DeviceKit
|
||||
- HandyJSON
|
||||
- Kingfisher
|
||||
- MBProgressHUD
|
||||
- Moya
|
||||
- "NSObject+Rx"
|
||||
- Reusable
|
||||
- RxCocoa
|
||||
- RxRelay
|
||||
@@ -44,17 +51,19 @@ SPEC REPOS:
|
||||
- SnapKit
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: 0123a34370cb170936ae79a8df46cc62b2edeb88
|
||||
Alamofire: 3ca42e259043ee0dc5c0cdd76c4bc568b8e42af7
|
||||
DeviceKit: 847709bf70b78fd9ab765bd571fb9f5f815c3fc1
|
||||
HandyJSON: 9e4e236f5d2dbefad5155a77417bbea438201c03
|
||||
Kingfisher: 99edc495d3b7607e6425f0d6f6847b2abd6d716d
|
||||
MBProgressHUD: 3ee5efcc380f6a79a7cc9b363dd669c5e1ae7406
|
||||
Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
|
||||
"NSObject+Rx": 61cf1f7306a73dcef8b36649198af0813ec18dfd
|
||||
Reusable: 6bae6a5e8aa793c9c441db0213c863a64bce9136
|
||||
RxCocoa: 94f817b71c07517321eb4f9ad299112ca8af743b
|
||||
RxRelay: 1de1523e604c72b6c68feadedd1af3b1b4d0ecbd
|
||||
RxSwift: 5710a9e6b17f3c3d6e40d6e559b9fa1e813b2ef8
|
||||
SnapKit: e01d52ebb8ddbc333eefe2132acf85c8227d9c25
|
||||
|
||||
PODFILE CHECKSUM: e291658151a1fcada5c9dd297587942ae9475225
|
||||
PODFILE CHECKSUM: c70d2998947e71f4b799d573fbe428797987a5b9
|
||||
|
||||
COCOAPODS: 1.12.1
|
||||
|
5068
Pods/Pods.xcodeproj/project.pbxproj
generated
5068
Pods/Pods.xcodeproj/project.pbxproj
generated
File diff suppressed because it is too large
Load Diff
@@ -11,83 +11,97 @@
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>HandyJSON.xcscheme</key>
|
||||
<key>DeviceKit.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>Kingfisher-Kingfisher.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>3</integer>
|
||||
</dict>
|
||||
<key>Kingfisher.xcscheme</key>
|
||||
<key>HandyJSON.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
<key>MBProgressHUD.xcscheme</key>
|
||||
<key>Kingfisher-Kingfisher.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>4</integer>
|
||||
</dict>
|
||||
<key>Moya.xcscheme</key>
|
||||
<key>Kingfisher.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>3</integer>
|
||||
</dict>
|
||||
<key>MBProgressHUD.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>5</integer>
|
||||
</dict>
|
||||
<key>Pods-yinmeng-ios.xcscheme</key>
|
||||
<key>Moya.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>6</integer>
|
||||
</dict>
|
||||
<key>Reusable.xcscheme</key>
|
||||
<key>NSObject+Rx.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>7</integer>
|
||||
</dict>
|
||||
<key>RxCocoa.xcscheme</key>
|
||||
<key>Pods-yinmeng-ios.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>8</integer>
|
||||
</dict>
|
||||
<key>RxRelay.xcscheme</key>
|
||||
<key>Reusable.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>9</integer>
|
||||
</dict>
|
||||
<key>RxSwift.xcscheme</key>
|
||||
<key>RxCocoa.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>10</integer>
|
||||
</dict>
|
||||
<key>SnapKit.xcscheme</key>
|
||||
<key>RxRelay.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>11</integer>
|
||||
</dict>
|
||||
<key>RxSwift.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>12</integer>
|
||||
</dict>
|
||||
<key>SnapKit.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
<key>orderHint</key>
|
||||
<integer>13</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict/>
|
||||
|
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>5.7.1</string>
|
||||
<string>5.8.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
@@ -24,6 +24,28 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
||||
## DeviceKit
|
||||
|
||||
Copyright (c) 2015 Dennis Weissmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
## HandyJSON
|
||||
|
||||
Copyright 1999-2016 Alibaba Group Holding Ltd.
|
||||
@@ -149,6 +171,32 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
## NSObject+Rx
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Ash Furrow
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
|
||||
## Reusable
|
||||
|
||||
The MIT License (MIT)
|
||||
|
@@ -41,6 +41,34 @@ THE SOFTWARE.
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Copyright (c) 2015 Dennis Weissmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.</string>
|
||||
<key>License</key>
|
||||
<string>MIT</string>
|
||||
<key>Title</key>
|
||||
<string>DeviceKit</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string> Copyright 1999-2016 Alibaba Group Holding Ltd.
|
||||
@@ -194,6 +222,38 @@ SOFTWARE.
|
||||
<key>FooterText</key>
|
||||
<string>The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Ash Furrow
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
</string>
|
||||
<key>License</key>
|
||||
<string>MIT</string>
|
||||
<key>Title</key>
|
||||
<string>NSObject+Rx</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 AliSoftware
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
|
@@ -1,9 +1,11 @@
|
||||
${PODS_ROOT}/Target Support Files/Pods-yinmeng-ios/Pods-yinmeng-ios-frameworks.sh
|
||||
${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework
|
||||
${BUILT_PRODUCTS_DIR}/DeviceKit/DeviceKit.framework
|
||||
${BUILT_PRODUCTS_DIR}/HandyJSON/HandyJSON.framework
|
||||
${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework
|
||||
${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework
|
||||
${BUILT_PRODUCTS_DIR}/Moya/Moya.framework
|
||||
${BUILT_PRODUCTS_DIR}/NSObject+Rx/NSObject_Rx.framework
|
||||
${BUILT_PRODUCTS_DIR}/Reusable/Reusable.framework
|
||||
${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework
|
||||
${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework
|
||||
|
@@ -1,8 +1,10 @@
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DeviceKit.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HandyJSON.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MBProgressHUD.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Moya.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NSObject_Rx.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reusable.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxRelay.framework
|
||||
|
@@ -1,9 +1,11 @@
|
||||
${PODS_ROOT}/Target Support Files/Pods-yinmeng-ios/Pods-yinmeng-ios-frameworks.sh
|
||||
${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework
|
||||
${BUILT_PRODUCTS_DIR}/DeviceKit/DeviceKit.framework
|
||||
${BUILT_PRODUCTS_DIR}/HandyJSON/HandyJSON.framework
|
||||
${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework
|
||||
${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework
|
||||
${BUILT_PRODUCTS_DIR}/Moya/Moya.framework
|
||||
${BUILT_PRODUCTS_DIR}/NSObject+Rx/NSObject_Rx.framework
|
||||
${BUILT_PRODUCTS_DIR}/Reusable/Reusable.framework
|
||||
${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework
|
||||
${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework
|
||||
|
@@ -1,8 +1,10 @@
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DeviceKit.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HandyJSON.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Kingfisher.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MBProgressHUD.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Moya.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/NSObject_Rx.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Reusable.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxCocoa.framework
|
||||
${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/RxRelay.framework
|
||||
|
@@ -177,10 +177,12 @@ code_sign_if_enabled() {
|
||||
|
||||
if [[ "$CONFIGURATION" == "Debug" ]]; then
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/DeviceKit/DeviceKit.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/HandyJSON/HandyJSON.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Moya/Moya.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/NSObject+Rx/NSObject_Rx.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Reusable/Reusable.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework"
|
||||
@@ -189,10 +191,12 @@ if [[ "$CONFIGURATION" == "Debug" ]]; then
|
||||
fi
|
||||
if [[ "$CONFIGURATION" == "Release" ]]; then
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/DeviceKit/DeviceKit.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/HandyJSON/HandyJSON.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Kingfisher/Kingfisher.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/MBProgressHUD/MBProgressHUD.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Moya/Moya.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/NSObject+Rx/NSObject_Rx.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/Reusable/Reusable.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/RxCocoa/RxCocoa.framework"
|
||||
install_framework "${BUILT_PRODUCTS_DIR}/RxRelay/RxRelay.framework"
|
||||
|
@@ -1,11 +1,11 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/HandyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/Moya" "${PODS_CONFIGURATION_BUILD_DIR}/Reusable" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/DeviceKit" "${PODS_CONFIGURATION_BUILD_DIR}/HandyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/Moya" "${PODS_CONFIGURATION_BUILD_DIR}/NSObject+Rx" "${PODS_CONFIGURATION_BUILD_DIR}/Reusable" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/HandyJSON/HandyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Moya/Moya.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Reusable/Reusable.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers"
|
||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DeviceKit/DeviceKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/HandyJSON/HandyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Moya/Moya.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/NSObject+Rx/NSObject_Rx.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Reusable/Reusable.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers"
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "Alamofire" -framework "CFNetwork" -framework "CoreGraphics" -framework "Foundation" -framework "HandyJSON" -framework "Kingfisher" -framework "MBProgressHUD" -framework "Moya" -framework "QuartzCore" -framework "Reusable" -framework "RxCocoa" -framework "RxRelay" -framework "RxSwift" -framework "SnapKit" -framework "UIKit" -weak_framework "Combine" -weak_framework "SwiftUI"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "Alamofire" -framework "CFNetwork" -framework "CoreGraphics" -framework "DeviceKit" -framework "Foundation" -framework "HandyJSON" -framework "Kingfisher" -framework "MBProgressHUD" -framework "Moya" -framework "NSObject_Rx" -framework "QuartzCore" -framework "Reusable" -framework "RxCocoa" -framework "RxRelay" -framework "RxSwift" -framework "SnapKit" -framework "UIKit" -weak_framework "Combine" -weak_framework "SwiftUI"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
|
@@ -1,11 +1,11 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/HandyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/Moya" "${PODS_CONFIGURATION_BUILD_DIR}/Reusable" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/DeviceKit" "${PODS_CONFIGURATION_BUILD_DIR}/HandyJSON" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD" "${PODS_CONFIGURATION_BUILD_DIR}/Moya" "${PODS_CONFIGURATION_BUILD_DIR}/NSObject+Rx" "${PODS_CONFIGURATION_BUILD_DIR}/Reusable" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/HandyJSON/HandyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Moya/Moya.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Reusable/Reusable.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers"
|
||||
HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/DeviceKit/DeviceKit.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/HandyJSON/HandyJSON.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Kingfisher/Kingfisher.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MBProgressHUD/MBProgressHUD.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Moya/Moya.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/NSObject+Rx/NSObject_Rx.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Reusable/Reusable.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxCocoa/RxCocoa.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxRelay/RxRelay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift/RxSwift.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/SnapKit/SnapKit.framework/Headers"
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "Alamofire" -framework "CFNetwork" -framework "CoreGraphics" -framework "Foundation" -framework "HandyJSON" -framework "Kingfisher" -framework "MBProgressHUD" -framework "Moya" -framework "QuartzCore" -framework "Reusable" -framework "RxCocoa" -framework "RxRelay" -framework "RxSwift" -framework "SnapKit" -framework "UIKit" -weak_framework "Combine" -weak_framework "SwiftUI"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "Accelerate" -framework "Alamofire" -framework "CFNetwork" -framework "CoreGraphics" -framework "DeviceKit" -framework "Foundation" -framework "HandyJSON" -framework "Kingfisher" -framework "MBProgressHUD" -framework "Moya" -framework "NSObject_Rx" -framework "QuartzCore" -framework "Reusable" -framework "RxCocoa" -framework "RxRelay" -framework "RxSwift" -framework "SnapKit" -framework "UIKit" -weak_framework "Combine" -weak_framework "SwiftUI"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
|
@@ -8,6 +8,9 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
25C63BC8F805551E8754E409 /* Pods_yinmeng_ios.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B2F175918AD0811681497739 /* Pods_yinmeng_ios.framework */; };
|
||||
E81A7BAE2B885B20009E736E /* Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = E81A7BAA2B885B20009E736E /* Base64.m */; };
|
||||
E81A7BAF2B885B20009E736E /* MAIDESEncryptTool.m in Sources */ = {isa = PBXBuildFile; fileRef = E81A7BAB2B885B20009E736E /* MAIDESEncryptTool.m */; };
|
||||
E81A7BB22B886299009E736E /* HUDTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = E81A7BB12B886299009E736E /* HUDTool.swift */; };
|
||||
E86A43AA2B85DFA90084C04D /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86A43A92B85DFA90084C04D /* BaseViewController.swift */; };
|
||||
E86A43AE2B85DFEA0084C04D /* Color+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86A43AD2B85DFEA0084C04D /* Color+.swift */; };
|
||||
E86A43B02B85E11B0084C04D /* BaseNavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86A43AF2B85E11B0084C04D /* BaseNavigationViewController.swift */; };
|
||||
@@ -21,26 +24,32 @@
|
||||
E86A43C82B8743EA0084C04D /* AuthFillDataVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86A43C72B8743EA0084C04D /* AuthFillDataVC.swift */; };
|
||||
E86A43CB2B874C6F0084C04D /* AuthPrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86A43CA2B874C6F0084C04D /* AuthPrivacyView.swift */; };
|
||||
E86A43CD2B874C8E0084C04D /* BaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86A43CC2B874C8E0084C04D /* BaseView.swift */; };
|
||||
E86A43D32B8773C90084C04D /* APPUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86A43D22B8773C90084C04D /* APPUtils.swift */; };
|
||||
E86A43D52B8774B70084C04D /* AuthViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86A43D42B8774B70084C04D /* AuthViewModel.swift */; };
|
||||
E86A43DA2B877A840084C04D /* AppConfigObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86A43D92B877A840084C04D /* AppConfigObject.swift */; };
|
||||
E86A43E82B884C5E0084C04D /* String+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E86A43E72B884C5E0084C04D /* String+.swift */; };
|
||||
E884E85F2B6900C500ADE6EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E884E85E2B6900C500ADE6EE /* AppDelegate.swift */; };
|
||||
E884E8662B6900C500ADE6EE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E884E8642B6900C500ADE6EE /* Main.storyboard */; };
|
||||
E884E8682B6900C600ADE6EE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E884E8672B6900C600ADE6EE /* Assets.xcassets */; };
|
||||
E884E86B2B6900C600ADE6EE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E884E8692B6900C600ADE6EE /* LaunchScreen.storyboard */; };
|
||||
E897B8D82B6C8D1600F884C2 /* YMNetworkAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = E897B8D72B6C8D1600F884C2 /* YMNetworkAPI.swift */; };
|
||||
E897B8DA2B6C903600F884C2 /* NetworkRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E897B8D92B6C903600F884C2 /* NetworkRequest.swift */; };
|
||||
E897B8DC2B6C916A00F884C2 /* HeadstreamRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = E897B8DB2B6C916A00F884C2 /* HeadstreamRequest.swift */; };
|
||||
E897B8DE2B6C91F500F884C2 /* YMRequestX.swift in Sources */ = {isa = PBXBuildFile; fileRef = E897B8DD2B6C91F500F884C2 /* YMRequestX.swift */; };
|
||||
E897B8E02B6C929500F884C2 /* SharedDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = E897B8DF2B6C929500F884C2 /* SharedDriver.swift */; };
|
||||
E897B8E22B6C933E00F884C2 /* LevelStatusBarWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E897B8E12B6C933E00F884C2 /* LevelStatusBarWindowController.swift */; };
|
||||
E897B8E42B6C93C700F884C2 /* YMRequestConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = E897B8E32B6C93C700F884C2 /* YMRequestConfig.swift */; };
|
||||
E897B8E62B6C941400F884C2 /* YMPluginSubType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E897B8E52B6C941400F884C2 /* YMPluginSubType.swift */; };
|
||||
E897B8E82B6C944F00F884C2 /* YMLastNeverResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = E897B8E72B6C944F00F884C2 /* YMLastNeverResult.swift */; };
|
||||
E897B8EB2B6CA1DA00F884C2 /* YMRequestLoadingPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = E897B8EA2B6CA1DA00F884C2 /* YMRequestLoadingPlugin.swift */; };
|
||||
E8D15A9D2B899E1500369467 /* YMNetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D15A9C2B899E1500369467 /* YMNetworkHelper.swift */; };
|
||||
E8D15A9F2B89AED600369467 /* AuthManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D15A9E2B89AED500369467 /* AuthManager.swift */; };
|
||||
E8D15AA12B89AF4F00369467 /* UserTokenObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D15AA02B89AF4F00369467 /* UserTokenObject.swift */; };
|
||||
E8D15AA32B89B03D00369467 /* Deserialized.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D15AA22B89B03D00369467 /* Deserialized.swift */; };
|
||||
E8D15AA62B89B0C600369467 /* List+.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D15AA52B89B0C600369467 /* List+.swift */; };
|
||||
E8D15AA82B89B74700369467 /* YMRequestX.swift in Sources */ = {isa = PBXBuildFile; fileRef = E8D15AA72B89B74700369467 /* YMRequestX.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
A9FB906EB4D17C552C15A2B3 /* Pods-yinmeng-ios.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-yinmeng-ios.debug.xcconfig"; path = "Target Support Files/Pods-yinmeng-ios/Pods-yinmeng-ios.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
B2F175918AD0811681497739 /* Pods_yinmeng_ios.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_yinmeng_ios.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
CB0AC98C54C1D41FA4CA102B /* Pods-yinmeng-ios.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-yinmeng-ios.release.xcconfig"; path = "Target Support Files/Pods-yinmeng-ios/Pods-yinmeng-ios.release.xcconfig"; sourceTree = "<group>"; };
|
||||
E81A7BA92B885B1F009E736E /* yinmeng-ios-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "yinmeng-ios-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
E81A7BAA2B885B20009E736E /* Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Base64.m; sourceTree = "<group>"; };
|
||||
E81A7BAB2B885B20009E736E /* MAIDESEncryptTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAIDESEncryptTool.m; sourceTree = "<group>"; };
|
||||
E81A7BAC2B885B20009E736E /* Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Base64.h; sourceTree = "<group>"; };
|
||||
E81A7BAD2B885B20009E736E /* MAIDESEncryptTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAIDESEncryptTool.h; sourceTree = "<group>"; };
|
||||
E81A7BB12B886299009E736E /* HUDTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDTool.swift; sourceTree = "<group>"; };
|
||||
E86A43A92B85DFA90084C04D /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = "<group>"; };
|
||||
E86A43AD2B85DFEA0084C04D /* Color+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+.swift"; sourceTree = "<group>"; };
|
||||
E86A43AF2B85E11B0084C04D /* BaseNavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseNavigationViewController.swift; sourceTree = "<group>"; };
|
||||
@@ -54,22 +63,22 @@
|
||||
E86A43C72B8743EA0084C04D /* AuthFillDataVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthFillDataVC.swift; sourceTree = "<group>"; };
|
||||
E86A43CA2B874C6F0084C04D /* AuthPrivacyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthPrivacyView.swift; sourceTree = "<group>"; };
|
||||
E86A43CC2B874C8E0084C04D /* BaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseView.swift; sourceTree = "<group>"; };
|
||||
E86A43D22B8773C90084C04D /* APPUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APPUtils.swift; sourceTree = "<group>"; };
|
||||
E86A43D42B8774B70084C04D /* AuthViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthViewModel.swift; sourceTree = "<group>"; };
|
||||
E86A43D92B877A840084C04D /* AppConfigObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConfigObject.swift; sourceTree = "<group>"; };
|
||||
E86A43E72B884C5E0084C04D /* String+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+.swift"; sourceTree = "<group>"; };
|
||||
E884E85B2B6900C500ADE6EE /* yinmeng-ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "yinmeng-ios.app"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E884E85E2B6900C500ADE6EE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
E884E8652B6900C500ADE6EE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
E884E8672B6900C600ADE6EE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
E884E86A2B6900C600ADE6EE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
E884E86C2B6900C600ADE6EE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
E897B8D72B6C8D1600F884C2 /* YMNetworkAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YMNetworkAPI.swift; sourceTree = "<group>"; };
|
||||
E897B8D92B6C903600F884C2 /* NetworkRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkRequest.swift; sourceTree = "<group>"; };
|
||||
E897B8DB2B6C916A00F884C2 /* HeadstreamRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadstreamRequest.swift; sourceTree = "<group>"; };
|
||||
E897B8DD2B6C91F500F884C2 /* YMRequestX.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YMRequestX.swift; sourceTree = "<group>"; };
|
||||
E897B8DF2B6C929500F884C2 /* SharedDriver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedDriver.swift; sourceTree = "<group>"; };
|
||||
E897B8E12B6C933E00F884C2 /* LevelStatusBarWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LevelStatusBarWindowController.swift; sourceTree = "<group>"; };
|
||||
E897B8E32B6C93C700F884C2 /* YMRequestConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YMRequestConfig.swift; sourceTree = "<group>"; };
|
||||
E897B8E52B6C941400F884C2 /* YMPluginSubType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YMPluginSubType.swift; sourceTree = "<group>"; };
|
||||
E897B8E72B6C944F00F884C2 /* YMLastNeverResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YMLastNeverResult.swift; sourceTree = "<group>"; };
|
||||
E897B8EA2B6CA1DA00F884C2 /* YMRequestLoadingPlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YMRequestLoadingPlugin.swift; sourceTree = "<group>"; };
|
||||
E8D15A9C2B899E1500369467 /* YMNetworkHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YMNetworkHelper.swift; sourceTree = "<group>"; };
|
||||
E8D15A9E2B89AED500369467 /* AuthManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthManager.swift; sourceTree = "<group>"; };
|
||||
E8D15AA02B89AF4F00369467 /* UserTokenObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTokenObject.swift; sourceTree = "<group>"; };
|
||||
E8D15AA22B89B03D00369467 /* Deserialized.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Deserialized.swift; sourceTree = "<group>"; };
|
||||
E8D15AA52B89B0C600369467 /* List+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "List+.swift"; sourceTree = "<group>"; };
|
||||
E8D15AA72B89B74700369467 /* YMRequestX.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = YMRequestX.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -101,9 +110,20 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E81A7BB02B88628B009E736E /* Hud */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E81A7BB12B886299009E736E /* HUDTool.swift */,
|
||||
);
|
||||
path = Hud;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E86A43A72B85DF7A0084C04D /* Base */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E8D15A9B2B899DD400369467 /* Request */,
|
||||
E81A7BB02B88628B009E736E /* Hud */,
|
||||
E8EE60802B8858A500D02F6E /* Security */,
|
||||
E86A43BD2B8620BA0084C04D /* Utils */,
|
||||
E86A43A82B85DF850084C04D /* ViewController */,
|
||||
);
|
||||
@@ -124,6 +144,8 @@
|
||||
E86A43AB2B85DFC20084C04D /* Extension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E8D15AA42B89B0BA00369467 /* List */,
|
||||
E86A43E62B884C520084C04D /* String */,
|
||||
E86A43C42B862CB70084C04D /* UIImage */,
|
||||
E86A43AC2B85DFD70084C04D /* Color */,
|
||||
);
|
||||
@@ -149,6 +171,7 @@
|
||||
E86A43B22B85E2170084C04D /* Auth */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E86A43D82B877A6C0084C04D /* Model */,
|
||||
E86A43C92B874C5C0084C04D /* View */,
|
||||
E86A43B42B85E2340084C04D /* VM */,
|
||||
E86A43B32B85E22A0084C04D /* VC */,
|
||||
@@ -171,6 +194,9 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E86A43B52B85E2520084C04D /* AuthAPI.swift */,
|
||||
E86A43D42B8774B70084C04D /* AuthViewModel.swift */,
|
||||
E8D15A9E2B89AED500369467 /* AuthManager.swift */,
|
||||
E8D15AA02B89AF4F00369467 /* UserTokenObject.swift */,
|
||||
);
|
||||
path = VM;
|
||||
sourceTree = "<group>";
|
||||
@@ -179,6 +205,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E86A43BE2B8620C40084C04D /* Utils.swift */,
|
||||
E86A43D22B8773C90084C04D /* APPUtils.swift */,
|
||||
);
|
||||
path = Utils;
|
||||
sourceTree = "<group>";
|
||||
@@ -199,6 +226,22 @@
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E86A43D82B877A6C0084C04D /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E86A43D92B877A840084C04D /* AppConfigObject.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E86A43E62B884C520084C04D /* String */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E86A43E72B884C5E0084C04D /* String+.swift */,
|
||||
);
|
||||
path = String;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E884E8522B6900C500ADE6EE = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -223,7 +266,6 @@
|
||||
E86A43B12B85E1FC0084C04D /* Modules */,
|
||||
E86A43AB2B85DFC20084C04D /* Extension */,
|
||||
E86A43A72B85DF7A0084C04D /* Base */,
|
||||
E897B8D62B6C8CF600F884C2 /* HttpRequest */,
|
||||
E884E85E2B6900C500ADE6EE /* AppDelegate.swift */,
|
||||
E884E8642B6900C500ADE6EE /* Main.storyboard */,
|
||||
E884E8672B6900C600ADE6EE /* Assets.xcassets */,
|
||||
@@ -233,29 +275,34 @@
|
||||
path = "yinmeng-ios";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E897B8D62B6C8CF600F884C2 /* HttpRequest */ = {
|
||||
E8D15A9B2B899DD400369467 /* Request */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E897B8E92B6CA1B500F884C2 /* Plugins */,
|
||||
E897B8D72B6C8D1600F884C2 /* YMNetworkAPI.swift */,
|
||||
E897B8D92B6C903600F884C2 /* NetworkRequest.swift */,
|
||||
E897B8DB2B6C916A00F884C2 /* HeadstreamRequest.swift */,
|
||||
E897B8DD2B6C91F500F884C2 /* YMRequestX.swift */,
|
||||
E897B8DF2B6C929500F884C2 /* SharedDriver.swift */,
|
||||
E897B8E12B6C933E00F884C2 /* LevelStatusBarWindowController.swift */,
|
||||
E897B8E32B6C93C700F884C2 /* YMRequestConfig.swift */,
|
||||
E897B8E52B6C941400F884C2 /* YMPluginSubType.swift */,
|
||||
E897B8E72B6C944F00F884C2 /* YMLastNeverResult.swift */,
|
||||
E8D15AA72B89B74700369467 /* YMRequestX.swift */,
|
||||
E8D15AA22B89B03D00369467 /* Deserialized.swift */,
|
||||
E8D15A9C2B899E1500369467 /* YMNetworkHelper.swift */,
|
||||
);
|
||||
path = HttpRequest;
|
||||
path = Request;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E897B8E92B6CA1B500F884C2 /* Plugins */ = {
|
||||
E8D15AA42B89B0BA00369467 /* List */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E897B8EA2B6CA1DA00F884C2 /* YMRequestLoadingPlugin.swift */,
|
||||
E8D15AA52B89B0C600369467 /* List+.swift */,
|
||||
);
|
||||
path = Plugins;
|
||||
path = List;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E8EE60802B8858A500D02F6E /* Security */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E81A7BAC2B885B20009E736E /* Base64.h */,
|
||||
E81A7BAA2B885B20009E736E /* Base64.m */,
|
||||
E81A7BAD2B885B20009E736E /* MAIDESEncryptTool.h */,
|
||||
E81A7BAB2B885B20009E736E /* MAIDESEncryptTool.m */,
|
||||
E81A7BA92B885B1F009E736E /* yinmeng-ios-Bridging-Header.h */,
|
||||
);
|
||||
path = Security;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
@@ -292,6 +339,7 @@
|
||||
TargetAttributes = {
|
||||
E884E85A2B6900C500ADE6EE = {
|
||||
CreatedOnToolsVersion = 15.0;
|
||||
LastSwiftMigration = 1500;
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -373,30 +421,33 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E897B8E02B6C929500F884C2 /* SharedDriver.swift in Sources */,
|
||||
E86A43AE2B85DFEA0084C04D /* Color+.swift in Sources */,
|
||||
E897B8E22B6C933E00F884C2 /* LevelStatusBarWindowController.swift in Sources */,
|
||||
E8D15A9F2B89AED600369467 /* AuthManager.swift in Sources */,
|
||||
E86A43B62B85E2520084C04D /* AuthAPI.swift in Sources */,
|
||||
E86A43B02B85E11B0084C04D /* BaseNavigationViewController.swift in Sources */,
|
||||
E897B8DE2B6C91F500F884C2 /* YMRequestX.swift in Sources */,
|
||||
E86A43E82B884C5E0084C04D /* String+.swift in Sources */,
|
||||
E8D15AA32B89B03D00369467 /* Deserialized.swift in Sources */,
|
||||
E86A43DA2B877A840084C04D /* AppConfigObject.swift in Sources */,
|
||||
E8D15AA62B89B0C600369467 /* List+.swift in Sources */,
|
||||
E81A7BAE2B885B20009E736E /* Base64.m in Sources */,
|
||||
E81A7BB22B886299009E736E /* HUDTool.swift in Sources */,
|
||||
E86A43BC2B85FA640084C04D /* AuthForgetVC.swift in Sources */,
|
||||
E86A43C32B8628AF0084C04D /* BaeTabBarViewController.swift in Sources */,
|
||||
E897B8DC2B6C916A00F884C2 /* HeadstreamRequest.swift in Sources */,
|
||||
E86A43AA2B85DFA90084C04D /* BaseViewController.swift in Sources */,
|
||||
E884E85F2B6900C500ADE6EE /* AppDelegate.swift in Sources */,
|
||||
E897B8E62B6C941400F884C2 /* YMPluginSubType.swift in Sources */,
|
||||
E86A43B82B85F0B80084C04D /* AuthLaunchVC.swift in Sources */,
|
||||
E86A43C82B8743EA0084C04D /* AuthFillDataVC.swift in Sources */,
|
||||
E897B8DA2B6C903600F884C2 /* NetworkRequest.swift in Sources */,
|
||||
E86A43CD2B874C8E0084C04D /* BaseView.swift in Sources */,
|
||||
E897B8D82B6C8D1600F884C2 /* YMNetworkAPI.swift in Sources */,
|
||||
E8D15AA12B89AF4F00369467 /* UserTokenObject.swift in Sources */,
|
||||
E86A43C62B862CC70084C04D /* UIImage+.swift in Sources */,
|
||||
E86A43D32B8773C90084C04D /* APPUtils.swift in Sources */,
|
||||
E86A43CB2B874C6F0084C04D /* AuthPrivacyView.swift in Sources */,
|
||||
E897B8E42B6C93C700F884C2 /* YMRequestConfig.swift in Sources */,
|
||||
E86A43BF2B8620C40084C04D /* Utils.swift in Sources */,
|
||||
E86A43BA2B85F1360084C04D /* AuthLoginVC.swift in Sources */,
|
||||
E897B8E82B6C944F00F884C2 /* YMLastNeverResult.swift in Sources */,
|
||||
E897B8EB2B6CA1DA00F884C2 /* YMRequestLoadingPlugin.swift in Sources */,
|
||||
E81A7BAF2B885B20009E736E /* MAIDESEncryptTool.m in Sources */,
|
||||
E8D15AA82B89B74700369467 /* YMRequestX.swift in Sources */,
|
||||
E86A43D52B8774B70084C04D /* AuthViewModel.swift in Sources */,
|
||||
E8D15A9D2B899E1500369467 /* YMNetworkHelper.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -547,8 +598,10 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = KQKX28SU5S;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -556,17 +609,18 @@
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "yinmeng.yinmeng-ios";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "yinmeng-ios/Base/Security/yinmeng-ios-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
@@ -578,8 +632,10 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEFINES_MODULE = YES;
|
||||
DEVELOPMENT_TEAM = KQKX28SU5S;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@@ -587,17 +643,17 @@
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = Main;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "yinmeng.yinmeng-ios";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "yinmeng-ios/Base/Security/yinmeng-ios-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<key>yinmeng-ios.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>12</integer>
|
||||
<integer>14</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
|
Binary file not shown.
@@ -3,4 +3,38 @@
|
||||
uuid = "265D86DA-810F-46B5-8843-7CF61C036487"
|
||||
type = "0"
|
||||
version = "2.0">
|
||||
<Breakpoints>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "904BC081-F189-4956-A57F-7ACAED4ADA8A"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "yinmeng-ios/HttpRequest/YMLastNeverResult.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "34"
|
||||
endingLineNumber = "34"
|
||||
landmarkName = "mapResult(success:failure:progress:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "8C81B94B-5918-47EC-A4D7-DA45EBFC4202"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "yinmeng-ios/HttpRequest/YMLastNeverResult.swift"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "47"
|
||||
endingLineNumber = "47"
|
||||
landmarkName = "mapResult(success:failure:progress:)"
|
||||
landmarkType = "7">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
import DeviceKit
|
||||
@main
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
var window: UIWindow?
|
||||
@@ -17,7 +17,11 @@ var window: UIWindow?
|
||||
self.window = UIWindow.init(frame: UIScreen.main.bounds)
|
||||
self.window?.backgroundColor = UIColor.white
|
||||
self.window?.rootViewController = BaseNavigationViewController(rootViewController:AuthLoginVC())
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
145
yinmeng-ios/Base/Hud/HUDTool.swift
Normal file
145
yinmeng-ios/Base/Hud/HUDTool.swift
Normal file
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// HUDTool.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MBProgressHUD
|
||||
|
||||
class HUDTool: NSObject {
|
||||
|
||||
static var currentHud : MBProgressHUD?
|
||||
|
||||
private static let kDelayTime: TimeInterval = 2
|
||||
|
||||
/** 隐藏HUD*/
|
||||
class func hidden(_ time:TimeInterval = 0){
|
||||
guard let HUD = currentHud else {
|
||||
return
|
||||
}
|
||||
HUD.hide(animated: false)
|
||||
currentHud = nil
|
||||
}
|
||||
|
||||
/**
|
||||
显示成功message
|
||||
|
||||
- Parameter message: 文字
|
||||
- Parameter view: 显示在哪个view上
|
||||
- Parameter afterDelay: 延迟消失时间
|
||||
- Parameter enabled: 是否可以拦截事件 no:不拦截 yes:拦截
|
||||
*/
|
||||
class func showSuccess(with message: String, in view: UIView? = YMRequestX.topViewController()?.view, delay afterDelay: TimeInterval = kDelayTime, enabled: Bool = true, icon:String = "") {
|
||||
if message.isEmpty { return }
|
||||
|
||||
DispatchQueue.main.async {
|
||||
hidden(0)
|
||||
var view = view
|
||||
if view == nil {
|
||||
view = YMRequestX.topViewController()?.view ?? YMRequestX.keyWindow()
|
||||
}
|
||||
if let view = view {
|
||||
let hud = normalProgressHUD(in: view)
|
||||
currentHud = hud
|
||||
hud.isUserInteractionEnabled = enabled
|
||||
hud.mode = .customView
|
||||
hud.bezelView.style = .solidColor
|
||||
hud.margin = 8
|
||||
hud.backgroundColor = .clear
|
||||
hud.removeFromSuperViewOnHide = true
|
||||
|
||||
let messageView = HudMessageView()
|
||||
messageView.titleLb.text = message
|
||||
|
||||
let maxWidth = 242.0
|
||||
let size = message.boundingRect(with: CGSize(width: maxWidth, height: CGFLOAT_MAX), font: UIFont.systemFont(ofSize: 14, weight: .medium), lineSpacing: 6)
|
||||
var width = size.width + 5
|
||||
var height = size.height
|
||||
if icon.count > 0 {
|
||||
messageView.logoImgView.image = UIImage(named: icon)
|
||||
messageView.logoImgView.isHidden = false
|
||||
width += 22.0
|
||||
} else {
|
||||
messageView.logoImgView.isHidden = true
|
||||
}
|
||||
|
||||
hud.bezelView.backgroundColor = ThemeColor(hexStr: "#000000", alpha: 0.7)
|
||||
hud.bezelView.layer.cornerRadius = 8
|
||||
hud.bezelView.layer.masksToBounds = true
|
||||
hud.bezelView.addSubview(messageView)
|
||||
|
||||
messageView.snp.makeConstraints { make in
|
||||
make.height.equalTo(height)
|
||||
make.width.equalTo(width)
|
||||
make.center.equalTo(hud.bezelView)
|
||||
}
|
||||
hud.minSize = CGSize(width: width + 40, height: height + 24)
|
||||
hud.show(animated: true)
|
||||
hud.hide(animated: false, afterDelay: kDelayTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class func normalProgressHUD(in view: UIView) -> MBProgressHUD {
|
||||
let hud = MBProgressHUD.showAdded(to: view, animated: true)
|
||||
hud.mode = .indeterminate
|
||||
hud.bezelView.style = .solidColor
|
||||
hud.margin = 8
|
||||
// 方框背景颜色
|
||||
hud.bezelView.color = UIColor.black.withAlphaComponent(0.8)
|
||||
return hud
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class HudMessageView: UIView {
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
self.addSubview(stackView)
|
||||
stackView.addArrangedSubview(logoImgView)
|
||||
stackView.addArrangedSubview(titleLb)
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.edges.equalTo(self)
|
||||
}
|
||||
|
||||
logoImgView.snp.makeConstraints { make in
|
||||
make.size.equalTo(CGSize(width: 20, height: 20))
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let stackView = UIStackView()
|
||||
stackView.distribution = .fill
|
||||
stackView.axis = .horizontal
|
||||
stackView.alignment = .top
|
||||
stackView.spacing = 2
|
||||
return stackView
|
||||
}()
|
||||
|
||||
lazy var logoImgView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.isUserInteractionEnabled = true
|
||||
imageView.layer.masksToBounds = true
|
||||
imageView.contentMode = .scaleAspectFill
|
||||
return imageView
|
||||
}()
|
||||
|
||||
lazy var titleLb: UILabel = {
|
||||
let label = UILabel()
|
||||
label.textColor = UIColor.white
|
||||
label.font = UIFont.systemFont(ofSize: 14, weight: .medium)
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 0
|
||||
return label
|
||||
}()
|
||||
|
||||
|
||||
}
|
37
yinmeng-ios/Base/Request/Deserialized.swift
Normal file
37
yinmeng-ios/Base/Request/Deserialized.swift
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Deserialized.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
@_exported import HandyJSON
|
||||
|
||||
/// Deserialized json converts to Model or Array.
|
||||
public struct Deserialized<H> where H: HandyJSON {
|
||||
|
||||
public static func toModel(with element: Any?) -> H? {
|
||||
if let string = element as? String, let model = H.deserialize(from: string) {
|
||||
return model
|
||||
}
|
||||
if let dictionary = element as? Dictionary<String, Any>, let model = H.deserialize(from: dictionary) {
|
||||
return model
|
||||
}
|
||||
if let dictionary = element as? [String : Any], let model = H.deserialize(from: dictionary) {
|
||||
return model
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
public static func toArray(with element: Any?) -> [H]? {
|
||||
if let string = element as? String, let array = [H].deserialize(from: string) as? [H] {
|
||||
return array
|
||||
}
|
||||
if let array = [H].deserialize(from: element as? [Any]) as? [H] {
|
||||
return array
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
134
yinmeng-ios/Base/Request/YMNetworkHelper.swift
Normal file
134
yinmeng-ios/Base/Request/YMNetworkHelper.swift
Normal file
@@ -0,0 +1,134 @@
|
||||
//
|
||||
// YMNetworkAPI.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
import HandyJSON
|
||||
import DeviceKit
|
||||
typealias SessionCallSucceed = (Any) -> Void
|
||||
typealias SessionCallFail = (Int,String) -> Void
|
||||
|
||||
class YMNetworkHelper: NSObject {
|
||||
|
||||
var baseParameters: [String: Any] {
|
||||
var parameters: [String: Any] = Dictionary()
|
||||
parameters["os"] = "iOS"
|
||||
parameters["osVersion"] = Device.current.systemVersion
|
||||
parameters["model"] = "iPhone14,7"
|
||||
parameters["ispType"] = "1"
|
||||
parameters["channel"] = APPUtils.currentChannle
|
||||
parameters["netType"] = "2"
|
||||
parameters["app"] = "yinmeng"
|
||||
parameters["appVersion"] = APPUtils.appVersion
|
||||
parameters["deviceId"] = APPUtils.currentDeveiceId
|
||||
return parameters
|
||||
}
|
||||
|
||||
var sessionNetMana :Session!
|
||||
public static let share = YMNetworkHelper.init()
|
||||
var headersSet: HTTPHeaders = [
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": ""
|
||||
]
|
||||
|
||||
func requestSend(type:HTTPMethod,path:String,params:Dictionary<String, Any>, succeed:SessionCallSucceed?,fail:SessionCallFail?) -> Void {
|
||||
getHttpRequestHeaders()
|
||||
requestSend(type: type,host: "http://beta.api.ymlive.fun/", path: path, params: params, encoding: URLEncoding.queryString, header: headersSet, succeed: succeed, fail: fail)
|
||||
}
|
||||
|
||||
func requestSend(type:HTTPMethod,
|
||||
host:String,
|
||||
path:String,
|
||||
params:[String: Any],
|
||||
encoding:ParameterEncoding,
|
||||
header:HTTPHeaders,
|
||||
succeed:SessionCallSucceed?,
|
||||
fail:SessionCallFail?) -> Void {
|
||||
let encrypteChonParma = baseParameters.merging(params) {$1}
|
||||
sessionNetMana.request(host+path, method: type, parameters: encrypteChonParma,encoding: encoding,headers: header)
|
||||
.validate(contentType: ["application/json"])
|
||||
.responseJSON { [weak self] (response) in
|
||||
self?.analyzeThe(response1: response, succeed2: succeed, fail3: fail,uuid4:"")
|
||||
}
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
let configCo = AF.sessionConfiguration
|
||||
configCo.httpShouldSetCookies = false
|
||||
configCo.timeoutIntervalForRequest = 30
|
||||
sessionNetMana = Session(configuration: configCo)
|
||||
}
|
||||
|
||||
private func getHttpRequestHeaders() {
|
||||
headersSet["pub_uid"] = "\(AuthManager.userUid)"
|
||||
headersSet["pub_ticket"] = AuthManager.ticket
|
||||
|
||||
}
|
||||
|
||||
|
||||
func analyzeThe(response1:AFDataResponse<Any>,
|
||||
succeed2:SessionCallSucceed?,
|
||||
fail3: SessionCallFail?,uuid4:String) -> Void {
|
||||
let maiUrlSss = response1.request?.url?.absoluteString ?? "unkown"
|
||||
switch response1.result {
|
||||
case .success:
|
||||
let maiResponNk :Dictionary = response1.value as? Dictionary<String, Any> ?? Dictionary.init()
|
||||
let maiResultMo = maiResponNk
|
||||
if maiResultMo.keys.contains("code") {
|
||||
let maicodeNum :Int = maiResultMo["code"] as? Int ?? 0
|
||||
if maicodeNum == 200 {
|
||||
if maiResultMo.keys.contains("data") {
|
||||
let maiDDD = maiResultMo["data"] as Any
|
||||
succeed2?(maiDDD)
|
||||
}else{
|
||||
succeed2?(Dictionary<String, Any>.init())
|
||||
}
|
||||
}else{
|
||||
if maicodeNum == 401 && maiUrlSss.contains("auth-center/sso/logout") == false {
|
||||
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "MAISessionTickValid"), object: nil)
|
||||
sessionNetMana.cancelAllRequests()
|
||||
}
|
||||
var messageIn = response1.error.debugDescription
|
||||
if maiResultMo.keys.contains("message") { messageIn = maiResultMo["message"] as? String ?? "" }
|
||||
fail3?(maicodeNum,messageIn)
|
||||
}
|
||||
} else if maiResultMo.keys.contains("errno") {
|
||||
let maiCodeNum :Int = maiResultMo["errno"] as? Int ?? 0
|
||||
if maiCodeNum == 0 {
|
||||
if maiResultMo.keys.contains("data") {
|
||||
let dataSc = maiResultMo["data"] as Any
|
||||
succeed2?(dataSc)
|
||||
}else{
|
||||
succeed2?(Dictionary<String, Any>.init())
|
||||
}
|
||||
}else{
|
||||
var majmessageStr = response1.error.debugDescription
|
||||
if maiResultMo.keys.contains("errmsg") { majmessageStr = maiResultMo["errmsg"] as? String ?? ""}
|
||||
fail3?(maiCodeNum,majmessageStr)
|
||||
}
|
||||
} else {
|
||||
fail3?(10000,"请求失败")
|
||||
}
|
||||
case let .failure(error):
|
||||
var maiErrorMssg = response1.error?.errorDescription ?? ""
|
||||
var maicodeNum = response1.error?.responseCode ?? 0
|
||||
fail3?(maicodeNum,maiErrorMssg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
struct ResponseModel: HandyJSON {
|
||||
var code:Int? = 0
|
||||
var message:String? = ""
|
||||
var data:Any?
|
||||
}
|
||||
|
||||
|
99
yinmeng-ios/Base/Request/YMRequestX.swift
Normal file
99
yinmeng-ios/Base/Request/YMRequestX.swift
Normal file
@@ -0,0 +1,99 @@
|
||||
//
|
||||
// YMRequestX.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct YMRequestX {
|
||||
/// Maps data received from the signal into a JSON object.
|
||||
public static func mapJSON<T>(_ type: T.Type, named: String, forResource: String = "RxNetworks") -> T? {
|
||||
guard let data = jsonData(named, forResource: forResource) else {
|
||||
return nil
|
||||
}
|
||||
let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
|
||||
return json as? T
|
||||
}
|
||||
|
||||
/// Read json data
|
||||
public static func jsonData(_ named: String, forResource: String = "RxNetworks") -> Data? {
|
||||
let bundle: Bundle?
|
||||
if let bundlePath = Bundle.main.path(forResource: forResource, ofType: "bundle") {
|
||||
bundle = Bundle.init(path: bundlePath)
|
||||
} else {
|
||||
bundle = Bundle.main
|
||||
}
|
||||
guard let path = ["json", "JSON", "Json"].compactMap({
|
||||
bundle?.path(forResource: named, ofType: $0)
|
||||
}).first else {
|
||||
return nil
|
||||
}
|
||||
let contentURL = URL(fileURLWithPath: path)
|
||||
return try? Data(contentsOf: contentURL)
|
||||
}
|
||||
|
||||
public static func toJSON(form value: Any, prettyPrint: Bool = false) -> String? {
|
||||
guard JSONSerialization.isValidJSONObject(value) else {
|
||||
return nil
|
||||
}
|
||||
var jsonData: Data? = nil
|
||||
if prettyPrint {
|
||||
jsonData = try? JSONSerialization.data(withJSONObject: value, options: [.prettyPrinted])
|
||||
} else {
|
||||
jsonData = try? JSONSerialization.data(withJSONObject: value, options: [])
|
||||
}
|
||||
guard let data = jsonData else { return nil }
|
||||
return String(data: data ,encoding: .utf8)
|
||||
}
|
||||
|
||||
public static func toDictionary(form json: String) -> [String : Any]? {
|
||||
guard let jsonData = json.data(using: .utf8),
|
||||
let object = try? JSONSerialization.jsonObject(with: jsonData, options: []),
|
||||
let result = object as? [String : Any] else {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public static func keyWindow() -> UIWindow? {
|
||||
if #available(iOS 13.0, *) {
|
||||
return UIApplication.shared.connectedScenes
|
||||
.filter { $0.activationState == .foregroundActive }
|
||||
.first(where: { $0 is UIWindowScene })
|
||||
.flatMap({ $0 as? UIWindowScene })?.windows
|
||||
.first(where: \.isKeyWindow)
|
||||
} else {
|
||||
return UIApplication.shared.keyWindow
|
||||
}
|
||||
}
|
||||
|
||||
public static func topViewController() -> UIViewController? {
|
||||
let window = UIApplication.shared.delegate?.window
|
||||
guard window != nil, let rootViewController = window?!.rootViewController else {
|
||||
return nil
|
||||
}
|
||||
return self.getTopViewController(controller: rootViewController)
|
||||
}
|
||||
|
||||
public static func getTopViewController(controller: UIViewController) -> UIViewController {
|
||||
if let presentedViewController = controller.presentedViewController {
|
||||
return self.getTopViewController(controller: presentedViewController)
|
||||
} else if let navigationController = controller as? UINavigationController {
|
||||
if let topViewController = navigationController.topViewController {
|
||||
return self.getTopViewController(controller: topViewController)
|
||||
}
|
||||
return navigationController
|
||||
} else if let tabbarController = controller as? UITabBarController {
|
||||
if let selectedViewController = tabbarController.selectedViewController {
|
||||
return self.getTopViewController(controller: selectedViewController)
|
||||
}
|
||||
return tabbarController
|
||||
} else {
|
||||
return controller
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
16
yinmeng-ios/Base/Security/Base64.h
Executable file
16
yinmeng-ios/Base/Security/Base64.h
Executable file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Base64.h
|
||||
// BellFramework
|
||||
//
|
||||
// Created by 罗兴志 on 2017/5/4.
|
||||
// Copyright © 2017年 罗兴志. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface Base64 : NSObject
|
||||
|
||||
+(NSString *)encode:(NSData *)data;
|
||||
+(NSData *)decode:(NSString *)dataString;
|
||||
|
||||
@end
|
133
yinmeng-ios/Base/Security/Base64.m
Executable file
133
yinmeng-ios/Base/Security/Base64.m
Executable file
@@ -0,0 +1,133 @@
|
||||
//
|
||||
// Base64.m
|
||||
// BellFramework
|
||||
//
|
||||
// Created by 罗兴志 on 2017/5/4.
|
||||
// Copyright © 2017年 罗兴志. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Base64.h"
|
||||
|
||||
@interface Base64()
|
||||
+(int)char2Int:(char)c;
|
||||
@end
|
||||
|
||||
@implementation Base64
|
||||
|
||||
static const char encodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
+(NSString *)encode:(NSData *)data
|
||||
{
|
||||
if (data.length == 0)
|
||||
return nil;
|
||||
|
||||
char *characters = malloc(data.length * 3 / 2);
|
||||
|
||||
if (characters == NULL)
|
||||
return nil;
|
||||
|
||||
int end = data.length - 3;
|
||||
int index = 0;
|
||||
int charCount = 0;
|
||||
int n = 0;
|
||||
|
||||
while (index <= end) {
|
||||
int d = (((int)(((char *)[data bytes])[index]) & 0x0ff) << 16)
|
||||
| (((int)(((char *)[data bytes])[index + 1]) & 0x0ff) << 8)
|
||||
| ((int)(((char *)[data bytes])[index + 2]) & 0x0ff);
|
||||
|
||||
characters[charCount++] = encodingTable[(d >> 18) & 63];
|
||||
characters[charCount++] = encodingTable[(d >> 12) & 63];
|
||||
characters[charCount++] = encodingTable[(d >> 6) & 63];
|
||||
characters[charCount++] = encodingTable[d & 63];
|
||||
|
||||
index += 3;
|
||||
|
||||
if(n++ >= 14)
|
||||
{
|
||||
n = 0;
|
||||
characters[charCount++] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if(index == data.length - 2)
|
||||
{
|
||||
int d = (((int)(((char *)[data bytes])[index]) & 0x0ff) << 16)
|
||||
| (((int)(((char *)[data bytes])[index + 1]) & 255) << 8);
|
||||
characters[charCount++] = encodingTable[(d >> 18) & 63];
|
||||
characters[charCount++] = encodingTable[(d >> 12) & 63];
|
||||
characters[charCount++] = encodingTable[(d >> 6) & 63];
|
||||
characters[charCount++] = '=';
|
||||
}
|
||||
else if(index == data.length - 1)
|
||||
{
|
||||
int d = ((int)(((char *)[data bytes])[index]) & 0x0ff) << 16;
|
||||
characters[charCount++] = encodingTable[(d >> 18) & 63];
|
||||
characters[charCount++] = encodingTable[(d >> 12) & 63];
|
||||
characters[charCount++] = '=';
|
||||
characters[charCount++] = '=';
|
||||
}
|
||||
NSString * rtnStr = [[NSString alloc] initWithBytesNoCopy:characters length:charCount encoding:NSUTF8StringEncoding freeWhenDone:YES];
|
||||
return rtnStr;
|
||||
|
||||
}
|
||||
|
||||
+(NSData *)decode:(NSString *)data
|
||||
{
|
||||
if(data == nil || data.length <= 0) {
|
||||
return nil;
|
||||
}
|
||||
NSMutableData *rtnData = [[NSMutableData alloc]init];
|
||||
int slen = data.length;
|
||||
int index = 0;
|
||||
while (true) {
|
||||
while (index < slen && [data characterAtIndex:index] <= ' ') {
|
||||
index++;
|
||||
}
|
||||
if (index >= slen || index + 3 >= slen) {
|
||||
break;
|
||||
}
|
||||
|
||||
int byte = ([self char2Int:[data characterAtIndex:index]] << 18) + ([self char2Int:[data characterAtIndex:index + 1]] << 12) + ([self char2Int:[data characterAtIndex:index + 2]] << 6) + [self char2Int:[data characterAtIndex:index + 3]];
|
||||
Byte temp1 = (byte >> 16) & 255;
|
||||
[rtnData appendBytes:&temp1 length:1];
|
||||
if([data characterAtIndex:index + 2] == '=') {
|
||||
break;
|
||||
}
|
||||
Byte temp2 = (byte >> 8) & 255;
|
||||
[rtnData appendBytes:&temp2 length:1];
|
||||
if([data characterAtIndex:index + 3] == '=') {
|
||||
break;
|
||||
}
|
||||
Byte temp3 = byte & 255;
|
||||
[rtnData appendBytes:&temp3 length:1];
|
||||
index += 4;
|
||||
|
||||
}
|
||||
return rtnData;
|
||||
}
|
||||
|
||||
+(int)char2Int:(char)c
|
||||
{
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
return c - 65;
|
||||
} else if (c >= 'a' && c <= 'z') {
|
||||
return c - 97 + 26;
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
return c - 48 + 26 + 26;
|
||||
} else {
|
||||
switch(c) {
|
||||
case '+':
|
||||
return 62;
|
||||
case '/':
|
||||
return 63;
|
||||
case '=':
|
||||
return 0;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@end
|
16
yinmeng-ios/Base/Security/MAIDESEncryptTool.h
Executable file
16
yinmeng-ios/Base/Security/MAIDESEncryptTool.h
Executable file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// MAIDESEncryptTool.h
|
||||
// BellFramework
|
||||
//
|
||||
// Created by 罗兴志 on 2017/5/4.
|
||||
// Copyright © 2017年 罗兴志. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface MAIDESEncryptTool : NSObject
|
||||
//加密方法
|
||||
+(NSString *)encryptUseDES:(NSString *)plainText key:(NSString *)key;
|
||||
//解密方法
|
||||
+(NSString *)decryptUseDES:(NSString *)cipherText key:(NSString *)key;
|
||||
@end
|
63
yinmeng-ios/Base/Security/MAIDESEncryptTool.m
Executable file
63
yinmeng-ios/Base/Security/MAIDESEncryptTool.m
Executable file
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// MAIDESEncryptTool.m
|
||||
// BellFramework
|
||||
//
|
||||
// Created by 罗兴志 on 2017/5/4.
|
||||
// Copyright © 2017年 罗兴志. All rights reserved.
|
||||
//
|
||||
|
||||
#import "MAIDESEncryptTool.h"
|
||||
#import <CommonCrypto/CommonCrypto.h>
|
||||
#import "Base64.h"
|
||||
|
||||
@implementation MAIDESEncryptTool : NSObject
|
||||
|
||||
const Byte iv[] = {1,2,3,4,5,6,7,8};
|
||||
|
||||
#pragma mark- 加密算法
|
||||
+(NSString *) encryptUseDES:(NSString *)plainText key:(NSString *)key
|
||||
{
|
||||
NSString *ciphertext = nil;
|
||||
NSData *textData = [plainText dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSUInteger dataLength = [textData length];
|
||||
unsigned char buffer[20000];
|
||||
memset(buffer, 0, sizeof(char));
|
||||
size_t numBytesEncrypted = 0;
|
||||
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmDES,
|
||||
kCCOptionPKCS7Padding|kCCOptionECBMode,
|
||||
[key UTF8String], kCCKeySizeDES,
|
||||
iv,
|
||||
[textData bytes], dataLength,
|
||||
buffer, 20000,
|
||||
&numBytesEncrypted);
|
||||
if (cryptStatus == kCCSuccess) {
|
||||
NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
|
||||
ciphertext = [Base64 encode:data];
|
||||
}
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
#pragma mark- 解密算法
|
||||
+(NSString *)decryptUseDES:(NSString *)cipherText key:(NSString *)key
|
||||
{
|
||||
NSString *plaintext = nil;
|
||||
NSData *cipherdata = [Base64 decode:cipherText];
|
||||
unsigned char buffer[20000];
|
||||
memset(buffer, 0, sizeof(char));
|
||||
size_t numBytesDecrypted = 0;
|
||||
// kCCOptionPKCS7Padding|kCCOptionECBMode 最主要在这步
|
||||
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmDES,
|
||||
kCCOptionPKCS7Padding|kCCOptionECBMode,
|
||||
[key UTF8String], kCCKeySizeDES,
|
||||
iv,
|
||||
[cipherdata bytes], [cipherdata length],
|
||||
buffer, 20000,
|
||||
&numBytesDecrypted);
|
||||
if(cryptStatus == kCCSuccess) {
|
||||
NSData *plaindata = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesDecrypted];
|
||||
plaintext = [[NSString alloc]initWithData:plaindata encoding:NSUTF8StringEncoding];
|
||||
}
|
||||
return plaintext;
|
||||
}
|
||||
@end
|
||||
|
5
yinmeng-ios/Base/Security/yinmeng-ios-Bridging-Header.h
Normal file
5
yinmeng-ios/Base/Security/yinmeng-ios-Bridging-Header.h
Normal file
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
#import "MAIDESEncryptTool.h"
|
47
yinmeng-ios/Base/Utils/APPUtils.swift
Normal file
47
yinmeng-ios/Base/Utils/APPUtils.swift
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// APPUtils.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreTelephony
|
||||
import DeviceKit
|
||||
enum TelephonyType: String{
|
||||
case Unknow = "0"
|
||||
case Mobile = "1"
|
||||
case Unicom = "2"
|
||||
case Telecom = "3"
|
||||
}
|
||||
|
||||
|
||||
public struct APPUtils {
|
||||
static var currentCarrierName: String {
|
||||
getCurrentCarrierName()
|
||||
}
|
||||
|
||||
static var currentChannle: String {
|
||||
getCurrentChannle()
|
||||
}
|
||||
|
||||
static var appVersion: String {
|
||||
return Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as! String
|
||||
}
|
||||
|
||||
static var currentDeveiceId: String {
|
||||
var udid = UIDevice.current.identifierForVendor?.uuidString
|
||||
udid = udid?.replacingOccurrences(of: "-", with: "")
|
||||
udid = udid?.lowercased()
|
||||
return udid ?? ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private extension APPUtils {
|
||||
static func getCurrentCarrierName() -> String {
|
||||
return TelephonyType.Unicom.rawValue
|
||||
}
|
||||
|
||||
static func getCurrentChannle() -> String { return "yinmeng_appstore"}
|
||||
}
|
@@ -27,3 +27,6 @@ let SafeAraeBottomHeight = isSafeScreen ? 34.0 : 0.0
|
||||
let SafeAraeTopmHeight = isSafeScreen ? 24.0 : 0.0
|
||||
let NavHeight = (StatusBarHeight + 44)
|
||||
let TabHeight = (49)
|
||||
|
||||
|
||||
let DesKey = "1ea53d260ecf11e7b56e00163e046a26"
|
||||
|
@@ -6,7 +6,6 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
/// 遵循这个协议,可以隐藏导航栏
|
||||
protocol HiddenNavigationBarProtocol where Self: UIViewController {}
|
||||
|
||||
|
49
yinmeng-ios/Extension/List/List+.swift
Normal file
49
yinmeng-ios/Extension/List/List+.swift
Normal file
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// List+.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
extension Array where Element: Equatable {
|
||||
|
||||
mutating func remove(_ element: Element) {
|
||||
|
||||
if let index = firstIndex(of: element) {
|
||||
remove(at: index)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func addObjects(_ elements: [Element]) {
|
||||
for value in elements {
|
||||
self.append(value)
|
||||
}
|
||||
}
|
||||
|
||||
mutating func replaceObject(_ element: Element, index: Int) {
|
||||
if self.count == index {
|
||||
self.append(element)
|
||||
}
|
||||
else if self.count > index {
|
||||
self.insert(element, at: index)
|
||||
self.remove(at: index + 1)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public extension Collection {
|
||||
subscript(safe index: Index) -> Element? {
|
||||
return indices.contains(index) ? self[index] : nil
|
||||
}
|
||||
}
|
||||
|
||||
extension Encodable {
|
||||
var dictionary: [String: Any]? {
|
||||
guard let data = try? JSONEncoder().encode(self) else { return nil }
|
||||
return (try? JSONSerialization.jsonObject(with: data, options: .allowFragments)).flatMap { $0 as? [String: Any] }
|
||||
}
|
||||
}
|
||||
|
||||
|
68
yinmeng-ios/Extension/String/String+.swift
Normal file
68
yinmeng-ios/Extension/String/String+.swift
Normal file
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// String+.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CommonCrypto
|
||||
extension String {
|
||||
|
||||
func encrypt() -> String? {
|
||||
let str = MAIDESEncryptTool.encryptUseDES(self, key: DesKey)
|
||||
return str
|
||||
}
|
||||
|
||||
func decrypt() -> String? {
|
||||
let str = MAIDESEncryptTool.decryptUseDES(self, key: DesKey)
|
||||
return str
|
||||
}
|
||||
|
||||
func decrypt(key:String) -> String? {
|
||||
let str = MAIDESEncryptTool.decryptUseDES(self, key: key)
|
||||
return str
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension String {
|
||||
/// 截取字符串
|
||||
/// - Parameters:
|
||||
/// - begin: 开始截取的索引
|
||||
/// - count: 需要截取的个数
|
||||
/// - Returns: 字符串
|
||||
func substring(start: Int, _ count: Int) -> String {
|
||||
let begin = index(startIndex, offsetBy: max(0, start))
|
||||
let end = index(startIndex, offsetBy: min(count, start + count))
|
||||
return String(self[begin..<end])
|
||||
}
|
||||
|
||||
|
||||
/// 判断字符串是否全部空格
|
||||
var isBlank: Bool {
|
||||
let trimmedStr = self.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
return trimmedStr.isEmpty
|
||||
}
|
||||
|
||||
func boundingRect(with constrainedSize: CGSize, font: UIFont, lineSpacing: CGFloat? = nil) -> CGSize {
|
||||
let attritube = NSMutableAttributedString(string: self)
|
||||
let range = NSRange(location: 0, length: attritube.length)
|
||||
attritube.addAttributes([NSAttributedString.Key.font: font], range: range)
|
||||
if lineSpacing != nil {
|
||||
let paragraphStyle = NSMutableParagraphStyle()
|
||||
paragraphStyle.lineSpacing = lineSpacing ?? 0
|
||||
attritube.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: range)
|
||||
}
|
||||
let rect = attritube.boundingRect(with: constrainedSize, options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil)
|
||||
var size = rect.size
|
||||
if let currentLineSpacing = lineSpacing {
|
||||
let spacing = size.height - font.lineHeight
|
||||
if spacing <= currentLineSpacing && spacing > 0 {
|
||||
size = CGSize(width: size.width, height: font.lineHeight)
|
||||
}
|
||||
}
|
||||
return size
|
||||
}
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
//
|
||||
// HeadstreamRequest.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public final class HeadstreamRequest {
|
||||
/// Empty data, convenient for subsequent plugin operations.
|
||||
public var result: Result<Moya.Response, MoyaError>?
|
||||
|
||||
public var session: Moya.Session?
|
||||
|
||||
/// 是否结束后序网络请求
|
||||
public var endRequest: Bool = false
|
||||
|
||||
public init() { }
|
||||
}
|
||||
|
||||
extension HeadstreamRequest {
|
||||
func toJSON() throws -> Any {
|
||||
guard let result = result else {
|
||||
let userInfo = [
|
||||
NSLocalizedDescriptionKey: "The result is empty."
|
||||
]
|
||||
let error = NSError(domain: "com.condy.rx.network", code: 2004, userInfo: userInfo)
|
||||
throw error
|
||||
}
|
||||
switch result {
|
||||
case .success(let response):
|
||||
return try YMRequestX.toJSON(with: response)
|
||||
case .failure(let error):
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,190 +0,0 @@
|
||||
//
|
||||
// LevelStatusBarWindowController.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
public protocol LevelStatusBarWindowShowUpable {
|
||||
/// 打开状态
|
||||
/// - Parameter superview: 父视图
|
||||
func makeOpenedStatusConstraint(superview: UIView)
|
||||
|
||||
/// 根据添加设置内容,刷新界面
|
||||
func refreshBeforeShow()
|
||||
|
||||
/// 显示
|
||||
/// - Parameters:
|
||||
/// - animated: 是否动画效果
|
||||
/// - animation: 动画内容
|
||||
/// - completion: 完成回调
|
||||
func show(animated: Bool, animation: (() -> Void)?, completion: ((Bool) -> Void)?)
|
||||
|
||||
/// 关闭
|
||||
/// - Parameters:
|
||||
/// - animated: 是否动画效果
|
||||
/// - animation: 动画内容
|
||||
/// - completion: 完成回调
|
||||
func close(animated: Bool, animation: (() -> Void)?, completion: ((Bool) -> Void)?)
|
||||
}
|
||||
|
||||
/// 状态窗口显示器
|
||||
open class LevelStatusBarWindowController: UIViewController {
|
||||
private var isCalledClose = false
|
||||
private var canNotBeCanceled = false
|
||||
private var loadingCount: Int = 0
|
||||
private lazy var lock = NSLock()
|
||||
|
||||
private lazy var overlay: UIView = {
|
||||
let view = UIView(frame: self.view.bounds)
|
||||
view.backgroundColor = overlayBackgroundColor
|
||||
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(overlayTap)))
|
||||
view.isUserInteractionEnabled = true
|
||||
return view
|
||||
}()
|
||||
|
||||
public var key: String?
|
||||
|
||||
public var showUpView: LevelStatusBarWindowShowUpable?
|
||||
|
||||
/// 点击外面区域是否可关闭
|
||||
public var canCloseWhenTapOutSize: Bool = true
|
||||
|
||||
/// 外界已经将`showUpView`添加到控制器
|
||||
public var addedShowUpView: Bool = false
|
||||
|
||||
public var overlayBackgroundColor: UIColor = UIColor.black.withAlphaComponent(0.2) {
|
||||
didSet {
|
||||
self.overlay.backgroundColor = overlayBackgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
public func addedLoadingCount() {
|
||||
self.lock.lock()
|
||||
self.loadingCount += 1
|
||||
self.lock.unlock()
|
||||
}
|
||||
|
||||
public func subtractLoadingCount() -> Int {
|
||||
self.lock.lock()
|
||||
defer { self.lock.unlock() }
|
||||
self.loadingCount -= 1
|
||||
return self.loadingCount
|
||||
}
|
||||
|
||||
open override var prefersStatusBarHidden: Bool {
|
||||
if let controller = YMRequestX.topViewController() {
|
||||
return controller.prefersStatusBarHidden
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
open override var preferredStatusBarStyle: UIStatusBarStyle {
|
||||
if let controller = YMRequestX.topViewController() {
|
||||
return controller.preferredStatusBarStyle
|
||||
}
|
||||
return .default
|
||||
}
|
||||
|
||||
open override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.view.backgroundColor = UIColor.clear
|
||||
self.view.addSubview(self.overlay)
|
||||
if self.addedShowUpView {
|
||||
if let alertView = self.showUpView as? UIView {
|
||||
self.view.bringSubviewToFront(alertView)
|
||||
}
|
||||
} else if let alertView = self.showUpView as? UIView {
|
||||
self.view.addSubview(alertView)
|
||||
}
|
||||
self.showUpView?.makeOpenedStatusConstraint(superview: self.view)
|
||||
}
|
||||
|
||||
private var overlayTapCloseBlock: ((LevelStatusBarWindowController) -> Void)?
|
||||
public func setOverlayTapCloseBlock(block: @escaping (LevelStatusBarWindowController) -> Void) {
|
||||
self.overlayTapCloseBlock = block
|
||||
}
|
||||
|
||||
public func show(completion: ((Bool) -> Void)? = nil) {
|
||||
Self.controllers.removeAll { $0 == self }
|
||||
if let rootViewController = Self.window.rootViewController as? Self, !rootViewController.isCalledClose {
|
||||
Self.controllers.append(rootViewController)
|
||||
Self.window.rootViewController = nil
|
||||
}
|
||||
self.showUpView?.refreshBeforeShow()
|
||||
if Self.lastKeyWindow != Self.window {
|
||||
Self.lastKeyWindow = YMRequestX.keyWindow()
|
||||
}
|
||||
Self.window.isHidden = false
|
||||
Self.window.windowLevel = UIWindow.Level.statusBar
|
||||
Self.window.rootViewController = self
|
||||
Self.window.makeKeyAndVisible()
|
||||
|
||||
self.overlay.alpha = 0
|
||||
self.showUpView?.show(animated: true, animation: { [weak self] in
|
||||
self?.overlay.alpha = 1.0
|
||||
self?.overlay.backgroundColor = self?.overlayBackgroundColor
|
||||
}, completion: completion)
|
||||
}
|
||||
|
||||
public func close(animated: Bool = true) {
|
||||
self.isCalledClose = true
|
||||
self.showUpView?.close(animated: animated, animation: { [weak self] in
|
||||
self?.overlay.alpha = 0
|
||||
}, completion: self.closeCompleted)
|
||||
}
|
||||
|
||||
private func closeCompleted(_: Bool) {
|
||||
guard Self.window.rootViewController == self else {
|
||||
return
|
||||
}
|
||||
if let lastKeyWindow = Self.lastKeyWindow {
|
||||
if lastKeyWindow.rootViewController != nil {
|
||||
lastKeyWindow.makeKeyAndVisible()
|
||||
}
|
||||
Self.lastKeyWindow = nil
|
||||
} else if let window = UIApplication.shared.delegate?.window, window != nil {
|
||||
window?.makeKeyAndVisible()
|
||||
}
|
||||
Self.window.rootViewController = nil
|
||||
Self.window.isHidden = true
|
||||
if Self.controllers.count < 10 {
|
||||
while let rootViewController = Self.controllers.last {
|
||||
if rootViewController.isCalledClose {
|
||||
Self.controllers.removeLast()
|
||||
continue
|
||||
}
|
||||
rootViewController.show()
|
||||
break
|
||||
}
|
||||
} else {
|
||||
Self.controllers.removeAll()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func overlayTap() {
|
||||
if canCloseWhenTapOutSize {
|
||||
close()
|
||||
overlayTapCloseBlock?(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension LevelStatusBarWindowController {
|
||||
private static let window = UIWindow(frame: UIScreen.main.bounds)
|
||||
private static var lastKeyWindow: UIWindow?
|
||||
private static var controllers = [LevelStatusBarWindowController]()
|
||||
|
||||
public static func cancelAllBackgroundControllersShow() {
|
||||
Self.controllers = Self.controllers.filter({ $0.canNotBeCanceled })
|
||||
}
|
||||
|
||||
public static func forcecancelAllControllers() {
|
||||
if let controller = Self.window.rootViewController as? LevelStatusBarWindowController, !controller.canNotBeCanceled {
|
||||
Self.window.rootViewController = nil
|
||||
Self.window.isHidden = true
|
||||
}
|
||||
cancelAllBackgroundControllersShow()
|
||||
}
|
||||
}
|
@@ -1,139 +0,0 @@
|
||||
//
|
||||
// NewworkRequest.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
import Moya
|
||||
|
||||
public extension YMNetworkAPI {
|
||||
@discardableResult func HTTPRequest(
|
||||
success: @escaping APISuccess,
|
||||
failure: @escaping APIFailure,
|
||||
progress: ProgressBlock? = nil,
|
||||
queue: DispatchQueue? = nil,
|
||||
plugins: APIPlugins = []
|
||||
) -> Cancellable? {
|
||||
let key = self.keyPrefix
|
||||
let plugins__ = YMRequestX.setupPluginsAndKey(key, plugins: self.plugins + plugins)
|
||||
|
||||
SharedDriver.shared.addedRequestingAPI(self, key: key, plugins: plugins__)
|
||||
|
||||
let request = self.setupConfiguration(plugins: plugins__)
|
||||
if request.endRequest, let result = request.result {
|
||||
let lastResult = LastNeverResult(result: result, plugins: plugins__)
|
||||
lastResult.mapResult(success: { json in
|
||||
SharedDriver.shared.removeRequestingAPI(key)
|
||||
DispatchQueue.main.async { success(json) }
|
||||
}, failure: { error in
|
||||
SharedDriver.shared.removeRequestingAPI(key)
|
||||
DispatchQueue.main.async { failure(error) }
|
||||
}, progress: progress)
|
||||
return nil
|
||||
}
|
||||
|
||||
let session = request.session ?? {
|
||||
let configuration = URLSessionConfiguration.af.default
|
||||
configuration.timeoutIntervalForRequest = YMRequestConfig.timeoutIntervalForRequest
|
||||
return Moya.Session(
|
||||
configuration: configuration,
|
||||
startRequestsImmediately: false,
|
||||
interceptor: YMRequestConfig.interceptor
|
||||
)
|
||||
}()
|
||||
|
||||
let queue = queue ?? {
|
||||
DispatchQueue(label: "condy.request.network.queue", attributes: [.concurrent])
|
||||
}()
|
||||
|
||||
let target = MultiTarget.target(self)
|
||||
let endpointTask = self.task
|
||||
var endpointHeaders = YMRequestX.hasNetworkHttpHeaderPlugin(key) ?? YMRequestConfig.baseHeaders
|
||||
if let dict = self.headers {
|
||||
// Merge the dictionaries and take the second value.
|
||||
endpointHeaders = endpointHeaders.merging(dict) { $1 }
|
||||
}
|
||||
let provider = MoyaProvider<MultiTarget>.init(endpointClosure: { _ in
|
||||
Endpoint(url: URL(target: target).absoluteString,
|
||||
sampleResponseClosure: { .networkResponse(200, self.sampleData) },
|
||||
method: self.method,
|
||||
task: endpointTask,
|
||||
httpHeaderFields: endpointHeaders)
|
||||
}, stubClosure: { _ in
|
||||
stubBehavior
|
||||
}, callbackQueue: queue, session: session, plugins: plugins__)
|
||||
|
||||
// 先抛出本地数据
|
||||
if let json = try? request.toJSON() {
|
||||
DispatchQueue.main.async { success(json) }
|
||||
}
|
||||
|
||||
// 再处理网络数据
|
||||
return self.request(plugins__, provider: provider, success: { json in
|
||||
SharedDriver.shared.removeRequestingAPI(key)
|
||||
DispatchQueue.main.async { success(json) }
|
||||
}, failure: { error in
|
||||
SharedDriver.shared.removeRequestingAPI(key)
|
||||
DispatchQueue.main.async { failure(error) }
|
||||
}, progress: progress)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func request(plugins: APIPlugins = [], complete: @escaping APIComplete) -> Cancellable? {
|
||||
HTTPRequest(success: { json in
|
||||
complete(.success(json))
|
||||
}, failure: { error in
|
||||
complete(.failure(error))
|
||||
}, plugins: plugins)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension YMNetworkAPI {
|
||||
/// 最开始配置插件信息
|
||||
private func setupConfiguration(plugins: APIPlugins) -> HeadstreamRequest {
|
||||
var request = HeadstreamRequest()
|
||||
plugins.forEach {
|
||||
request = $0.configuration(request, target: self)
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
/// 最后的输出结果,插件配置处理
|
||||
private func setupOutputResult(plugins: APIPlugins, result: APIResponseResult, onNext: @escaping LastNeverCallback) {
|
||||
var lastResult = LastNeverResult(result: result, plugins: plugins)
|
||||
var iterator = plugins.makeIterator()
|
||||
func handleLastNever(_ plugin: PluginSubType?) {
|
||||
guard let plugin = plugin else {
|
||||
onNext(lastResult)
|
||||
return
|
||||
}
|
||||
plugin.lastNever(lastResult, target: self) {
|
||||
lastResult = $0
|
||||
handleLastNever(iterator.next())
|
||||
}
|
||||
}
|
||||
handleLastNever(iterator.next())
|
||||
}
|
||||
|
||||
private func request(_ plugins: APIPlugins,
|
||||
provider: MoyaProvider<MultiTarget>,
|
||||
success: @escaping APISuccess,
|
||||
failure: @escaping APIFailure,
|
||||
progress: ProgressBlock? = nil) -> Cancellable {
|
||||
let target = MultiTarget.target(self)
|
||||
return provider.request(target, progress: progress, completion: { result in
|
||||
setupOutputResult(plugins: plugins, result: result) { lastResult in
|
||||
if lastResult.againRequest {
|
||||
_ = request(plugins, provider: provider, success: success, failure: failure, progress: progress)
|
||||
return
|
||||
}
|
||||
lastResult.mapResult(success: success, failure: failure)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@@ -1,167 +0,0 @@
|
||||
//
|
||||
// YMRequestLoadingPlugin.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Moya
|
||||
import MBProgressHUD
|
||||
|
||||
/// 加载插件,基于MBProgressHUD封装
|
||||
/// Loading plugin, based on MBProgressHUD package
|
||||
public struct YMRequestLoadingPlugin: PluginPropertiesable {
|
||||
|
||||
public var plugins: APIPlugins = []
|
||||
|
||||
public var key: String?
|
||||
|
||||
public var delay: Double {
|
||||
options.delayHideHUD
|
||||
}
|
||||
|
||||
public var options: Options
|
||||
|
||||
public init(options: Options = .init()) {
|
||||
self.options = options
|
||||
}
|
||||
|
||||
/// Hide the loading hud.
|
||||
public func hideMBProgressHUD() {
|
||||
let vc = YMRequestX.removeHUD(key: key)
|
||||
vc?.close()
|
||||
}
|
||||
}
|
||||
|
||||
extension YMRequestLoadingPlugin {
|
||||
public struct Options {
|
||||
/// Loading will not be automatically hidden and display window.
|
||||
public static let dontAutoHide: Options = .init(autoHide: false)
|
||||
|
||||
/// Do you need to display an error message, the default is empty
|
||||
let displayLoadText: String
|
||||
/// Delay hidden, the default is zero seconds
|
||||
let delayHideHUD: Double
|
||||
/// Do you need to automatically hide the loading hud.
|
||||
let autoHideLoading: Bool
|
||||
|
||||
public init(text: String = "", delay: Double = 0.0, autoHide: Bool = true) {
|
||||
self.displayLoadText = text
|
||||
self.delayHideHUD = delay
|
||||
self.autoHideLoading = autoHide
|
||||
}
|
||||
|
||||
var hudCallback: ((_ hud: MBProgressHUD) -> Void)?
|
||||
|
||||
/// Change hud related configuration closures.
|
||||
public mutating func setChangeHudParameters(block: @escaping (_ hud: MBProgressHUD) -> Void) {
|
||||
self.hudCallback = block
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension YMRequestLoadingPlugin: PluginSubType {
|
||||
|
||||
public var pluginName: String {
|
||||
return "Loading"
|
||||
}
|
||||
|
||||
public func willSend(_ request: RequestType, target: TargetType) {
|
||||
DispatchQueue.main.async {
|
||||
self.showText(options.displayLoadText)
|
||||
}
|
||||
}
|
||||
|
||||
public func didReceive(_ result: Result<Moya.Response, MoyaError>, target: TargetType) {
|
||||
if options.autoHideLoading == false, case .success = result {
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + options.delayHideHUD) {
|
||||
self.hideMBProgressHUD()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension YMRequestLoadingPlugin {
|
||||
|
||||
/// Display the prompt text
|
||||
private func showText(_ text: String) {
|
||||
guard let key = self.key else {
|
||||
return
|
||||
}
|
||||
if let vc = YMRequestX.readHUD(key: key) {
|
||||
if let _ = MBProgressHUD.forView(vc.view) {
|
||||
return
|
||||
}
|
||||
vc.show()
|
||||
} else {
|
||||
let vc = LevelStatusBarWindowController()
|
||||
|
||||
// Set Activity Indicator View to white for hud loading.
|
||||
let indicatorView = UIActivityIndicatorView.appearance(whenContainedInInstancesOf: [MBProgressHUD.self])
|
||||
indicatorView.color = UIColor.white
|
||||
|
||||
let hud = MBProgressHUD.showAdded(to: vc.view, animated: true)
|
||||
hud.mode = MBProgressHUDMode.indeterminate
|
||||
hud.animationType = MBProgressHUDAnimation.zoom
|
||||
hud.removeFromSuperViewOnHide = true
|
||||
hud.bezelView.style = MBProgressHUDBackgroundStyle.solidColor
|
||||
hud.bezelView.color = UIColor.black.withAlphaComponent(0.7)
|
||||
hud.bezelView.layer.cornerRadius = 14
|
||||
hud.detailsLabel.text = text
|
||||
hud.detailsLabel.font = UIFont.systemFont(ofSize: 16)
|
||||
hud.detailsLabel.numberOfLines = 0
|
||||
hud.detailsLabel.textColor = UIColor.white
|
||||
|
||||
// User defined the hud configuration.
|
||||
self.options.hudCallback?(hud)
|
||||
|
||||
vc.key = key
|
||||
vc.showUpView = hud
|
||||
vc.addedShowUpView = true
|
||||
vc.show()
|
||||
YMRequestX.saveHUD(key: key, window: vc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension MBProgressHUD: LevelStatusBarWindowShowUpable {
|
||||
|
||||
public func makeOpenedStatusConstraint(superview: UIView) {
|
||||
|
||||
}
|
||||
|
||||
public func refreshBeforeShow() {
|
||||
|
||||
}
|
||||
|
||||
public func show(animated: Bool, animation: (() -> Void)?, completion: ((Bool) -> Void)?) {
|
||||
DispatchQueue.main.async {
|
||||
self.show(animated: animated)
|
||||
if animated {
|
||||
UIView.animate(withDuration: 0.2, animations: {
|
||||
animation?()
|
||||
}, completion: completion)
|
||||
} else {
|
||||
animation?()
|
||||
completion?(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func close(animated: Bool, animation: (() -> Void)?, completion: ((Bool) -> Void)?) {
|
||||
DispatchQueue.main.async {
|
||||
self.hide(animated: animated)
|
||||
if animated {
|
||||
UIView.animate(withDuration: 0.2, animations: {
|
||||
animation?()
|
||||
}, completion: completion)
|
||||
} else {
|
||||
animation?()
|
||||
completion?(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,169 +0,0 @@
|
||||
//
|
||||
// SharedDriver.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Moya
|
||||
|
||||
/// 共享网络中转数据
|
||||
struct SharedDriver {
|
||||
typealias Key = String
|
||||
|
||||
static var shared = SharedDriver()
|
||||
|
||||
private let lock = NSLock()
|
||||
private let tasklock = NSLock()
|
||||
private let HUDsLock = NSLock()
|
||||
|
||||
private var requestingAPIs = [Key: (api: YMNetworkAPI, plugins: APIPlugins)]()
|
||||
private var tasks = [Key: Moya.Cancellable]()
|
||||
|
||||
private var cacheBlocks = [(key: Key, success: APISuccess, failure: APIFailure)]()
|
||||
|
||||
private var cacheHUDs = [Key: LevelStatusBarWindowController]()
|
||||
}
|
||||
|
||||
// MARK: - api
|
||||
extension SharedDriver {
|
||||
|
||||
func readRequestAPI(_ key: Key) -> YMNetworkAPI? {
|
||||
self.lock.lock()
|
||||
defer { lock.unlock() }
|
||||
return self.requestingAPIs[key]?.api
|
||||
}
|
||||
|
||||
func readRequestPlugins(_ key: Key) -> APIPlugins {
|
||||
self.lock.lock()
|
||||
defer { lock.unlock() }
|
||||
return self.requestingAPIs[key]?.plugins ?? []
|
||||
}
|
||||
|
||||
mutating func removeRequestingAPI(_ key: Key) {
|
||||
self.lock.lock()
|
||||
let plugins = self.requestingAPIs[key]?.plugins
|
||||
self.requestingAPIs.removeValue(forKey: key)
|
||||
// 没有正在请求的网络,则移除全部加载Loading
|
||||
if YMRequestConfig.lastCompleteAndCloseLoadingHUDs, self.requestingAPIs.isEmpty, let p = plugins {
|
||||
let maxTime = YMRequestX.maxDelayTime(with: p)
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + maxTime) {
|
||||
SharedDriver.shared.removeLoadingHUDs()
|
||||
}
|
||||
}
|
||||
self.lock.unlock()
|
||||
}
|
||||
|
||||
mutating func addedRequestingAPI(_ api: YMNetworkAPI, key: Key, plugins: APIPlugins) {
|
||||
self.lock.lock()
|
||||
self.requestingAPIs[key] = (api, plugins)
|
||||
self.lock.unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - task and blocks
|
||||
extension SharedDriver {
|
||||
|
||||
func readTask(key: Key) -> Cancellable? {
|
||||
self.tasklock.lock()
|
||||
defer { tasklock.unlock() }
|
||||
return self.tasks[key]
|
||||
}
|
||||
|
||||
mutating func cacheBlocks(key: Key, success: @escaping APISuccess, failure: @escaping APIFailure) {
|
||||
self.tasklock.lock()
|
||||
defer { tasklock.unlock() }
|
||||
self.cacheBlocks.append((key, success, failure))
|
||||
}
|
||||
|
||||
mutating func cacheTask(key: Key, task: Cancellable) {
|
||||
self.tasklock.lock()
|
||||
defer { tasklock.unlock() }
|
||||
self.tasks[key] = task
|
||||
}
|
||||
|
||||
mutating func result(_ type: Result<APISuccessJSON, APIFailureError>, key: Key) {
|
||||
self.tasklock.lock()
|
||||
defer { tasklock.unlock() }
|
||||
switch type {
|
||||
case .success(let json):
|
||||
self.cacheBlocks.forEach {
|
||||
$0.key == key ? $0.success(json) : nil
|
||||
}
|
||||
case .failure(let error):
|
||||
self.cacheBlocks.forEach {
|
||||
$0.key == key ? $0.failure(error) : nil
|
||||
}
|
||||
}
|
||||
self.tasks.removeValue(forKey: key)
|
||||
self.cacheBlocks.removeAll { $0.key == key }
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - hud
|
||||
extension SharedDriver {
|
||||
|
||||
func readHUD(key: String) -> LevelStatusBarWindowController? {
|
||||
self.HUDsLock.lock()
|
||||
defer { HUDsLock.unlock() }
|
||||
return self.cacheHUDs[key]
|
||||
}
|
||||
|
||||
func readHUD(prefix: String) -> [LevelStatusBarWindowController] {
|
||||
self.HUDsLock.lock()
|
||||
defer { HUDsLock.unlock() }
|
||||
return self.cacheHUDs.compactMap {
|
||||
if let prefix_ = $0.key.components(separatedBy: "_").first, prefix_ == prefix {
|
||||
return $0.value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func readHUD(suffix: String) -> [LevelStatusBarWindowController] {
|
||||
self.HUDsLock.lock()
|
||||
defer { HUDsLock.unlock() }
|
||||
return self.cacheHUDs.compactMap {
|
||||
if let suffix_ = $0.key.components(separatedBy: "_").last, suffix_ == suffix {
|
||||
return $0.value
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
mutating func saveHUD(key: Key, window: LevelStatusBarWindowController) {
|
||||
self.HUDsLock.lock()
|
||||
self.cacheHUDs[key] = window
|
||||
self.HUDsLock.unlock()
|
||||
}
|
||||
|
||||
@discardableResult mutating func removeHUD(key: Key?) -> LevelStatusBarWindowController? {
|
||||
guard let key = key else {
|
||||
return nil
|
||||
}
|
||||
self.HUDsLock.lock()
|
||||
let window = self.cacheHUDs[key]
|
||||
self.cacheHUDs.removeValue(forKey: key)
|
||||
self.HUDsLock.unlock()
|
||||
return window
|
||||
}
|
||||
|
||||
mutating func removeAllAtLevelStatusBarWindow() {
|
||||
self.HUDsLock.lock()
|
||||
self.cacheHUDs.forEach {
|
||||
$0.value.close()
|
||||
}
|
||||
self.cacheHUDs.removeAll()
|
||||
self.HUDsLock.unlock()
|
||||
}
|
||||
|
||||
mutating func removeLoadingHUDs() {
|
||||
self.HUDsLock.lock()
|
||||
for (key, hud) in self.cacheHUDs where YMRequestX.loadingSuffix(key: key) {
|
||||
self.cacheHUDs.removeValue(forKey: key)
|
||||
hud.close()
|
||||
}
|
||||
self.HUDsLock.unlock()
|
||||
}
|
||||
}
|
@@ -1,69 +0,0 @@
|
||||
//
|
||||
// YMLastNeverResult.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
public typealias LastNeverCallback = ((_ lastResult: LastNeverResult) -> Void)
|
||||
|
||||
/// Containing the data source and whether auto last network request.
|
||||
public final class LastNeverResult {
|
||||
|
||||
public var result: Result<Moya.Response, MoyaError>
|
||||
|
||||
/// 解决重复解析问题,如果某款插件已经对数据进行解析成Any之后
|
||||
/// Solve the problem of repeated parsing, if a plugin has parsed the data into `Any`
|
||||
public var mapResult: Result<Any, MoyaError>?
|
||||
|
||||
/// 是否自动上次网络请求
|
||||
public var againRequest: Bool = false
|
||||
|
||||
private let plugins: APIPlugins
|
||||
|
||||
public init(result: Result<Moya.Response, MoyaError>, plugins: APIPlugins) {
|
||||
self.result = result
|
||||
self.plugins = plugins
|
||||
}
|
||||
}
|
||||
|
||||
extension LastNeverResult {
|
||||
|
||||
func mapResult(success: APISuccess? = nil, failure: APIFailure? = nil, progress: ProgressBlock? = nil) {
|
||||
if let mapResult = mapResult {
|
||||
switch mapResult {
|
||||
case let .success(json):
|
||||
success?(json)
|
||||
case let .failure(error):
|
||||
failure?(error)
|
||||
}
|
||||
return
|
||||
}
|
||||
switch result {
|
||||
case let .success(response):
|
||||
do {
|
||||
let json = try YMRequestX.toJSON(with: response)
|
||||
self.mapResult = .success(json)
|
||||
success?(json)
|
||||
progress?(ProgressResponse(response: response))
|
||||
} catch MoyaError.statusCode(let response) {
|
||||
let error = MoyaError.statusCode(response)
|
||||
self.mapResult = .failure(error)
|
||||
failure?(error)
|
||||
} catch MoyaError.jsonMapping(let response) {
|
||||
let error = MoyaError.jsonMapping(response)
|
||||
self.mapResult = .failure(error)
|
||||
failure?(error)
|
||||
} catch {
|
||||
if let error = error as? MoyaError {
|
||||
self.mapResult = .failure(error)
|
||||
}
|
||||
failure?(error)
|
||||
}
|
||||
case let .failure(error):
|
||||
self.mapResult = .failure(error)
|
||||
failure?(error)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// YMNetworkAPI.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
@_exported import Alamofire
|
||||
@_exported import Moya
|
||||
public typealias APIHost = String
|
||||
public typealias APIPath = String
|
||||
public typealias APINumber = Int
|
||||
public typealias APIMethod = Moya.Method
|
||||
public typealias APIParameters = Alamofire.Parameters
|
||||
public typealias APIPlugins = [PluginSubType]
|
||||
public typealias APIStubBehavior = Moya.StubBehavior
|
||||
public typealias APISuccessJSON = Any
|
||||
public typealias APIFailureError = Swift.Error
|
||||
public typealias APIResponseResult = Result<Moya.Response, MoyaError>
|
||||
|
||||
public typealias APISuccess = (_ json: APISuccessJSON) -> Void
|
||||
public typealias APIFailure = (_ error: APIFailureError) -> Void
|
||||
public typealias APIComplete = (_ result: Result<APISuccessJSON, APIFailureError>) -> Void
|
||||
|
||||
public protocol YMNetworkAPI: Moya.TargetType {
|
||||
var hostUrl:APIHost {get}
|
||||
var pararms:APIParameters? {get}
|
||||
var plugins:APIPlugins {get}
|
||||
var stubBehavior: APIStubBehavior {get}
|
||||
var retry:APINumber {get}
|
||||
var keyPrefix: String { get }
|
||||
func removeHUD()
|
||||
func removeLoading()
|
||||
}
|
@@ -1,73 +0,0 @@
|
||||
//
|
||||
// YMPluginSubType.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Moya
|
||||
|
||||
public protocol PluginPropertiesable: PluginSubType {
|
||||
var plugins: APIPlugins { get set }
|
||||
|
||||
var key: String? { get set }
|
||||
|
||||
/// Loading HUD delay hide time.
|
||||
var delay: Double { get }
|
||||
}
|
||||
|
||||
extension PluginPropertiesable {
|
||||
public var delay: Double {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
/// 继承Moya插件协议,方便后序扩展,所有插件方法都必须实现该协议
|
||||
/// Inherit the Moya plug-in protocol, which is convenient for subsequent expansion. All plug-in methods must implement this protocol
|
||||
public protocol PluginSubType: Moya.PluginType {
|
||||
|
||||
/// 插件名
|
||||
var pluginName: String { get }
|
||||
|
||||
/// 设置网络配置信息之后,开始准备请求之前,
|
||||
/// 该方法可以用于本地缓存存在时直接抛出数据而不用再执行后序网络请求等场景
|
||||
/// - Parameters:
|
||||
/// - request: 配置信息,其中包含数据源和是否结束后序网络请求
|
||||
/// - target: 参数协议
|
||||
/// - Returns: 包涵数据源和是否结束后序网络请求
|
||||
///
|
||||
/// After setting the network configuration information, before starting to prepare the request,
|
||||
/// This method can be used in scenarios such as throwing data directly when the local cache exists without executing subsequent network requests.
|
||||
/// - Parameters:
|
||||
/// - request: Configuration information, which contains the data source and whether to end the subsequent network request.
|
||||
/// - target: The protocol used to define the specifications necessary for a `MoyaProvider`.
|
||||
/// - Returns: Containing the data source and whether to end the subsequent network request.
|
||||
func configuration(_ request: HeadstreamRequest, target: TargetType) -> HeadstreamRequest
|
||||
|
||||
/// 最后的最后网络响应返回时刻,
|
||||
/// 该方法可以用于密钥失效重新去获取密钥然后自动再次网络请求等场景
|
||||
/// - Parameters:
|
||||
/// - result: 包含数据源和是否自动上次网络请求
|
||||
/// - target: 参数协议
|
||||
/// - onNext: 给插件异步处理任务,回调包含数据源和是否再次开启上次网络请求的元组
|
||||
///
|
||||
/// The last time the last network response is returned,
|
||||
/// This method can be used in scenarios such as key invalidation to obtain the key again and then automatically request the network again.
|
||||
/// - Parameters:
|
||||
/// - result: Containing the data source and whether auto-last network request.
|
||||
/// - target: The protocol used to define the specifications necessary for a `MoyaProvider`.
|
||||
/// - onNext: Provide callbacks for the plug-in to process tasks asynchronously.
|
||||
func lastNever(_ result: LastNeverResult, target: TargetType, onNext: @escaping LastNeverCallback)
|
||||
}
|
||||
|
||||
extension PluginSubType {
|
||||
|
||||
public func configuration(_ request: HeadstreamRequest, target: TargetType) -> HeadstreamRequest {
|
||||
return request
|
||||
}
|
||||
|
||||
public func lastNever(_ result: LastNeverResult, target: TargetType, onNext: @escaping LastNeverCallback) {
|
||||
onNext(result)
|
||||
}
|
||||
}
|
@@ -1,56 +0,0 @@
|
||||
//
|
||||
// YMRequestConfig.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Moya
|
||||
|
||||
/// 网络配置信息,只需要在程序开启的时刻配置一次
|
||||
/// Network configuration information, only need to be configured once when the program is started
|
||||
public struct YMRequestConfig {
|
||||
|
||||
/// Whether to add the Debugging plugin by default
|
||||
public static var addDebugging: Bool = false
|
||||
/// Whether to add the Indicator plugin by default
|
||||
public static var addIndicator: Bool = false
|
||||
/// Set the request timeout, the default is 30 seconds
|
||||
public static var timeoutIntervalForRequest: Double = 30
|
||||
|
||||
public static var interceptor: RequestInterceptor? = nil
|
||||
/// Root path address
|
||||
public static var baseURL: APIHost = ""
|
||||
/// Default request type, default `post`
|
||||
public static var baseMethod: APIMethod = APIMethod.post
|
||||
/// Default basic parameters, similar to: userID, token, etc.
|
||||
public static var baseParameters: APIParameters = [:]
|
||||
/// Default Header argument, 相同数据时该数据会被`NetworkHttpHeaderPlugin`插件覆盖.
|
||||
public static var baseHeaders: [String: String] = [:]
|
||||
/// Plugins that require default injection, generally not recommended
|
||||
/// However, you can inject this kind of global unified general plugin, such as secret key plugin, certificate plugin, etc.
|
||||
public static var basePlugins: [PluginSubType]?
|
||||
|
||||
/// Loading animation JSON, for `AnimatedLoadingPlugin` used.
|
||||
public static var animatedJSON: String?
|
||||
/// Loading the plugin name, to remove the loading plugin from level status bar window.
|
||||
public static var loadingPluginNames: [String] = ["Loading", "AnimatedLoading"]
|
||||
/// Auto close all loading after the end of the last network requesting.
|
||||
public static var lastCompleteAndCloseLoadingHUDs: Bool = true
|
||||
|
||||
/// Update the default basic parameter data, which is generally used for what operation the user has switched.
|
||||
/// - Parameters:
|
||||
/// - value: Update value
|
||||
/// - key: Update key
|
||||
public static func updateBaseParametersWithValue(_ value: AnyObject?, key: String) {
|
||||
var dict = YMRequestConfig.baseParameters
|
||||
if let value = value {
|
||||
dict.updateValue(value, forKey: key)
|
||||
} else {
|
||||
dict.removeValue(forKey: key)
|
||||
}
|
||||
YMRequestConfig.baseParameters = dict
|
||||
}
|
||||
}
|
||||
|
@@ -1,228 +0,0 @@
|
||||
//
|
||||
// YMRequestX.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/2.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public struct YMRequestX {
|
||||
/// Maps data received from the signal into a JSON object.
|
||||
public static func mapJSON<T>(_ type: T.Type, named: String, forResource: String = "RxNetworks") -> T? {
|
||||
guard let data = jsonData(named, forResource: forResource) else {
|
||||
return nil
|
||||
}
|
||||
let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
|
||||
return json as? T
|
||||
}
|
||||
|
||||
/// Read json data
|
||||
public static func jsonData(_ named: String, forResource: String = "RxNetworks") -> Data? {
|
||||
let bundle: Bundle?
|
||||
if let bundlePath = Bundle.main.path(forResource: forResource, ofType: "bundle") {
|
||||
bundle = Bundle.init(path: bundlePath)
|
||||
} else {
|
||||
bundle = Bundle.main
|
||||
}
|
||||
guard let path = ["json", "JSON", "Json"].compactMap({
|
||||
bundle?.path(forResource: named, ofType: $0)
|
||||
}).first else {
|
||||
return nil
|
||||
}
|
||||
let contentURL = URL(fileURLWithPath: path)
|
||||
return try? Data(contentsOf: contentURL)
|
||||
}
|
||||
|
||||
public static func toJSON(form value: Any, prettyPrint: Bool = false) -> String? {
|
||||
guard JSONSerialization.isValidJSONObject(value) else {
|
||||
return nil
|
||||
}
|
||||
var jsonData: Data? = nil
|
||||
if prettyPrint {
|
||||
jsonData = try? JSONSerialization.data(withJSONObject: value, options: [.prettyPrinted])
|
||||
} else {
|
||||
jsonData = try? JSONSerialization.data(withJSONObject: value, options: [])
|
||||
}
|
||||
guard let data = jsonData else { return nil }
|
||||
return String(data: data ,encoding: .utf8)
|
||||
}
|
||||
|
||||
public static func toDictionary(form json: String) -> [String : Any]? {
|
||||
guard let jsonData = json.data(using: .utf8),
|
||||
let object = try? JSONSerialization.jsonObject(with: jsonData, options: []),
|
||||
let result = object as? [String : Any] else {
|
||||
return nil
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
public static func keyWindow() -> UIWindow? {
|
||||
if #available(iOS 13.0, *) {
|
||||
return UIApplication.shared.connectedScenes
|
||||
.filter { $0.activationState == .foregroundActive }
|
||||
.first(where: { $0 is UIWindowScene })
|
||||
.flatMap({ $0 as? UIWindowScene })?.windows
|
||||
.first(where: \.isKeyWindow)
|
||||
} else {
|
||||
return UIApplication.shared.keyWindow
|
||||
}
|
||||
}
|
||||
|
||||
public static func topViewController() -> UIViewController? {
|
||||
let window = UIApplication.shared.delegate?.window
|
||||
guard window != nil, let rootViewController = window?!.rootViewController else {
|
||||
return nil
|
||||
}
|
||||
return self.getTopViewController(controller: rootViewController)
|
||||
}
|
||||
|
||||
public static func getTopViewController(controller: UIViewController) -> UIViewController {
|
||||
if let presentedViewController = controller.presentedViewController {
|
||||
return self.getTopViewController(controller: presentedViewController)
|
||||
} else if let navigationController = controller as? UINavigationController {
|
||||
if let topViewController = navigationController.topViewController {
|
||||
return self.getTopViewController(controller: topViewController)
|
||||
}
|
||||
return navigationController
|
||||
} else if let tabbarController = controller as? UITabBarController {
|
||||
if let selectedViewController = tabbarController.selectedViewController {
|
||||
return self.getTopViewController(controller: selectedViewController)
|
||||
}
|
||||
return tabbarController
|
||||
} else {
|
||||
return controller
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - HUD
|
||||
extension YMRequestX {
|
||||
/// 移除窗口所有HUD
|
||||
public static func removeAllAtLevelStatusBarWindow() {
|
||||
SharedDriver.shared.removeAllAtLevelStatusBarWindow()
|
||||
}
|
||||
|
||||
/// 移除所有加载HUD
|
||||
public static func removeLoadingHUDs() {
|
||||
SharedDriver.shared.removeLoadingHUDs()
|
||||
}
|
||||
|
||||
public static func readHUD(key: String) -> LevelStatusBarWindowController? {
|
||||
SharedDriver.shared.readHUD(key: key)
|
||||
}
|
||||
|
||||
public static func saveHUD(key: String, window vc: LevelStatusBarWindowController) {
|
||||
SharedDriver.shared.saveHUD(key: key, window: vc)
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
public static func removeHUD(key: String?) -> LevelStatusBarWindowController? {
|
||||
SharedDriver.shared.removeHUD(key: key)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - 网络相关
|
||||
extension YMRequestX {
|
||||
|
||||
static func maxDelayTime(with plugins: APIPlugins) -> Double {
|
||||
let times: [Double] = plugins.compactMap {
|
||||
if let p = $0 as? PluginPropertiesable {
|
||||
return p.delay
|
||||
}
|
||||
return 0.0
|
||||
}
|
||||
let maxTime = times.max() ?? 0.0
|
||||
return maxTime
|
||||
}
|
||||
|
||||
static func sortParametersToString(_ parameters: APIParameters?) -> String {
|
||||
guard let params = parameters, !params.isEmpty else {
|
||||
return ""
|
||||
}
|
||||
var paramString = "?"
|
||||
let sorteds = params.sorted(by: { $0.key > $1.key })
|
||||
for index in sorteds.indices {
|
||||
paramString.append("\(sorteds[index].key)=\(sorteds[index].value)")
|
||||
if index != sorteds.count - 1 { paramString.append("&") }
|
||||
}
|
||||
return paramString
|
||||
}
|
||||
|
||||
static func requestLink(with target: TargetType, parameters: APIParameters? = nil) -> String {
|
||||
let parameters: APIParameters? = parameters ?? {
|
||||
if case .requestParameters(let parame, _) = target.task {
|
||||
return parame
|
||||
}
|
||||
return nil
|
||||
}()
|
||||
let paramString = sortParametersToString(parameters)
|
||||
return target.baseURL.absoluteString + target.path + paramString
|
||||
}
|
||||
|
||||
static func toJSON(with response: Moya.Response) throws -> APISuccessJSON {
|
||||
let response = try response.filterSuccessfulStatusCodes()
|
||||
return try response.mapJSON()
|
||||
}
|
||||
|
||||
static func loadingSuffix(key: SharedDriver.Key?) -> Bool {
|
||||
guard let key = key else { return false }
|
||||
if let suffix = key.components(separatedBy: "_").last, YMRequestConfig.loadingPluginNames.contains(suffix) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
static func setupPluginsAndKey(_ key: String, plugins: APIPlugins) -> APIPlugins {
|
||||
var plugins = plugins
|
||||
YMRequestX.setupBasePlugins(&plugins)
|
||||
return plugins.map({
|
||||
if var plugin = $0 as? PluginPropertiesable {
|
||||
plugin.plugins = plugins
|
||||
plugin.key = key + "_" + plugin.pluginName
|
||||
return plugin
|
||||
}
|
||||
return $0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - 模块宏定义
|
||||
extension YMRequestX {
|
||||
|
||||
/// 注入默认插件
|
||||
static func setupBasePlugins(_ plugins: inout APIPlugins) {
|
||||
var plugins_ = plugins
|
||||
if let others = YMRequestConfig.basePlugins {
|
||||
plugins_ += others
|
||||
}
|
||||
#if RXNETWORKS_PLUGINGS_INDICATOR
|
||||
if NetworkConfig.addIndicator, !plugins_.contains(where: { $0 is NetworkIndicatorPlugin}) {
|
||||
let Indicator = NetworkIndicatorPlugin.shared
|
||||
plugins_.insert(Indicator, at: 0)
|
||||
}
|
||||
#endif
|
||||
#if DEBUG && RXNETWORKS_PLUGINGS_DEBUGGING
|
||||
if NetworkConfig.addDebugging, !plugins_.contains(where: { $0 is NetworkDebuggingPlugin}) {
|
||||
let Debugging = NetworkDebuggingPlugin.init()
|
||||
plugins_.append(Debugging)
|
||||
}
|
||||
#endif
|
||||
plugins = plugins_
|
||||
}
|
||||
|
||||
/// 是否存在请求头插件
|
||||
static func hasNetworkHttpHeaderPlugin(_ key: String) -> [String: String]? {
|
||||
#if RXNETWORKS_PLUGINGS_HTTPHEADER
|
||||
let plugins = SharedDriver.shared.readRequestPlugins(key)
|
||||
if let p = plugins.first(where: { $0 is NetworkHttpHeaderPlugin }) {
|
||||
return (p as? NetworkHttpHeaderPlugin)?.dictionary
|
||||
}
|
||||
#endif
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,6 +2,11 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
|
15
yinmeng-ios/Modules/Auth/Model/AppConfigObject.swift
Normal file
15
yinmeng-ios/Modules/Auth/Model/AppConfigObject.swift
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// AppConfigObject.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct AppConfigObject : HandyJSON {
|
||||
var certificationType:Bool? = false
|
||||
var reportSwitch:Bool? = false
|
||||
var teenagerMode:Bool? = false
|
||||
var homeTabList:[String]? = []
|
||||
}
|
@@ -7,12 +7,23 @@
|
||||
|
||||
import UIKit
|
||||
import SnapKit
|
||||
|
||||
import NSObject_Rx
|
||||
|
||||
class AuthLoginVC: BaseViewController, HiddenNavigationBarProtocol {
|
||||
var countdownSeconds = 60
|
||||
var timer: Timer?
|
||||
var viewModel:AuthViewModel = AuthViewModel()
|
||||
var phone:String = ""
|
||||
var code:String = ""
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
loadSubViews()
|
||||
viewModel.data.subscribe(onNext: { [weak self] success in
|
||||
if success {
|
||||
self?.startCountdown()
|
||||
}
|
||||
}).disposed(by: rx.disposeBag)
|
||||
}
|
||||
|
||||
func loadSubViews() {
|
||||
@@ -180,6 +191,7 @@ class AuthLoginVC: BaseViewController, HiddenNavigationBarProtocol {
|
||||
button.setTitleColor(UIColor.white, for: .normal)
|
||||
button.titleLabel?.font = UIFont.systemFont(ofSize: 18, weight: .semibold)
|
||||
button.addTarget(self, action: #selector(phoneLoginBtnAction), for: .touchUpInside)
|
||||
button.isSelected = true
|
||||
return button
|
||||
}()
|
||||
|
||||
@@ -374,11 +386,19 @@ extension AuthLoginVC {
|
||||
}
|
||||
|
||||
@objc func getCodeBtnAction() {
|
||||
|
||||
if phone.count > 0 {
|
||||
viewModel.getSmsCode(phone: phone, type: 1)
|
||||
} else {
|
||||
HUDTool.showSuccess(with: "请输入正确的手机号码")
|
||||
}
|
||||
}
|
||||
|
||||
@objc func confirmBtnAction() {
|
||||
|
||||
if self.phoneLoginBtn.isSelected == true {
|
||||
viewModel.authPhoneCode(phone: phone, code: code)
|
||||
} else {
|
||||
//TODO: id登录
|
||||
}
|
||||
}
|
||||
|
||||
@objc func forgetBtnAction() {
|
||||
@@ -386,11 +406,21 @@ extension AuthLoginVC {
|
||||
}
|
||||
|
||||
@objc func phoneTextFiledDidChange(_ textField: UITextField) {
|
||||
|
||||
if let text = textField.text {
|
||||
if text.count > 11 {
|
||||
textField.text = text.substring(start: 0, 11)
|
||||
}
|
||||
}
|
||||
phone = textField.text ?? ""
|
||||
}
|
||||
|
||||
@objc func codeTextFiledDidChange(_ textField: UITextField) {
|
||||
|
||||
if let text = textField.text {
|
||||
if text.count > 11 {
|
||||
textField.text = text.substring(start: 0, 11)
|
||||
}
|
||||
}
|
||||
code = textField.text ?? ""
|
||||
}
|
||||
|
||||
@objc func idTextFiledDidChange(_ textField: UITextField) {
|
||||
@@ -401,3 +431,38 @@ extension AuthLoginVC {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension AuthLoginVC {
|
||||
|
||||
func startCountdown() {
|
||||
if timer != nil {
|
||||
timer?.invalidate()
|
||||
timer = nil
|
||||
}
|
||||
countdownSeconds = 60
|
||||
timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateCountdown), userInfo: nil, repeats: true)
|
||||
timer!.fire()
|
||||
}
|
||||
|
||||
@objc func updateCountdown() {
|
||||
countdownSeconds -= 1
|
||||
|
||||
if countdownSeconds <= 0 {
|
||||
getCodeBtn.setTitle("重新获取验证码", for: .normal)
|
||||
getCodeBtn.isEnabled = true
|
||||
stopCountdown()
|
||||
return
|
||||
}
|
||||
getCodeBtn.isHidden = false
|
||||
let seconds = countdownSeconds % 60
|
||||
getCodeBtn.setTitle("重新获取验证码(\(seconds)s)", for: .disabled)
|
||||
getCodeBtn.isEnabled = false
|
||||
}
|
||||
|
||||
func stopCountdown() {
|
||||
timer?.invalidate()
|
||||
timer = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -5,8 +5,50 @@
|
||||
// Created by MaiMang on 2024/2/21.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
//import Foundation
|
||||
//import Moya
|
||||
//enum AuthAPI {
|
||||
//
|
||||
// case appConfig
|
||||
// case getCode(String, String)
|
||||
// case authToken(String, String)
|
||||
//}
|
||||
//
|
||||
//extension AuthAPI: YMNetworkAPI {
|
||||
// var hostUrl: APIHost {
|
||||
// return YMRequestConfig.baseURL
|
||||
// }
|
||||
//
|
||||
// var pararms: APIParameters? {
|
||||
// switch self {
|
||||
// case .getCode(let phone, let type):
|
||||
// return ["mobile":phone, "type":type]
|
||||
// case .authToken(let phone, let code):
|
||||
// return ["phone":phone, "code":code, "client_secret":"uyzjdhds", "version":"1", "client_id":"erban-client", "grant_type":"password"]
|
||||
// default:
|
||||
// return [:]
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// var path: String {
|
||||
// switch self {
|
||||
// case .appConfig:
|
||||
// return "/client/init"
|
||||
// case .getCode:
|
||||
// return "/sms/getCode"
|
||||
// case .authToken:
|
||||
// return "/oauth/token"
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// var method: Moya.Method {
|
||||
// switch self {
|
||||
// case .appConfig:
|
||||
// return .get
|
||||
// case .getCode:
|
||||
// return .post
|
||||
// case .authToken:
|
||||
// return .post
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
67
yinmeng-ios/Modules/Auth/VM/AuthManager.swift
Normal file
67
yinmeng-ios/Modules/Auth/VM/AuthManager.swift
Normal file
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// AuthManager.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
private let UserTokenKey = "UserTokenKey"
|
||||
private let UserTicketKey = "UserTicketKey"
|
||||
|
||||
class AuthManager: NSObject {
|
||||
var tokenInfo:UserTokenObject?
|
||||
|
||||
static var userUid:Int {
|
||||
return LoginTokenConfig.config.getAccountInfo()?.uid ?? 0
|
||||
}
|
||||
|
||||
static var ticket:String{
|
||||
return LoginTokenConfig.config.getTicket()
|
||||
}
|
||||
}
|
||||
|
||||
class LoginTokenConfig: NSObject {
|
||||
public static let config = LoginTokenConfig.init()
|
||||
var tokenInfo: UserTokenObject?
|
||||
var ticket:String?
|
||||
func saveTokenToLocaltion(token: UserTokenObject) {
|
||||
self.tokenInfo = token
|
||||
if let dic = token.dictionary {
|
||||
UserDefaults.standard.setValue(dic, forKey: UserTokenKey)
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
}
|
||||
|
||||
func saveTicketToLoaction(ticket:String) {
|
||||
self.ticket = ticket
|
||||
UserDefaults.standard.setValue(ticket, forKey: UserTicketKey)
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
|
||||
func getTicket() -> String {
|
||||
if let ticket = self.ticket {
|
||||
return ticket
|
||||
}
|
||||
|
||||
if let ticket = UserDefaults.standard.value(forKey: UserTicketKey) as? String{
|
||||
self.ticket = ticket
|
||||
}
|
||||
|
||||
return self.ticket ?? ""
|
||||
}
|
||||
|
||||
func getAccountInfo() -> UserTokenObject? {
|
||||
if let accountModel = self.tokenInfo {
|
||||
return accountModel
|
||||
}
|
||||
|
||||
if let dic = UserDefaults.standard.value(forKey: UserTokenKey), let model = Deserialized<UserTokenObject>.toModel(with: dic){
|
||||
self.tokenInfo = model
|
||||
}
|
||||
|
||||
return self.tokenInfo
|
||||
}
|
||||
|
||||
}
|
28
yinmeng-ios/Modules/Auth/VM/AuthViewModel.swift
Normal file
28
yinmeng-ios/Modules/Auth/VM/AuthViewModel.swift
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// AuthViewModel.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RxSwift
|
||||
class AuthViewModel: NSObject {
|
||||
|
||||
let data = PublishSubject<Bool>()
|
||||
|
||||
func getSmsCode(phone:String, type:Int) {
|
||||
if let phoneDes = phone.encrypt() {
|
||||
let params:[String: Any] = ["mobile":phoneDes, "type":type]
|
||||
YMNetworkHelper.share.requestSend(type: .post, path: "sms/getCode", params: params, succeed: { data in
|
||||
self.data.onNext(true)
|
||||
}, fail: { code, msg in
|
||||
self.data.onNext(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func authPhoneCode(phone:String, code:String) {
|
||||
|
||||
}
|
||||
}
|
15
yinmeng-ios/Modules/Auth/VM/UserTokenObject.swift
Normal file
15
yinmeng-ios/Modules/Auth/VM/UserTokenObject.swift
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// UserTokenObject.swift
|
||||
// yinmeng-ios
|
||||
//
|
||||
// Created by MaiMang on 2024/2/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import HandyJSON
|
||||
|
||||
struct UserTokenObject: HandyJSON, Codable {
|
||||
var uid:Int? = 0
|
||||
var netEaseToken:String? = ""
|
||||
var access_token:String? = ""
|
||||
}
|
Reference in New Issue
Block a user