Change a NSURL's scheme - ios

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];
}

Related

Can WKWebView support encoded url?

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;
}

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;
}

how to convert host of nsurl to lowercase

Let's say I have www.GOOgle.com/.......
I want to change it to www.google.com/....
and keep the rest of url as it is.
I have tried with NSURLComponents, but it didn't work.
// I am taking input from textfield and making the nsurl.
NSURLComponents *components = [NSURLComponents componentsWithString: _textfield.text]; // input from textfield
[[components host] lowercaseString];
NSURL *urlin = [components URL]; //but this gives, www.GOOgle.com
Any lead is appreciated.
As #Larme Suggests you can use method to setHost in url
see below example
NSURLComponents *components = [NSURLComponents componentsWithString: #"https://sTackoverFlow.com/questions/47924276/how-to-convert-host-of-nsurl-to-lowercase"];
[components setHost:[components.host lowercaseString] ];
NSLog(#"%#",components.URL)
H
ttps://stackoverflow.com/questions/47924276/how-to-convert-host-of-nsurl-to-lowercase
NOTE:
http:// is required to add in String otherwise you will get host nil
eg https://www.sTackoverFlow.com/questions/47924276/how-to-convert-host-of-nsurl-to-lowercase it will work
while
www.sTackoverFlow.com/questions/47924276/how-to-convert-host-of-nsurl-to-lowercase
Will Not work
If your string is only url then, you can try this,
let strURL = "http://GOogLe.Com/Testt/xyz"
let url = NSURL(string: strURL)
let domain: String = (url?.host)! //get your host name
print(domain) //GOogLe.Com
let str = strURL.replacingOccurrences(of: domain, with: domain.lowercased())
print(str) //http://google.com/Testt/xyz
Convert the string to lowercase.
Then pass the converted string value to the componentsWithString method.
Sample:
NSString *lowerCaseStringValue = [_textfield.text lowercaseString];
[NSURLComponents componentsWithString: lowerCaseStringValue];

Extracting values from the url in iOS

my url is https://photos.googleapis.com/data/upload/resumable/media/create-session/feed/api/user/111066158452258/albumid/60281009241807
i want to extract the value of user & albumid, i had tried to extract with different methods which i found in stack overflow ,but they didn't work.
Please help me out.
Thank you for your precious time.
You can take your NSURL (or init one from the URL string), and use the method pathComponents which return an array of the words in the URL (separated from the slash /), so:
pathComponents[0] == #"photos.googleapis.com"
pathComponents[1] == #"data"
...etc.
Here the snippet of code:
NSURL *url = [NSURL urlWithString:#"https://photos.googleapis.com/data/upload/resumable/media/create-session/feed/api/user/111066158452258/albumid/60281009241807"];
NSString *user = url.pathComponents[9];
NSString *album = url.pathComponents[11];
I give you an example here, NSURL class is your friend. You can use e.g. pathComponents: to get an array of all components and then process this array as you need it:
NSURL *url = [NSURL URLWithString:#"https://photos.googleapis.com/data/upload/resumable/media/create-session/feed/api/user/111066158452258/albumid/60281009241807"];
NSArray *components = [url pathComponents];
NSLog(#"path components: %#", components);
NSLog(#"user: %#", components[9]);
NSLog(#"albumid: %#", components[11]);
NSURL *url = [NSURL URLWithString:#"https://photos.googleapis.com/data/upload/resumable/media/create-session/feed/api/user/111066158452258/albumid/60281009241807"];
NSArray *pathComponentsArray = [url pathComponents];
NSString*userValue;
NSString*albumidValue;
for(int i=0;i<[pathComponentsArray count];i++)
{
if([pathComponentsArray[i] isEqualToString:#"user"])
{
userValue = pathComponentsArray[i+1];
}
if([pathComponentsArray[i] isEqualToString:#"albumid"])
{
albumidValue = pathComponentsArray[i+1];
}
}

How to change parameter in URL iOS

I have a URL like myApp://action/1?parameter=2&secondparameter=3&thirdparameter=10
I need to change parameter = 2
and secondparameter =3 like myApp://action/1?parameter=10&secondparameter=15&thirdparameter=10
Any ideas
Thx a lot
NSString *myURL
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
NSString * parameter =#"2";
NSString * secondparameter =#"3";
myURL =[[NSString alloc] initWithFormat:#"myApp://action/1?parameter=%#&secondparameter=%#&thirdparameter=10",parameter,secondparameter];
}
else
{
NSString * parameter =#"10";
NSString * secondparameter =#"15";
myURL =[[NSString alloc] initWithFormat:#"myApp://action/1?parameter=%#&secondparameter=%#&thirdparameter=10",parameter,secondparameter];
}
NSURL *url = [NSURL URLWithString:myURL];
Try this code...
You're saying you need to perform this on an arbitrary URL, so the steps are:
Break the query down into something you can work with, i.e. a dictionary
Mutate the query dictionary
Construct a new URL with the new query
I maintain the KSFileUtilities repository. The KSURLQueryUtilities routines will help you easily achieve the above.

Resources