Help making a Unified address bar in ios 5 for a Browser App? So here is my address bar.
-(IBAction)url:(id)sender {
NSString *query = [urlBar.text stringByReplacingOccurrencesOfString:#" " withString:#"+"];
NSURL *urlQuery = [NSURL URLWithString:[NSString stringWithFormat:#"http://%#", query]];
NSURLRequest *request = [NSURLRequest requestWithURL:urlQuery];
[webPage loadRequest:request];
}
Couldn't I add an "else" reference to say if it is not an address then append the google search tag? If so how? And would you know how to use Bing instead of google?
-(IBAction)googleSearch:(id)sender {
NSString *query = [googleSearch.text stringByReplacingOccurrencesOfString:#" " withString:#"+"];
NSURL *urlQuery = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.google.com/search?hl=en&site=&q=%#", query]];
NSURLRequest *request = [NSURLRequest requestWithURL:urlQuery];
[webPage loadRequest:request];
}
Here are some tips to help you:
use stringByAddingPercentEscapesUsingEncoding: instead of your "+" replacement.
you should check if http:// is not a prefix to the URL string before adding it
you should implement the UIWebViewDelegate protocol to identify when an error occurs when loading an invalid URL
then as a fallback launch your Google search (now you can replace " " by "+")... or Bing, whatever and up to you!
Your code should looks something as follow:
...
webView.delegate = self; // Should appear in your code somewhere
...
-(IBAction)performSearch {
if ([searchBar.text hasPrefix:#"http://"]) {
... // Make NSURL from NSString using stringByAddingPercentEscapesUsingEncoding: among other things
[webView loadRequest:...]
} else if ([self isProbablyURL:searchBar.text]) {
... // Make NSURL from NSString appending http:// and using stringByAddingPercentEscapesUsingEncoding: among other things
[webView loadRequest:...]
} else {
[self performGoogleSearchWithText:searchBar.text]
}
}
- (BOOL)isProbablyURL:(NSString *)text {
... // do something smart and return YES or NO
}
- (void)performGoogleSearchWithText:(NSString *)text {
... // Make a google request from text and mark it as not being "fallbackable" on a google search as it is already a Google Search
[webView loadRequest:...]
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
... // Notify user
if (was not already a Google Search) {
[self performGoogleSearchWithText:searchBar.text]
}
}
Related
I'm pretty new to iOS development, and can't find an answer that helps my problem anywhere.
I'm making an app where the user must first login, using a UIWebView.
Once the user logs in, they are taken to the app, but in the background the server has passed a unique authentication key for each user.
Example
The user logs in at the URL www.example.com/login.
on a successful login the URL changes to www.example.com/key/jsaeglihndzlgaskn with the end bit being the key I need to get.
I have a method which gets the last segment of the URL but it takes the starting URL not the one that changes.
NSString *absoluteString= _webView.request.URL.absoluteString;
NSArray* foo = [absoluteString componentsSeparatedByString: #"/"];
NSUInteger arrsize = [foo count];//count the size of array
NSString* bar = foo[arrsize-1];//get last element
Any help would be massively appreciated
Edit
This is how my code now looks, but It still doesn't function as I need it to, any help getting this to work would be greatly appreciated.
NSString *urlString = #"https://probablyrational.com/alpha/dashboard/register/?callback=inline";
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[_webView loadRequest:urlRequest];
NSString* absoluteString = [url absoluteString];
NSArray* foo = [absoluteString componentsSeparatedByString: #"/"];//explode() .split()
NSUInteger arrsize = [foo count];//count the size of array
NSString* bar = foo[arrsize-1];//get last element
NSLog(#"bar %#", bar);
//bar = "?callback=inline"
if ([foo[arrsize-2] isEqualToString:#"key"]) {
// user is authenticated
NSLog(#"bar %#", bar);
- (BOOL)_webView:(UIWebView *)_webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *URLString = [[request URL] absoluteString];
if ([URLString isEqualToString:#"https://probablyrational.com/alpha/key"]) {
// The user reached step 3!
}
return YES;
}
EDIT 2
My code is now running but still not tracking the URL change..
NSString *urlString = #"https://probablyrational.com/alpha/dashboard/register/?callback=inline";
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[_webView loadRequest:urlRequest];
NSString* absoluteString = [url absoluteString];
NSArray* foo = [absoluteString componentsSeparatedByString: #"/"];//explode() .split()
NSUInteger arrsize = [foo count];//count the size of array
NSString* bar = foo[arrsize-1];//get last element
NSLog(#"bar %#", bar);
//bar = "?callback=inline"
if ([foo[arrsize-2] isEqualToString:#"key"]) {
// user is authenticated
NSLog(#"bar %#", bar);
}
}
- (BOOL)webView:(UIWebView *)webView didFinishLoading:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *absoluteString = [[request URL] query];
if ([absoluteString isEqualToString:#"https://probablyrational.com/alpha/key"]) {
// The user reached step 3!
( NSLog(#"this is the code you're looking for"));
return YES;
}
else
{
( NSLog(#"this is not code you're looking for"));
return 0;
}
}
Any clue how I can get this to work would be life saving, i'm stuck at this point
you can use [foo lastObject]; to get the last component.
I have looked everywhere and have not found exactly what I am looking for, so here is my question:
I have a basic app I am playing around with. I have created a webview and would like to be able to download a file from the website that loads in the webview and save the file to say the Downloads folder on the local machine. The site loads fine inside the webview, now how do I download a file, say an .xml file from the site and save it to the Downloads folder on the local machine?
This is what I have so far:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSURL *url = [NSURL URLWithString:#"http://www.google.com"];//<-- example site
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[[webView mainFrame] loadRequest:request];
}
I would like to be able to download a file (possible using a delegate) then save it to a location on the local computer. I am pretty new to this so I'd appreciate any help.
The issue has been resolved. I added the following code to make it work:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSURL *url = [NSURL URLWithString:#"http://www.google.com"]; // <-- example website
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.webView.policyDelegate = self;
[self.webView setDownloadDelegate:self];
[[self.webView mainFrame] loadRequest:request];
}
- (void)webView:(WebView *)webView decidePolicyForMIMEType:(NSString *)type
request:(NSURLRequest *)request
frame:(WebFrame *)frame
decisionListener:(id < WebPolicyDecisionListener >)listener
{
if([type isEqualToString:#"application/octet-stream"]) //this is the type I was looking for
{
//figure out how to save file here
[listener download];
NSURLDownload *downLoad = [[NSURLDownload alloc] initWithRequest:request delegate:self];
if(downLoad)
{
[self download:downLoad decideDestinationWithSuggestedFilename:#"filename.ext"];
NSLog(#"File Downloaded Succesfully");
//[webView close];
[self.window close];
}
else
{
NSLog(#"The download failed");
}
}
//just ignore all other types; the default behaviour will be used
}
-(void)download:(NSURLDownload *)download decideDestinationWithSuggestedFilename:(NSString *)filename
{
NSString *destinationFileName;
NSString *homeDirectory = NSHomeDirectory();
destinationFileName = [[homeDirectory stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:filename];
[download setDestination:destinationFileName allowOverwrite:NO]; //file is being saved to the Documents folder on the local machine
}
Hope this will be helpful to someone else.
I have a problem I have discovered in my app that has a UIWebView. iOS 7 caches a blank body 304 response, resulting in blank pages being shown when the user refreshes the UIWebView. This is not good user expierience and I'm trying to figure out how to solve this on the iOS side, as I do not have control over how Amazon S3 responds to headers (that's who I use for my resource hosting).
More details of this bug were found by these people: http://tech.vg.no/2013/10/02/ios7-bug-shows-white-page-when-getting-304-not-modified-from-server/
I'd appreciate any help offered to how I can solve this on the app side and not the server side.
Thank you.
Update: fixed this bug using the bounty's suggestion as a guideline:
#property (nonatomic, strong) NSString *lastURL;
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if ([self.webView stringByEvaluatingJavaScriptFromString:#"document.body.innerHTML"].length < 1)
{
NSLog(#"Reconstructing request...");
NSString *uniqueURL = [NSString stringWithFormat:#"%#?t=%#", self.lastURL, [[NSProcessInfo processInfo] globallyUniqueString]];
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:uniqueURL] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:5.0]];
}
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
self.lastURL = [request.URL absoluteString];
return YES;
}
You can implement a NSURLProtocol, and then in +canonicalRequestForRequest: modify the request to override the cache policy.
This will work for all requests made, including for static resources in the web view which are not normally consulted with the public API delegate.
This is very powerful, and yet, rather easy to implement.
Here is more information:
http://nshipster.com/nsurlprotocol/
Reference:
https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/Classes/NSURLProtocol_Class/Reference/Reference.html
Here is an example:
#interface NoCacheProtocol : NSURLProtocol
#end
#implementation NoCacheProtocol
+ (void)load
{
[NSURLProtocol registerClass:[NoCacheProtocol class]];
}
+ (BOOL)canInitWithRequest:(NSURLRequest*)theRequest
{
if ([NSURLProtocol propertyForKey:#“ProtocolRequest” inRequest:theRequest] == nil) {
return YES;
}
return NO;
}
+ (NSURLRequest*)canonicalRequestForRequest:(NSURLRequest*)theRequest
{
NSMutableURLRequest* request = [theRequest mutableCopy];
[request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData];
//Prevent infinite recursion:
[NSURLProtocol setProperty:#YES forKey:#"ProtocolRequest" inRequest:request];
return request;
}
- (void)startLoading
{
//This is an example and very simple load..
[NSURLConnection sendAsynchronousRequest:self.request queue:[NSOperationQueue currentQueue] completionHandler:^ (NSURLResponse* response, NSData* data, NSError* error) {
[[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[[self client] URLProtocol:self didLoadData:data];
[[self client] URLProtocolDidFinishLoading:self];
}];
}
- (void)stopLoading
{
NSLog(#"something went wrong!");
}
#end
As the other questions are to use the NSURLConnection every time, which seems like a bit of an overhead:
Why don't you execute a small javascript after the page was loaded (complete or incomplete) that can tell you if the page is actually showing? Query for a tag that should be there (say your content div) and give a true/false back using the
[UIWebView stringByEvaluatingJavaScriptFromString:#"document.getElementById('adcHeader')!=null"]
And then, should that return false, you can reload the URL manually using the cache-breaker technique you described yourself:
NSString *uniqueURL = [NSString stringWithFormat:#"%#?t=%d", self.url, [[NSDate date] timeIntervalSince1970]];
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:uniqueURL] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:5.0]];
[edit]
based on the discussion in the comments and some of the other answers, I think you might have the best solution manually changing the NSURLCache.
From what I gathered, you're mainly trying to solve a reload/reshow scenario. In that case, query the NSURLCache if a correct response is there, and if not delete the storedvalue before reloading the UIWebView.
[edit 2]
based on your new results, try to delete the NSURLCache when it is corrupted:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache]cachedResponseForRequest:request];
if (cachedResponse != nil && [[cachedResponse data] length] > 0)
{
NSLog(#"%#",cachedResponse.response);
} else {
[[NSURLCache sharedURLCache] removeCachedResponseForRequest:request];
}
return YES;
}
We might have to refine the check if the cache is invalid again, but in theory this should do the trick!
NSURL *URL = [NSURL URLWithString:#"http://mywebsite.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:30.0];
[myWebView loadRequest: request];
When creating NSURLRequest instance, you can set Cache Policy.
Hope it works!
I am storing website addresses from users in regular NSStrings.
Some are given as "www.somewebsite.com" and some as "http://somewebsiteothersite.org".
My app should open a UIWebView and open that webpage:
NSURLRequest *requestObj = [NSURLRequest requestWithURL:[NSURL URLWithString:[self websiteString]]];
NSLog(#"visiting: %#",websiteString);
[webView loadRequest:requestObj];
But what happens is that if the http:// is omitted, the UIWebView won't open the page.
Is there a descent way to build the NSURL correctly for UIWebView?
Thanks!
Just add http:// if it's not there?
if (![urlStr hasPrefix:#"http://"] && ![urlStr hasPrefix:#"https://"]) {
urlStr = [#"http://" stringByAppendingString:urlStr];
}
beware of links that are intended to not have http:// for example ftp:// or mailto:
I know Mathiass answered quicker but I want to share a similar solution
//first detect if your string has contains http:// if not add http:// to your string
NSMutableString *websiteString = #"www.x.com";
if ([websiteString rangeOfString:#"http://"].location == NSNotFound) {
NSLog(#"contains http:// == false");
websiteString = [#"http://" stringByAppendingString:websiteString];
} else {
NSLog(#"contains http:// == true");
}
NSURLRequest *requestObj = [NSURLRequest requestWithURL:[NSURL URLWithString:[self websiteString]]];
NSLog(#"visiting: %#",websiteString);
[webView loadRequest:requestObj];
I'm loading a remote webpage into an iOS webview which relies on js and css assets. To improve the performance particularly on 3G networks, I'm hoping to call these assets from files local to the iOS device.
The website backing the iOS app is also used by mobile phone browsers, not just the iOS app, so subclassing NSURLRequest to register my own URL prefix (myurl://) is not ideal.
I already have code that launches mobileSafari for URLs outside of my domain:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
NSString *hostname = [url host];
if (![hostname hasSuffix:#".mysite.com"] && navigationType == UIWebViewNavigationTypeLinkClicked) {
[[UIApplication sharedApplication] openURL:url];
return NO;
}
return YES;
}
This method is called from the same controller implementation with code like this:
- (void)viewDidLoad {
[super viewDidLoad];
// ...
webView.delegate = self;
// ...
NSURL *url = [[NSURL alloc] initWithString:([path length] > 0 ? path : #"http://mysite.com/mobile/index")];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
[webView loadRequest:request];
// ...
}
I've reviewed several other questions ( How to use an iPhone webView with an external HTML that references local images? , Dynamically loading javascript files in UIWebView with local cache not working, iOS WebView remote html with local image files, Using local resources in an iPhone webview ) but they all seem to miss a key element to my problem.
The first link has the start of something promising:
if ([url isEqualToString:#"http://path-to-cdn.com/jquery-1.8.2.min.js"]) {
fileToLoad = [[NSBundle mainBundle] pathForResource:#"jquery-1.8.2.min" ofType:#"js"];
}
If that's a sensible approach, I'm stuck on how to get from passing that fileToLoad NSBundle into the webView's loadRequest, since that's expecting a URL.
I think I'm on the right path after realizing that I could use the output of stringByAppendingPathComponent as a URL, like so...
if (![hostname hasSuffix:#".mysite.com"] && navigationType == UIWebViewNavigationTypeLinkClicked) {
NSString *urlString = [url absoluteString];
if ([urlString isEqualToString:#"http://path-to-cdn.com/jquery-1.8.2.min.js"]) {
NSString *tempurl = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"js/jquery-1.8.2.min.js"];
[webView loadRequest:[NSMutableURLRequest requestWithURL:tempurl]];
} else {
[[UIApplication sharedApplication] openURL:url];
}
return NO;
}
return YES;
I don't have it working yet (it's still loading the remote URL) but I think I'm on the right path.