@@ -11,6 +11,14 @@ public class AlamofireWrapper: NSObject {
1111 private var securityPolicy : SecurityPolicyWrapper ?
1212 private var cacheResponseHandler : ( ( URLSession , URLSessionDataTask , CachedURLResponse ) -> CachedURLResponse ? ) ?
1313
14+ // Store active requests by ID for cancellation
15+ private var activeRequests : [ String : Request ] = [ : ]
16+ private let requestsLock = NSLock ( )
17+
18+ // Interceptors
19+ private var requestInterceptors : [ RequestInterceptor ] = [ ]
20+ private var eventMonitors : [ EventMonitor ] = [ ]
21+
1422 @objc public static let shared = AlamofireWrapper ( )
1523
1624 @objc public override init ( ) {
@@ -78,14 +86,52 @@ public class AlamofireWrapper: NSObject {
7886 // Use allHostsMustBeEvaluated: false to allow default trust evaluation for non-pinned hosts
7987 let serverTrustManager = ServerTrustManager ( allHostsMustBeEvaluated: false , evaluators: [ : ] )
8088
81- // Create new session with server trust manager
89+ // Create new session with server trust manager and interceptors
8290 // Keep the session alive by replacing it atomically
8391 session = Session (
8492 configuration: configuration,
85- serverTrustManager: serverTrustManager
93+ serverTrustManager: serverTrustManager,
94+ eventMonitors: eventMonitors
8695 )
8796 }
8897
98+ // MARK: - Interceptors
99+
100+ /// Add a request interceptor (for request/response modification)
101+ @objc public func addInterceptor( _ interceptor: RequestInterceptor ) {
102+ requestInterceptors. append ( interceptor)
103+ }
104+
105+ /// Add an event monitor (for network-level events like Android's network interceptor)
106+ @objc public func addEventMonitor( _ monitor: EventMonitor ) {
107+ eventMonitors. append ( monitor)
108+ recreateSession ( ) // Recreate session to apply new event monitors
109+ }
110+
111+ // MARK: - Request Management
112+
113+ /// Store a request by ID
114+ private func storeRequest( _ request: Request , id: String ) {
115+ requestsLock. lock ( )
116+ defer { requestsLock. unlock ( ) }
117+ activeRequests [ id] = request
118+ }
119+
120+ /// Remove a request by ID
121+ private func removeRequest( id: String ) {
122+ requestsLock. lock ( )
123+ defer { requestsLock. unlock ( ) }
124+ activeRequests. removeValue ( forKey: id)
125+ }
126+
127+ /// Cancel a request by ID
128+ @objc public func cancelRequest( id: String ) {
129+ requestsLock. lock ( )
130+ let request = activeRequests [ id]
131+ requestsLock. unlock ( )
132+ request? . cancel ( )
133+ }
134+
89135 /// Get dispatch queue for responses
90136 private func responseQueue( mainThread: Bool ? ) -> DispatchQueue {
91137 // Default to main thread if not specified (matches Android behavior)
@@ -131,16 +177,18 @@ public class AlamofireWrapper: NSObject {
131177 _ urlString: String ,
132178 _ parameters: NSDictionary ? ,
133179 _ headers: NSDictionary ? ,
180+ _ requestId: String ,
134181 _ uploadProgress: ( ( Progress ) -> Void ) ? ,
135182 _ downloadProgress: ( ( Progress ) -> Void ) ? ,
136- _ success: @escaping ( URLSessionTask ? , Any ? ) -> Void ,
137- _ failure: @escaping ( URLSessionTask ? , Error ) -> Void
138- ) -> URLSessionTask ? {
139- return requestWithThreading (
183+ _ success: @escaping ( NSHTTPURLResponse ? , Any ? ) -> Void ,
184+ _ failure: @escaping ( NSHTTPURLResponse ? , Error ) -> Void
185+ ) {
186+ requestWithThreading (
140187 method,
141188 urlString,
142189 parameters,
143190 headers,
191+ requestId,
144192 nil , // responseOnMainThread - defaults to true
145193 nil , // progressOnMainThread - defaults to responseOnMainThread
146194 uploadProgress,
@@ -156,18 +204,19 @@ public class AlamofireWrapper: NSObject {
156204 _ urlString: String ,
157205 _ parameters: NSDictionary ? ,
158206 _ headers: NSDictionary ? ,
207+ _ requestId: String ,
159208 _ responseOnMainThread: NSNumber ? , // NSNumber wrapper for optional Bool
160209 _ progressOnMainThread: NSNumber ? , // NSNumber wrapper for optional Bool
161210 _ uploadProgress: ( ( Progress ) -> Void ) ? ,
162211 _ downloadProgress: ( ( Progress ) -> Void ) ? ,
163- _ success: @escaping ( URLSessionTask ? , Any ? ) -> Void ,
164- _ failure: @escaping ( URLSessionTask ? , Error ) -> Void
165- ) -> URLSessionTask ? {
212+ _ success: @escaping ( NSHTTPURLResponse ? , Any ? ) -> Void ,
213+ _ failure: @escaping ( NSHTTPURLResponse ? , Error ) -> Void
214+ ) {
166215
167216 guard let url = URL ( string: urlString) else {
168217 let error = NSError ( domain: " AlamofireWrapper " , code: - 1 , userInfo: [ NSLocalizedDescriptionKey: " Invalid URL " ] )
169218 failure ( nil , error)
170- return nil
219+ return
171220 }
172221
173222 var request : URLRequest
@@ -182,11 +231,19 @@ public class AlamofireWrapper: NSObject {
182231 try requestSerializer. encodeParameters ( parameters, into: & request, method: HTTPMethod ( rawValue: method. uppercased ( ) ) )
183232 } catch {
184233 failure ( nil , error)
185- return nil
234+ return
186235 }
187236
188237 var afRequest : DataRequest = session. request ( request)
189238
239+ // Store request for cancellation
240+ storeRequest ( afRequest, id: requestId)
241+
242+ // Apply interceptors
243+ for interceptor in requestInterceptors {
244+ afRequest = afRequest. interceptor ( interceptor) as! DataRequest
245+ }
246+
190247 // Apply server trust evaluation if security policy is set
191248 if let host = url. host {
192249 afRequest = applyServerTrustValidation ( afRequest, host: host)
@@ -216,26 +273,25 @@ public class AlamofireWrapper: NSObject {
216273 afRequest. response ( queue: respQueue) { [ weak self] response in
217274 guard let self = self else { return }
218275
219- // Get the actual task from the DataRequest (available after request started)
220- let task = response. request? . task
276+ // Remove request from active list
277+ self . removeRequest ( id: requestId)
278+
279+ // Get the HTTP response
280+ let httpResponse = response. response as? NSHTTPURLResponse
221281
222282 if let error = response. error {
223283 let nsError = self . createNSError ( from: error, response: response. response, data: response. data)
224- failure ( task , nsError)
284+ failure ( httpResponse , nsError)
225285 return
226286 }
227287
228288 // Deserialize response based on responseSerializer
229289 if let data = response. data {
230- // let result = self.responseSerializer.deserialize(data: data, response: response.response)
231- success ( task, data)
290+ success ( httpResponse, data)
232291 } else {
233- success ( task , nil )
292+ success ( httpResponse , nil )
234293 }
235294 }
236-
237- // Return the task (it will be available after request starts)
238- return afRequest. task
239295 }
240296
241297 // MARK: - Multipart Form Data
@@ -244,14 +300,16 @@ public class AlamofireWrapper: NSObject {
244300 @objc public func uploadMultipart(
245301 _ urlString: String ,
246302 _ headers: NSDictionary ? ,
303+ _ requestId: String ,
247304 _ constructingBodyWithBlock: @escaping ( MultipartFormDataWrapper ) -> Void ,
248305 _ progress: ( ( Progress ) -> Void ) ? ,
249- _ success: @escaping ( URLSessionTask ? , Any ? ) -> Void ,
250- _ failure: @escaping ( URLSessionTask ? , Error ) -> Void
251- ) -> URLSessionTask ? {
252- return uploadMultipartWithThreading (
306+ _ success: @escaping ( NSHTTPURLResponse ? , Any ? ) -> Void ,
307+ _ failure: @escaping ( NSHTTPURLResponse ? , Error ) -> Void
308+ ) {
309+ uploadMultipartWithThreading (
253310 urlString,
254311 headers,
312+ requestId,
255313 nil , // responseOnMainThread
256314 nil , // progressOnMainThread
257315 constructingBodyWithBlock,
@@ -265,18 +323,19 @@ public class AlamofireWrapper: NSObject {
265323 @objc public func uploadMultipartWithThreading(
266324 _ urlString: String ,
267325 _ headers: NSDictionary ? ,
326+ _ requestId: String ,
268327 _ responseOnMainThread: NSNumber ? ,
269328 _ progressOnMainThread: NSNumber ? ,
270329 _ constructingBodyWithBlock: @escaping ( MultipartFormDataWrapper ) -> Void ,
271330 _ progress: ( ( Progress ) -> Void ) ? ,
272- _ success: @escaping ( URLSessionTask ? , Any ? ) -> Void ,
273- _ failure: @escaping ( URLSessionTask ? , Error ) -> Void
274- ) -> URLSessionTask ? {
331+ _ success: @escaping ( NSHTTPURLResponse ? , Any ? ) -> Void ,
332+ _ failure: @escaping ( NSHTTPURLResponse ? , Error ) -> Void
333+ ) {
275334
276335 guard let url = URL ( string: urlString) else {
277336 let error = NSError ( domain: " AlamofireWrapper " , code: - 1 , userInfo: [ NSLocalizedDescriptionKey: " Invalid URL " ] )
278337 failure ( nil , error)
279- return nil
338+ return
280339 }
281340
282341 let wrapper = MultipartFormDataWrapper ( )
@@ -292,13 +351,21 @@ public class AlamofireWrapper: NSObject {
292351 )
293352 } catch {
294353 failure ( nil , error)
295- return nil
354+ return
296355 }
297356
298357 var afRequest = session. upload ( multipartFormData: { multipartFormData in
299358 wrapper. apply ( to: multipartFormData)
300359 } , with: request)
301360
361+ // Store request for cancellation
362+ storeRequest ( afRequest, id: requestId)
363+
364+ // Apply interceptors
365+ for interceptor in requestInterceptors {
366+ afRequest = afRequest. interceptor ( interceptor) as! UploadRequest
367+ }
368+
302369 // Apply server trust evaluation if security policy is set
303370 if let host = url. host {
304371 afRequest = applyServerTrustValidation ( afRequest, host: host)
@@ -321,25 +388,25 @@ public class AlamofireWrapper: NSObject {
321388 afRequest. response ( queue: respQueue) { [ weak self] response in
322389 guard let self = self else { return }
323390
324- // Get the actual task from the DataRequest (available after request started)
325- let task = response. request? . task
391+ // Remove request from active list
392+ self . removeRequest ( id: requestId)
393+
394+ // Get the HTTP response
395+ let httpResponse = response. response as? NSHTTPURLResponse
326396
327397 if let error = response. error {
328398 let nsError = self . createNSError ( from: error, response: response. response, data: response. data)
329- failure ( task , nsError)
399+ failure ( httpResponse , nsError)
330400 return
331401 }
332402
333403 // Deserialize response based on responseSerializer
334404 if let data = response. data {
335- // let result = self.responseSerializer.deserialize(data: data, response: response.response)
336- success ( task, data)
405+ success ( httpResponse, data)
337406 } else {
338- success ( task , nil )
407+ success ( httpResponse , nil )
339408 }
340409 }
341-
342- return afRequest. task
343410 }
344411
345412 // MARK: - Upload Tasks
@@ -689,16 +756,17 @@ public class AlamofireWrapper: NSObject {
689756 _ urlString: String ,
690757 _ parameters: NSDictionary ? ,
691758 _ headers: NSDictionary ? ,
759+ _ requestId: String ,
692760 _ sizeThreshold: Int64 ,
693761 _ progress: ( ( Progress ) -> Void ) ? ,
694- _ success: @escaping ( URLSessionTask ? , Any ? , String ? ) -> Void ,
695- _ failure: @escaping ( URLSessionTask ? , Error ) -> Void
696- ) -> URLSessionTask ? {
762+ _ success: @escaping ( NSHTTPURLResponse ? , Any ? , String ? ) -> Void ,
763+ _ failure: @escaping ( NSHTTPURLResponse ? , Error ) -> Void
764+ ) {
697765
698766 guard let url = URL ( string: urlString) else {
699767 let error = NSError ( domain: " AlamofireWrapper " , code: - 1 , userInfo: [ NSLocalizedDescriptionKey: " Invalid URL " ] )
700768 failure ( nil , error)
701- return nil
769+ return
702770 }
703771
704772 var request : URLRequest
@@ -713,12 +781,20 @@ public class AlamofireWrapper: NSObject {
713781 try requestSerializer. encodeParameters ( parameters, into: & request, method: HTTPMethod ( rawValue: method. uppercased ( ) ) )
714782 } catch {
715783 failure ( nil , error)
716- return nil
784+ return
717785 }
718786
719787 // Start as data request to get headers quickly
720788 var afRequest : DataRequest = session. request ( request)
721789
790+ // Store request for cancellation
791+ storeRequest ( afRequest, id: requestId)
792+
793+ // Apply interceptors
794+ for interceptor in requestInterceptors {
795+ afRequest = afRequest. interceptor ( interceptor) as! DataRequest
796+ }
797+
722798 // Apply server trust evaluation if security policy is set
723799 if let host = url. host {
724800 afRequest = applyServerTrustValidation ( afRequest, host: host)
@@ -735,12 +811,15 @@ public class AlamofireWrapper: NSObject {
735811 afRequest. response ( queue: . main) { [ weak self] response in
736812 guard let self = self else { return }
737813
738- // Get the actual task from the DataRequest (available after request started)
739- let task = response. request? . task
814+ // Remove request from active list
815+ self . removeRequest ( id: requestId)
816+
817+ // Get the HTTP response
818+ let httpResponse = response. response as? NSHTTPURLResponse
740819
741820 if let error = response. error {
742821 let nsError = self . createNSError ( from: error, response: response. response, data: response. data)
743- failure ( task , nsError)
822+ failure ( httpResponse , nsError)
744823 return
745824 }
746825
@@ -762,23 +841,21 @@ public class AlamofireWrapper: NSObject {
762841 do {
763842 try data. write ( to: tempFileURL)
764843 // Return with temp file path
765- success ( task , nil , tempFileURL. path)
844+ success ( httpResponse , nil , tempFileURL. path)
766845 } catch {
767846 // Failed to write, just return data in memory
768847 let result = self . responseSerializer. deserialize ( data: data, response: response. response)
769- success ( task , result, nil )
848+ success ( httpResponse , result, nil )
770849 }
771850 } else {
772851 // Small response or threshold not set, return data in memory
773852 let result = self . responseSerializer. deserialize ( data: data, response: response. response)
774- success ( task , result, nil )
853+ success ( httpResponse , result, nil )
775854 }
776855 } else {
777- success ( task , nil , nil )
856+ success ( httpResponse , nil , nil )
778857 }
779858 }
780-
781- return task
782859 }
783860
784861 // MARK: - Helper Methods
0 commit comments