From 8cac9df8c6d9168e1b82286bb6da0aa1bd498e35 Mon Sep 17 00:00:00 2001 From: Thomas Durand Date: Fri, 27 Jan 2023 20:35:16 +0100 Subject: [PATCH] Action extension that would open a deep link in the app (#423) * Early version of an action that would open a deeplink in the app * Extend routeur support + catch deeplinks * Cleaning extension code, using what local packages has to offer * Removed useless stuff from the extension * Added action icon ; Thanks Dall-E for the icon * Added the action name within a localizable file * Fix routeur --------- Co-authored-by: Thomas Ricouard --- IceCubesActionExtension/Action.js | 22 +++ .../ActionRequestHandler.swift | 104 ++++++++++ .../ActionIcon.appiconset/ActionIcon1024.png | Bin 0 -> 58047 bytes .../ActionIcon.appiconset/Contents.json | 14 ++ .../Assets.xcassets/Contents.json | 6 + IceCubesActionExtension/Info.plist | 33 ++++ .../en.lproj/InfoPlist.strings | 9 + IceCubesApp.xcodeproj/project.pbxproj | 185 ++++++++++++++++++ IceCubesApp/App/SafariRouter.swift | 7 + Packages/Env/Sources/Env/Router.swift | 10 + 10 files changed, 390 insertions(+) create mode 100644 IceCubesActionExtension/Action.js create mode 100644 IceCubesActionExtension/ActionRequestHandler.swift create mode 100644 IceCubesActionExtension/Assets.xcassets/ActionIcon.appiconset/ActionIcon1024.png create mode 100644 IceCubesActionExtension/Assets.xcassets/ActionIcon.appiconset/Contents.json create mode 100644 IceCubesActionExtension/Assets.xcassets/Contents.json create mode 100644 IceCubesActionExtension/Info.plist create mode 100644 IceCubesActionExtension/en.lproj/InfoPlist.strings diff --git a/IceCubesActionExtension/Action.js b/IceCubesActionExtension/Action.js new file mode 100644 index 00000000..272b2a43 --- /dev/null +++ b/IceCubesActionExtension/Action.js @@ -0,0 +1,22 @@ +// +// Action.js +// IceCubesActionExtension +// +// Created by Thomas Durand on 26/01/2023. +// + +var Action = function() {}; + +Action.prototype = { + run: function(arguments) { + arguments.completionFunction({ "url" : document.URL }) + }, + finalize: function(arguments) { + var openingUrl = arguments["deeplink"] + if (openingUrl) { + document.location.href = openingUrl + } + } +}; + +var ExtensionPreprocessingJS = new Action diff --git a/IceCubesActionExtension/ActionRequestHandler.swift b/IceCubesActionExtension/ActionRequestHandler.swift new file mode 100644 index 00000000..4a04bad0 --- /dev/null +++ b/IceCubesActionExtension/ActionRequestHandler.swift @@ -0,0 +1,104 @@ +// +// ActionRequestHandler.swift +// IceCubesActionExtension +// +// Created by Thomas Durand on 26/01/2023. +// + +import UIKit +import MobileCoreServices +import UniformTypeIdentifiers + +import Models +import Network + +// Sample code was sending this from a thread to another, let asume @Sendable for this +extension NSExtensionContext: @unchecked Sendable { } + +class ActionRequestHandler: NSObject, NSExtensionRequestHandling { + enum Error: Swift.Error { + case inputProviderNotFound + case loadedItemHasWrongType + case urlNotFound + case noHost + case notMastodonInstance + } + + func beginRequest(with context: NSExtensionContext) { + // Do not call super in an Action extension with no user interface + Task { + do { + let url = try await url(from: context) + guard await url.isMastodonInstance else { + throw Error.notMastodonInstance + } + await MainActor.run { + let deeplink = url.iceCubesAppDeepLink + let output = output(wrapping: deeplink) + context.completeRequest(returningItems: output) + } + } catch { + await MainActor.run { + context.completeRequest(returningItems: []) + } + } + } + } +} + +extension URL { + var isMastodonInstance: Bool { + get async { + do { + guard let host = host() else { + throw ActionRequestHandler.Error.noHost + } + let _: Instance = try await Client(server: host).get(endpoint: Instances.instance) + return true + } catch { + return false + } + } + } + + var iceCubesAppDeepLink: URL { + var components = URLComponents(url: self, resolvingAgainstBaseURL: false)! + components.scheme = AppInfo.scheme.trimmingCharacters(in: [":", "/"]) + return components.url! + } +} + +extension ActionRequestHandler { + /// Will look for an input item that might provide the property list that Javascript sent us + private func url(from context: NSExtensionContext) async throws -> URL { + for item in context.inputItems as! [NSExtensionItem] { + guard let attachments = item.attachments else { + continue + } + for itemProvider in attachments { + guard itemProvider.hasItemConformingToTypeIdentifier(UTType.propertyList.identifier) else { + continue + } + guard let dictionary = try await itemProvider.loadItem(forTypeIdentifier: UTType.propertyList.identifier) as? [String: Any] else { + throw Error.loadedItemHasWrongType + } + let input = dictionary[NSExtensionJavaScriptPreprocessingResultsKey] as! [String: Any]? ?? [:] + guard let absoluteStringUrl = input["url"] as? String, let url = URL(string: absoluteStringUrl) else { + throw Error.urlNotFound + } + return url + } + } + throw Error.inputProviderNotFound + } + + /// Wrap the output to the expected object so we send back results to JS + private func output(wrapping deeplink: URL) -> [NSExtensionItem] { + let results = ["deeplink": deeplink.absoluteString] + let dictionary = [NSExtensionJavaScriptFinalizeArgumentKey: results] + let provider = NSItemProvider(item: dictionary as NSDictionary, typeIdentifier: UTType.propertyList.identifier) + let item = NSExtensionItem() + item.attachments = [provider] + return [item] + } +} diff --git a/IceCubesActionExtension/Assets.xcassets/ActionIcon.appiconset/ActionIcon1024.png b/IceCubesActionExtension/Assets.xcassets/ActionIcon.appiconset/ActionIcon1024.png new file mode 100644 index 0000000000000000000000000000000000000000..e93668c56b3a338cd271878e875e27fe0e92ee2e GIT binary patch literal 58047 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 z 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 + + + + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + + NSExtensionActivationSupportsFileWithMaxCount + 0 + NSExtensionActivationSupportsImageWithMaxCount + 0 + NSExtensionActivationSupportsMovieWithMaxCount + 0 + NSExtensionActivationSupportsText + + NSExtensionActivationSupportsWebURLWithMaxCount + 1 + + NSExtensionJavaScriptPreprocessingFile + Action + NSExtensionServiceFinderPreviewIconName + NSActionTemplate + + NSExtensionPointIdentifier + com.apple.services + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).ActionRequestHandler + + + diff --git a/IceCubesActionExtension/en.lproj/InfoPlist.strings b/IceCubesActionExtension/en.lproj/InfoPlist.strings new file mode 100644 index 00000000..562aa6ea --- /dev/null +++ b/IceCubesActionExtension/en.lproj/InfoPlist.strings @@ -0,0 +1,9 @@ +/* + InfoPlist.strings + IceCubesApp + + Created by Thomas Durand on 27/01/2023. + +*/ + +"CFBundleDisplayName" = "Open in Ice Cubes"; diff --git a/IceCubesApp.xcodeproj/project.pbxproj b/IceCubesApp.xcodeproj/project.pbxproj index 75a57525..b5d1cb17 100644 --- a/IceCubesApp.xcodeproj/project.pbxproj +++ b/IceCubesApp.xcodeproj/project.pbxproj @@ -74,7 +74,15 @@ 9FE151A6293C90F900E9683D /* IconSelectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FE151A5293C90F900E9683D /* IconSelectorView.swift */; }; 9FE3DB57296FEFCA00628CB0 /* AppAccount in Frameworks */ = {isa = PBXBuildFile; productRef = 9FE3DB56296FEFCA00628CB0 /* AppAccount */; }; C9B22677297F6C2E001F9EFE /* ContentSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9B22676297F6C2E001F9EFE /* ContentSettingsView.swift */; }; + E92817FA298443D600875FD1 /* Models in Frameworks */ = {isa = PBXBuildFile; productRef = E92817F9298443D600875FD1 /* Models */; }; + E92817FC298443D600875FD1 /* Network in Frameworks */ = {isa = PBXBuildFile; productRef = E92817FB298443D600875FD1 /* Network */; }; + E92817FE29844DB700875FD1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E92817FD29844DB700875FD1 /* Assets.xcassets */; }; + E970C10829845A9400E88A8C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = E970C10A29845A9400E88A8C /* InfoPlist.strings */; }; E9B576C329743F4C00BCE646 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E9B576C529743F4C00BCE646 /* Localizable.strings */; }; + E9DF41FC29830FEC0003AAD2 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E9DF41FB29830FEC0003AAD2 /* UniformTypeIdentifiers.framework */; }; + E9DF420129830FEC0003AAD2 /* ActionRequestHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9DF420029830FEC0003AAD2 /* ActionRequestHandler.swift */; }; + E9DF420329830FEC0003AAD2 /* Action.js in Resources */ = {isa = PBXBuildFile; fileRef = E9DF420229830FEC0003AAD2 /* Action.js */; }; + E9DF420729830FEC0003AAD2 /* IceCubesActionExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E9DF41FA29830FEC0003AAD2 /* IceCubesActionExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -92,6 +100,13 @@ remoteGlobalIDString = 9FAD858729743F7400496AB1; remoteInfo = IceCubesShareExtension; }; + E9DF420529830FEC0003AAD2 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 9FBFE631292A715500C250E9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = E9DF41F929830FEC0003AAD2; + remoteInfo = IceCubesActionExtension; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -101,6 +116,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( + E9DF420729830FEC0003AAD2 /* IceCubesActionExtension.appex in Embed Foundation Extensions */, 9F2A541D296AB631009B2D7C /* IceCubesNotifications.appex in Embed Foundation Extensions */, 9FAD859229743F7400496AB1 /* IceCubesShareExtension.appex in Embed Foundation Extensions */, ); @@ -181,8 +197,15 @@ C465A53D297C5E0C00864FB7 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = ""; }; C9B22676297F6C2E001F9EFE /* ContentSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentSettingsView.swift; sourceTree = ""; }; DD31E2E5297FB68B00A4BE29 /* IceCubesApp.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = IceCubesApp.xcconfig; sourceTree = ""; }; + E92817FD29844DB700875FD1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + E970C10929845A9400E88A8C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; E9B576C429743F4C00BCE646 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; E9B576CC2974AAAF00BCE646 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; + E9DF41FA29830FEC0003AAD2 /* IceCubesActionExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = IceCubesActionExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + E9DF41FB29830FEC0003AAD2 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; + E9DF420029830FEC0003AAD2 /* ActionRequestHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionRequestHandler.swift; sourceTree = ""; }; + E9DF420229830FEC0003AAD2 /* Action.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = Action.js; sourceTree = ""; }; + E9DF420429830FEC0003AAD2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; F355EEDA297A8BD500E362C0 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = ""; }; /* End PBXFileReference section */ @@ -236,6 +259,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E9DF41F729830FEC0003AAD2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E92817FC298443D600875FD1 /* Network in Frameworks */, + E92817FA298443D600875FD1 /* Models in Frameworks */, + E9DF41FC29830FEC0003AAD2 /* UniformTypeIdentifiers.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -321,6 +354,7 @@ DD31E2E5297FB68B00A4BE29 /* IceCubesApp.xcconfig */, 9F7D939529800B0300EE6B7A /* IceCubesApp-release.xcconfig */, 9FBFE63B292A715500C250E9 /* IceCubesApp */, + E9DF41FD29830FEC0003AAD2 /* IceCubesActionExtension */, 9F2A5417296AB631009B2D7C /* IceCubesNotifications */, 9FAD858929743F7400496AB1 /* IceCubesShareExtension */, 9FBFE63A292A715500C250E9 /* Products */, @@ -346,6 +380,7 @@ 9FBFE639292A715500C250E9 /* IceCubesApp.app */, 9F2A5416296AB631009B2D7C /* IceCubesNotifications.appex */, 9FAD858829743F7400496AB1 /* IceCubesShareExtension.appex */, + E9DF41FA29830FEC0003AAD2 /* IceCubesActionExtension.appex */, ); name = Products; sourceTree = ""; @@ -370,6 +405,7 @@ 9F2A5404296995FB009B2D7C /* QuickLookUI.framework */, 9F7335EE29674F7100AFF0BA /* QuickLook.framework */, 9F7335EB2967461B00AFF0BA /* AVKit.framework */, + E9DF41FB29830FEC0003AAD2 /* UniformTypeIdentifiers.framework */, ); name = Frameworks; sourceTree = ""; @@ -399,6 +435,18 @@ path = Localization; sourceTree = ""; }; + E9DF41FD29830FEC0003AAD2 /* IceCubesActionExtension */ = { + isa = PBXGroup; + children = ( + E9DF420029830FEC0003AAD2 /* ActionRequestHandler.swift */, + E9DF420229830FEC0003AAD2 /* Action.js */, + E9DF420429830FEC0003AAD2 /* Info.plist */, + E92817FD29844DB700875FD1 /* Assets.xcassets */, + E970C10A29845A9400E88A8C /* InfoPlist.strings */, + ); + path = IceCubesActionExtension; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -465,6 +513,7 @@ dependencies = ( 9F2A541C296AB631009B2D7C /* PBXTargetDependency */, 9FAD859129743F7400496AB1 /* PBXTargetDependency */, + E9DF420629830FEC0003AAD2 /* PBXTargetDependency */, ); name = IceCubesApp; packageProductDependencies = ( @@ -487,6 +536,27 @@ productReference = 9FBFE639292A715500C250E9 /* IceCubesApp.app */; productType = "com.apple.product-type.application"; }; + E9DF41F929830FEC0003AAD2 /* IceCubesActionExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = E9DF420A29830FEC0003AAD2 /* Build configuration list for PBXNativeTarget "IceCubesActionExtension" */; + buildPhases = ( + E9DF41F629830FEC0003AAD2 /* Sources */, + E9DF41F729830FEC0003AAD2 /* Frameworks */, + E9DF41F829830FEC0003AAD2 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = IceCubesActionExtension; + packageProductDependencies = ( + E92817F9298443D600875FD1 /* Models */, + E92817FB298443D600875FD1 /* Network */, + ); + productName = IceCubesActionExtension; + productReference = E9DF41FA29830FEC0003AAD2 /* IceCubesActionExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -506,6 +576,9 @@ 9FBFE638292A715500C250E9 = { CreatedOnToolsVersion = 14.1; }; + E9DF41F929830FEC0003AAD2 = { + CreatedOnToolsVersion = 14.2; + }; }; }; buildConfigurationList = 9FBFE634292A715500C250E9 /* Build configuration list for PBXProject "IceCubesApp" */; @@ -534,6 +607,7 @@ projectRoot = ""; targets = ( 9FBFE638292A715500C250E9 /* IceCubesApp */, + E9DF41F929830FEC0003AAD2 /* IceCubesActionExtension */, 9F2A5415296AB631009B2D7C /* IceCubesNotifications */, 9FAD858729743F7400496AB1 /* IceCubesShareExtension */, ); @@ -576,6 +650,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E9DF41F829830FEC0003AAD2 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E92817FE29844DB700875FD1 /* Assets.xcassets in Resources */, + E970C10829845A9400E88A8C /* InfoPlist.strings in Resources */, + E9DF420329830FEC0003AAD2 /* Action.js in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -624,6 +708,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E9DF41F629830FEC0003AAD2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E9DF420129830FEC0003AAD2 /* ActionRequestHandler.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -639,6 +731,11 @@ target = 9FAD858729743F7400496AB1 /* IceCubesShareExtension */; targetProxy = 9FAD859029743F7400496AB1 /* PBXContainerItemProxy */; }; + E9DF420629830FEC0003AAD2 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = E9DF41F929830FEC0003AAD2 /* IceCubesActionExtension */; + targetProxy = E9DF420529830FEC0003AAD2 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -658,6 +755,14 @@ name = Localizable.stringsdict; sourceTree = ""; }; + E970C10A29845A9400E88A8C /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + E970C10929845A9400E88A8C /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; E9B576C529743F4C00BCE646 /* Localizable.strings */ = { isa = PBXVariantGroup; children = ( @@ -1018,6 +1123,69 @@ }; name = Release; }; + E9DF420829830FEC0003AAD2 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = ActionIcon; + CODE_SIGN_IDENTITY = "-"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 730; + DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = IceCubesActionExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Open in Ice Cube"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.1; + PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesActionExtension"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + E9DF420929830FEC0003AAD2 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = ActionIcon; + CODE_SIGN_IDENTITY = "-"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 730; + DEVELOPMENT_TEAM = "$(DEVELOPMENT_TEAM)"; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = IceCubesActionExtension/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = "Open in Ice Cube"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.1; + PRODUCT_BUNDLE_IDENTIFIER = "$(BUNDLE_ID_PREFIX).IceCubesApp.IceCubesActionExtension"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1057,6 +1225,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + E9DF420A29830FEC0003AAD2 /* Build configuration list for PBXNativeTarget "IceCubesActionExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E9DF420829830FEC0003AAD2 /* Debug */, + E9DF420929830FEC0003AAD2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ @@ -1184,6 +1361,14 @@ isa = XCSwiftPackageProductDependency; productName = AppAccount; }; + E92817F9298443D600875FD1 /* Models */ = { + isa = XCSwiftPackageProductDependency; + productName = Models; + }; + E92817FB298443D600875FD1 /* Network */ = { + isa = XCSwiftPackageProductDependency; + productName = Network; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 9FBFE631292A715500C250E9 /* Project object */; diff --git a/IceCubesApp/App/SafariRouter.swift b/IceCubesApp/App/SafariRouter.swift index 3446ee12..be0c6edc 100644 --- a/IceCubesApp/App/SafariRouter.swift +++ b/IceCubesApp/App/SafariRouter.swift @@ -19,8 +19,15 @@ private struct SafariRouter: ViewModifier { func body(content: Content) -> some View { content .environment(\.openURL, OpenURLAction { url in + // Open internal URL. routerPath.handle(url: url) }) + .onOpenURL(perform: { url in + // Open external URL (from icecubesapp://) + let urlString = url.absoluteString.replacingOccurrences(of: "icecubesapp://", with: "https://") + guard let url = URL(string: urlString) else { return } + _ = routerPath.handle(url: url) + }) .onAppear { routerPath.urlHandler = { url in if url.absoluteString.contains("@twitter.com"), url.absoluteString.hasPrefix("mailto:") { diff --git a/Packages/Env/Sources/Env/Router.swift b/Packages/Env/Sources/Env/Router.swift index 6cc1e202..bd7cabab 100644 --- a/Packages/Env/Sources/Env/Router.swift +++ b/Packages/Env/Sources/Env/Router.swift @@ -107,6 +107,16 @@ public class RouterPath: ObservableObject { await navigateToAccountFrom(acct: acct, url: url) } return .handled + } else if let client = client, + client.isAuth, + client.hasConnection(with: url), + let id = Int(url.lastPathComponent) { + if url.absoluteString.contains(client.server) { + navigate(to: .statusDetail(id: String(id))) + } else { + navigate(to: .remoteStatusDetail(url: url)) + } + return .handled } return urlHandler?(url) ?? .systemAction }