Make a UIWebview display dektop not mobile page - ios

I'm making a simple UIWebView iOS app. In it, the website I want to display is displaying as the mobile version, when I want it to display as the full version.
I have this code under viewDidLoad:
NSString *fullURL = #"www.facebook.com";
NSURL *url = [NSURL URLWithString:fullURL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// [request setValue:#"Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3" forHTTPHeaderField:#"User-Agent"];
[self.webView loadRequest: request];
The commented out code I have found makes the website display as the mobile version. Does anyone know how I could change commented line to be the desktop version? When the commented line stays commented, it still runs as the mobile version.
Thanks that would be really helpful!

set a desktop user agent for HTTP requests: e.g. '#"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13+ (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2";'
BUT that doesnt work for a webview because the webview doesn't use the agent set for the request. Instead, it uses the agent from NSUserDefaults.
so:
NSString *secretagent = #"%%MyUserAgent%%"; //the one you chose
NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys:secretAgent, #"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
to get this to take effect, do it before you load the UIWebview!

Related

iOS Objective-C - Problem during the restore of WKWebView status using cookies

We are using WKWebViews in our native iPhone application, on a website that allows login and stores the session information in cookies.
We tried to properly mange web cookies but we have some problems when we kill and reopen the app.
Preamble: the app manages a web login toward two WKWebViews (let's call them WKW_A and WKW_B) in two different sections.
Use case 1: we open the app, the app loads WKW_A, and the user fill in the credentials to login on the website. At this point we stores the related cookies. The user then opens a section of the app loading WKW_B . Here we load the above mentioned cookies. What we see is that the website bring us to the expected screen without asking user credentials i.e. in WKW_B cookies are properly sent to the website.
Use case 2: we open the app, the app loads WKW_A, and the user fill in the credentials to login on the website. At this point the app stores the related cookies. The user kills the app.
The user opens the app again, goes directly to the WKW_B section . Here the app loads the cookies mentioned above. What we see is that the website is asking the user to login again. i.e. it looks like there is something wrong with cookies loaded by WKW_B and sent to the website.
Briefly, cookies management looks like it is working only when we don’t kill the app. We tested the flow and the cookies are stored and reloaded correctly when we kill and reopen the app.
Below some reference code describing the way we manage the store/loading of the Cookies.
a) We’ve added this line in the applicationDidBecomeActive of AppDelegate
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
b) This is the WKWebView loading function in the ViewController managing the WKW_A.
- (void)loadWebView {
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
[config setWebsiteDataStore:[WKWebsiteDataStore defaultDataStore]];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
[self.webView setCustomUserAgent:#"Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/79.0.3945.73 Mobile/15E148 Safari/604.1"];
[self.webView setNavigationDelegate:self];
[self.webView evaluateJavaScript:#"window.open = function(open) { return function (url, name, features) { window.location.href = url; return window; }; } (window.open);" completionHandler:nil];
[self.webViewContainer addSubview:self.webView];
[self.webView loadRequest:[NSURLRequest requestWithURL:self.loginURL]];
}
c) This is the WKWebView loading function in the ViewController managing the WKW_B.
- (void)loadWebView {
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
[config setWebsiteDataStore:[WKWebsiteDataStore defaultDataStore]];
self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
[self.webView setCustomUserAgent:#"Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/79.0.3945.73 Mobile/15E148 Safari/604.1"];
[self.webView setNavigationDelegate:self];
[self.webView evaluateJavaScript:#"window.open = function(open) { return function (url, name, features) { window.location.href = url; return window; }; } (window.open);" completionHandler:nil];
[self.webViewContainer addSubview:self.webView];
NSMutableURLRequest *sRequest = [NSMutableURLRequest requestWithURL:self.loginURL];
[WKWebsiteDataStore.defaultDataStore.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *aCookies) {
NSDictionary *sCookieHeaderFields = [NSHTTPCookie requestHeaderFieldsWithCookies:aCookies];
[sRequest setAllHTTPHeaderFields:sCookieHeaderFields];
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"cookie_array"];
NSArray *myArrayCookies = [NSKeyedUnarchiver unarchiveObjectWithData:data];
for (int i=0;i< myArrayCookies.count;i++) {
[WKWebsiteDataStore.defaultDataStore.httpCookieStore setCookie:[myArrayCookies objectAtIndex:i] completionHandler:^{
}];
}
[sRequest setAllHTTPHeaderFields:[NSHTTPCookie requestHeaderFieldsWithCookies:myArrayCookies]];
[self.webView loadRequest:sRequest];
}];
}
d) This is the function to load the cookies inside the decidePolicyForNavigationResponse function in the ViewController managing the WKW_B
[WKWebsiteDataStore.defaultDataStore.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *aCookies) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:aCookies];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"cookie_array"];
[[NSUserDefaults standardUserDefaults] synchronize];
for (int i=0;i< aCookies.count;i++) {
[WKWebsiteDataStore.defaultDataStore.httpCookieStore setCookie:[aCookies objectAtIndex:i] completionHandler:^{
}];
}
}];
e) This is the function that we put in the applicationDidEnterBackground function of AppDelegate to store the cookies before kill the app
[WKWebsiteDataStore.defaultDataStore.httpCookieStore getAllCookies:^(NSArray<NSHTTPCookie *> *aCookies) {
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:aCookies];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"cookie_array"];
[[NSUserDefaults standardUserDefaults] synchronize];
}];
We think that could be a problem of something behind the WKWebView configuration that can be lost when we kill the app.
We were thinking also to store directly the WKWebView in the UserDefaults instead of the list of cookies but it is impossible.
How could we do to store the WKWebView status for re-uploading after the reopen of the app?

How to use different User-Agent in different iOS Webview request

I know I can use the below code to change the default agent:
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:#"Your user agent", #"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
but I want to request a different User-Agent for different requests. Examples: request 'www.google.com', use agent=‘google Agent’, request 'www.github.com', use agent='github Agent'.
I have tried the below way to set the 'User_Agent' in each request, but it doesn't seem to work.
- (void)viewDidLoad {
NSString *urlAddress = #"http://www.amazon.com";
//Create a URL object.
NSURL *url = [NSURL URLWithString:urlAddress];
//URL Requst Object
NSMutableURLRequest *requestObj = [NSMutableURLRequest requestWithURL:url];
[requestObj setValue:#"Foobar/1.0" forHTTPHeaderField:#"User_Agent"];
// But the value is not "Foobar/1.0"
NSString* secretAgent = [webView stringByEvaluatingJavaScriptFromString:#"navigator.userAgent"];
NSLog(#"agent - %#", secretAgent);
//Load the request in the UIWebView.
[webView loadRequest:requestObj];
}
One more question:
It seems a change to the default agent only work change in 'AppDelegate' or 'initialize'. Am I right? Because I try to change in 'viewDidLoad' but it doesn't seem to work.
I observed that if you load any url in webView with a user-agent set
to it. After some time you load the different url & different user
agent but used the same allocated WebView instane.The web view will
load the new url but can not set new user-agent. It just set old one
that you have set before loading first time.
You can not change untill you initiate new instanse of UIWebview(or
we can say that user agent can be set once per session). So I coame to result that user-agent can be set only once.
What I did for this problem is, I allocated new instance when I want set new user-agent.
You don't need to set it using JavaScript.
You have misspelled User-Agent. Use this minimal code taken from here
NSString* userAgent = #"My Cool User Agent";
NSURL* url = [NSURL URLWithString:#"http://whatsmyuseragent.com/"];
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setValue:userAgent forHTTPHeaderField:#"User-Agent"];

How to set http header for all requests being loaded in a UIWebView?

I tried the following :
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSLog([request valueForHTTPHeaderField:#"User-Agent"]);
if ([[request valueForHTTPHeaderField:#"User-Agent"] isEqualToString:#"CustomName"]) {
return YES;
}
else {
NSMutableURLRequest *mutable_request= [request mutableCopy];
[mutable_request setValue:#"CustomName" forHTTPHeaderField:#"User-Agent"];
request = [mutable_request copy];
[self.web loadRequest:request];
return NO;
}
}
I even added the following lines of code to viewDidLoad() method :
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"CustomName",#"User-Agent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dict];
However whenever I try to load a request using [self.web loadRequest:request] it enters an infinite loop and the value for HTTPHeaderField "User-Agent" is always printed as
"Mozilla/5.0 (iPhone; CPU iPhone OS 10_10_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Mobile/12B411"
instead of "CustomName".
NSLog(#" web url to load : %#",urlToLoad);
NSMutableURLRequest *requestObj = [NSMutableURLRequest requestWithURL:urlToLoad];
[requestObj setValue:[NSString stringWithFormat:#"%# Safari/528.16", [requestObj valueForHTTPHeaderField:#"User-Agent"]] forHTTPHeaderField:#"User_Agent"];
requestObj.timeoutInterval = 120;//Request Timeout interval added for request
[requestObj setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];//added for removing cache data of webView
[webview loadRequest:requestObj];
I found the answer, I had to replace the HTTPHeader "User-Agent" to "UserAgent".
Removing the hyphen (-) did the thing for me.
Adding following method to my AppDelegate.h also worked
+ (void)initialize {
NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:#"CustomName", #"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary];
}

How to use json data from localhost in objective-c?

- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
NSURL *site_url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/json/data/post?sid=%#", SECURE, PASSCODE]];
NSData *jsonData = [NSData dataWithContentsOfURL:site_url];
NSError *error = nil;
NSDictionary *dataDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&error];
self.items = dataDictionary;
}
I am trying to parse json data. It works fine with data from the live server. However, when I change the link to http://localhost:8090. It stops working.
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil'
I can access it from the data from the web browser. Does anyone know why is that?
Does it work on emulator and not on a real device?
You should never use localhost when developing apps, use the local IP for the server instead. Localhost is the machine who make the call to the server. When you try on the emulator and you have the server on the same machine it works because they are the same.
But when you try on a real device, localhost is the device, and the device doesn't have a server installed, so it will fail.
BTW, to test on a real device, it has to be connected to the same network.
What you need here is to implement the NSURLConnection and receive data from it
Check out this
NSURL *site_url = [NSURL URLWithString:[NSString stringWithFormat:#"%#/json/data/post?sid=%#", SECURE, PASSCODE]];
NSURLRequest *req = [NSURLRequest requestWithURL:site_url];
NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:req delegate:self];
[con start];
and from the delegates get the response
this document can help you a lot in this

Change User Agent in UIWebView

I have a business need to be able to customize the UserAgent for an embedded UIWebView. (For instance, I'd like the server to respond differently if, say, a user is using one version of the app versus another.)
Is it possible to customize the UserAgent in the existing UIWebView control the way it is, say, for an embedded IE browser in a Windows app?
Modern Swift
Here's a suggestion for Swift 3+ projects from StackOverflow users PassKit and Kheldar:
UserDefaults.standard.register(defaults: ["UserAgent" : "Custom Agent"])
Source: https://stackoverflow.com/a/27330998/128579
Earlier Objective-C Answer
With iOS 5 changes, I recommend the following approach, originally from this StackOverflow question: UIWebView iOS5 changing user-agent as pointed out in an answer below. In comments on that page, it appears to work in 4.3 and earlier also.
Change the "UserAgent" default value by running this code once when
your app starts:
NSDictionary *dictionary = #{#"UserAgent": #"Your user agent"};
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
[[NSUserDefaults standardUserDefaults] synchronize];
See previous edits on this post if you need methods that work in versions of iOS before 4.3/5.0. Note that because of the extensive edits, the following comments / other answers on this page may not make sense. This is a four year old question, after all. ;-)
I had this problem too, and tried all methods. I found that only this method works (iOS 5.x):
UIWebView iOS5 changing user-agent
The principle is to set the user agent permanently in the user settings. This works; Webview sends the given header. Just two lines of code:
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:#"Mozilla/Whatever version 913.6.beta", #"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
Setting User-Agent, or User_Agent in the mutable request, or overriding the setValue in the NSHttpRequest by swizzling, - I tried all that and controlled the results with wireshark, and none of that seems to work, because Webview still uses the user agent value from the user defaults, no matter what you try to set in the NSHttpRequest.
It should work with an NSMutableURLRequest as Kuso has written.
NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString: #"http://www.google.com/"]];
[urlRequest setValue: #"iPhone" forHTTPHeaderField: #"User-Agent"]; // Or any other User-Agent value.
You'll have to use NSURLConnection to get the responseData. Set the responseData to your UIWebView and the webView should render:
[webView loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)encodingName baseURL:(NSURL *)baseURL];
Very simple in Swift. Just place the following into your App Delegate.
UserDefaults.standard.register(defaults: ["UserAgent" : "Custom Agent"])
If you want to append to the existing agent string then:
let userAgent = UIWebView().stringByEvaluatingJavaScript(from: "navigator.userAgent")! + " Custom Agent"
UserDefaults.standard.register(defaults: ["UserAgent" : userAgent])
Note: You may will need to uninstall and reinstall the App to avoid appending to the existing agent string.
Actually adding any header field to the NSURLRequest argument in shouldStartLoadWithRequest seems to work, because the request responds to setValue:ForHTTPHeaderField - but it doesn't actually work - the request is sent out without the header.
So I used this workaround in shouldStartLoadWithRequest which just copies the given request to a new mutable request, and re-loads it. This does in fact modify the header which is sent out.
if ( [request valueForHTTPHeaderField:#"MyUserAgent"] == nil )
{
NSMutableURLRequest *modRequest = [request mutableCopyWithZone:NULL];
[modRequest setValue:#"myagent" forHTTPHeaderField:#"MyUserAgent"];
[webViewArgument loadRequest:modRequest];
return NO;
}
Unfortunately, this still doesn't allow overriding the user-agent http header, which is apparently overwritten by Apple. I guess for overriding it you would have to manage a NSURLConnection by yourself.
Using #"User_Agent" simply causes a custom header to appear in the GET request.
User_agent: Foobar/1.0\r\nUser-Agent: Mozilla/5.0 (iPhone; U; CPU
iPhone OS 3_1_2 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like
Gecko) Mobile/7D11\r\n
The above is what appears in the dissected HTTP packet, essentially confirming what Sfjava was quoting from that forum. It's interesting to note that "User-Agent" gets turned into "User_agent."
Taking everything this is how it was solved for me:
- (void)viewDidLoad {
NSURL *url = [NSURL URLWithString: #"http://www.amazon.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setValue:#"Foobar/1.0" forHTTPHeaderField:#"User-Agent"];
[webView loadRequest:request];
}
Thanks Everyone.
By pooling the answer by Louis St-Amour and the NSUserDefaults+UnRegisterDefaults category from this question/answer, you can use the following methods to start and stop user-agent spoofing at any time while your app is running:
#define kUserAgentKey #"UserAgent"
- (void)startSpoofingUserAgent:(NSString *)userAgent {
[[NSUserDefaults standardUserDefaults] registerDefaults:#{ kUserAgentKey : userAgent }];
}
- (void)stopSpoofingUserAgent {
[[NSUserDefaults standardUserDefaults] unregisterDefaultForKey:kUserAgentKey];
}
This solution seems to have been seen as a pretty clever way to do it
changing-the-headers-for-uiwebkit-http-requests
It uses Method Swizzling and you can learn more about it on the CocoaDev page
Give it a look !
I faced the same question. I want to add some info to the user-agent, also need to keep the original user-agent of webview. I solved it by using the code below:
//get the original user-agent of webview
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero];
NSString *oldAgent = [webView stringByEvaluatingJavaScriptFromString:#"navigator.userAgent"];
NSLog(#"old agent :%#", oldAgent);
//add my info to the new agent
NSString *newAgent = [oldAgent stringByAppendingString:#" Jiecao/2.4.7 ch_appstore"];
NSLog(#"new agent :%#", newAgent);
//regist the new agent
NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:newAgent, #"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary];
Use it before you instancing webview.
Try this in the AppDelegate.m
+ (void)initialize
{
// Set user agent (the only problem is that we can’t modify the User-Agent later in the program)
// iOS 5.1
NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:#”Mozilla/5.0 (iPad; CPU OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B176 Safari/7534.48.3”, #”UserAgent”, nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary];
}
The only problem I have found was change user agent only
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDictionary *dictionary = [NSDictionary
dictionaryWithObjectsAndKeys:
#"Mozilla/5.0 (iPod; U; CPU iPhone OS 4_3_3 like Mac OS X; ja-jp) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5",
#"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];
}
Apple will soon stop accepting apps with UIWebView. Find below for how you could change the user agent in WKWebView.
let config = WKWebViewConfiguration()
config.applicationNameForUserAgent = "My iOS app"
webView = WKWebView(frame: <the frame you need>, configuration: config)
To just add a custom content to the current UserAgent value, do the following:
1 - Get the user agent value from a NEW WEBVIEW
2 - Append the custom content to it
3 - Save the new value in a dictionary with the key UserAgent
4 - Save the dictionary in standardUserDefaults.
See the exemple below:
NSString *userAgentP1 = [[[UIWebView alloc] init] stringByEvaluatingJavaScriptFromString:#"navigator.userAgent"];
NSString *userAgentP2 = #"My_custom_value";
NSString *userAgent = [NSString stringWithFormat:#"%# %#", userAgentP1, userAgentP2];
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:userAgent, #"UserAgent", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:dictionary];

Resources