Can WKWebView support encoded url? - ios

If I use an encoded url to open in WKWebView, this webView can not open this link。
NSString* request = #"http%3A%2F%2Fwww.baidu.com%0A";
NSURL* url = [NSURL URLWithString:request];
[self.webView loadRequest:[NSURLRequest requestWithURL:url]];
So I must to decode the url before passed it to WKWebView .
Any other pretty way to make the WKWebView support encoded url?

No, there's no other way. Decode the URL. I'm guessing you got this from a URL query string field. If so, take advantage of NSURLComponents. That makes it easy to grab the unencoded value for a query string part.
NSString *valueForKeyInURL(NSString *key, NSURL *URL) {
NSURLComponents *components =
[NSURLComponents componentsWithURL:URL
resolvingAgainstBaseURL:NO];
NSURLQueryItem *theField = nil;
for (NSURLQueryItem *item in components.queryItems) {
if ([item.name isEqual:key]) {
theField = item;
break;
}
}
return item.value;
}

Related

Parse NSURL scheme iOS [duplicate]

What's an efficient way to take an NSURL object such as the following:
foo://name/12345
and break it up into one string and one unsigned integer, where the string val is 'name' and the unsigned int is 12345?
I'm assuming the algorithm involves converting NSURL to an NSString and then using some components of NSScanner to finish the rest?
I can only add an example here, the NSURL class is the one to go. This is not complete but will give you a hint on how to use NSURL:
NSString *url_ = #"foo://name.com:8080/12345;param?foo=1&baa=2#fragment";
NSURL *url = [NSURL URLWithString:url_];
NSLog(#"scheme: %#", [url scheme]);
NSLog(#"host: %#", [url host]);
NSLog(#"port: %#", [url port]);
NSLog(#"path: %#", [url path]);
NSLog(#"path components: %#", [url pathComponents]);
NSLog(#"parameterString: %#", [url parameterString]);
NSLog(#"query: %#", [url query]);
NSLog(#"fragment: %#", [url fragment]);
output:
scheme: foo
host: name.com
port: 8080
path: /12345
path components: (
"/",
12345
)
parameterString: param
query: foo=1&baa=2
fragment: fragment
This Q&A NSURL's parameterString confusion with use of ';' vs '&' is also interesting regarding URLs.
NSURL has a method pathComponents, which returns an array with all the different path components. That should help you get the integer part. To get the name I'd use the host method of the NSURL. The docs say, that it should work if the URL is properly formatted, might as well give it a try then.
All in all, no need to convert into a string, there seems to be plenty of methods to work out the components of the URL from the NSURL object itself.
Actually there is a better way to parse NSURL. Use NSURLComponents. Here is a simle example:
Swift:
extension URL {
var params: [String: String]? {
if let urlComponents = URLComponents(url: self, resolvingAgainstBaseURL: true) {
if let queryItems = urlComponents.queryItems {
var params = [String: String]()
queryItems.forEach{
params[$0.name] = $0.value
}
return params
}
}
return nil
}
}
Objective-C:
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
NSArray *queryItems = [components queryItems];
NSMutableDictionary *dict = [NSMutableDictionary new];
for (NSURLQueryItem *item in queryItems)
{
[dict setObject:[item value] forKey:[item name]];
}
Thanks to Nick for pointing me in the right direction.
I wanted to compare file urls but was having problems with extra slashes making isEqualString useless. You can use my example below for comparing two urls by first de-constructing them and then comparing the parts against each other.
- (BOOL) isURLMatch:(NSString*) url1 url2:(NSString*) url2
{
NSURL *u1 = [NSURL URLWithString:url1];
NSURL *u2 = [NSURL URLWithString:url2];
if (![[u1 scheme] isEqualToString:[u2 scheme]]) return NO;
if (![[u1 host] isEqualToString:[u2 host]]) return NO;
if (![[url1 pathComponents] isEqualToArray:[url2 pathComponents]]) return NO;
//check some properties if not nil as isEqualSting fails when comparing them
if ([u1 port] && [u2 port])
{
if (![[u1 port] isEqualToNumber:[u2 port]]) return NO;
}
if ([u1 query] && [u2 query])
{
if (![[u1 query] isEqualToString:[u2 query]]) return NO;
}
return YES;
}

iOS: NSASCIIStringEncoding doesn't encode certain characters correctly

I have url that I am going to request data from. Here is the code.
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:
NSASCIIStringEncoding];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:urlStr]];
This works except when I have certain characters such as ş. The urlstr will return null. Is there a way around this to except certain character types? Any tips or suggestions are appreciated.
I've used the following method with success in many applications:
- (NSString *)urlEncode:(NSString *)str {
return (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)str, NULL, CFSTR("!*'();:#&=+$,/?%#[]"), kCFStringEncodingUTF8));
}
Note that I use this on only the params of the URL, so the following would work (notice I added the ş, which seemed to work, although I'm not familiar with that character):
NSString *baseURL = #"http://www.google.com";
NSString *paramsString = #"testKey=test value_with some (weirdness)!___ş";
NSString *resultingURLString = [NSString stringWithFormat:#"%#?%#", baseURL, [self urlEncode:paramsString]];
Which produces the result:
http://www.google.com?testKey%3Dtest%20value_with%20some%20%28weirdness%29%21___%C5%9F

Creating NSURL with custom query parameter returns nil

I have a UISearchBar from which I'm extracting the text that represents an address and building from it a JSON URL for Google Geocoder.
NSString* address = searchbar.text;
NSString* url = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?address=%#&sensor=false", address];
If I copy & paste the url from debug window to the browser it works like a charm but when I try to convert it to NSURL i get nil
NSURL* theUrl = [NSURL URLWithString:url];
Any ideas?
I added the encoding to the address prior to concatenating the url and that fixed the problem so now the code looks like this:
NSString* address = searchbar.text;
NSString *encodedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, CFBridgingRetain(address), NULL, (CFStringRef)#"!*'();:#&=+$,/?%#[]", kCFStringEncodingUTF8));
NSString* url = [NSString stringWithFormat:#"http://maps.google.com/maps/api/geocode/json?address=%#&sensor=false", encodedString];

Data argument not used by format string but it works fine

I used this code from the Stack Overflow question: URLWithString: returns nil:
//localisationName is a arbitrary string here
NSString* webName = [localisationName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString* stringURL = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%#,Montréal,Communauté-Urbaine-de-Montréal,Québec,Canadae&output=csv&oe=utf8&sensor=false", webName];
NSString* webStringURL = [stringURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL* url = [NSURL URLWithString:webStringURL];
When I copied it into my code, there wasn't any issue but when I modified it to use my url, I got this issue:
Data argument not used by format string.
But it works fine. In my project:
.h:
NSString *localisationName;
.m:
NSString* webName = [localisationName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString* stringURL = [NSString stringWithFormat:#"http://en.wikipedia.org/wiki/Hősök_tere", webName];
NSString* webStringURL = [stringURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL* url = [NSURL URLWithString:webStringURL];
[_webView loadRequest:[NSURLRequest requestWithURL:url]];
How can I solve this? Anything missing from my code?
The # in the original string is used as a placeholder where the value of webName is inserted. In your code, you have no such placeholder, so you are telling it to put webName into your string, but you aren't saying where.
If you don't want to insert webName into the string, then half your code is redundant. All you need is:
NSString* stringURL = #"http://en.wikipedia.org/wiki/Hősök_tere";
NSString* webStringURL = [stringURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL* url = [NSURL URLWithString:webStringURL];
[_webView loadRequest:[NSURLRequest requestWithURL:url]];
The +stringWithFormat: method will return a string created by using a given format string as a template into which the remaining argument values are substituted. And in the first code block, %# will be replaced by value of webName.
In your modified version, the format parameter, which is #"http://en.wikipedia.org/wiki/Hősök_tere", does not contain any format specifiers, so
NSString* stringURL = [NSString stringWithFormat:#"http://en.wikipedia.org/wiki/Hősök_tere", webName];
just runs like this (with the warning Data argument not used by format string.):
NSString* stringURL = #"http://en.wikipedia.org/wiki/Hősök_tere";

Change a NSURL's scheme

Is there an easy way to change the scheme of a NSURL? I do realize that NSURL is immutable. My goal is to change the scheme of an URL to "https" if the Security.framework is linked, and "http" if the framework is not linked. I do know how to detect if the framework is linked.
This code works wonderfully if the URL has no parameters (such as "?param1=foo&param2=bar"):
+(NSURL*)adjustURL:(NSURL*)inURL toSecureConnection:(BOOL)inUseSecure {
if ( inUseSecure ) {
return [[[NSURL alloc] initWithScheme:#"https" host:[inURL host] path:[inURL path]] autorelease];
}
else {
return [[[NSURL alloc] initWithScheme:#"http" host:[inURL host] path:[inURL path]] autorelease];
}
}
But if the URL does have parameters, [inURL path] drops them.
Any suggestions short of parsing the URL string myself (which I can do but I want to try not doing)? I do what to be able to pass URLs with either http or https to this method.
Updated answer
NSURLComponents is your friend here. You can use it to swap out the http scheme for https. The only caveat is NSURLComponents uses RFC 3986 whereas NSURL uses the older RFCs 1738 and 1808, so there is some behavior differences in edge cases, but you're extremely unlikely to hit those cases (and NSURLComponents has the better behavior anyway).
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:YES];
components.scheme = inUseSecure ? #"https" : #"http";
return components.URL;
Original answer
Why not just do a bit of string manipulation?
NSString *str = [url absoluteString];
NSInteger colon = [str rangeOfString:#":"].location;
if (colon != NSNotFound) { // wtf how would it be missing
str = [str substringFromIndex:colon]; // strip off existing scheme
if (inUseSecure) {
str = [#"https" stringByAppendingString:str];
} else {
str = [#"http" stringByAppendingString:str];
}
}
return [NSURL URLWithString:str];
If you are using iOS 7 and later, you can use NSURLComponents, as show here
NSURLComponents *components = [NSURLComponents new];
components.scheme = #"http";
components.host = #"joris.kluivers.nl";
components.path = #"/blog/2013/10/17/nsurlcomponents/";
NSURL *url = [components URL];
// url now equals:
// http://joris.kluivers.nl/blog/2013/10/17/nsurlcomponents/
Swift5
extension URL {
func settingScheme(_ value: String) -> URL {
let components = NSURLComponents.init(url: self, resolvingAgainstBaseURL: true)
components?.scheme = value
return (components?.url!)!
}
}
Usage
if nil == url.scheme { url = url.settingScheme("file") }
Perhaps using the resourceSpecifier would help:
return [[[NSURL alloc] initWithString:[NSString stringWithFormat:#"https:%#", [inURL resourceSpecifier]]]];
NSString *newUrlString = [NSString stringWithFormat:#"https://%#%#",
inURL.host, inURL.path];
if (inURL.query) {
newUrlString = [newUrlString stringByAppendingFormat:#"?%#", inURL.query];
}
return [NSURL URLWithString:newUrl];
[NOTE]
Code related to port and other fields handling are removal for simplicity.
I did it like this, using a variable resourceSpecifier in NSURL
SWIFT
var resourceSpecifier: String? { get }
OBJECTIVE-C
#property(readonly, copy) NSString *resourceSpecifier Discussion
This property contains the resource specifier. For example, in the URL http://www.example.com/index.html?key1=value1#jumplink, the resource specifier is //www.example.com/index.html?key1=value1#jumplink (everything after the colon).
-(NSURL*) URLByReplacingScheme
{
NSString *newUrlString = kHttpsScheme;
if([self.scheme isEqualToString:kEmbeddedScheme])
newUrlString = kHttpScheme;
newUrlString = [newUrlString stringByAppendingString:[NSString stringWithFormat:#":%#", self.resourceSpecifier]];
return [NSURL URLWithString:newUrlString];
}

Resources