spiegel-keyman/ios/engine/KMEI/KeymanEngine/Classes/UniversalLinks.swift
Joshua Horton ff601489dd
chore(ios/engine): typo fix
Co-authored-by: Marc Durdin <marc@durdin.net>
2020-11-20 12:02:45 +07:00

82 lines
3.7 KiB
Swift

//
// UniversalLinks.swift
// KeymanEngine
//
// Created by Joshua Horton on 7/27/20.
// Copyright © 2020 SIL International. All rights reserved.
//
import Foundation
public class UniversalLinks {
public struct ParsedKeyboardInstallLink {
public let keyboard_id: String
public let lang_id: String?
public var packageKey: KeymanPackage.Key {
return KeymanPackage.Key(id: keyboard_id, type: .keyboard)
}
}
// The standard technique for launching URLs externally is dependent upon being
// within an app, not in an app-extension. Furthermore, that distinction is made
// at bundle compile-time... so we simply CAN'T condition on that within the framework.
// It's thus up to the app to define this method-field when desired.
public static var externalLinkLauncher: ((URL) -> Void)? = nil
// e.g. https://keyman.com/keyboards/install/foo
private static let KEYBOARD_INSTALL_LINK_REGEX = try! NSRegularExpression(pattern: "^http(?:s)?://keyman(?:-staging)?\\.com(?:\\.local)?/keyboards/install/([^?/]+)(?:\\?(.+))?$")
// e.g. http://keyman.com.local/keyboards/foo
private static let KEYBOARD_MATCH_ROOT_REGEX = try! NSRegularExpression(pattern: "^http(?:s)?://keyman(?:-staging)?\\.com(?:\\.local)?/keyboards([/?].*)?$");
// e.g. https://keyman-staging.com/go/windows/14.0/download-keyboards?version=14.0.146.0
private static let KEYBOARD_MATCH_GO_REGEX = try! NSRegularExpression(pattern: "^http(?:s)?://keyman(?:-staging)?\\.com(?:\\.local)?/go/windows/[^/]+/download-keyboards")
public static func tryParseKeyboardInstallLink(_ link: URL) -> ParsedKeyboardInstallLink? {
let linkString = link.absoluteString
// If it matches the format for the Keyboard Universal Link URL Pattern...
// (see https://docs.google.com/document/d/1rhgMeJlCdXCi6ohPb_CuyZd0PZMoSzMqGpv1A8cMFHY/edit?ts=5f11cb13#heading=h.qw7pas2adckj)
if let match = KEYBOARD_INSTALL_LINK_REGEX.firstMatch(in: linkString,
options: [],
range: NSRange(location: 0, length: linkString.utf16.count)) {
let keyboard_id_range = Range(match.range(at: 1), in: linkString)!
let keyboard_id = String(linkString[keyboard_id_range])
var lang_id: String? = nil
let urlComponents = URLComponents(string: linkString)!
if let lang_id_component = urlComponents.queryItems?.first(where: { $0.name == "bcp47" }) {
lang_id = lang_id_component.value
}
return ParsedKeyboardInstallLink(keyboard_id: keyboard_id, lang_id: lang_id)
} else {
return nil
}
}
/**
* Returns `true` for links that should be opened externally, rather than in an app-hosted WebView.
* `false` is returned for links we consider to be 'internal' within the Keyman ecosystem.
*/
public static func isExternalLink(_ link: URL) -> Bool {
let linkString = link.absoluteString
let linkRange = NSRange(location: 0, length: linkString.utf16.count)
// Case 1: the link captured for keyboard search
if let _ = tryParseKeyboardInstallLink(link) {
return false
} else if let _ = KEYBOARD_MATCH_ROOT_REGEX.firstMatch(in: linkString,
options: [],
range: linkRange) {
return false
} else if let _ = KEYBOARD_MATCH_GO_REGEX.firstMatch(in: linkString,
options: [],
range: linkRange) {
return false
} else if linkString.starts(with: "keyman:") {
return false
}
return true
}
}