@@ -1786,6 +1786,63 @@ int HTTPMessage::copySerializedMessage()() {
17861786}
17871787```
17881788
1789+ #### 下行流量
1790+
1791+ 下行流量的思路也类似,主要计算每个响应报文的大小,包含报文首部和报文主体,两者之间有个空行,报文首部包含状态行和首部字段。实现上会用到 ` NSHTTPURLResponse ` 的 ` allHeaderFields ` 和 ` expectedContentLength ` 属性。但这里需要注意的是 ` expectedContentLength ` 属性可能会为 ` NSURLResponseUnknownLength ` (-1),主要是在有些请求的响应的首部字段中没有 ` Content-Length ` 字段,或者没有告知具体响应大小时出现。那么这个时候需要通过其他的机制去计算。
1792+
1793+ ```
1794+ - (int64_t)p_getResponseLength {
1795+ int64_t responseLength = 0;
1796+ if (_response && [_response isKindOfClass:[NSHTTPURLResponse class]]) {
1797+ NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)_response;
1798+ NSDictionary<NSString *, NSString *> *headerFields = httpResponse.allHeaderFields;
1799+ NSUInteger headersLength = [self p_getHeadersLength:headerFields];
1800+ int64_t contentLength = (httpResponse.expectedContentLength != NSURLResponseUnknownLength) ?
1801+ httpResponse.expectedContentLength :
1802+ _dataLength;
1803+ responseLength = headersLength + contentLength;
1804+ }
1805+ return responseLength;
1806+ }
1807+ ```
1808+
1809+ 在上面代码中会去判断 ` expectedContentLength ` 是否为 ` NSURLResponseUnknownLength ` ,如果不是响应报文主体的大小就是 ` expectedContentLength ` ,否则将其赋值为 ` _dataLength ` 。` _dataLength ` 的计算可以在响应的回调中去计算,比如下面代码罗列的这几个地方。
1810+
1811+ ```
1812+ - (void)wtn_URLSession:(NSURLSession *)session
1813+ dataTask:(NSURLSessionDataTask *)dataTask
1814+ didReceiveData:(NSData *)data {
1815+ WTNHTTPTransactionMetrics *httpTransaction = dataTask.httpTransaction;
1816+ httpTransaction.dataLength += data.length;
1817+
1818+ if ([self.originalDelegate respondsToSelector:@selector(URLSession:dataTask:didReceiveData:)]) {
1819+ [(id)self.originalDelegate URLSession:session dataTask:dataTask didReceiveData:data];
1820+ }
1821+ }
1822+
1823+
1824+ - (NSURLSessionDataTask *)wtn_dataTaskWithRequest:(NSURLRequest *)request
1825+ completionHandler:(void (^)(NSData * _Nullable data,
1826+ NSURLResponse * _Nullable response,
1827+ NSError * _Nullable error))completionHandler {
1828+ WTNHTTPTransactionMetrics *httpTransaction = [WTNHTTPTransactionMetrics new];
1829+
1830+ ······
1831+
1832+ if (completionHandler) {
1833+ wrappedCompletionHandler = ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
1834+ httpTransaction.dataLength = data.length;
1835+ };
1836+ }
1837+
1838+ ······
1839+
1840+ return dataTask;
1841+ }
1842+ ```
1843+
1844+ ` wtn_URLSession:dataTask:didReceiveData ` 是 hook 之后的回调函数,因为在大文件中这个回调会执行多次,所以这里使用 ` += ` 。` wtn_dataTaskWithRequest:completionHandler: ` 也是 hook 函数,类似的还有 ` wtn_uploadTaskWithRequest:fromData:completionHandler: ` 、` wtn_uploadTaskWithRequest:fromFile:completionHandler ` 等。
1845+
17891846## Power consumption
17901847
17911848iOS 设备的电量一直是用户非常关心的问题。如果你的应用由于某些缺陷不幸成为电量杀手,用户会毫不犹豫的卸载你的应用,所以耗电也是 App 性能的重要衡量标准之一。然而事实上业内对耗电量的监控的方案都做的不太好,下面会介绍和对比业内已有的耗电量的监控方案。
0 commit comments