iOS URL Loading System: Go Beyond

78
1 пятница, 4 октября 13 г.

Transcript of iOS URL Loading System: Go Beyond

  • 1.1, 4 13.

2. iOS URL Loading System: Go Beyond Alexey Dodonov 2, 4 13. 3. 3 3, 4 13. 4. 4, 4 13. 5. Network Activity Log 5 Log all network requests Simple way to see all events for every request HTTP headers and other related information Received/sent data for any request in different formats Including HTTPS requests 5, 4 13. 6. 2013-09-23 12:43:43.136 Start loading 2013-09-23 12:43:43.138 Will send request 2013-09-23 12:43:43.152 Received response Response: 200 Header fields:{ "Cache-Control" = "no-cache"; Connection = "keep-alive"; "Content-Encoding" = gzip; "Content-Length" = 351; "Content-Type" = "text/xml; encoding=utf-8"; Date = "Mon, 23 Sep 2013 08:43:34 GMT"; Server = "nginx/1.2.1"; "X-YaMisc" = "region_id=9999;"; "X-YaReqFinish" = "1379925814.110185"; } 2013-09-23 12:43:43.153 Did receive data (685 bytes). 2013-09-23 12:43:43.153 Did finish loading. 2013-09-23 12:43:43.154 Stop loading 2013-09-23 12:43:44.169 Received response Response: 200 Header fields:{ Connection = close; "Content-Length" = 0; "Content-Type" = "application/octet-stream"; Date = "Mon, 23 Sep 2013 08:43:35 GMT"; Server = nginx; } 2013-09-23 12:43:44.169 Did finish loading. 2013-09-23 12:43:44.170 Stop loading 2013-09-23 12:43:58.314 Initialized URL: http://www.yandex.com/?clid=2035378 HTTP Method: GET HTTP Headers: { Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; "User-Agent" = "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Mobile/11A465"; Network Activity Log 6 NSLog(...) 6, 4 13. 7. "Content-Encoding" = gzip; "Content-Type" = "text/css"; Date = "Mon, 23 Sep 2013 08:43:49 GMT"; Expires = "Thu, 31 Dec 2037 23:55:55 GMT"; "Last-Modified" = "Thu, 19 Sep 2013 18:25:56 GMT"; Server = "nginx/1.4.1"; "Transfer-Encoding" = Identity; } 2013-09-23 12:43:58.476 Did receive data (23122 bytes). 2013-09-23 12:43:58.477 Did finish loading. 2013-09-23 12:43:58.477 Initialized URL: http://yandex.st/www/1.686/com/pages-desktop/index/_index.js HTTP Method: GET HTTP Headers: { Accept = "*/*"; Referer = "http://www.yandex.com/"; "User-Agent" = "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Mobile/11A465"; } HTTP Body: 2013-09-23 12:43:58.477 Start loading 2013-09-23 12:43:58.478 Will send request 2013-09-23 12:43:58.478 Start loading 2013-09-23 12:43:58.478 Will send request 2013-09-23 12:43:58.480 Received response Response: 200 Header fields:{ "Access-Control-Allow-Origin" = "*"; "Cache-Control" = "max-age=315360000"; Connection = "keep-alive"; "Content-Encoding" = gzip; "Content-Type" = "application/x-javascript"; Date = "Mon, 23 Sep 2013 08:43:49 GMT"; Expires = "Thu, 31 Dec 2037 23:55:55 GMT"; "Last-Modified" = "Thu, 10 May 2012 20:10:56 GMT"; Server = "nginx/1.4.1"; "Transfer-Encoding" = Identity; } 2013-09-23 12:43:58.480 Did receive data (1553 bytes). 2013-09-23 12:43:58.481 Did finish loading. 2013-09-23 12:43:58.482 Received response Response: 200 Header fields:{ "Accept-Ranges" = bytes; "Access-Control-Allow-Origin" = "*"; "Cache-Cont Network Activity Log 6 NSLog(...) 6, 4 13. 8. Network Activity Log 3rd party instruments Wireshark Charles Fiddler mitmproxy They are all good, but we want a look from inside the application. 7 7, 4 13. 9. Test Networking 8 Test application state after making network requests: with various responses. Test application state if a network request fails due to numerous reasons: different HTTP status codes, timeout, etc. 8, 4 13. 10. Test Networking 9 Mock NSURLConnection github.com/weming/MockNSURLConnection bit.ly/yac_nsurlprotocol (all links for this talk) NSURLConnection objects are often hidden from the public interface. It does not work if you use another framework like AFNetworking. 9, 4 13. 11. Hybrid Applications 10 UIWebView as the main interface. Ship static resources within the application bundle. Smart caching. 10, 4 13. 12. Extend iOS Networking 11 UIWebView support for new media formats WebP WebM 11, 4 13. 13. Extend iOS Networking 11 UIWebView support for new media formats WebP WebM Application-wide support for new protocols SPDY 11, 4 13. 14. NSURLProtocol 12, 4 13. 15. NSURLProtocol 13 NSURLConnection Frameworks Application UIWebview NSURLProtocol Network 13, 4 13. 16. 14 NSURLConnection file:// NSURLProtocol ftp:// https:// http:// 14, 4 13. 17. @interface MyProtocol : NSURLProtocol @end [NSURLProtocol registerClass:[MyProtocol class]]; NSURLProtocol 15 Registration of the new protocol: 15, 4 13. 18. 16 NSURLConnection NSURLProtocol xmmp:// ftp:// http:// iOS URLProtocols http:// NSURLRequest 16, 4 13. 19. 16 NSURLConnection NSURLProtocol xmmp:// ftp:// http:// iOS URLProtocols http:// NSURLRequest 16, 4 13. 20. 16 NSURLConnection NSURLProtocol xmmp:// ftp:// http:// iOS URLProtocols http:// NSURLRequest 16, 4 13. 21. + (BOOL)canInitWithRequest:(NSURLRequest *)request { return [[[request URL] scheme] isEqual:@"xmpp"]; } NSURLProtocol 17 Can we handle this request? 17, 4 13. 22. 18 NSURLConnection NSURLProtocol xmmp:// ftp:// http:// iOS URLProtocols http:// NSURLRequest 18, 4 13. 23. 18 NSURLConnection NSURLProtocol xmmp:// ftp:// http:// iOS URLProtocols http:// NSURLRequest 18, 4 13. 24. 18 NSURLConnection NSURLProtocol xmmp:// ftp:// http:// iOS URLProtocols http:// NSURLRequest 18, 4 13. 25. 18 NSURLConnection NSURLProtocol xmmp:// ftp:// http:// iOS URLProtocols http:// NSURLRequest 18, 4 13. 26. NSURLProtocol 19 NSURLProtocolNSURLConnection Client NSURLConnection Delegate URLProtocol:didReceiveResponse:cacheStoragePolicy:required method URLProtocol:didLoadData:required method URLProtocolDidFinishLoading:required method URLProtocol:didFailWithError:required method ... 19, 4 13. 27. NSURLProtocol 19 NSURLProtocolNSURLConnection Client NSURLConnection Delegate URLProtocol:didReceiveResponse:cacheStoragePolicy:required method URLProtocol:didLoadData:required method URLProtocolDidFinishLoading:required method URLProtocol:didFailWithError:required method ... 19, 4 13. 28. NSURLProtocol 19 NSURLProtocolNSURLConnection Client NSURLConnection Delegate URLProtocol:didReceiveResponse:cacheStoragePolicy:required method URLProtocol:didLoadData:required method URLProtocolDidFinishLoading:required method URLProtocol:didFailWithError:required method ... 19, 4 13. 29. 20, 4 13. 30. Network Activity Log 21 Log all network requests Simple way to see all events for every request HTTP headers and other related information Received/sent data for any request in different formats Including HTTPS requests 21, 4 13. 31. Network Activity Log 22 NSURLConnection Logger NSURLConnection iOS URLProtocols 22, 4 13. 32. Network Activity Log 22 NSURLConnection Logger NSURLConnection iOS URLProtocols 22, 4 13. 33. Network Activity Log 22 NSURLConnection Logger NSURLConnection iOS URLProtocols 22, 4 13. 34. Network Activity Log 22 NSURLConnection Logger NSURLConnection iOS URLProtocols 22, 4 13. 35. NSMutableURLRequest *mutableRequest = [request mutableCopy]; [NSURLProtocol setProperty:@"marker" forKey:@"markerKey" inRequest:mutableRequest]; Network Activity Log 23 Outgoing request 23, 4 13. 36. + (BOOL)canInitWithRequest:(NSURLRequest *)request { id marker = [NSURLProtocol propertyForKey:@"markerKey" inRequest:request]; return (marker == nil); } Network Activity Log 24 Incoming request 24, 4 13. 37. Network Activity Log 25 iOS URLProtocols LoggerNSURLConnection NSURLConnection NSURLProtocol 25, 4 13. 38. Network Activity Log 25 iOS URLProtocols LoggerNSURLConnection NSURLConnection NSURLProtocol 25, 4 13. 39. Network Activity Log 26 Objective-C HTTP Server github.com/robbiehanson/CocoaHTTPServer bit.ly/yac_nsurlprotocol github.com/mattstevens/RoutingHTTPServer github.com/stevestreza/Barista 26, 4 13. 40. Network Activity Log 27 localhost:8080 27, 4 13. 41. Network Activity Log 28 URLProtocol Logger Sample Code github.com/dodonov/YACURLProtocolLogger bit.ly/yac_nsurlprotocol 28, 4 13. 42. Test Networking 29 Test application state after making network requests: with various responses. Test application state if a network request fails due to numerous reasons: different HTTP status codes, timeout, etc. 29, 4 13. 43. Test Networking 30 Special Test ProtocolNSURLConnection iOS URLProtocols NSURLConnection Delegate 30, 4 13. 44. Test Networking 30 Special Test ProtocolNSURLConnection iOS URLProtocols NSURLConnection Delegate 30, 4 13. 45. Test Networking 30 Special Test ProtocolNSURLConnection iOS URLProtocols NSURLConnection Delegate 30, 4 13. 46. Test Networking 31 Sample test - (void)testImageLoader { [NSURLProtocol registerClass:[ILCannedURLProtocol class]]; [ILCannedURLProtocol setCannedStatusCode:500]; [ILCannedURLProtocol setSupportedBaseURL:[NSURL URLWithString:@"yandex.ru"]]; ImageLoader *loader = [[ImageLoader alloc] init]; [loader load]; NSAssert([loader hasBadResponse], @"Loader should have bad response"); [NSURLProtocol unregisterClass:[ILCannedURLProtocol class]]; } 31, 4 13. 47. Test Networking 31 Sample test - (void)testImageLoader { [NSURLProtocol registerClass:[ILCannedURLProtocol class]]; [ILCannedURLProtocol setCannedStatusCode:500]; [ILCannedURLProtocol setSupportedBaseURL:[NSURL URLWithString:@"yandex.ru"]]; ImageLoader *loader = [[ImageLoader alloc] init]; [loader load]; NSAssert([loader hasBadResponse], @"Loader should have bad response"); [NSURLProtocol unregisterClass:[ILCannedURLProtocol class]]; } 31, 4 13. 48. Test Networking 31 Sample test - (void)testImageLoader { [NSURLProtocol registerClass:[ILCannedURLProtocol class]]; [ILCannedURLProtocol setCannedStatusCode:500]; [ILCannedURLProtocol setSupportedBaseURL:[NSURL URLWithString:@"yandex.ru"]]; ImageLoader *loader = [[ImageLoader alloc] init]; [loader load]; NSAssert([loader hasBadResponse], @"Loader should have bad response"); [NSURLProtocol unregisterClass:[ILCannedURLProtocol class]]; } 31, 4 13. 49. Test Networking 31 Sample test - (void)testImageLoader { [NSURLProtocol registerClass:[ILCannedURLProtocol class]]; [ILCannedURLProtocol setCannedStatusCode:500]; [ILCannedURLProtocol setSupportedBaseURL:[NSURL URLWithString:@"yandex.ru"]]; ImageLoader *loader = [[ImageLoader alloc] init]; [loader load]; NSAssert([loader hasBadResponse], @"Loader should have bad response"); [NSURLProtocol unregisterClass:[ILCannedURLProtocol class]]; } 31, 4 13. 50. Test Networking 31 Sample test - (void)testImageLoader { [NSURLProtocol registerClass:[ILCannedURLProtocol class]]; [ILCannedURLProtocol setCannedStatusCode:500]; [ILCannedURLProtocol setSupportedBaseURL:[NSURL URLWithString:@"yandex.ru"]]; ImageLoader *loader = [[ImageLoader alloc] init]; [loader load]; NSAssert([loader hasBadResponse], @"Loader should have bad response"); [NSURLProtocol unregisterClass:[ILCannedURLProtocol class]]; } 31, 4 13. 51. Test Networking 31 Sample test - (void)testImageLoader { [NSURLProtocol registerClass:[ILCannedURLProtocol class]]; [ILCannedURLProtocol setCannedStatusCode:500]; [ILCannedURLProtocol setSupportedBaseURL:[NSURL URLWithString:@"yandex.ru"]]; ImageLoader *loader = [[ImageLoader alloc] init]; [loader load]; NSAssert([loader hasBadResponse], @"Loader should have bad response"); [NSURLProtocol unregisterClass:[ILCannedURLProtocol class]]; } 31, 4 13. 52. Test Networking 31 Sample test - (void)testImageLoader { [NSURLProtocol registerClass:[ILCannedURLProtocol class]]; [ILCannedURLProtocol setCannedStatusCode:500]; [ILCannedURLProtocol setSupportedBaseURL:[NSURL URLWithString:@"yandex.ru"]]; ImageLoader *loader = [[ImageLoader alloc] init]; [loader load]; NSAssert([loader hasBadResponse], @"Loader should have bad response"); [NSURLProtocol unregisterClass:[ILCannedURLProtocol class]]; } 31, 4 13. 53. Test Networking 31 Sample test - (void)testImageLoader { [NSURLProtocol registerClass:[ILCannedURLProtocol class]]; [ILCannedURLProtocol setCannedStatusCode:500]; [ILCannedURLProtocol setSupportedBaseURL:[NSURL URLWithString:@"yandex.ru"]]; ImageLoader *loader = [[ImageLoader alloc] init]; [loader load]; NSAssert([loader hasBadResponse], @"Loader should have bad response"); [NSURLProtocol unregisterClass:[ILCannedURLProtocol class]]; } 31, 4 13. 54. Test Networking 32 Testing via NSURLProtocol github.com/InniteLoopDK/ILTesting bit.ly/yac_nsurlprotocol github.com/AliSoftware/OHHTTPStubs 32, 4 13. 55. Hybrid Applications 33 UIWebView as the main interface. Ship static resources within the application bundle. Smart caching. 33, 4 13. 56. Hybrid Applications 34 local-img:// 34, 4 13. 57. Hybrid Applications 35 Sample html code: 35, 4 13. 58. + (BOOL)canInitWithRequest:(NSURLRequest *)request { return [[[request URL] scheme] isEqual:@"local-img"]; } Hybrid Applications 36 URLProtocol 36, 4 13. 59. Hybrid Applications 37 - (void)startLoading { NSString *imagePath = [[NSBundle mainBundle] pathForResource:self.imageName ofType:self.extension]; NSData *data = [NSData dataWithContentsOfFile:imagePath]; NSURLResponse *response =[[NSURLResponse alloc] initWithURL:self.request.URL MIMEType:nil expectedContentLength:[data length] textEncodingName:nil]; [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; [[self client] URLProtocol:self didLoadData:data]; [[self client] URLProtocolDidFinishLoading:self]; } 37, 4 13. 60. Hybrid Applications 37 - (void)startLoading { NSString *imagePath = [[NSBundle mainBundle] pathForResource:self.imageName ofType:self.extension]; NSData *data = [NSData dataWithContentsOfFile:imagePath]; NSURLResponse *response =[[NSURLResponse alloc] initWithURL:self.request.URL MIMEType:nil expectedContentLength:[data length] textEncodingName:nil]; [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; [[self client] URLProtocol:self didLoadData:data]; [[self client] URLProtocolDidFinishLoading:self]; } 37, 4 13. 61. Hybrid Applications 37 - (void)startLoading { NSString *imagePath = [[NSBundle mainBundle] pathForResource:self.imageName ofType:self.extension]; NSData *data = [NSData dataWithContentsOfFile:imagePath]; NSURLResponse *response =[[NSURLResponse alloc] initWithURL:self.request.URL MIMEType:nil expectedContentLength:[data length] textEncodingName:nil]; [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; [[self client] URLProtocol:self didLoadData:data]; [[self client] URLProtocolDidFinishLoading:self]; } 37, 4 13. 62. Hybrid Applications 37 - (void)startLoading { NSString *imagePath = [[NSBundle mainBundle] pathForResource:self.imageName ofType:self.extension]; NSData *data = [NSData dataWithContentsOfFile:imagePath]; NSURLResponse *response =[[NSURLResponse alloc] initWithURL:self.request.URL MIMEType:nil expectedContentLength:[data length] textEncodingName:nil]; [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; [[self client] URLProtocol:self didLoadData:data]; [[self client] URLProtocolDidFinishLoading:self]; } 37, 4 13. 63. Hybrid Applications 37 - (void)startLoading { NSString *imagePath = [[NSBundle mainBundle] pathForResource:self.imageName ofType:self.extension]; NSData *data = [NSData dataWithContentsOfFile:imagePath]; NSURLResponse *response =[[NSURLResponse alloc] initWithURL:self.request.URL MIMEType:nil expectedContentLength:[data length] textEncodingName:nil]; [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; [[self client] URLProtocol:self didLoadData:data]; [[self client] URLProtocolDidFinishLoading:self]; } 37, 4 13. 64. Hybrid Applications 37 - (void)startLoading { NSString *imagePath = [[NSBundle mainBundle] pathForResource:self.imageName ofType:self.extension]; NSData *data = [NSData dataWithContentsOfFile:imagePath]; NSURLResponse *response =[[NSURLResponse alloc] initWithURL:self.request.URL MIMEType:nil expectedContentLength:[data length] textEncodingName:nil]; [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed]; [[self client] URLProtocol:self didLoadData:data]; [[self client] URLProtocolDidFinishLoading:self]; } 37, 4 13. 65. Hybrid Applications 38 NSURLImageProtocol github.com/xr1337/NSURLImageProtocol bit.ly/yac_nsurlprotocol 38, 4 13. 66. Hybrid Applications 39 Smart Cache github.com/rnapier/RNCachingURLProtocol bit.ly/yac_nsurlprotocol github.com/artifacts/AFCache 39, 4 13. 67. Extend iOS Networking 40 UIWebView support for new media formats WebP WebM Application-wide support for new protocols SPDY 40, 4 13. 68. Extend iOS Networking 41 ProtocolNSURLConnection NSURLConnection NSURLConnection Delegate Converter WebPPNG 41, 4 13. 69. Extend iOS Networking 41 ProtocolNSURLConnection NSURLConnection NSURLConnection Delegate Converter WebPPNG 41, 4 13. 70. Extend iOS Networking 42 WebP Decoding github.com/cysp/STWebPDecoder bit.ly/yac_nsurlprotocol 42, 4 13. 71. Replace iOS Networking 43 Protocol Chromium Network Stack iOS Network Stack NSURLConnection 43, 4 13. 72. 44, 4 13. 73. Bonus stage NSURLProtocol in the Mothership 45, 4 13. 74. NSURLProtocol in the Mothership NSCFURLProtocol NSCFURLProtocolBridge NSCFURLProtocolBridgeWithTrampoline 46 46, 4 13. 75. NSURLProtocol in the Mothership MFMessageURLProtocol x-msg: cid: x-cid: MFMessageWebProtocol x-apple-msg-load: CKMessagePartURLProtocol x-ckmsgpart: QLPreviewURLProtocol x-apple-ql-id:// UUID/x-apple-ql-magic SUWebImagePoolURLProtocol x-itmsimg: 47 47, 4 13. 76. NSURLProtocol in the Mothership NSAboutURLProtocol about: 48 48, 4 13. 77. Thank you! 49, 4 13. 78. 50 Alexey Dodonov iOS Developer [email protected] @ddnv 50, 4 13.