Using rangeOfString for different links, URL's etc - ios

Thanks to rmaddy for getting me in the right direction by answering THIS question, this leads me into some other issues using that acepted answer. For my original question on that thread, it did solve what I was trying to do. But now I am having issues with the use on some other sites.
I have a webview in which I have a few links to different sites like Media Fire, Copy, Box, etc. Even a direct download link. The media fire link for example starts the download without even going to the site, almost like its just downloading the text. The direct download wont even fire my downloader at all.
Using the accepted answer, what would be the cleanest way to distinguish these?
Here is the code that works for most sites.
- (BOOL)webView:(UIWebView *)awebView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked){
//External file links
NSURL* externalURL = [request URL];
NSString *urlString = [externalURL absoluteString];
NSSet *supportedFileExtensions = [NSSet setWithObjects:#"mpeg", #"mpg", #"m1s", #"mpa", #"mp2", #"m2a", #"mp2v", #"mv2", #"m2s", #"avi", #"mov", #"qt", #"asf", #"asx", #"wmv", #"wma", #"wmx", #"rm", #"ra", #"ram", #"rmvb", #"mp4", #"3gp", #"3gpp", #"ogm", #"mkv", #"flv", #"mv4", #"srt", #"swf", #"vob", #"aif", #"iff", #"m3u", #"m4a", #"mid", #"mp3", #"mpa", #"wav", #"aac", #"7z", #"cbr", #"deb", #"gz", #"pkg", #"rar", #"rpm", #"sitx", #"tar.gz", #"zip", #"zipx", #"ipsw", #"bin", #"cue", #"dmg", #"iso", #"mdf", #"toast", #"vcd", #"torrent", #"nes", #"rom", #"doc", #"docs", #"msg", #"odt", #"rtf", #"txt", #"wpd", #"wps", nil];
for (NSString *extension in supportedFileExtensions) {
if ([urlString rangeOfString:extension].location != NSNotFound) {
// Found extension somewhere in the URL - process it as needed
break; // stop looking for more
}
}
}
Example Links: https://www.dropbox.com/s/57jcgnbnfhcpw9y/Test.zip?dl=0
http://www.mediafire.com/download/wt77jvm3szwjehm/Test.zip
https://copy.com/QFvw3fw4FF2k4foX
https://app.box.com/s/fixnvrym13eylcr73njv
Direct download link: http://download.thinkbroadband.com/5MB.zip

Use regular expressions to search for a match like this:
NSString *urlString = #"http://www.youtube.co.uk/someVideo.mp2";
NSSet *supportedFileExtensions = [NSSet setWithObjects:#"mpeg", #"mpg", #"m1s", #"mpa", #"mp2", #"m2a", #"mp2v", #"mv2", #"m2s", #"avi", #"mov", #"qt", #"asf", #"asx", #"wmv", #"wma", #"wmx", #"rm", #"ra", #"ram", #"rmvb", #"mp4", #"3gp", #"3gpp", #"ogm", #"mkv", #"flv", #"mv4", #"srt", #"swf", #"vob", #"aif", #"iff", #"m3u", #"m4a", #"mid", #"mp3", #"mpa", #"wav", #"aac", #"7z", #"cbr", #"deb", #"gz", #"pkg", #"rar", #"rpm", #"sitx", #"tar.gz", #"zip", #"zipx", #"ipsw", #"bin", #"cue", #"dmg", #"iso", #"mdf", #"toast", #"vcd", #"torrent", #"nes", #"rom", #"doc", #"docs", #"msg", #"odt", #"rtf", #"txt", #"wpd", #"wps", nil];
// Expression to match any your mime types
NSString *pattern = [NSString stringWithFormat:#"(\\W|^)(%#)(\\W|$)", [supportedFileExtensions.allObjects componentsJoinedByString:#"|"]];
NSRegularExpression *regx = [NSRegularExpression regularExpressionWithPattern:pattern
options:NSRegularExpressionCaseInsensitive
error:nil];
// returns first match in the string
NSTextCheckingResult *match = [regx firstMatchInString:urlString options:NSMatchingReportProgress range:NSMakeRange(0, urlString.length)];
NSLog(#"matched type: %#", [urlString substringWithRange:match.range]);
You then need to implement a custom HTTP URL protocol that inspects all HTTP responses. copy.com link sends a Content-Disposition: attachment; for it files and shouldStartLoadWithRequest won't no about it until it execute the request.
once you have created your protocol use this method to register it for all your web communications:
[MyURLProtocol registerClass:[MyURLProtocol class]];
see this tutorial for creating custom protocol

Related

Use NSScanner or NSRange for url to find NSSet objects

Basically I'm trying to find NSSet objects contained in a url for my webview.
How would I use NSScanner or NSRange to do this?
Below is what I'm working with.
//External file links
NSURL* externalURL = [request URL];
NSString *externalFileExtension = [[request URL] pathExtension];
//External file extensions
NSLog(#"fileExtension is: %#", externalFileExtension);
NSSet *supportedFileExtensions = [NSSet setWithObjects:#"mpeg", #"mpg", #"m1s", #"mpa", #"mp2", #"m2a", #"mp2v", #"mv2", #"m2s", #"avi", #"mov", #"qt", #"asf", #"asx", #"wmv", #"wma", #"wmx", #"rm", #"ra", #"ram", #"rmvb", #"mp4", #"3gp", #"3gpp", #"ogm", #"mkv", #"flv", #"mv4", #"srt", #"swf", #"vob", #"aif", #"iff", #"m3u", #"m4a", #"mid", #"mp3", #"mpa", #"wav", #"aac", #"7z", #"cbr", #"deb", #"gz", #"pkg", #"rar", #"rpm", #"sitx", #"tar.gz", #"zip", #"zipx", #"ipsw", #"bin", #"cue", #"dmg", #"iso", #"mdf", #"toast", #"vcd", #"torrent", #"nes", #"rom", #"doc", #"docs", #"msg", #"odt", #"rtf", #"txt", #"wpd", #"wps", nil];
if ([supportedFileExtensions containsObject:externalFileExtension]) {
//my actions
}
Because of the type of links, some sites don't exactly use file extensions, some use the extension type in the link i.e. "zip=blahblah" or "blahblahzipblah'
I need to search the link clicked to find the supportedFileExtensions portion.
Thank you in advanced.
UPDATE:
Thanks to rmaddy for getting me in the right direction. For my original question, it did solve it. But I am having issues with the use on some other sites.
I have a webview in which I have a few links to different sites like Media Fire, Copy, Box, etc. Even a direct download link. The media fire link for example starts the download without even going to the site, almost like its just downloading the text. The direct download wont even fire my downloader at all.
Using the accepted answer, what would be the cleanest way to distinguish these?
The following should be what you want:
//External file links
NSURL* externalURL = [request URL];
NSString *urlString = [externalURL absoluteString];
NSSet *supportedFileExtensions = [NSSet setWithObjects:#"mpeg", #"mpg", #"m1s", #"mpa", #"mp2", #"m2a", #"mp2v", #"mv2", #"m2s", #"avi", #"mov", #"qt", #"asf", #"asx", #"wmv", #"wma", #"wmx", #"rm", #"ra", #"ram", #"rmvb", #"mp4", #"3gp", #"3gpp", #"ogm", #"mkv", #"flv", #"mv4", #"srt", #"swf", #"vob", #"aif", #"iff", #"m3u", #"m4a", #"mid", #"mp3", #"mpa", #"wav", #"aac", #"7z", #"cbr", #"deb", #"gz", #"pkg", #"rar", #"rpm", #"sitx", #"tar.gz", #"zip", #"zipx", #"ipsw", #"bin", #"cue", #"dmg", #"iso", #"mdf", #"toast", #"vcd", #"torrent", #"nes", #"rom", #"doc", #"docs", #"msg", #"odt", #"rtf", #"txt", #"wpd", #"wps", nil];
for (NSString *extension in supportedFileExtensions) {
if ([urlString rangeOfString:extension].location != NSNotFound) {
// Found extension somewhere in the URL - process it as needed
break; // stop looking for more
}
}
Perhaps something like this without using NSScanner or NSRange:
BOOL result = NO;
for (NSString *extension in supportedFileExtensions) {
if ([externalFileExtension isEqualToString:extension]) {
result = YES;
break;
}
}

How can i get the response when i am submiting a form in UIWebView?

As I am implementing a Webpage load in the UIWebView ,where the user has to fill the form and have to click the submit button. During submitting the request I am sending a return url to webpage along with the request.Once the request validates at the website end if return back to my return url.along with this it is sending some parameters.
It is successfully happening,but i am not getting that parameters.How can i get those parameters.
I have implemented the delegate method,but is not giving the parameters.
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
Any help greatly appreciated.
I have been in the same Problem ,As iOS webview is not have as much functionality like in the android ,as in android there is JavaScriptInterface.But there is a method in iOS to execute the JS that is stringByEvaluatingJavaScriptFromString.
As you mention you are getting the parameters on the return url then your web developer have to get that parameters(i don't know how he will do ,but my developer did this and converted all the parameters in string) and to store in string parameter.then you can get that value using a JS Function.
NSURL *requestURL = [self.WebView.request URL];
NSLog(#"Reuest URl here is:%#",requestURL);
NSString *javaScript = [NSString stringWithFormat:#"function givResponse(){var x=document.getElementById('div-id').innerHTML;return x; } givResponse(); "];
NSString *jsonString = [self.webView stringByEvaluatingJavaScriptFromString:javaScript];
NSLog(#"The returned value is %#",jsonString);
/* Converting the string to JSON */
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
id json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"Here the JSon String from the respose is :%#",json);

iOS - sending URL through mail showing different behavior in simulator and device

A strange behaviour is happening when I am trying to send mail from device.
I have used SMTP to send mail from background in my app and I have to send user's current location URL in app.
Now, when I send it from simulator it works almost fine and i got this url -
https://maps.google.com/maps?f=q&q=0.000000,0.000000
But, when I send it from device it sends the url like this -
https://maps.google.com/maps?f=q&q".719793,75.877068
The code I used to make url is
-(NSString*)LocationLinkTosentInMail
{
CLLocationCoordinate2D coordinate = [self getLocation];
NSString *latitude = [NSString stringWithFormat:#"%f", coordinate.latitude];
NSString *longitude = [NSString stringWithFormat:#"%f", coordinate.longitude];
NSLog(#"*dLatitude : %#", latitude);
NSLog(#"*dLongitude : %#",longitude);
NSString *currentLocationURL = [NSString stringWithFormat:#"https://maps.google.com/maps?f=q&q=%#,%#",latitude,longitude];
return currentLocationURL;
}
NSURL *locationURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#",[self LocationLinkTosentInMail]]];
In SMTP mail function, I use this code to make dictionary
NSDictionary *plain_text_part = [NSDictionary dictionaryWithObjectsAndKeys:
#"text/plain\r\n\tcharset=UTF-8;\r\n\tformat=flowed", kSKPSMTPPartContentTypeKey,
[NSString stringWithFormat:#"My Location is: %#",locationURL], kSKPSMTPPartMessageKey,
#"quoted-printable", kSKPSMTPPartContentTransferEncodingKey,
nil];
Can anyone suggest me if any change required in code?
Why simulator and device are showing different behavior to send this url?
Use HTML Tag and in mail body enable HTML in iOS
[emailDialog setMessageBody:mailBody isHTML:YES];
Check this page for href tag!
Whenever we have to send URL thourgh smtp in objective c, we should always careful about the special character of url.
Finally i got the solution of my problem in the encoding process.
the Encoding in the NSDictionary object, I changed it from quoted-printable
to 8bit .
Now dictionary obj would be:
NSDictionary *plain_text_part = [NSDictionary dictionaryWithObjectsAndKeys:
#"text/plain", kSKPSMTPPartContentTypeKey,
strMessage, kSKPSMTPPartMessageKey,
#"8bit", kSKPSMTPPartContentTransferEncodingKey,
nil];

iOS NSURL queuing mechansim for multiple requests from file

I am very new to iOS development, but I would like to make an app that has two table view controllers (columns): both are a row of images that act as links. The first would be a column of YouTube videos and the second a column of websites. I would like to have all these listed in a file file.txt listed like so: V, http://youtube.com/example W, http://example.com
There would be a long list of those, the V meaning its a video (for the video column) and W for the websites. Now, I understand how to being the single file in, but what happens afterwards is my concern. Can I read each line into some sort of queue and then fire the NSURL request for each one consecutively? How can that be done with NSURL? Is there perhaps a better approach?
There are two questions for me:
Is a text file really the best format?
I might suggest a plist or archive (if the file is only going to exist only in your app's bundle and/or documents folder) or JSON (if it's going to live on a server before delivering it to the user) instead of a text file. It will make it easier to parse this file than a text file. For example, consider the following dictionary:
NSDictionary *dictionary = #{#"videos" : #[#"http://youtube.com/abc", #"http://vimeo.com/xyz"],
#"websites": #[#"http://apple.com", #"http://microsoft.com"]};
You can save that to a plist with:
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *plistPath = [documentsPath stringByAppendingPathComponent:#"files.plist"];
[dictionary writeToFile:plistPath atomically:YES];
You can add that file to your bundle or whatever, and then read it at a future date with:
dictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath];
You can, alternatively, write that to a JSON file with:
NSError *error = nil;
NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:NSJSONWritingPrettyPrinted error:&error];
NSString *jsonPath = [documentsPath stringByAppendingPathComponent:#"files.json"];
[data writeToFile:jsonPath atomically:YES];
You can read that JSON file with:
data = [NSData dataWithContentsOfFile:jsonPath];
dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
Either way, you can get the list of videos or web sites like so:
NSArray *videos = dictionary[#"videos"];
NSArray *websites = dictionary[#"websites"];
Now that you have your arrays of videos and websites, the question then is how you then use those URLs.
You could do something like:
for (NSString *urlString in videos) {
NSURL *url = [NSURL URLWithString: urlString];
// now do something with the URL
}
The big question is what is the "do something" logic. Because you're dealing with a lot of URLs, you would want to use a NSOperation based solution, not a GCD solution, because NSOperationQueue lets you control the degree of concurrency. I'd suggest a NSOperation-based networking library like AFNetworking. For example, to download the HTML for your websites:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 4;
for (NSString *urlString in websites)
{
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
// convert the `NSData` responseObject to a string, if you want
NSString *string = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
// now do something with it, like saving it in a cache or persistent storage
// I'll just log it
NSLog(#"responseObject string = %#", string);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error = %#", error);
}];
[queue addOperation:operation];
}
Having said that, I'm not sure it makes sense to kick off a ton of network requests. Wouldn't you really prefer to wait until the user taps on one of those cells before retrieving it (and for example, then just open that URL in a UIWebView)? You don't want an app that unnecessarily chews up the user's data plan and battery retrieving stuff that they might not want to retrieve. (Apple has rejected apps that request too much data from a cellular connection.) Or, at the very least, if you want to retrieve stuff up front, only retrieve stuff as you need it (e.g. in cellForRowAtIndexPath), which will retrieve the visible rows, rather than the hundreds of rows that might be in your text/plist/json file.
Frankly, we need a clearer articulation of what you're trying to do, and we might be able to help you with more concise counsel.

UIWebView displays blank page on form submit

I'm an iOS newb (.NET professional), so this may be a simple issue but I couldn't find anything through the SO search or Google (and maybe not looking for the right terms).
I'm writing an app that displays information from a DD-WRT router through it's web interface. I have no problem displaying the initial page and navigating through any of the other pages, but if I make any change on a form (and it redirects to apply.cgi or applyuser.cgi), the UIWebView is blank - it's supposed to display the same page, with the form submission changes. The site works fine in Mobile Safari, which I find intriguing, but I guess UIWebView isn't totally the same.
I think the iOS code is pretty standard for display a webpage, but I'll list it below. I can't give you access to my router because, well, that's not a good idea :) Hopefully someone with a DD-WRT router can help (or know what my issue is anyway).
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *sURL = #"http://user:pass#XXX.XXX.X.X";
NSURL *url = [NSURL URLWithString:sURL];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
self.webView.delegate = self ;
}
And I'm doing a few things with Javascript in the webViewDidFinishLoad method, but I know that's not the culprit because it still happens when I comment it out.
Well I figured out the problem on my own. I think part of it was putting the username & password in the URL (which was just a temporary measure) because I found that method provided the same results in mobile Safari and desktop Chrome.
So I added MKNetworkKit to my project that provided a simple way to add authentication to my request, and found I had to make a specific request to POST the data, then reloaded the page the to see the changes.
In the (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType method, I check if ([request.HTTPMethod isEqualToString:#"POST"]) and do this:
NSString *sPostData = [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding];
NSArray *aPostData = [sPostData componentsSeparatedByString:#"&"];
NSMutableDictionary *dPostData = [[NSMutableDictionary alloc] init];
//i don't know if this is the best way to set a dictionary, but it works
for (id apd in aPostData)
{
NSString *key = [apd componentsSeparatedByString:#"="][0];
NSString *val = [apd componentsSeparatedByString:#"="][1];
[dPostData setValue:val forKey:key];
}
MKNetworkEngine *engine = [[MKNetworkEngine alloc] init];
MKNetworkOperation *op = [engine operationWithURLString:[request.URL description] params:dPostData httpMethod:#"POST"];
[op setUsername:#"myUserName" password:#"myPassword" basicAuth:YES];
self.postedRequest = TRUE; //a bool I set so, when it comes to webViewDidFinishLoad, I reload the current page
[op start]; //send POST operation

Resources