In my application i have UIWebView and i want to detect if a MP3 file is load(download).
So i use this UIWebView Delegate method:
- (BOOL)webView:(UIWebView*)webview shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
if ([[[url pathExtension] lowercaseString] isEqualToString:#"mp3"]) {
[self userDidClickUrl:url];
return NO;
}
return YES;
}
The problem is that sometimes the URL is without mp3 string inside,and the UIWebView open the Native player. It's possible to detect it? I want to detect when a mp3 file is start loading.
Try to detect MIMEType based on your request - check if MIMEType from response is either one of those kind:
audio/mp3 || audio/mpeg3 || audio/x-mp3 || audio/x-mpeg3
Update: check this already answered:
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = request.URL;
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self];
[conn start];
return YES; }
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
NSString *mime = [response MIMEType];
NSLog(#"%#",mime); }
Full link bellow:
UIWebView Delegate get MIME Type
Related
I am working on a native cum web iOS app. When i try to load Urls in UIWebView on any button press inside WebView i am unable to get the next URL to be loaded. Can anyone suggest anything for this? Thanks in advance.
Here is my Code:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *myString = [[request URL] absoluteString];
[myString lowercaseString];
NSLog(#"%#",myString)
NSDictionary *headers = [request allHTTPHeaderFields];
BOOL hasReferer = [headers objectForKey:#"X"]!=nil;
if (hasReferer)
{
return YES;
}
else
{
// relaunch with a modified request
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *url = [request URL];
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
[request setValue:X forHTTPHeaderField:#"X"];
[request setValue:Y forHTTPHeaderField:#"Y"];
[loadingWebView loadRequest:request];
});
});
return NO;
}
return 0;
}
set delegate
- (void)webViewDidStartLoad:(UIWebView *)webView;
- (void)webViewDidFinishLoad:(UIWebView *)webView;
- (void)webView:(UIWebView *)webView didFailLoadWithError:(nullable NSError *)error;
see in this method what it returns
and make sure you are passing correct url ie stringByAddingPercentEscapesUsingEncoding
I'm facing a problem building a web browser with download functionality, here's my code:
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *url = request.URL;
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self];
[conn start];
return YES;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if ([[response MIMEType] rangeOfString:#"video"].location != NSNotFound) {
// Do something with that video
}
}
This is currently working as intended, video files will be handled correctly but the webview will also load it, what i need to do is capture the mime type of the file before returning YES in shouldStartLoadWithRequest and return NO if it's a video.
I tried the sendSynchronousRequest method but it slows the app, I also tried:
#import <MobileCoreServices/MobileCoreServices.h>
NSString *fileExtension = [myFileURL pathExtension];
NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)fileExtension, NULL);
NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);
But I often get wrong myme types, last thing, I dont want to detect type by the file extension since urls can be formatted as aliases.
Thank you for your help.
NSURLConnection is dead so stop using it. Switch to NSURLSession. NSURLSession gives you a data task delegate method that lets you examine the response header and bow out.
I want to load a webpage with a huge javascript file.
<script src="js/sample.js"></script>
I cannot change the html file, but i can download the javascript file to my Application.
NSString* path = [NSString stringWithFormat:#"http://www.demo.url/index.html"];
NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:path] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0];
[webView loadRequest:request];
Everytime I start my App the chached javascript file have to reload again. Maybe I have the wrong cache settings.
Two possible solution:
Cache the javascipt in the right way. Do not delete on app close.
Manual download javascript file and use it.
are you trying to inject javascript?
[webView stringByEvaluatingJavaScriptFromString:jsString];
if you are trying to load local html file for the 1st time, add it to the bundle and call it liek this:
NSURL *relativeURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
NSURL *u = [NSURL URLWithString:#"xxx.html" relativeToURL:relativeURL];
and then when you need to reload you do a normal uiwebview request method call!
I found the solution:
Implement an own NSURL Protocol:
NSURLProtocolCustom.h
#import <Foundation/Foundation.h>
#interface NSURLProtocolCustom : NSURLProtocol<NSURLConnectionDelegate> {
NSMutableData *responseData;
}
#property (nonatomic, strong) NSURLConnection *connection;
#end
NSURLProtocolCustom.m
#import "NSURLProtocolCustom.h"
#implementation NSURLProtocolCustom
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([[request.URL lastPathComponent] isEqualToString:--Your precached file--]) {
return true;
} else {
return false;
}
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
- (void)startLoading {
NSString* file = --Your local file--;
NSData *data = [NSData dataWithContentsOfFile:file];
NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[self.request URL] MIMEType:#"text/javascript" expectedContentLength:-1 textEncodingName:nil];
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
[self.client URLProtocol:self didLoadData:data];
[self.client URLProtocolDidFinishLoading:self];
}
- (void)stopLoading {
}
And your request
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:--your URL-- cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:50.0];
[NSURLProtocol registerClass:[NSURLProtocolCustom class]];
I am learing WebView.
when I do something like
NSString *url = #"www.google.com";
[_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:url]]];
it fails.
But when I type www.google.com (or even google.com) in standard browser, it works fine.
I also noticed that after loading the page, the url text field in standard browser changes the link from www.google.com to https:// www. google.co.in/?gws_rd=ssl
In above code when I set NSString *url = #"https://www.google.co.in/?gws_rd=ssl" it works fine
So how do I implement my WebView view so that if should work like a standard browser it terms of above context
UIWebView always needs http or https when starting request, if you click on links inside the webView it will handle it itself. So here is how to handle it:
- (void)viewDidLoad
{
[super viewDidLoad];
UITextField *addressBar = [[UITextField alloc] init];
[addressBar setDelegate:self];
[self loadRequestFromString:#"www.google.com"];
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self loadRequestFromString:textField.text];
[textField resignFirstResponder];
return YES;
}
- (void)loadRequestFromString:(NSString *)urlString
{
NSURL *webpageUrl;
if ([urlString hasPrefix:#"http://"] || [urlString hasPrefix:#"https://"]) {
webpageUrl = [NSURL URLWithString:urlString];
} else if ([urlString containsString:#" "] || ![urlString containsString:#"."]) {
webpageUrl = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.google.com/search?q=%#", [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]];
} else {
webpageUrl = [NSURL URLWithString:[NSString stringWithFormat:#"http://%#", urlString]];
}
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:webpageUrl];
[_webView loadRequest:urlRequest];
}
to open any URL in UIWebView you should add url with protocol
eg #"http://www.google.com".
[NSURL URLWithString:#"http://www.google.com"];
then it will work.
Currently I am developing an hybrid app which uses webView shouldStartLoadWithRequest: to provide a token for the login. My function works fine for every normal request I make (a click e.g.)
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request
NSLog([NSString stringWithFormat:#"Loading View: %#",[[request URL] absoluteString]]);
if ([[[request URL] absoluteString] rangeOfString:BASE_URL].location != NSNotFound) {
NSString *token = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginToken];
NSString *hash = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginHash];
NSString *params = [NSString stringWithFormat:#"mobile=app&user_token=%#&user_hash=%#",token,hash];
if([[request URL] query] == nil) {
[self LoadUrl:[[request URL] absoluteString] withGetParams:params append:NO];
return NO;
}else{
if([[[request URL] absoluteString] rangeOfString:params].location == NSNotFound){
[self LoadUrl:[[request URL] absoluteString] withGetParams:params append:YES];
return NO;
}
}
}
-(void)LoadUrl:(NSString *)url withGetParams:(NSString *)params append:(BOOL)append{
NSString *PreUrl;
if(append == YES) PreUrl = [NSString stringWithFormat:#"%#&%#",url,params];
else PreUrl = [NSString stringWithFormat:#"%#?%#",url,params];
NSURL *nsurl = [NSURL URLWithString: PreUrl];
NSURLRequest *request = [NSURLRequest requestWithURL:nsurl];
[self.WebView loadRequest:request];
}
The Problem I have with this Code is that if I load an Image e.g. it will be detected as "to be hashed-appended" (which is correct, I want every request to have the Auth included) BUT the Image will get loaded in the Webview itself.
My first try (before I switched to this model) was to modify the request parsed. But every change got Ignored....
Has anyone an Idea how I could fix this problem? Is there a way to really modify requests? Or if not, can I at least determine the "target" of the request or forward it?
Thanks for any help
I found a Solution for my Problem. Sublcassing was the right approach but not UIWebView but a own NSURLProtocol.
So what I did:
Create an own Sublcass of NSURLProtocol
#interface MyURL : NSURLProtocol <NSURLConnectionDelegate>
Add some standard handling for HTTP-Connections
#interface MyURL () <NSURLConnectionDelegate>
#property (nonatomic, strong) NSURLConnection *connection;
#property (nonatomic, strong) NSMutableData *mutableData;
#property (nonatomic, strong) NSURLResponse *response;
#end
#implementation MyURL
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
return request;
}
- (void)stopLoading
{
[self.connection cancel];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.client URLProtocol:self didLoadData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[self.client URLProtocol:self didFailWithError:error];
self.connection = nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self.client URLProtocolDidFinishLoading:self];
self.connection = nil;
}
#end
And now the interesting part - Modifying every request that goes to my server
So first: Check if this Request goes to my Server and determine if my protocol should take care of it
+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
NSString *token = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginToken];
NSString *hash = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginHash];
if([NSURLProtocol propertyForKey:#"TokenSet" inRequest:request]) return NO; // We already handled it
if((hash == nil) || (token == nil) ) return NO; // We are not logged in
NSString *params = [NSString stringWithFormat:#"mobile=app&user_token=%#&user_hash=%#",token,hash];
if (([[[request URL] absoluteString] rangeOfString:BASE_URL].location != NSNotFound) && ([[[request URL] absoluteString] rangeOfString:#"/assets/"].location == NSNotFound)){
if([[[request URL] absoluteString] rangeOfString:params].location == NSNotFound){
return YES; // URL does not contain the login token & we're not requesting an asset (js/img/etc.)
}
}
return NO;
}
So if + (BOOL)canInitWithRequest:(NSURLRequest *)request returned yes, I have to handle the request. I already know that it does not contain the login token & hash so I've got to determine if it has to be appended or not. To modify the request in general, I create a MutableCopy of our request, Modify it and set our URLConnection to the request.
- (void)startLoading
{
NSMutableURLRequest *newRequest = [self.request mutableCopy];
NSString *PreURL;
NSString *token = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginToken];
NSString *hash = [[NSUserDefaults standardUserDefaults] stringForKey:kDefaultsKeyLoginHash];
NSString *params = [NSString stringWithFormat:#"mobile=app&user_token=%#&user_hash=%#",token,hash];
if([[newRequest URL] query] == nil) {
PreURL = [NSString stringWithFormat:#"%#?%#",[[newRequest URL] absoluteString],params];
}else{
if([[[newRequest URL] absoluteString] rangeOfString:params].location == NSNotFound){
PreURL = [NSString stringWithFormat:#"%#&%#",[[newRequest URL] absoluteString],params];
}
}
NSURL *nsurl = [NSURL URLWithString: PreURL];
[newRequest setURL:nsurl];
[NSURLProtocol setProperty:#"YES" forKey:#"TokenSet" inRequest:newRequest];
self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
And to finish it all, we register our URL-Protocol as Protocol in AppDelegate.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[NSURLProtocol registerClass:[MyURL class]];
}
With this Solution I first have the advantage of having my login token in ANY request ANY part of my App sends to my Server. No more worries about this. And I can do cool stuff, like saving resources after loading them the first time or even use Images from my App-Bundle in Webviews...
I hope this helps someone.