My IOS app has several UIWebView's in it. From time-to-time, the user may needs to change from a mobile site to a desktop site of any given URL. I'm using spoofing to do this by changing the UserAgent:
+ (void) startSpoofingUserAgent
{
[[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"UserAgent" : @"Desktop" }];
[[NSUserDefaults standardUserDefaults] synchronize];
}
I also have a method that kills the spoofing:
+ (void)stopSpoofingUserAgent
{
NSDictionary *registeredDefaults = [[NSUserDefaults standardUserDefaults] volatileDomainForName:NSRegistrationDomain];
if ([registeredDefaults objectForKey:@"UserAgent"] != nil)
{
NSMutableDictionary *mutableCopy = [NSMutableDictionary dictionaryWithDictionary:registeredDefaults];
[mutableCopy removeObjectForKey:@"UserAgent"];
[[NSUserDefaults standardUserDefaults] setVolatileDomain:mutableCopy forName:NSRegistrationDomain];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
I then give the user the ability to change from desktop-to-mobile and mobile-to-desktop with a button. I then reload the URL with this code:
self.webView.delegate = self;
self.webView.scalesPageToFit = YES;
self.webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
//Create a URL object.
NSURL *url = [NSURL URLWithString:self.convertedURL];
//URL Request Object
if(self.defaultToDesktopSite)
{
[MINNetworkingUtils startSpoofingUserAgent];
}
else
{
[MINNetworkingUtils stopSpoofingUserAgent];
}
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
//Load the request in the UIWebView.
[self.webView loadRequest:requestObj];
I also buffer the current state the user has the UIWebView in so that it retains the setting across instances. The first time the app runs, it works great regardless of which state it's in (Desktop or Mobile).
THE PROBLEM: The problem is that I cannot change the state and have that reflected in the app AFTER the initial load.
Scenario 1:
Scenario 2:
Scenario 3:
Scenario 4:
What seems to be happening, is that the UIWebView is buffering something somewhere and won't allow me to reload the UIWebView with a different spoofing. If the app is unloaded and reloaded, UIWebView works as expected.
I have tried to the following things to force the UIWebView to NOT buffer anything and have had no success:
[[NSURLCache sharedURLCache] removeAllCachedResponses];
... reload URL
self.convertedPageURL = [NSString stringWithFormat:@"%@?t=%@", self.convertedPageURL, randomString];
... reload URL
Like I said, I can't get the UIWebView to change from Desktop-to-Mobile or Mobile-to-Desktop WITHOUT unloading the app and reloading it.
HELP!!!
EDIT
This is the code that I was using to get the current value. Once I've called this line of code, I can no longer change the UserAgent:
defaultUserAgentString = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
The UserAgent
user-defaults key is private API. It therefore has no guaranteed behaviour. All answers will be empirical.
That being said, it sounds like the correct solution is to kill and recreate your UIWebView
following each change. UIView
doesn't conform to NSCopying
so you'll need to do something manual such as:
UIWebView *newWebView = [[UIWebView alloc] initWithFrame:self.webView.frame];
newWebView.delegate = self;
newWebView.scalesPageToFit = YES;
// ... and the autoreseizing mask, etc — no need to do this upon every load
[self.webView.superview insertSubview:newWebView aboveSubview:self.webView];
[self.webView removeFromSuperview];
self.webView = newWebView;
If that fails to work, you probably need to switch to a documented means of setting the user agent. I'd suggest implementing your own NSURLProtocol
handler that accepts http
and https
requests it hasn't yet seen, modifies the header field and dispatches them a second time, that time declining to take them so that they drop down to the system. It'll be hassle but it'll allow you to change that, or any other header field, reliably and with immediate effect.
See kifi's engineering blog for an example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With