Skip to content
This repository has been archived by the owner on Dec 29, 2020. It is now read-only.

Aptt260 fake #44

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 17 additions & 33 deletions RPerformanceTracking/Private/_RPTClassManipulator+UIWebView.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@

static const void *_RPT_UIWEBVIEW_TRACKINGIDENTIFIER = &_RPT_UIWEBVIEW_TRACKINGIDENTIFIER;

static void startTrackingWithUIWebView(UIWebView *webView)
static void startTrackingWithUIWebViewWithRequest(UIWebView *webView, NSURLRequest *request)
{
_RPTTrackingManager *manager = [_RPTTrackingManager sharedInstance];
[manager.tracker prolongMetric];

NSURLRequest *request = webView.request;

// bail out if there's no URL or if tracking is already done by _RPTNSURLProtocol
if (!request || manager.enableProtocolWebviewTracking) { return; }

Expand All @@ -36,23 +34,23 @@ static void endTrackingWithUIWebView(UIWebView *webView)
{
_RPTTrackingManager *manager = [_RPTTrackingManager sharedInstance];
[manager.tracker prolongMetric];
[manager.tracker endMetric];

uint_fast64_t trackingIdentifier = [objc_getAssociatedObject(webView, _RPT_UIWEBVIEW_TRACKINGIDENTIFIER) unsignedLongLongValue];
NSURLRequest* request = webView.request;
NSURL *url = request.URL;
NSCachedURLResponse *urlResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)urlResponse.response;
NSInteger statusCode = httpResponse.statusCode;

if (trackingIdentifier)
uint_fast64_t trackingIdentifier = [objc_getAssociatedObject(webView, _RPT_UIWEBVIEW_TRACKINGIDENTIFIER) unsignedLongLongValue];
if (trackingIdentifier && url)
{
// Update status code
NSURLRequest* request = webView.request;
NSCachedURLResponse *urlResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)urlResponse.response;
if (httpResponse.URL)
{
[_RPTTrackingManager.sharedInstance.tracker updateStatusCode:httpResponse.statusCode trackingIdentifier:trackingIdentifier];
}
[manager.tracker updateURL:url trackingIdentifier:trackingIdentifier];
[manager.tracker updateStatusCode:statusCode trackingIdentifier:trackingIdentifier];
[manager.tracker end:trackingIdentifier];
objc_setAssociatedObject(webView, _RPT_UIWEBVIEW_TRACKINGIDENTIFIER, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
objc_setAssociatedObject(webView, _RPT_UIWEBVIEW_TRACKINGIDENTIFIER, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[manager.tracker endMetric];
}

@implementation _RPTClassManipulator (UIWebView)
Expand All @@ -79,7 +77,11 @@ + (void)_swizzleUIWebView
RPTLogVerbose(@"UIWebView loadRequest_swizzle_blockImp called");

if (request.URL) { [[_RPTTrackingManager sharedInstance].tracker prolongMetric]; }

if ([selfRef isKindOfClass:UIWebView.class])
{
UIWebView *webView = (UIWebView*)selfRef;
startTrackingWithUIWebViewWithRequest(webView, request);
}
SEL selector = @selector(loadRequest:);
IMP originalImp = [_RPTClassManipulator implementationForOriginalSelector:selector class:UIWebView.class];

Expand Down Expand Up @@ -120,24 +122,6 @@ + (void)_swizzleUIWebViewDelegate:(id<UIWebViewDelegate>)delegate
{
Class recipient = delegate.class;

// MARK: UIWebViewDelegate webViewDidStartLoad:
id webViewDidStartLoad_swizzle_blockImp = ^(id<NSObject> selfRef, UIWebView *webView) {
RPTLogVerbose(@"UIWevView webViewDidStartLoad_swizzle_blockImp called");

SEL selector = @selector(webViewDidStartLoad:);
IMP originalImp = [_RPTClassManipulator implementationForOriginalSelector:selector class:selfRef.class];
if (originalImp)
{
((void(*)(id, SEL, id))originalImp)(selfRef, selector, webView);
}

startTrackingWithUIWebView(webView);
};
[self swizzleSelector:@selector(webViewDidStartLoad:)
onClass:recipient
newImplementation:imp_implementationWithBlock(webViewDidStartLoad_swizzle_blockImp)
types:"v@:@"];

// MARK: UIWebViewDelegate webViewDidFinishLoad:
id webViewDidFinishLoad_swizzle_blockImp = ^(id<NSObject> selfRef, UIWebView *webView) {
RPTLogVerbose(@"UIWevView webViewDidFinishLoad_swizzle_blockImp called");
Expand Down
25 changes: 12 additions & 13 deletions RPerformanceTracking/Private/_RPTClassManipulator+WKWebView.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@

static void startTrackingWithWKWebView(WKWebView *webView)
{
[_RPTTrackingManager.sharedInstance.tracker prolongMetric];
_RPTTrackingManager *manager = [_RPTTrackingManager sharedInstance];
[manager.tracker prolongMetric];

uint_fast64_t trackingIdentifier = [objc_getAssociatedObject(webView, _RPT_WKWEBVIEW_TRACKINGIDENTIFIER) unsignedLongLongValue];

NSURL *webViewURL = webView.URL;
if (!trackingIdentifier && webViewURL)
{
trackingIdentifier = [_RPTTrackingManager.sharedInstance.tracker startRequest:[NSURLRequest requestWithURL:webViewURL]];
trackingIdentifier = [manager.tracker startRequest:[NSURLRequest requestWithURL:webViewURL]];
if (trackingIdentifier)
{
objc_setAssociatedObject(webView, _RPT_WKWEBVIEW_TRACKINGIDENTIFIER, [NSNumber numberWithUnsignedLongLong:trackingIdentifier], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
Expand All @@ -28,25 +29,27 @@ static void startTrackingWithWKWebView(WKWebView *webView)

static void endTrackingWithWKWebView(WKWebView *webView)
{
[_RPTTrackingManager.sharedInstance.tracker prolongMetric];
[_RPTTrackingManager.sharedInstance.tracker endMetric];
_RPTTrackingManager *manager = [_RPTTrackingManager sharedInstance];
[manager.tracker prolongMetric];

uint_fast64_t trackingIdentifier = [objc_getAssociatedObject(webView, _RPT_WKWEBVIEW_TRACKINGIDENTIFIER) unsignedLongLongValue];
if (trackingIdentifier)
{
[_RPTTrackingManager.sharedInstance.tracker end:trackingIdentifier];
[manager.tracker end:trackingIdentifier];
objc_setAssociatedObject(webView, _RPT_WKWEBVIEW_TRACKINGIDENTIFIER, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
objc_setAssociatedObject(webView, _RPT_WKWEBVIEW_TRACKINGIDENTIFIER, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[manager.tracker endMetric];
}

static void updateStatusCodeForWebView(NSInteger statusCode, WKWebView *webView)
{
[_RPTTrackingManager.sharedInstance.tracker prolongMetric];
_RPTTrackingManager *manager = [_RPTTrackingManager sharedInstance];
[manager.tracker prolongMetric];

uint_fast64_t trackingIdentifier = [objc_getAssociatedObject(webView, _RPT_WKWEBVIEW_TRACKINGIDENTIFIER) unsignedLongLongValue];
if (trackingIdentifier)
{
[_RPTTrackingManager.sharedInstance.tracker updateStatusCode:statusCode trackingIdentifier:trackingIdentifier];
[manager.tracker updateStatusCode:statusCode trackingIdentifier:trackingIdentifier];
}
}

Expand Down Expand Up @@ -254,10 +257,6 @@ + (void)_swizzleWKWebViewNavDelegate:(id<WKNavigationDelegate>)delegate
{
((void(*)(id, SEL, id, id, id))originalImp)(selfRef, selector, webView, navigationResponse, decisionHandler);
}
else
{
decisionHandler(WKNavigationResponsePolicyAllow);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep this should crash if the swizzle gets called.
It'd be nice if the branch was rebased on master so only this diff is shown.

if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]])
{
Expand Down
7 changes: 4 additions & 3 deletions RPerformanceTracking/Private/_RPTSender.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

static const NSInteger MIN_COUNT = 10;
static const NSTimeInterval SLEEP_INTERVAL_SECONDS = 10.0; // 10s
static const NSTimeInterval MIN_TIME = 5.0 / 1000; // 5ms
static const NSTimeInterval MIN_TIME_METRIC = 5.0 / 1000; // 5ms
static const NSTimeInterval MIN_TIME_MEASUREMENT = 1.0 / 1000; // 1ms
static const NSTimeInterval SLEEP_MAX_INTERVAL = 1800; // 30 minutes

@interface _RPTTrackingManager()
Expand Down Expand Up @@ -193,7 +194,7 @@ - (NSUInteger)sendWithStartIndex:(NSUInteger)startIndex endIndex:(NSUInteger)end

- (void)writeMetric:(_RPTMetric *)metric
{
if (metric.endTime - metric.startTime < MIN_TIME) { return; }
if (metric.endTime - metric.startTime < MIN_TIME_METRIC) { return; }

if (!_sentCount) { [_eventWriter begin]; }

Expand All @@ -203,7 +204,7 @@ - (void)writeMetric:(_RPTMetric *)metric

- (void)writeMeasurement:(_RPTMeasurement *)measurement metricId:(NSString *)metricId
{
if (measurement.endTime - measurement.startTime < MIN_TIME) { return; }
if (measurement.endTime - measurement.startTime < MIN_TIME_MEASUREMENT) { return; }

if (!_sentCount) { [_eventWriter begin]; }

Expand Down
1 change: 1 addition & 0 deletions RPerformanceTracking/Private/_RPTTracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ RPT_EXPORT @interface _RPTTracker : NSObject
- (uint_fast64_t)addDevice:(NSString *)name start:(NSTimeInterval)startTime end:(NSTimeInterval)endTime;
- (void)end:(uint_fast64_t)trackingIdentifier;
- (void)updateStatusCode:(NSInteger)statusCode trackingIdentifier:(uint_fast64_t)trackingIdentifier;
- (void)updateURL:(NSURL *)url trackingIdentifier:(uint_fast64_t)trackingIdentifier;

- (instancetype)initWithRingBuffer:(_RPTRingBuffer *)ringBuffer currentMetric:(_RPTMetric *)currentMetric NS_DESIGNATED_INITIALIZER;
@end
Expand Down
12 changes: 12 additions & 0 deletions RPerformanceTracking/Private/_RPTTracker.m
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ - (void)updateStatusCode:(NSInteger)statusCode trackingIdentifier:(uint_fast64_t
}
}

- (void)updateURL:(NSURL *)url trackingIdentifier:(uint_fast64_t)trackingIdentifier
{
if (trackingIdentifier)
{
_RPTMeasurement *measurement = [_ringBuffer measurementWithTrackingIdentifier:trackingIdentifier];
if (measurement.kind == _RPTURLMeasurementKind)
{
measurement.receiver = url.absoluteString;
}
}
}

- (_RPTMeasurement *)_startWithKind:(_RPTMeasurementKind)kind receiver:(NSObject *)receiver method:(nullable NSString *)method
{
return [self _startWithKind:kind
Expand Down
62 changes: 39 additions & 23 deletions Tests/UIWebViewHookTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,42 @@ @interface WebViewController : NSObject <UIWebViewDelegate>
@property (nonatomic) UIWebView *webView;
@end

@interface WebViewControllerChild : WebViewController <UIWebViewDelegate>
@interface WebViewControllerFirstChild : WebViewController <UIWebViewDelegate>
@property (nonatomic) UIWebView *webViewInChild;
@end

@interface WebViewControllerSecondChild : WebViewController <UIWebViewDelegate>
@property (nonatomic) UIWebView *webViewInChild;
@end

@implementation WebViewController
- (void)webViewDidStartLoad:(UIWebView *)webView

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
}
@end

@implementation WebViewControllerFirstChild
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[super webViewDidFinishLoad:webView];
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
// intentionally do not call super
}
@end

@implementation WebViewControllerChild
- (void)webViewDidStartLoad:(UIWebView *)webView
- (void)methodNotImplementedInSuperclass
{
[super webViewDidStartLoad:webView];
}
@end

@implementation WebViewControllerSecondChild
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
// intentionally do not call super
Expand Down Expand Up @@ -106,14 +118,6 @@ - (void)testProlongMetricCalledOnLoadRequest
[mockTracker stopMocking];
}

- (void)testProlongMetricCalledOnWebViewDidStartLoad
{
id mockTracker = OCMPartialMock(_trackingManager.tracker);
[_webView.delegate webViewDidStartLoad:_webView];
OCMVerify([mockTracker prolongMetric]);
[mockTracker stopMocking];
}

- (void)testProlongMetricCalledOnWebViewDidFinishLoad
{
id mockTracker = OCMPartialMock(_trackingManager.tracker);
Expand Down Expand Up @@ -151,19 +155,18 @@ - (void)testEndMetricCalledOnWebViewDidFailLoadWithError
- (void)testWebViewDelegateSubclassedMethodCallsSuper
{
id mockTracker = OCMPartialMock(self.trackingManager.tracker);

WebViewControllerChild *child = [self childWebViewController];
[child.webViewInChild.delegate webViewDidStartLoad:child.webViewInChild];

OCMVerify([mockTracker prolongMetric]);
WebViewControllerFirstChild *child = [self firstChildWebViewController];
[child.webViewInChild.delegate webViewDidFinishLoad:child.webViewInChild];

OCMVerify([mockTracker endMetric]);
[mockTracker stopMocking];
}

- (void)testWebViewDelegateSubclassedMethodIsForwardedToParent
{
id mockTracker = OCMPartialMock(self.trackingManager.tracker);

WebViewControllerChild *child = [self childWebViewController];
WebViewControllerSecondChild *child = [self secondChildWebViewController];
[child.webViewInChild.delegate webViewDidFinishLoad:child.webViewInChild];

OCMVerify([mockTracker endMetric]);
Expand All @@ -176,7 +179,7 @@ - (void)DISABLE_testWebViewDelegateSubclassedMethodDoesNotCallSuper
{
id mockTracker = OCMPartialMock(self.trackingManager.tracker);

WebViewControllerChild *child = [self childWebViewController];
WebViewControllerFirstChild *child = [self firstChildWebViewController];
[child.webViewInChild.delegate webView:child.webViewInChild didFailLoadWithError:[NSError errorWithDomain:NSCocoaErrorDomain code:NSURLErrorNotConnectedToInternet userInfo:nil]];

OCMVerify([mockTracker endMetric]);
Expand All @@ -196,18 +199,31 @@ - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
}

- (WebViewControllerChild *)childWebViewController
- (WebViewControllerFirstChild *)firstChildWebViewController
{
WebViewController *parent = WebViewController.new;
parent.webView = [UIWebView.alloc initWithFrame:CGRectMake(0, 0, 200, 300)];
parent.webView.delegate = parent;

WebViewControllerChild *child = WebViewControllerChild.new;
WebViewControllerFirstChild *child = WebViewControllerFirstChild.new;
child.webViewInChild = [UIWebView.alloc initWithFrame:CGRectMake(0, 0, 200, 300)];
child.webViewInChild.delegate = child;

return child;
}

- (WebViewControllerSecondChild *)secondChildWebViewController
{
WebViewController *parent = WebViewController.new;
parent.webView = [UIWebView.alloc initWithFrame:CGRectMake(0, 0, 200, 300)];
parent.webView.delegate = parent;

WebViewControllerSecondChild *child = WebViewControllerSecondChild.new;
child.webViewInChild = [UIWebView.alloc initWithFrame:CGRectMake(0, 0, 200, 300)];
child.webViewInChild.delegate = child;

return child;
}

@end