I have been able to change the user-agent by using
- (BOOL)webView:(UIWebView *)webView2 shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSMutableURLRequest *req = (NSMutableURLRequest *)request;
NSString *versionString = [[NSBundle mainBundle] objectForInfoDictionaryKey:(NSString*)kCFBundleVersionKey];
NSLog(#"user agent = %#", [req valueForHTTPHeaderField: #"User-Agent"]);
if ([req valueForHTTPHeaderField:#"User-Agent"] != NULL) {
[req setValue:[NSString stringWithFormat:#"%# %#", versionString, [req valueForHTTPHeaderField:#"User-Agent"]] forHTTPHeaderField:#"User-Agent"];
NSLog(#"user agent = %#", [req valueForHTTPHeaderField: #"User-Agent"]);
return YES
}
}
But when I go to this website on the device http://whatsmyuseragent.com/ my user-agent hasn't changed. Is there a way to change the user-agent for good?
After playing around for a really long time, I discovered that you can change the User Agent without rooting. Not sure if this helps you if you are building an app.
You cannot change the user-agent displayed by Safari, only the one used by your own application.
I have noticed that the simulator reports nil when testing at times. I'm not sure if this is intentional or on purpose.
You can change the value of the user agent when doing "manual" NSURLRequests but I don't think you can change them in a UIWebView.
Reason being, the values that are passed into the method you show above are not mutable -- you can't change them and expect that the rest of the application will "take" the modifications. Honestly, I'm surprised that casting a NSURLRequest to its mutable variant and then changing it didn't cause your app to crash.
Related
I am consuming Web Service to fetch data and it returns a set of data from server, this works great before i install xcode 5, previously my app was compatible with ios6 now i changed to ios 7. Now i have one issue while fetching data from web service .
When i go first time to the UIViewController view i call web service in -(void)ViewDidLoad and no data return and if i call one more time ( without going back from view, i call again the same web service) it returns data, when i call first time it returns empty data but second time it return data, This is happening in ios 6 but the same code work perfect without any web service issue in ios 7. after i change
I am Receiving response from server but the data inside is null for first time, but the same time i run in ios 7 device its return data, so i don't understand where i am wrong??????
NSMutableData *serverData;
//delegate methods for NSURLConnection
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *str = [[NSString alloc] initWithData:serverData encoding:NSUTF8StringEncoding];//here i am initializing
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[serverData appendData:data]; // here i get data that is null but i get response from server
}
Myviewwillappear code here...
- (void)viewWillAppear:(BOOL)animated {
[self performSelector:#selector(GetDataFromServer) withObject:nil afterDelay:0.001];
}
- (void) GetDataFromServer {
NSString *soapMessage = [NSString stringWithFormat:#"<?xml version=\"1.0\" encoding=\"utf-8\"?>"
#"<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
#"<soap:Body>"
#"<GetProductList xmlns=\"http://tempuri.org/\">"
#"<inCompany>%#</inCompany>"
#"<inUserName>%#</inUserName>"
#"<inType>%#</inType>"
#"<inTypeValue>%#</inTypeValue>"
#"<inSearchVal>%#</inSearchVal>"
#"<inPage>%#</inPage>"
#"</GetProductList>"
#"</soap:Body>"
#"</soap:Envelope>",Company,Username,type,typevalue,searchval,page];
NSURL *url = [NSURL URLWithString:PVBASE_URL];
NSString *msgLength = [NSString stringWithFormat:#"%d",[soapMessage length]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request addValue:#"text/xml; charset=utf-8" forHTTPHeaderField:#"Content-Type"];
[request addValue:PVPRODUCTLIST forHTTPHeaderField:#"SOAPAction"];
[request setHTTPMethod:#"POST"];
[request addValue:msgLength forHTTPHeaderField:#"Content-Length"];
[request setHTTPBody:[soapMessage dataUsingEncoding:NSUTF8StringEncoding]];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (connection) {
if (serverData) {
serverData = nil;
}
serverData = [[NSMutableData alloc] init];
}
connection = nil;
}
Basically i have en-counted this issue several times as when ever viewDidLoad execute didn't get any data but explicit call from IBaction it does. this is nothing to deal with iOS. basic problem with your web-service call.
You might be be calling data with using public variable which not execute or initialize.
Please provide your code for better understanding.
Thanks !!
I thought I would share my answer here as a possible solution. I had a similar problem occur with iOS6 and when I upgraded to iOS7 the network stack appeared to not be working because I was not getting data on the didRecieveResponse function of NSURLConnection. When in actuality from comparing how my code acted between iOS platforms it only looked like I was not receiving data from the didRecieveResponse function because sometimes the expectedContentLength mostly returned -1, but this also happened in iOS 6. In iOS7 the problem originated from another source that is unrelated to this example or my network connection that was affecting my use of NSOperation. So my point is, possibly the problem is not your platform differences but your code running your functionality. I would go through your code again for errors.
I have a webview app tool, which essentially consists of the webview and two buttons on a toolbar. One button to view the source of the page, and another button to view/change the current User Agent.
I have both functions working on iOS 5 (view source, and change User Agent), but I cant seem to grab the User Agent in iOS 4.x.
I'm using the following now:
userAgentViewController.UAText = [self.webView stringByEvaluatingJavaScriptFromString:#"navigator.userAgent"];
This works in iOS5, but in iOS 4.x, it doesnt return anything. Is there a way to achieve the same functionality in iOS 4.x?
Thank you!
to get the useragent, check the HTTP header in the NSURLRequest of your response.
You can retreive this one in the webViewDidFinishLoad delegate method.
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSLog(#"%#", [[webView request] valueForHTTPHeaderField: #"User-Agent"]);
}
to set it, you have to custom an NSMutableURLRequest and give it to your webView
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:#"yourwebsite.com"]];
[request setHTTPMethod:#"POST"];
[request setValue:USERAGENT_STRING forHTTPHeaderField: #"User-Agent"];
[webView loadRequest:request];
[request release];
and that's it !
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];
}
I m using sendSynchronousRequest to get the data from the server. I know that synchronous will wait until the data received for that request.
But the problem comes when user by mistake enters some non-existing url and than tries to get response. In this case, if user goes in to background and than comes into foreground it shows only black screen. It only shows status bar. Also its not showing any background application. I have to press Home button to come out of my application.
On simulator, After 1+ minute it shows me the message that "Request time out" (No crash).
On Device, within 1 min application get crashes.
Any suggestion. Any Help. This is really a serious issue in my app.
Thanks.
Just like Julien said, the watchdog is killing your app. To answer some questions:
why does this happen only on the simulator?
Because when you're debugging the watchdog leaves your app alone, it can take time.
why does this happen only when the user enters a wrong url?
Because of the system timeout, the system will keep trying for 60 secs if it can't find a server.
so the problem is synchronous vs asynchronous?
No, the problem is the thread, you can do the same operation in a background thread, just don't do it on the main thread and the watchdog will leave you alone.
why is the screen black when the app comes up?
Remember, you are making blocking stuff on the main thread, the thread that draws...
Hope that was all. Let me know if I missed something.
Why not setting a timeout for your connection?
NSString *urlString = TEST_CONNECTION;
NSError *error = nil;
NSHTTPURLResponse *response = nil;
NSURLRequest *request = [NSURLRequest
requestWithURL:[NSURL URLWithString:urlString]
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:5.0];
NSData *conn = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
This should release the synchronous waiting after a number of seconds, which should solve your problem without going with an asynchronous call (which sometimes isn't the proper solution)
I know this works properly because this is how I check if I am connected to a certain VPN (where reachability flags totally fail).
you should take a look to this article: https://developer.apple.com/library/ios/#qa/qa1693/_index.html
iOs contains a watchdog, if your application is blocked to much time on an operation on the main thread, this one will be killed. (for more details about Watchdog: http://en.wikipedia.org/wiki/Watchdog_timer)
So if you want to download something, don't download it on the main thread.
RELATE
UIImage *image = [self.imgCache objectForKey:urlString];
if(!image){
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:60.0];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
NSLog(#"%#",response);
UIImage *img = [UIImage imageWithData:data];
//
if(img)
{
dispatch_sync(dispatch_get_main_queue(), ^{
[self.imgCache setObject:img forKey:urlString];
completionBlock(img);
});
}
});
}
else{
completionBlock(image);
}
use ASIHttpRequest class instead of NSURLConnection , its nothing but wrapper around NSURLConnection and has very simple callbacks , you can also set time to complete a request. Please go through this link for more info http://allseeing-i.com/ASIHTTPRequest/
I think you first have to test user data whether it is correct or not and than only if it is correct, sends the request otherwise prompt user that "please enter correct data"...
or
when your parsing of data in response failed. You can also make protocol delegate method i.e FinishWithError so that you come up with your last UI.
Try this one:
#import "ASIHTTPRequest.h"
//In a method
[self performSelectorInBackground:#selector(DownLoadImageInBackground:) withObject:imgUrlArr];
-(void) DownLoadImageInBackground:(NSArray *)imgUrlArr1
{
NSURL * url = [Image URL];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
}
-(void)requestFailed:(ASIHTTPRequest *)request
{
NSLog(#"URL Fail : %#",request.url);
NSError *error = [request error];
// you can give here alert too..
}
-(void)requestFinished:(ASIHTTPRequest *)request
{
NSData *responseData = [request responseData];
UIImage *imgInBackground = [[UIImage alloc]
initWithData:responseData];
[imageView setImage: imgInBackground];
}
This might help you: I am also loading a number of images at one time, so images that have no proper data show a black screen. To avoid this, try to resize your imageview.
You could check the reachability of the URL before starting the request.
Apple has Reachability Methods to do so. But its easier to use a wrapper. E.g. ASIReachability.
I think the application crashing because you does not get any data when user enters wrong URL and you are using this 'returned' nil NSData to do stuffs.
I think this will fix your problem
NSData *data=[NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if(data!=nil){
///
} else {
NSLog(#"NO DATA");
}
I need to connect to a protected site and try to use ASIHTTPRequest
Here is my code:
url = [NSURL URLWithString:#"http://myurl/page.aspx"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setUsername:username];
[request setPassword:password];
[request setDomain:domain];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
[webView loadHTMLString:[request responseString] baseURL:[request url]];
}
When I use NSLog to see [request responseString], I get the correct HTML, but the result is a blank white webview.
From the outgoing request warnings that little snitch displays, I see the initial request and one going to an external resource.
My guess so far is that the inital request correctly uses the authentication from ASIHTTPRequest and fetches the page, but the uiwebview will try to load the included .js files and since uiwebview is not authenticating, it will not render the page at all ...
Anybody knows how to fix my problem?
Have you tried ASIWebPageRequest? My guess is you have resources in that page that are not downloaded, like http://myurl/image.jpg
ASIHttpRequest runs asynchronously. You need to put your webview loading code into the ASIHTTPRequest callbacks. (requestFinished).
Add a method to your class as follows:
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSError *error = [request error];
if (!error) {
[webView loadHTMLString:[request responseString] baseURL:[request url]];
}
}
There is also a requestFailed method that you can use to trap additional errors, you should implement this as well. One or the other of these methods will be called once ASIHttpRequest completes.
Note you will probably also need to set the delegate on the request before making the asynch call. (so same place you set the auth stuff).
request.delegate = self;
I wonder how I can check if a file exist on a server or not, without downloading the data first.
I have around 30 different objects and some of them is connected to a movie on a server. At the moment I use NSData to control if the the URL exist, and then shows the movie, or if it doesn't and then alerts the user that there is no video for that object. The code I use for the moment:
NSString *fPath = [[NSString alloc] initWithFormat:#"http://www.myserver/%#", [rows idNr]];
NSURL *videoURL = [NSURL URLWithString:fPath];
NSData *videoData = [NSData dataWithContentsOfURL:videoURL];
url = [NSURL URLWithString:fPath];
[fPath release];
if (videoData) {
[self performSelectorOnMainThread:#selector(playVideo:) withObject:url waitUntilDone:NO];
} else {
NSLog(#"videodata false");
errorLabel.hidden = NO;
activityView.hidden = YES;
}
"rows idNr" is the name of the object. This method is doing what I want, but the problem is that with NSData it first "downloading" the file, and when the URL is validated as a file, the movie is loading once again in the movieplayer. This means that it takes twice as long to load the file.
Suggestions?
It took me a while to dig out my answer to one of the previous questions on this topic. Quote:
You can use a NSMutableURLRequest to send a HTTP HEAD request
(there’s a method called setHTTPMethod). You’ll get the same
response headers as with GET, but you won’t have to download the whole
resource body. And if you want to get the data synchronously, use the
sendSynchronousRequest… method of NSURLConnection.
This way you’ll know if the file exists and won’t download it all if it does.
Make an URLConnecion object with desired url request and add NSURLConnectionDelegate into .h file like I want to check "yoururl" is exist or not then you need to do is
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString: #"http://www.google.com"]];
NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self];
and then you can track http status code in delegate function of NSURLConnectionDelegate
-(void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
int code = [(NSHTTPURLResponse *)response statusCode];
if (code == 404)
{
// website not found
// do your stuff according to your need
}
}
You can also find various status code here.
NSError *err;
if ([videoURL checkResourceIsReachableAndReturnError:&err] == NO)
NSLog(#"wops!");
Here's the code for the accepted answer (for your convenience):
How to make call
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:#"HEAD"];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
You could do this by checking the size of the file via an FTP server, using the SIZE command. If the file size is zero then the file simply do not exist.
Check here on how to do this.
You could of course also do this by using a NSURLRequest with NSURLConnection, checking for the status to be either 200 (success) or 404 (failed). The 404 status doesn't have to be that the file doesn't exist though, it could also be that the file just couldn't be retrieved.