I'm trying to programme a mini browser in Xcode however at the moment the UIWebView will only load URLs that include the http ://www The user submits their URL using a UITextField and the contents become a string.
I wondered if there was a way to either search the submitted string and add the http or www or both where required or format the text input so it automatically checks to see if the correct address is used.
Thanks
Do something like this:
NSString *urlString = ... // the user entered URL string
if (![urlString hasPrefix:#"http://"]) {
urlString = [#"http://" stringByAppendingString:urlString];
}
Note that this is just a rough suggestion to get you started. This code doesn't handle cases such as the URL already having a prefix of "https://" or typos such as "htp://".
A better approach might be:
NSURL *url = [NSURL URLWithString:urlString];
NSString *scheme = [url scheme];
if (scheme.length == 0) {
// The string has no scheme - add "http://"
} else {
// check for valid schemes
}
Related
I am storing file URLs so that they be retrieved on subsequent runs of an iOS app. The URL's are generated from the user selecting local or iCloud files on their device. It seems that the given URL points to a file in Documents but which is not actually there.
I have the following code to resolve a URL from a bookmark:
BOOL isBookmarkStale = false;
NSError* error = nil;
auto nsURL = [NSURL URLByResolvingBookmarkData:bookmark
options:NSURLBookmarkResolutionWithoutUI
relativeToURL:nil
bookmarkDataIsStale:&isBookmarkStale
error:&error];
The bookmark is created with
if ([nsURL startAccessingSecurityScopedResource])
{
NSError* error = nil;
NSData* securityScopedBookmark = [nsURL bookmarkDataWithOptions:NSURLBookmarkCreationMinimalBookmark
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&error];
[nsURL stopAccessingSecurityScopedResource];
}
I have verified that the stored bookmark contains the correct URL by checking the last known path with
NSDictionary *values = [NSURL resourceValuesForKeys:#[NSURLPathKey]
fromBookmarkData:static_cast<NSData*> (bookmarkData)];
NSString *path = [values objectForKey:NSURLPathKey];
Here path contains the last URL to the file. The URL strings from the local files I'm testing with look like this: /private/var/mobile/Containers/Data/Application/3BFEA0FB-AA84-4CFB-90E5-3535FA14738E/Documents/SomeFile.mp3
This seems to work while the app is running. But after restarting or rebuilding the app (debug build), then attempting to resolve a URL from a stored bookmark it fails with NSCocoaErrorDomain Code=4 and the message "The file doesn’t exist."
To get a URL to the user's documents use
[NSFileManager.defaultManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject
This will stay the same on device but will change between runs on the simulator. So you need to make your URL relative to this to test in the sim.
Yea the absolute path could change, so use the relative path.
Just save the part you want after the Documents.
let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
That will be an optional URL (because of the .first), so you might want to
if let documentsDirectory
or
guard let documentsDirectory
to make it non optional.
Then you can do documentsDirectory.appendingPathComponent(pathComponent: SomeFile.mp3)
My requirement is to get the URI scheme out of the dynamic link URL that has been generated. Even in the firebase sample app, its the deep link url that gets returned and not the URI scheme.
For eg:
Our dynamic link url is this -> https://my-app-code.app.goo.gl/value.
iOS custom app scheme (added from advanced options): myappscheme://some-tag/some-tag-id
Long dynamic link url is -> https://my-app-code.app.goo.gl/?link=my-web-url&apn=id&isi=android-google-play-id&ibi=ios-bundle-id&ius=ios-custom-app-scheme
When i click on the dynamic link url from email/notes (https://my-app-code.app.goo.gl/value), the callback will be the continueuseractivity function and i use the following block -
BOOL handled = [[FIRDynamicLinks dynamicLinks] handleUniversalLink:incomingUrl completion:^(FIRDynamicLink * _Nullable dynamicLink, NSError * _Nullable error)
to get the url (dynamicLink.url). In this block, i get the deep link url which is this
-> my-web-url (which is a part of the link parameter in the long dynamic link which i have mentioned above).
My actual requirement is to get the URI scheme myappscheme://some-tag/some-tag-id which associated with the URL. How do i get this?
I even tried the below -
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
In either cases, I do not get the URI scheme.
Please help.
What you are trying to do is not currently possible on iOS with Dynamic Links. You are confusing URI scheme (myappscheme://) with URI path (myappscheme://some-tag/some-tag-id).
To my knowledge, Dynamic Links on iOS only support the scheme (via the ius param). This is confusing because Android does support a URI path (via the al param). For iOS, you'll need to do your routing based on the deep link URL.
Alternatively, you could investigate a more robust deep linking platform like Branch.io (full disclosure: I'm on the Branch team). Branch does support custom link parameters containing any data you wish, including a custom URI path.
What Alex said is correct. It is not possible, but there is an easy workaround to this.
I appended my desired custom url deep link as a query parameter to the https link url I provided.
So in your case it would look something like this
https://my-app-code.app.goo.gl/?link=https://my-web-url.com/?myCustomSchemeUri%3Dmy-custom-scheme://my-custom-scheme-url&apn=id&isi=android-google-play-id&ibi=ios-bundle-id&ius=ios-custom-app-scheme
When the continueuseractivity callback gets to your app you can retrieve myCustomSchemeUri parameter from the query string and use it as you please.
Something like this:
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray *))restorationHandler {
BOOL handled = [[FIRDynamicLinks dynamicLinks]
handleUniversalLink:userActivity.webpageURL
completion:^(FIRDynamicLink * _Nullable dynamicLink,
NSError * _Nullable error) {
// ...
NSURL *url = dynamicLink.url;
NSString *myUri = [url queryParameterValueWithName:#"customUri"];
if (myUri.lenghth > 0){
NSURL *myURL = [NSURL URLWithString:myUri];
if (myURL != nil){
//source application is your bundle id in this case
[self application:application openURL:myURL sourceApplication:#"com.yourbundle.id" annotation:#{}];
}
}
}];
return handled;
}
And this is the method I wrote as a category of NSURL to retrieve the parameter
- (NSString *)queryParameterValueWithName:(NSString*)name{
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:self
resolvingAgainstBaseURL:NO];
NSArray *queryItems = urlComponents.queryItems;
NSString *param = [self valueForKey:name
fromQueryItems:queryItems];
return param;
}
- (NSString *)valueForKey:(NSString *)key
fromQueryItems:(NSArray *)queryItems
{
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"name=%#", key];
NSURLQueryItem *queryItem = [[queryItems
filteredArrayUsingPredicate:predicate]
firstObject];
return queryItem.value;
}
Maybe this answer is a bit late to you, but I ran into this problem just today.
Anyway I hope this helps somebody else out there.
Cheers,
Alessio
In my iOS app I am opening links using the code below:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#",myurl]]];
The links come dynamically and HTTP/HTTPS is not provided.
I cannot hardcode HTTP or HTTPS because I don't know if the URL has HTTP or HTTPS. How can I open a URL without specifying HTTP or HTTPS?
Solution for Swift:
let urlString = "example.com"
let urlHasHttpPrefix = urlString.hasPrefix("http://")
let urlHasHttpsPrefix = urlString.hasPrefix("https://")
let validUrlString = (urlHasHttpPrefix || urlHasHttpsPrefix) ? urlString : "http://\(urlString)"
I think this a better approach than the ones presented here, since it avoids string comparison & manipulation.
public extension URL {
var sanitise: URL {
if var components = URLComponents(url: self, resolvingAgainstBaseURL: false) {
if components.scheme == nil {
components.scheme = "http"
}
return components.url ?? self
}
return self
}
}
Who said you don't know whether url contain http or not? You can find out...
In prefixheader.pch write below.
#define contains(str1, str2) ([str1 rangeOfString: str2 ].location != NSNotFound)
Then in your .m write below.
if (!contains(myurl, "http")) {
myurl = [NSString stringWithFormat:#"http://%#", myurl];
}
You are done!!!
Let me know if you need anything else.
Matching with rangeOfString is not a good approach.
You can match it as:
NSString *urlScheme = [url scheme];
if (urlScheme == nil) {
url = [NSURL URLWithString:[NSString stringWithFormat:#"http://%#",urlString]];
}
And you don't have to worry about whether it's http or https. whenever you'll hit a url on http it'll automatically redirects to https
I need to retrieve the text from a specific website. However, I only need a few parts of it. How can I accomplish this using swift.
I have found the following in objective-c, but am not sure it provides how to reference it from a specific site:
NSString *webString = [webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.innerText"];
NSScanner *stringScanner = [NSScanner scannerWithString:webString];
NSString *content = [[NSString alloc] init];
while ([stringScanner isAtEnd] == NO) {
[stringScanner scanUpToString:#"Start of the text you want" intoString:null];
[stringScanner scanUpToString:#"End of the text you want" intoString:&content];
}`
I have put an example of what I mean below:
Again, I would like to accomplish this using Swift.
If your HTML was easily targetable with identifiers or class names, I would suggest using a library such as Kanna. But I've had a look at your page and the text you need is lost amidst an ocean of divs...
So I've quickly hacked a way to get your text with componentsSeparatedByString: I'm cutting the HTML in blocks until I get to the part we're interested in.
Note that it's far from being the most efficient way: instead of using componentsSeparatedByString you should come with a way of identifying the HTML block you want and search for it with NSScanner.
That being said, here's my example of a working hack, tested in a Playground:
enum CustomErrors : String, ErrorType {
case InvalidURL = "Invalid URL"
}
do {
let str = "http://www.golfwrx.com/328370/mizuno-to-offer-custom-grips-at-no-additional-charge/"
guard let url = NSURL(string: str) else { throw CustomErrors.InvalidURL }
let html = try String(contentsOfURL: url)
let separator1 = "<div class='mailmunch-forms-before-post' style='display: none !important;'></div><p>"
let temp = html.componentsSeparatedByString(separator1)
let separator2 = "</p>\n<p>"
let temp2 = temp[1].componentsSeparatedByString(separator2)
let separator3 = "</p><div class='mailmunch-forms-in-post-middle'"
let separated = temp2[1].componentsSeparatedByString(separator3)
let result = separated[0]
print(result)
} catch {
print(error)
}
Note: my example is in Swift 2 (Xcode 7).
Sorry about the specifics, I'm an Objective-C guy. but, here is an example of how to use NString to get the contents of a websites HTML
NSString *url = #"http://www.example.com"; // Your URL
NSURL *urlRequest = [NSURL URLWithString:url]; // Make a request with your URL
NSError *err = nil; // Error handler
NSString *html = [NSString stringWithContentsOfURL:urlRequest encoding:NSUTF8StringEncoding error:&err]; // Try to get the HTML in the string
if(err)
{
//Do something as it didn't work! Maybe a connection problem
}
else
{
// Use NScanner on html string
}
http://nshipster.com/nsscanner/ is a good place to learn about NScanner for swift
EDIT: Here is the above translated to swift
var err: NSError? // Error handler
let url: NSURL = NSURL(string: "http://www.example.com") // NSURL, put your website URL in here
let string = NSString(contentsOfURL: url, encoding: NSUTF8StringEncoding, error: &err) // String will now hold your HTML
// Now use NScanner (See Link) to parse the HTML output
My swift is rusty. but this might help you. This is roughly translated but outlines exactly what you need
URL which opens in Firefox,Chrome browsers on desktop, doesn't open in WebView on iPhone.
This URL is supposedly accessing a GET request.
When creating the NSURL without percentescaping the url doesn't get generated.
When using percentescape the url redirects to a Bad url content.
Is there a different encoding used on desktop browsers and not on the iPhone? or mobile Safari?
Are there different ways to encode the URL in iOS other than using
-stringByAddingPercentEscapesUsingEncoding
-CFURLCreateStringByAddingPercentEscapes
which generates bad request content pages from server.
Any help would be really great, Thanks.
EDIT:
The URL been generated is as below http://something.test.com/iostest/index.html?{"a":"b"}
Managed to figure that not encoding the curly brackets is causing the issue in iOS.
as in
NSString *tempUrlSting = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)tempURLA,CFSTR("{}"), CFSTR("\""), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)));
NSURL *tempUrl=[NSURL URLWithString:tempUrlSting];
If not encoding the braces in the URL but encoding the rest using [Rob's answer][1] as above. When creating the NSURL, the url is empty.
If encoding the braces the URL gets generated fine, but the server throws an exception.
This Question suggests to use CFNetworking.
EDIT
Used CFNetworking as below
-(void)getDataFromUrl{
CFStringRef tempURLA = CFSTR("http://my.test.server/iostest/index.html?{\"a\":\"b\"}");
CFStringRef tempUrlSting = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)tempURLA,CFSTR("{}"), CFSTR("\""), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding));
CFURLRef myURL = CFURLCreateWithString(kCFAllocatorDefault, tempUrlSting, NULL);
CFStringRef requestMethod = CFSTR("GET");
CFHTTPMessageRef myRequest = CFHTTPMessageCreateRequest(kCFAllocatorDefault, requestMethod, myURL,kCFHTTPVersion1_1);
CFStringRef headerFieldName = CFSTR("Accept");
CFStringRef headerFieldValue = CFSTR("text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
CFHTTPMessageSetHeaderFieldValue(myRequest, headerFieldName, headerFieldValue);
[self performHTTPRequest:myRequest];
}
-(void)performHTTPRequest:(CFHTTPMessageRef)request {
CFURLRef gotdatab = (__bridge CFURLRef)(CFBridgingRelease(CFHTTPMessageCopyRequestURL(request)));
// NSLog(#"(CFHTTPMessageRef request %#",gotdatab);
CFReadStreamRef requestStream = CFReadStreamCreateForHTTPRequest(NULL, request);
CFReadStreamOpen(requestStream);
NSMutableData *responseBytes = [NSMutableData data];
NSError *error;
while (TRUE) {
if (CFReadStreamHasBytesAvailable(requestStream)) {
UInt8 streambuffer[1024];
int readBytes = CFReadStreamRead (requestStream,streambuffer,sizeof(streambuffer));
NSLog(#"Read: %d",readBytes);
[responseBytes appendBytes:streambuffer length:readBytes];
}
if (CFReadStreamGetStatus(requestStream) == kCFStreamStatusError) {
error = (NSError*)CFBridgingRelease(CFReadStreamCopyError (requestStream));
if ([error code] == 61) {
// connection refused
NSLog(#"Error occured: %d",[error code]);
}
break;
}
if (CFReadStreamGetStatus(requestStream) == kCFStreamStatusAtEnd) {
NSLog(#"Stream reached end!");
error = nil;
break;
}
}//
CFHTTPMessageRef response = (CFHTTPMessageRef)CFReadStreamCopyProperty(requestStream, kCFStreamPropertyHTTPResponseHeader);
if (response==NULL) {
NSLog(#"response is null");
return;
}
}
The above was done using examples from here and here
Above method still has the same issue. That is: if {} are not encoded the URL doesn't get generated. If the {} are encoded the server doesn't return a proper value.
Any suggestions pls?
Sometimes URL encoded format already except for the é-character which should probably be encoded as %c3%a9. Desktop browser is quite liberal with invalid URLs, thats why it works in Safari etc.
So if you have a NSString and you want to convert it into a proper URL encoding then use the below method of NSString class.
NSURL* url = [NSURL URLWithString:[strURL stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
You should edit your question showing us an example of your URL and your GET parameters. If you're percent escaping, for example, some reserved character in the domain name or the URL path, that suggests one solution (e.g. stringByAddingPercentEscapesUsingEncoding is fine). If you're percent escaping the broader array of reserved characters in the parameters of a GET request (notably = or +), then stringByAddingPercentEscapesUsingEncoding is simply not up to the job and you'd have to use CFURLCreateStringByAddingPercentEscapes (but only on the parameter keys and their values, not on the full URL string). I use a method like the following on the parameters as I append them to the URL:
- (NSString *)percentEscapeURLParameter:(NSString *)string
{
return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
(CFStringRef)string,
NULL,
(CFStringRef)#":/?#!$&'()*+,;=",
kCFStringEncodingUTF8));
}
If you're saying that CFURLCreateStringByAddingPercentEscapes is not working for you, you'd have to show us how you're using it. Make sure you are doing it just on the GET parameter values, that you're supplying the necessary "legal characters to escape" parameter, that you're not escaping something that shouldn't be, etc.