diff --git a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj index 8125fec2d4..d6882fdecb 100644 --- a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj +++ b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj @@ -212,6 +212,7 @@ CEA9670B24BEC8030035AACF /* EngineStateBundler.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA9670A24BEC8030035AACF /* EngineStateBundler.swift */; }; CEA9670D24BEEFF80035AACF /* khmer_angkor update-base.bundle in Resources */ = {isa = PBXBuildFile; fileRef = CEA9670C24BEEFF80035AACF /* khmer_angkor update-base.bundle */; }; CEA9670F24BEF05A0035AACF /* Updates.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEA9670E24BEF05A0035AACF /* Updates.swift */; }; + CEB8276724C6811800F3D39C /* KeymanHostTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEB8276624C6811800F3D39C /* KeymanHostTests.swift */; }; CEC0C66C2410AC9A003E1BCD /* Sentry.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CEC0C66B2410AC9A003E1BCD /* Sentry.framework */; }; CEC0C6772410E049003E1BCD /* SentryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEC0C6762410E049003E1BCD /* SentryManager.swift */; }; CED8B63224A9C2400054E300 /* ResourceDownloadManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CED8B63124A9C2400054E300 /* ResourceDownloadManagerTests.swift */; }; @@ -510,6 +511,7 @@ CEA9670A24BEC8030035AACF /* EngineStateBundler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EngineStateBundler.swift; sourceTree = ""; }; CEA9670C24BEEFF80035AACF /* khmer_angkor update-base.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = "khmer_angkor update-base.bundle"; sourceTree = ""; }; CEA9670E24BEF05A0035AACF /* Updates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Updates.swift; sourceTree = ""; }; + CEB8276624C6811800F3D39C /* KeymanHostTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeymanHostTests.swift; sourceTree = ""; }; CEC0C66B2410AC9A003E1BCD /* Sentry.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sentry.framework; path = ../../Carthage/Build/iOS/Sentry.framework; sourceTree = ""; }; CEC0C6762410E049003E1BCD /* SentryManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SentryManager.swift; sourceTree = ""; }; CECB38931F2199BC0098882F /* Reachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Reachability.h; path = KeymanEngine/lib/Reachability/Reachability.h; sourceTree = SOURCE_ROOT; }; @@ -752,6 +754,7 @@ CE07E3D1247E3FB100DFA9D2 /* HTTPDownloaderTests.swift */, 9A079DD3223194B100581263 /* Info.plist */, CE8EDEB223F53F96009E1FF6 /* VersionTests.swift */, + CEB8276624C6811800F3D39C /* KeymanHostTests.swift */, CE4459CD23FBBA8D003151FD /* AppDelegate.swift */, CEF888D423FE786C00667693 /* KeyboardScaleTests.swift */, CEDFEF8E23FE43B700BECF39 /* MigrationTests.swift */, @@ -1475,6 +1478,7 @@ CEA9670924BEC4030035AACF /* ResourceUpdateTests.swift in Sources */, CE07E3D6247E41DB00DFA9D2 /* URLSessionMock.swift in Sources */, CE8EDEB323F53F96009E1FF6 /* VersionTests.swift in Sources */, + CEB8276724C6811800F3D39C /* KeymanHostTests.swift in Sources */, CEDFEF8F23FE43B700BECF39 /* MigrationTests.swift in Sources */, CED8B63224A9C2400054E300 /* ResourceDownloadManagerTests.swift in Sources */, CE9CD88023FCC1CA002BF2F8 /* TestUtils.swift in Sources */, diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Alerts.swift b/ios/engine/KMEI/KeymanEngine/Classes/Alerts.swift index 7e3ef343c2..a5726ab57c 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Alerts.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Alerts.swift @@ -31,7 +31,7 @@ open class Alerts { public static func showDownloadErrorAlert(in vc: UIViewController, handler: @escaping AcceptanceHandler) { var networkReachable: Reachability? do { - try networkReachable = Reachability(hostname: "keyman.com") + try networkReachable = Reachability(hostname: KeymanHosts.KEYMAN_COM.host!) } catch { log.debug("reachability could not start") } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeymanHosts.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeymanHosts.swift index 38f8c87308..bfed248e39 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeymanHosts.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeymanHosts.swift @@ -7,9 +7,73 @@ import Foundation +/** + * Defines constant-like definitions for Keyman's websites dependent upon the compile-time version + * of the KeymanEngine framework. + * + * Note that as a result, 'alpha', 'beta', and 'stable' versions of KeymanEngine may point to different + * sites. + */ +public enum KeymanHosts { + /** + * Used to enable '.local' variants of the endpoints for use in local development testing. + */ + internal static let useLocal = false -enum KeymanHosts { - static var API_KEYMAN_COM: URL { - return URL.init(string: "https://api.keyman.com")! + // This should never be used outside of the corresponding `static var`... + // save for use in automated testing. + internal static func getApiSiteURL(forTier: Version.Tier, useLocal: Bool) -> URL { + if useLocal { + return URL.init(string: "http://api.keyman.com.local")! + } else { + // TODO: Once the staging-site changes are in place, + // add switch-case here to select appropriate URL. + return URL.init(string: "https://api.keyman.com")! + } + } + + /** + * Used for package-version and model queries. + */ + public static var API_KEYMAN_COM: URL { + return getApiSiteURL(forTier: Version.currentTagged.tier ?? .stable, useLocal: useLocal) + } + + // This should never be used outside of the corresponding `static var`... + // save for use in automated testing. + internal static func getHelpSiteURL(forTier: Version.Tier, useLocal: Bool) -> URL { + if useLocal { + return URL.init(string: "http://help.keyman.com.local")! + } else { + // TODO: Once the staging-site changes are in place, + // add switch-case here to select appropriate URL. + return URL.init(string: "https://help.keyman.com")! + } + } + + /** + * Used for online help. + */ + public static var HELP_KEYMAN_COM: URL { + return getHelpSiteURL(forTier: Version.currentTagged.tier ?? .stable, useLocal: useLocal) + } + + // This should never be used outside of the corresponding `static var`... + // save for use in automated testing. + internal static func getMainSiteURL(forTier: Version.Tier, useLocal: Bool) -> URL { + if useLocal { + return URL.init(string: "http://keyman.com.local")! + } else { + // TODO: Once the staging-site changes are in place, + // add switch-case here to select appropriate URL. + return URL.init(string: "https://keyman.com")! + } + } + + /** + * Used for keyboard searches and resource sharing links. + */ + public static var KEYMAN_COM: URL { + return getMainSiteURL(forTier: Version.currentTagged.tier ?? .stable, useLocal: useLocal) } } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift index 0bc6312c0e..9b542ee982 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift @@ -69,7 +69,7 @@ class LexicalModelInfoViewController: UITableViewController, UIAlertViewDelegate override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if !isCustomLexicalModel { if indexPath.row == 1 { - let url = URL(string: "http://help.keyman.com/lexicalModel/\(lexicalModelID)/\(lexicalModelVersion)/")! + let url = URL(string: "\(KeymanHosts.HELP_KEYMAN_COM)/lexicalModel/\(lexicalModelID)/\(lexicalModelVersion)/")! if let openURL = Manager.shared.openURL { _ = openURL(url) } else { diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/ResourceInfoViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/ResourceInfoViewController.swift index de98082e25..bcc3e895a0 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/ResourceInfoViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/ResourceInfoViewController.swift @@ -129,7 +129,7 @@ class ResourceInfoViewController: UIViewController, UIAlertViewDelegate, UITable func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if !isCustomKeyboard { if indexPath.row == 1 { - let url = URL(string: "http://help.keyman.com/keyboard/\(resource.id)/\(resource.version)/")! + let url = URL(string: "\(KeymanHosts.HELP_KEYMAN_COM)/keyboard/\(resource.id)/\(resource.version)/")! if let openURL = Manager.shared.openURL { _ = openURL(url) } else { diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Model/InstallableKeyboard.swift b/ios/engine/KMEI/KeymanEngine/Classes/Model/InstallableKeyboard.swift index 31b8720276..aaa3f890bb 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Model/InstallableKeyboard.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Model/InstallableKeyboard.swift @@ -39,7 +39,7 @@ public struct InstallableKeyboard: Codable, KMPInitializableLanguageResource { public var oskFont: Font? public var isCustom: Bool - public static let sharingLink = "https://keyman.com/go/keyboard/%@/share" + public static let sharingLink = "\(KeymanHosts.KEYMAN_COM)/go/keyboard/%@/share" public var sharableURL: String? { get { diff --git a/ios/engine/KMEI/KeymanEngineTests/KeymanHostTests.swift b/ios/engine/KMEI/KeymanEngineTests/KeymanHostTests.swift new file mode 100644 index 0000000000..83cc6c9582 --- /dev/null +++ b/ios/engine/KMEI/KeymanEngineTests/KeymanHostTests.swift @@ -0,0 +1,31 @@ +// +// MiscellaneousTests.swift +// KeymanEngineTests +// +// Created by Joshua Horton on 7/21/20. +// Copyright © 2020 SIL International. All rights reserved. +// + +import XCTest +@testable import KeymanEngine + +class KeymanHostTests: XCTestCase { + /** + * Ensures a test failure in case we accidentally leave `useLocal` enabled. + */ + func testUseLocalDisabled() throws { + XCTAssertFalse(KeymanHosts.useLocal) + } + + /** + * Ensures no accidental permanent edits to the .local variant URLs occur. + */ + func testLocalSitesUnchanged() { + XCTAssertEqual(KeymanHosts.getApiSiteURL(forTier: .stable, useLocal: true), + URL.init(string: "http://api.keyman.com.local")) + XCTAssertEqual(KeymanHosts.getHelpSiteURL(forTier: .stable, useLocal: true), + URL.init(string: "http://help.keyman.com.local")) + XCTAssertEqual(KeymanHosts.getMainSiteURL(forTier: .stable, useLocal: true), + URL.init(string: "http://keyman.com.local")) + } +}