Use a different scheme for Element Call in the form of io.element.call:/?url=some_url

This commit is contained in:
Stefan Ceriu
2023-09-19 15:56:14 +03:00
committed by Stefan Ceriu
parent 501c3aed23
commit f95331d3a6
7 changed files with 43 additions and 21 deletions
-2
View File
@@ -5308,7 +5308,6 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
APP_CUSTOM_SCHEME = element;
APP_DISPLAY_NAME = "Element X"; APP_DISPLAY_NAME = "Element X";
APP_GROUP_IDENTIFIER = "group.$(BASE_APP_GROUP_IDENTIFIER)"; APP_GROUP_IDENTIFIER = "group.$(BASE_APP_GROUP_IDENTIFIER)";
APP_NAME = ElementX; APP_NAME = ElementX;
@@ -5378,7 +5377,6 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
APP_CUSTOM_SCHEME = element;
APP_DISPLAY_NAME = "Element X"; APP_DISPLAY_NAME = "Element X";
APP_GROUP_IDENTIFIER = "group.$(BASE_APP_GROUP_IDENTIFIER)"; APP_GROUP_IDENTIFIER = "group.$(BASE_APP_GROUP_IDENTIFIER)";
APP_NAME = ElementX; APP_NAME = ElementX;
@@ -80,15 +80,13 @@ struct ElementAppURLParser: URLParser {
/// The parser for Element Call links. This always returns a `.genericCallLink` /// The parser for Element Call links. This always returns a `.genericCallLink`
struct ElementCallURLParser: URLParser { struct ElementCallURLParser: URLParser {
private let knownHosts = ["call.element.io"] private let knownHosts = ["call.element.io"]
private let customSchemeHost = "call"
private let customSchemeURLQueryParameterName = "url" private let customSchemeURLQueryParameterName = "url"
func route(from url: URL) -> AppRoute? { func route(from url: URL) -> AppRoute? {
// First try processing URLs with custom schemes // First try processing URLs with custom schemes
if let scheme = url.scheme, if let scheme = url.scheme,
scheme == InfoPlistReader.app.appScheme { scheme == InfoPlistReader.app.elementCallScheme {
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false), guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
components.host == customSchemeHost else {
return nil return nil
} }
+19 -9
View File
@@ -33,6 +33,7 @@ struct InfoPlistReader {
static let otlpTracingPassword = "otlpTracingPassword" static let otlpTracingPassword = "otlpTracingPassword"
static let bundleURLTypes = "CFBundleURLTypes" static let bundleURLTypes = "CFBundleURLTypes"
static let bundleURLName = "CFBundleURLName"
static let bundleURLSchemes = "CFBundleURLSchemes" static let bundleURLSchemes = "CFBundleURLSchemes"
} }
@@ -117,14 +118,11 @@ struct InfoPlistReader {
// MARK: - Custom App Scheme // MARK: - Custom App Scheme
var appScheme: String { var appScheme: String {
let urlTypes: [[String: Any]] = infoPlistValue(forKey: Keys.bundleURLTypes) customSchemeForName("Application")
}
guard let urlSchemes = urlTypes.first?[Keys.bundleURLSchemes] as? [String],
let scheme = urlSchemes.first else { var elementCallScheme: String {
fatalError("Invalid custon application scheme configuration") customSchemeForName("Element Call")
}
return scheme
} }
// MARK: - Mention Pills // MARK: - Mention Pills
@@ -140,11 +138,23 @@ struct InfoPlistReader {
} }
// MARK: - Private // MARK: - Private
private func infoPlistValue<T>(forKey key: String) -> T { private func infoPlistValue<T>(forKey key: String) -> T {
guard let result = bundle.object(forInfoDictionaryKey: key) as? T else { guard let result = bundle.object(forInfoDictionaryKey: key) as? T else {
fatalError("Add \(key) into your target's Info.plst") fatalError("Add \(key) into your target's Info.plst")
} }
return result return result
} }
private func customSchemeForName(_ name: String) -> String {
let urlTypes: [[String: Any]] = infoPlistValue(forKey: Keys.bundleURLTypes)
guard let urlType = urlTypes.first(where: { $0[Keys.bundleURLName] as? String == name }),
let urlSchemes = urlType[Keys.bundleURLSchemes] as? [String],
let scheme = urlSchemes.first else {
fatalError("Invalid custom application scheme configuration")
}
return scheme
}
} }
+12 -2
View File
@@ -41,10 +41,20 @@
<key>CFBundleTypeRole</key> <key>CFBundleTypeRole</key>
<string>Editor</string> <string>Editor</string>
<key>CFBundleURLName</key> <key>CFBundleURLName</key>
<string>$(BASE_BUNDLE_IDENTIFIER)</string> <string>Element Call</string>
<key>CFBundleURLSchemes</key> <key>CFBundleURLSchemes</key>
<array> <array>
<string>$(APP_CUSTOM_SCHEME)</string> <string>io.element.call</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>Application</string>
<key>CFBundleURLSchemes</key>
<array>
<string>io.element</string>
</array> </array>
</dict> </dict>
</array> </array>
+9 -2
View File
@@ -57,9 +57,16 @@ targets:
CFBundleURLTypes: [ CFBundleURLTypes: [
{ {
CFBundleTypeRole: Editor, CFBundleTypeRole: Editor,
CFBundleURLName: $(BASE_BUNDLE_IDENTIFIER), CFBundleURLName: "Element Call",
CFBundleURLSchemes: [ CFBundleURLSchemes: [
$(APP_CUSTOM_SCHEME) io.element.call
]
},
{
CFBundleTypeRole: Editor,
CFBundleURLName: "Application",
CFBundleURLSchemes: [
io.element
] ]
} }
] ]
@@ -27,7 +27,7 @@ class AppRouteURLParserTests: XCTestCase {
XCTAssertEqual(AppRouteURLParser(appSettings: ServiceLocator.shared.settings).route(from: url), AppRoute.genericCallLink(url: url)) XCTAssertEqual(AppRouteURLParser(appSettings: ServiceLocator.shared.settings).route(from: url), AppRoute.genericCallLink(url: url))
guard let customSchemeURL = URL(string: "element://call?url=https%3A%2F%2Fcall.element.io%2Ftest") else { guard let customSchemeURL = URL(string: "io.element.call:/?url=https%3A%2F%2Fcall.element.io%2Ftest") else {
XCTFail("URL invalid") XCTFail("URL invalid")
return return
} }
-1
View File
@@ -28,7 +28,6 @@ settings:
BASE_BUNDLE_IDENTIFIER: io.element.elementx BASE_BUNDLE_IDENTIFIER: io.element.elementx
APP_NAME: ElementX APP_NAME: ElementX
APP_DISPLAY_NAME: Element X APP_DISPLAY_NAME: Element X
APP_CUSTOM_SCHEME: element
KEYCHAIN_ACCESS_GROUP_IDENTIFIER: $(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER) KEYCHAIN_ACCESS_GROUP_IDENTIFIER: $(AppIdentifierPrefix)$(BASE_BUNDLE_IDENTIFIER)
MARKETING_VERSION: 1.3.0 MARKETING_VERSION: 1.3.0
CURRENT_PROJECT_VERSION: 1 CURRENT_PROJECT_VERSION: 1