I have an NSString containing some HTML. I’m trying to pre-load that HTML, including any external image links inside it. So, to clarify: I have just HTML, and I need to basically load it, grab its images, and cache that data.
I can do this with a live website using the following code:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [NSString stringWithFormat:#"%#/%#", [paths objectAtIndex:0], #"index.html"];
NSURL *url = [NSURL URLWithString:#"http://www.google.co.uk"];
NSData *urlData = [NSData dataWithContentsOfURL:url];
[urlData writeToFile:filePath atomically:YES];
But this won’t work without an NSURL. I’m wondering if I can make an NSURL somehow from this string of HTML, and substitute it in the URLWithString: method here.
So, question: can I take some local HTML inside an NSString and turn that into an NSURL, so that I can feed it into the code above, and save the both the HTML and any images it links to?
The question you are asking makes absolutely no sense.
A URL is a pointer to the location of a resource online. In this context a html file. You can not make one into the other.
I suggest you create a UIWebView, load the string into that, have it render and cache the result.
[webView loadHTMLString:#"data" baseURL:nil];
I believe it will need to be actually place on the screen for it to render, so make it an invisible 1 X 1 pixel square and it should be fine. Then when the didFinishLoading fires. Cache the result
Yes, you can. You would have to parse the links out of HTML yourself. Real world HTML is not XML compliant, so a quick and dirty way to achieve your goals would be to treat HTML as text and parse links out using a regular expression library.
Related
I was wondering if property lists, (.plist) would save the contents if i were to exit the app and then re-open it. I would like to save a couple of variables to a plist so I could read from it every time I need some universal information about the user in my app.
Do plists save the variables if I were to close and reopen the app?
Should I be using plists or is there a better way to do this?
Thank you!
Yes, you can use plist to save user infomation. This is a sample way. Make a plist and write to the sandbox.
NSString *urlStr = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
urlStr = [urlStr stringByAppendingPathComponent:#"userInfo.dic"];
NSURL *url = [NSURL fileURLWithPath:urlStr];
[userInfoDictionary writeToURL:url error:NULL];
You can also use SQLite database or Core Data if the information is complex.
I am developing an app where I have to download a complete directory. This directory will contain for example:
article1/index.html
/images/image1.png
/image2.png
/image3.png...
I have tried to download this, but I only can download the index.html.
I am using this code:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(#"Downloading Started");
NSString *urlToDownload = #"http://localhost:8888/";
NSURL *url = [NSURL URLWithString:urlToDownload];
NSData *urlData = [NSData dataWithContentsOfURL:url];
if ( urlData )
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/issue/article%#/", documentsDirectory,articleID];
NSLog(#"filepath: %#", filePath);
//saving is done on main thread
dispatch_async(dispatch_get_main_queue(), ^{
[urlData writeToFile:filePath atomically:NO];
NSLog(#"File Saved !");
});
}
});
If anyone has an idea. Let me know.
Thank you
The reason you're only getting index.html is because this is what the web server is serving you when you request that directory. If there is no index.html page, it will probably give you a directory listing - however, this is usually in HTML format and you would have to manually extract the file names from this output.
If you don't have access to this web server, your job is much harder - if you can get an HTML directory listing, you'll have to parse it yourself; if not, you can't retrieve the directory list at all. In this case, it seems like you do have access to the web server, which is great! You can make this task a lot easier for yourself...
Option one
If the data isn't likely to change, you can create a simple text document in the root directory like filelist.txt that contain a list of files/paths in the directory. Your app can first request this list, separate the entries and then start downloading each file.
Option two
You could create a simple web script (in something like PHP or your language of choice) that lists the current directory contents in a format that can be easily digested by your app - JSON, newline-separated, or anything else.
Option three
Package the directory contents in a .zip file, and have your app download and extract the archive. ZipArchive is one library that allows you to unzip files in Objective-C, and there's an easy tutorial on how to do this available on iCodeBlog.
Also, as a side note, I see you're using NSDocumentDirectory for downloaded content. Apple advises that the Documents folder should only be used for user-generated content, which does not include downloaded content. You should use NSCachesDirectory or NSApplicationSupportDirectory for data that your app downloads (note that you may have to create them first).
i try get html page with UTF-8 charset
NSString *html=[NSString stringWithContentsOfURL:[NSURL URLWithString: #"http://forums.drom.ru/general/t1151288178.html"] encoding:NSUTF8StringEncoding error:&error]);
but NSLog(#"%#",html) return null
Why is this happening?
The problem is that while the file's meta tag purports to be UTF8, it's not (at least not entirely). You can confirm this by:
Download the html (as NSData, which succeeds):
NSError *error = nil;
NSURL *url = [NSURL URLWithString:#"http://forums.drom.ru/general/t1151288178.html"];
NSData *data = [NSData dataWithContentsOfURL:url options:0 error:&error];
NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *filename = [docsPath stringByAppendingPathComponent:#"test.html"];
[data writeToFile:filename atomically:YES];
Run iconv from the Terminal command line, it will report an error (including line number and character number):
iconv -f UTF-8 test.html > /dev/null
Thanks to Torsten Marek for sharing that with us.
When I look at that portion of the HTML, there are definitely not UTF8 characters there, buried in the setting of the clever_cut_pattern JavaScript variable.
If we thought you just got the encoding wrong, the typical counsel in these cases would generally be to use the rendition of stringWithContentOfURL with the usedEncoding parameter (i.e. rather than guessing what the encoding is, let NSString determine this for you):
NSStringEncoding encoding;
NSString *html = [NSString stringWithContentsOfURL:url usedEncoding:&encoding error:&error];
Unfortunately, in this case, even that fails (presumably because the file purports to be UTF8, but isn't).
The question then becomes "ok, so what do I do now". It depends upon why you were trying to download that HTML in your app, anyway. If you really need to convert this to UTF8 (i.e. strip out the non-UTF8 characters), you could theoretically get the GNU iconv(3) function, which is part of the libiconv library. That could identify non-conforming characters that you could presumably remove. It's a question of how much work you're willing to go through to handle this non-conforming web page.
I want to get URLs of all images or lets say "JPEG" files in a web directory (www.abcde.com/images). I just want their URLs in an array.. I couldnt manage that. Could u pls help me with this?
Thanks in advance..
Assuming you have access to an index file you could simply load via NSURL the whole html file and cut out the link lines. This however will not work (or hardly work) when you want to search ("spider or crawl") for links in more complex documents. On iOS i would suggest you use the simple, yet quite powerfull "hpple" framework (https://github.com/topfunky/hpple). It is used to parse html. You can search with it for certain html elements, such as <a href...> constructs.
a sample with hpple could looks like this:
NSURL *url = [NSURL URLWithString:#"whatver.com/images"];
NSData *data = [NSData url];
TFHpple *hppleParser = [TFHpple data];
NSString *images = #"//img"; // grabbs all image tags
NSArray *node = [hppleParser searchWithXPathQuery:images]
find a bigger example at http://www.raywenderlich.com/14172/how-to-parse-html-on-ios
Create a server side script(eg php) which gives you a list of all images in that directory as xml or json. From iOS send a request to that script get the xml or JSON parse it and use the image urls.
I have a webview which i want to load using the loadHtmlString method. The problem is that I want to be able to change the img src's with images that i have previously downloaded. I also use google analitics in the html so I need to set the baseUrl to the actual url so it will work. Here comes the problem. If I put the baseUrl in, the images will not load. If I don't set the baseUrl, it works. How can I get around this, so I will be able to both use google analitycs and have the images store locally in my application? I would prefer not having to implement the google analitics sdk in my project.
A strange thing is that if I run it in simulator, and not put the "http://" prefix in front of my baseUrl, it works fine. However, when I run it on a device, I receive the following error and it doesn't work:
Domain=WebKitErrorDomain Code=101 "The URL can’t be shown"
Thanks
EDIT
If I do this, it works:
[appsWebView loadHTMLString:htmlString baseURL:nil];
However, I must provide a baseURL in order to have Google Analitics working, I have two further cases:
This one gives the above mentioned error: (it works ok in simulator but gives error when running on device)
[appsWebView loadHTMLString:htmlString baseURL:[NSURL urlWithString:#"test.com"]];
This one simply doesn't show anything: (neither loads the html string or the url)
[appsWebView loadHTMLString:htmlString baseURL:[NSURL urlWithString:#"http://test.com"]];
I incorrectly assumed that the problem was that the local image was not fully specifying the full path, but that does not appear to be the problem here. But, you are quite right that it appears (somewhat surprisingly) that you cannot specify some web-based baseURL and also reference a local image in your HTML string. No simple solutions are leaping out at me, but at the very least, it appears that you might have a couple of (not very good) options:
First, you could base64 encode the local image using some base64 library like Mike Gallagher's NSData+Base64 category, e.g.:
NSData *imageData = [NSData dataWithContentsOfFile:imagePath];
NSString *imageDataBase64 = [imageData base64EncodedString];
NSString *imageHtml = [NSString stringWithFormat:#"<img src='data:image/png;base64,%#'>", imageDataBase64];
This slows the initial rendering, but maybe it's better than nothing.
Second, you could always try leaving the baseURL as nil, removing the JavaScript that does the Google Analytics from the HTML string, and then try injecting that JavaScript via stringByEvaluatingJavaScriptFromString. This approach may or may not work depending upon the complexity of the Google Analytics JavaScript (e.g. what further web-based references it might have), but there's a outside chance you might be able to do something that way.
My apologies for assuming the problem was a trivial img URL. Clearly you had identified a more fundamental issue.
Original answer:
Create your image URLs in your HTML string to be fully qualified file URLs within your local file system:
The image is either in Documents:
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *imagePath = [documentsPath stringByAppendingPathComponent:imageName];
Or in the bundle:
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName
ofType:nil];
But, once you have fully qualified path, you should be able to use that:
NSURL *imageUrl = [NSURL fileURLWithPath:imagePath];
NSString *imageHtml = [NSString stringWithFormat:#"<img src='%#'>", imageUrl];
I would bet it's a casing issue. Take into account that the Device is case sensitive whereas the Simulator is not. Check the URL and make sure it contains the right characters.