Injecting local files into UIWebView without breaking links - html

I am working on an iOS app that needs to display webpages from a server inside a UIWebView while injecting relevant local png and css files as needed in order to speed up load time. Here is the code I am using to try to do this:
NSData *myFileData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://www.example.com/index.html"]]];
NSString* myFileHtml = [[NSString alloc] initWithData:myFileData encoding:NSASCIIStringEncoding];
[myWebView loadHTMLString:myFileHtml baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]];
My problem is that some of the webpages have buttons in them that link to other webpages on the server, and because the UIWebView is only loading a string, the buttons when tapped don't cause the UIWebView to load the new webpage URL like it would if I had used the loadRequest method.
My question is how can I get the the UIWebView to behave like it is loading a request while still injecting local files from the baseurl?
Thanks

The relative links in the button cannot work, because the linked pages are on a remote server and not on the device's file system. However you can use a UIWebViewDelegate method to make it work:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
NSString *localRootPath = [NSString stringWithFormat:#"file://%#", [[NSBundle mainBundle] bundlePath]];
NSString *remoteRootPath = #"http://yourdomain.com";
NSString *remotePath = [[request.URL absoluteString] stringByReplacingOccurrencesOfString:localRootPath withString:remoteRootPath];
[self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:remotePath]]];
// or you can use your own loading mechanism here
return NO;
}
return YES;
}
This method intercepts all requests from your WebView. If the request was triggered by a user tap / click the URL gets modified from a relative URL to a absolute URL so it can be loaded from the server. Don't forget to set the delegate on the WebView or this method will not be called.

NSURLPRotocol is a handler for NSURLConnection and will give you the opportunity to intercept the calls to the server and substitute your own content.
1) Derive a class from NSURlProtocol
2) Call NSURLProtocol registerClass: in your application:didFinishLaunchingWithOption
3) Read the documentation on implement these methods as necessary:
initWithRequest:cachedResponse:client:,
startLoading,
URLProtocol:didReceiveResponse:cacheStoragePolicy:
URLProtocolDidFinishLoading:

Related

Display a preview of the website

I need to display a preview of the website with given url in the single image(e.g. like Facebook do in Messenger when you sending a url to someone). Is there any way to achieve that without actually loading the html file and reading it's metadata?
Try this,
NSString *urlStr = #"http://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png?v=c78bd457575a";
NSURL *url=[NSURL URLWithString: urlStr];
NSData *data=[NSData dataWithContentsOfURL:url];
UIImage *image=[[UIImage alloc] initWithData:data];
UIImageView *imagview = [[UIImageView alloc]initWithImage:image];
imagview.frame = CGRectMake(250, 500, 100, 100);
[self.view addSubview:imagview];
This will give just thumb or image.
You can use URLEmbeddedView Library for more functionality. I think this is the library what you want.

Loading local html from an array in xcode

I am attempting to load a locally hosted html file into a webview from an array. it looks something like this
_siteAddresses = [[NSArray alloc]
initWithObjects:#"file://localhost/var/mobile/Application/${APP_ID}/First Pentecostal Seminary.app/First_Pentecostal_Seminary/Main.html",...
with the corresponding code being
NSString *urlString = [_siteAddresses
objectAtIndex:indexPath.row];
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.detailViewController.webView.scalesPageToFit = YES;
[self.detailViewController.webView loadRequest:request];
What am I doing wrong...is it my coding or perhaps the html coding (I believe there may be some java in there)
Two thoughts:
That example file URL doesn't look right. How did you construct that? If it was something from your bundle on your device, I'd expect something more like:
file:///var/mobile/Applications/9E670C3C-C8B1-4B09-AE66-B43F7DB29F4D/First Pentecostal Seminary.app/...
Obviously, you have to programmatically determine this URL by using NSBundle instance method URLForResource or by using the bundle's bundleURL and then adding the appropriate path components.
You should (a) specify the view controller to be the delegate for your web view; and then (b) implement webView:didFailLoadWithError: and look at the error there, and it will inform you what the error was, if any.
For example, I have a file, test.html sitting in my bundle, which I can load into a web view like so:
NSURL *bundleURL = [[NSBundle mainBundle] bundleURL];
NSURL *url = [bundleURL URLByAppendingPathComponent:#"test.html"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
I have set up my view controller as the delegate for the web view and have the following didFailLoadWithError:
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error
{
NSLog(#"%s: %#", __FUNCTION__, error);
}
So, when I tried to load a request with an invalid URL this time (test2.html, which I do not have in my bundle), I get the following error:
2014-02-26 23:35:43.593 MyApp[3531:70b] -[ViewController webView:didFailLoadWithError:]: Error Domain=NSURLErrorDomain Code=-1100 "The requested URL was not found on this server." UserInfo=0x8c32f40 {NSErrorFailingURLStringKey=file:///Users/user/Library/Application%20Support/iPhone%20Simulator/7.0.3/Applications/FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF/MyApp.app/test2.html, NSErrorFailingURLKey=file:///Users/user/Library/Application%20Support/iPhone%20Simulator/7.0.3/Applications/FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF/MyApp.app/test2.html, NSLocalizedDescription=The requested URL was not found on this server., NSUnderlyingError=0x10424c90 "The requested URL was not found on this server."}
Try this code
UIWebView *documentsWebView=[[UIWebView alloc]init];
documentsWebView.delegate=self;
documentsWebView.frame=CGRectMake(0, 0, 1024, 616);
documentsWebView.backgroundColor=[UIColor clearColor];
[self.view addSubview:documentsWebView];
NSString* htmlString = [NSString stringWithContentsOfFile:[_siteAddresses
objectAtIndex:indexPath.row] encoding:NSUTF8StringEncoding error:nil];
[documentsWebView loadHTMLString:htmlString baseURL:nil];

Add a Webview Window to a existent iOS App that loads local stored HTML

Add a Webview Window to a existent iOS App that loads local stored HTML ... i am working on a app that loads a feed RSS and thats already done, but now the app needs a section that can be updated on a simple manner...
Your going to want to just drop a webview on in your xib, attatch it through your IBOutlet property, and then load your local stored HTML like the following:
NSError *fileReadError = nil;
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"HTMLFilename" ofType:#"html"];
NSString *fileContents = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&fileReadError];
if ( fileContents != nil )
{
[self.webView loadHTMLString:fileContents baseURL:nil];
}

Implementing 'Download to Computer' functionality of browser

I am trying to download a mp3 file at a given link using NSURLConnection. However, I usually get time-out errors. Entering the link into the browser shows the default player, however the music file is not loaded either:
However, if I create the following simple HTML file:
<html>
<body>
Download
</body>
</html>
And then load the file into Safari, right click on the Download link, then select Download to Computer (or whathever it's called in English), Safari downloads the file.
Any ideas on how I can implement this in my own app?
I tried using
NSData *data = [NSData dataWithContentsOfURL:url];
and
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *r, NSData *data, NSError *e) { /.../ }];`
without success.
Seems like you're trying to hit a fly with a sledgehammer, using "NSURLConnection".
Try doing something a wee bit more high level such as
NSData * mp3data = [[NSData alloc] initWithContentsOfURL:options:error: ];
(the added benefit here is that you can get useful errors back via the "error:" parameter you pass into the method.
Here's an example on what you need to do:
NSURL* url = [NSURL URLWithString:yourMp3URLString];
//URL of the mp3 file
NSString* fileName = [NSString stringWithFormat:#"%#.mp3", mp3Name];
//NSString with the name of the mp3
NSString* destinationPath = [filePathString stringByAppendingPathComponent:fileName];
//NSString with the filePathString (NSString with path destination, you could
//change it to something like this #"User/Desktop")
//and add the NSString filename to the end of it
//so, if we have like User/Desktop it will become User/Desktop/mp3Name.mp3
NSURLRequest* request = [NSURLRequest requestWithURL:url];
NSURLDownload* download = [[NSURLDownload alloc] initWithRequest:request delegate:self];
[download setDestination:destinationPath allowOverwrite:NO];
//create the URLRequest and Download the mp3 to the destinationPath

Reading HTML content from a UIWebView

Is it possible to read the raw HTML content of a web page that has been loaded into a UIWebView?
If not, is there another way to pull raw HTML content from a web page in the iPhone SDK (such as an equivalent of the .NET WebClient::openRead)?
The second question is actually easier to answer. Look at the stringWithContentsOfURL:encoding:error: method of NSString - it lets you pass in a URL as an instance of NSURL (which can easily be instantiated from NSString) and returns a string with the complete contents of the page at that URL. For example:
NSString *googleString = #"http://www.google.com";
NSURL *googleURL = [NSURL URLWithString:googleString];
NSError *error;
NSString *googlePage = [NSString stringWithContentsOfURL:googleURL
encoding:NSASCIIStringEncoding
error:&error];
After running this code, googlePage will contain the HTML for www.google.com, and error will contain any errors encountered in the fetch. (You should check the contents of error after the fetch.)
Going the other way (from a UIWebView) is a bit trickier, but is basically the same concept. You'll have to pull the request from the view, then do the fetch as before:
NSURL *requestURL = [[yourWebView request] URL];
NSError *error;
NSString *page = [NSString stringWithContentsOfURL:requestURL
encoding:NSASCIIStringEncoding
error:&error];
EDIT: Both these methods take a performance hit, however, since they do the request twice. You can get around this by grabbing the content from a currently-loaded UIWebView using its stringByEvaluatingJavascriptFromString: method, as such:
NSString *html = [yourWebView stringByEvaluatingJavaScriptFromString:
#"document.body.innerHTML"];
This will grab the current HTML contents of the view using the Document Object Model, parse the JavaScript, then give it to you as an NSString* of HTML.
Another way is to do your request programmatically first, then load the UIWebView from what you requested. Let's say you take the second example above, where you have NSString *page as the result of a call to stringWithContentsOfURL:encoding:error:. You can then push that string into the web view using loadHTMLString:baseURL:, assuming you also held on to the NSURL you requested:
[yourWebView loadHTMLString:page baseURL:requestURL];
I'm not sure, however, if this will run JavaScript found in the page you load (the method name, loadHTMLString, is somewhat ambiguous, and the docs don't say much about it).
For more info:
UIWebView class reference
NSString class reference
NSURL class reference
if you want to extract the contents of an already-loaded UIWebView, -stringByEvaluatingJavaScriptFromString. For example:
NSString *html = [webView stringByEvaluatingJavaScriptFromString: #"document.body.innerHTML"];
To get the whole HTML raw data (with <head> and <body>):
NSString *html = [webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.outerHTML"];
Note that the NSString stringWithContentsOfURL will report a totally different user-agent string than the UIWebView making the same request. So if your server is user-agent aware, and sending back different html depending on who is asking for it, you may not get correct results this way.
Also note that the #"document.body.innerHTML" mentioned above will only display what is in the body tag. If you use #"document.all[0].innerHTML" you will get both head and body. Which is still not the complete contents of the UIWebView, since it will not get back the !doctype or html tags, but it is a lot closer.
To read:-
NSString *html = [myWebView stringByEvaluatingJavaScriptFromString: #"document.getElementById('your div id').textContent"];
NSLog(html);
To modify:-
html = [myWebView stringByEvaluatingJavaScriptFromString: #"document.getElementById('your div id').textContent=''"];
In Swift v3:
let doc = webView.stringByEvaluatingJavaScript(from: "document.documentElement.outerHTML")
(Xcode 5 iOS 7) Universal App example for iOS 7 and Xcode 5. It is an open source project / example located here: Link to SimpleWebView (Project Zip and Source Code Example)
I use a swift extension like this:
extension UIWebView {
var htmlContent:String? {
return self.stringByEvaluatingJavaScript(from: "document.documentElement.outerHTML")
}
}
you should try this:
document.documentElement.outerHTML
UIWebView
get HTML from UIWebView`
let content = uiWebView.stringByEvaluatingJavaScript(from: "document.body.innerHTML")
set HTML into UIWebView
//Do not forget to extend a class from `UIWebViewDelegate` and nil the delegate
func someFunction() {
let uiWebView = UIWebView()
uiWebView.loadHTMLString("<html><body></body></html>", baseURL: nil)
uiWebView.delegate = self as? UIWebViewDelegate
}
func webViewDidFinishLoad(_ webView: UIWebView) {
//ready to be processed
}
[get/set HTML from WKWebView]