4
4
5
5
import Foundation
6
6
7
- final class NetworkLoggerURLSessionSwizzlerDelegate : URLSessionSwizzlerDelegate {
8
- private let logger : NetworkLogger
9
-
10
- init ( logger: NetworkLogger = . init( ) ) {
11
- self . logger = logger
12
- }
13
-
14
- func swizzlerSessionDidCallResume( task: URLSessionTask ) {
15
- logger. logTaskCreated ( task)
16
- }
17
-
18
- func swizzlerSessionDidComplete( task: URLSessionTask , error: ( any Error ) ? ) {
19
- logger. logTask ( task, didCompleteWithError: error)
20
- }
21
-
22
- func swizzlerSessionDidFinishCollectingMetrics( task: URLSessionTask , metrics: URLSessionTaskMetrics ) {
23
- logger. logTask ( task, didFinishCollecting: metrics)
24
- }
25
-
26
- func swizzlerSessionDidReceiveData( dataTask: URLSessionDataTask , data: Data ) {
27
- logger. logDataTask ( dataTask, didReceive: data)
28
- }
29
- }
30
-
31
- protocol URLSessionSwizzlerDelegate : AnyObject {
32
- func swizzlerSessionDidCallResume( task: URLSessionTask )
33
- func swizzlerSessionDidComplete( task: URLSessionTask , error: ( any Error ) ? )
34
- func swizzlerSessionDidFinishCollectingMetrics( task: URLSessionTask , metrics: URLSessionTaskMetrics )
35
- func swizzlerSessionDidReceiveData( dataTask: URLSessionDataTask , data: Data )
36
- }
37
-
38
7
@MainActor
39
8
public final class URLSessionProxy {
40
9
static var proxy : URLSessionProxy ?
@@ -59,32 +28,29 @@ public final class URLSessionProxy {
59
28
}
60
29
61
30
func enable( ) {
62
- injectIntoNSURLSessionTaskResume ( )
63
- if let sessionClass = NSClassFromString ( " __NSCFURLLocalSessionConnection " ) {
64
- injectIntoURLSessionDelegate ( anyClass: sessionClass)
31
+ swizzleURLSessionTaskResume ( )
32
+ // "__NSCFURLLocalSessionConnection"
33
+ if let sessionClass = NSClassFromString ( [ " __ " , " NS " , " CFURL " , " Local " , " Session " , " Connection " ] . joined ( ) ) {
34
+ swizzleDataTaskDidReceiveData ( baseClass: sessionClass)
35
+ swizzleDataDataDidCompleteWithError ( baseClass: sessionClass)
36
+ } else {
37
+ NSLog ( " URLSessionProxy failed to initialize. Please report at https://github.com/kean/Pulse/issues. " )
65
38
}
66
39
}
67
40
68
- private func injectIntoURLSessionDelegate( anyClass: AnyClass ) {
69
- swizzleDataTaskDidReceiveData ( baseClass: anyClass)
70
- swizzleDataDataDidCompleteWithError ( baseClass: anyClass)
71
- }
72
-
73
- private func injectIntoNSURLSessionTaskResume( ) {
74
- var methodsToSwizzle = [ Method] ( )
75
-
41
+ // - `resume` (optional)
42
+ private func swizzleURLSessionTaskResume( ) {
43
+ var methods = [ Method] ( )
76
44
if let method = class_getInstanceMethod ( URLSessionTask . self, #selector( URLSessionTask . resume) ) {
77
- methodsToSwizzle . append ( method)
45
+ methods . append ( method)
78
46
}
79
-
80
- if let cfURLSession = NSClassFromString ( " __NSCFURLSessionTask " ) ,
81
- let method = class_getInstanceMethod ( cfURLSession , NSSelectorFromString ( " resume " ) ) {
82
- methodsToSwizzle . append ( method)
47
+ // "__NSCFURLSessionTask"
48
+ if let sessionTaskClass = NSClassFromString ( [ " __ " , " NS " , " CFURL " , " Session " , " Task " ] . joined ( ) ) ,
49
+ let method = class_getInstanceMethod ( sessionTaskClass , NSSelectorFromString ( " resume " ) ) {
50
+ methods . append ( method)
83
51
}
84
-
85
- methodsToSwizzle. forEach {
52
+ methods. forEach {
86
53
let method = $0
87
-
88
54
var originalImplementation : IMP ?
89
55
let block : @convention ( block) ( URLSessionTask ) -> Void = { [ weak self] task in
90
56
self ? . logger. logTaskCreated ( task)
@@ -99,15 +65,11 @@ public final class URLSessionProxy {
99
65
originalImplementation = method_setImplementation ( method, swizzledIMP)
100
66
}
101
67
}
102
- }
103
-
104
- extension URLSessionProxy {
105
68
106
- /// Swizzles the folowing methods:
107
- ///
108
- /// - urlSession(_:task:didCompleteWithError:)
69
+ // - `urlSession(_:task:didCompleteWithError:)`
109
70
func swizzleDataDataDidCompleteWithError( baseClass: AnyClass ) {
110
- let selector = NSSelectorFromString ( " _didFinishWithError: " )
71
+ // "_didFinishWithError:"
72
+ let selector = NSSelectorFromString ( [ " _ " , " didFinish " , " With " , " Error " , " : " ] . joined ( ) )
111
73
guard let method = class_getInstanceMethod ( baseClass, selector) ,
112
74
baseClass. instancesRespond ( to: selector) else {
113
75
return
@@ -119,25 +81,21 @@ extension URLSessionProxy {
119
81
original ( object, selector, error)
120
82
121
83
if let task = object. value ( forKey: " task " ) as? URLSessionTask {
122
- if let metrics = task . value ( forKey : " _incompleteTaskMetrics " ) as? URLSessionTaskMetrics {
123
- #warning("FIX")
84
+ // "_incompleteTaskMetrics"
85
+ if let metrics = task . value ( forKey : [ " _ " , " incomplete " , " Task " , " Metrics " ] . joined ( ) ) as? URLSessionTaskMetrics {
124
86
self ? . logger. logTask ( task, didFinishCollecting: metrics)
125
87
}
126
88
let error = error as? Error
127
89
self ? . logger. logTask ( task, didCompleteWithError: error)
128
- } else {
129
- NSLog ( " Could not get data from _swizzleURLSessionTaskDidCompleteWithError. It might causes due to the latest iOS changes. \( object) " )
130
90
}
131
91
}
132
-
133
92
method_setImplementation ( method, imp_implementationWithBlock ( closure) )
134
93
}
135
94
136
- /// Swizzles the folowing methods:
137
- ///
138
- /// urlSession(_:dataTask:didReceive:)
95
+ // - `urlSession(_:dataTask:didReceive:)`
139
96
func swizzleDataTaskDidReceiveData( baseClass: AnyClass ) {
140
- let selector = NSSelectorFromString ( " _didReceiveData: " )
97
+ // "_didReceiveData"
98
+ let selector = NSSelectorFromString ( [ " _ " , " did " , " Receive " , " Data " , " : " ] . joined ( ) )
141
99
guard let method = class_getInstanceMethod ( baseClass, selector) ,
142
100
baseClass. instancesRespond ( to: selector) else {
143
101
return
@@ -150,23 +108,18 @@ extension URLSessionProxy {
150
108
original ( object, selector, data)
151
109
152
110
if let task = object. value ( forKey: " task " ) as? URLSessionDataTask {
153
- if let data = data as? Data {
154
- self ? . logger. logDataTask ( task, didReceive: data)
155
- } else {
156
- // TODO: what should it do?
157
- }
158
- } else {
159
- // TODO: update who to call
160
- NSLog ( " Could not get data from _swizzleURLSessionDataTaskDidReceiveData. It might causes due to the latest iOS changes. \( object) " )
111
+ let data = ( data as? Data ) ?? Data ( )
112
+ self ? . logger. logDataTask ( task, didReceive: data)
161
113
}
162
114
}
163
115
method_setImplementation ( method, imp_implementationWithBlock ( closure) )
164
116
}
165
117
}
166
118
119
+ // MARK: - Experimental (Deprecated)
120
+
167
121
@available ( * , deprecated, message: " Experimental.URLSessionProxy is replaced with a reworked URLSessionProxy " )
168
- public enum Experimental {
169
- }
122
+ public enum Experimental { }
170
123
171
124
@available ( * , deprecated, message: " Experimental.URLSessionProxy is replaced with a reworked URLSessionProxy " )
172
125
public extension Experimental {
0 commit comments