Trying to make an app launch the default browser to a URL, but only if the URL entered is valid, otherwise it displays a message saying the URL is invalid.
How would
For swift 4 you can use:
class func verifyUrl (urlString: String?) -> Bool {
//Check for nil
if let urlString = urlString {
// create NSURL instance
if let url = URL(string: urlString) {
// check if your application can open the NSURL instance
return UIApplication.shared.canOpenURL(url)
}
}
return false
}
Swift 4 elegant solution using NSDataDetector
:
extension String {
var isValidURL: Bool {
let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue)
if let match = detector.firstMatch(in: self, options: [], range: NSRange(location: 0, length: self.utf16.count)) {
// it is a link, if the match covers the whole string
return match.range.length == self.utf16.count
} else {
return false
}
}
}
Usage:
let string = "https://www.fs.blog/2017/02/naval-ravikant-reading-decision-making/"
if string.isValidURL {
// TODO
}
Reasoning behind using NSDataDetector
instead of UIApplication.shared.canOpenURL
:
I needed a method that would detect whether the user provided an input that is an URL to something. In many cases, users don't include the http://
nor https://
URL scheme in the URL they type in - e.g., instead of "http://www.google.com"
they would type in "www.google.com"
. Without the URL scheme, the UIApplication.shared.canOpenURL
will fail to recognize the URL and will return false
. NSDataDetector
is, compared to UIApplication.shared.canOpenURL
, a rather forgiving tool (as @AmitaiB mentioned in comments) - and it can detect even URLs without the http://
scheme. This way I am able to detect a URL without having to try to add the scheme everytime when testing the string.
Sidenote - SFSafariViewController
can open only URLs with http://
/https://
. Thus, if a detected URL does not have a URL scheme specified, and you want to open the link, you will have to prepend the scheme manually.
Helium having to deal with various schemes:
struct UrlHelpers {
// Prepends `http://` if scheme isn't `https?://` unless "file://"
static func ensureScheme(_ urlString: String) -> String {
if !(urlString.lowercased().hasPrefix("http://") || urlString.lowercased().hasPrefix("https://")) {
return urlString.hasPrefix("file://") ? urlString : "http://" + urlString
} else {
return urlString
}
}
// https://mathiasbynens.be/demo/url-regex
static func isValid(urlString: String) -> Bool {
// swiftlint:disable:next force_try
if urlString.lowercased().hasPrefix("file:"), let url = URL.init(string: urlString) {
return FileManager.default.fileExists(atPath:url.path)
}
let regex = try! NSRegularExpression(pattern: "^(https?://)[^\\s/$.?#].[^\\s]*$")
return (regex.firstMatch(in: urlString, range: urlString.nsrange) != nil)
}
}
This is for latest Swift 4, based on Doug Amos answer (for swift 3)
public static func verifyUrl (urlString: String?) -> Bool {
//Check for nil
if let urlString = urlString {
// create NSURL instance
if let url = NSURL(string: urlString) {
// check if your application can open the NSURL instance
return UIApplication.shared.canOpenURL(url as URL)
}
}
return false
}