diff --git a/FRW.xcodeproj/project.pbxproj b/FRW.xcodeproj/project.pbxproj index 1776d568..d9817179 100644 --- a/FRW.xcodeproj/project.pbxproj +++ b/FRW.xcodeproj/project.pbxproj @@ -893,6 +893,8 @@ 15DFD3332CD4576A004B0DB8 /* CGPoint+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15DFD3272CD4576A004B0DB8 /* CGPoint+Extensions.swift */; }; 15DFD3342CD4576A004B0DB8 /* BlobLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15DFD3262CD4576A004B0DB8 /* BlobLayer.swift */; }; 15DFD3352CD4576A004B0DB8 /* ResizableLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15DFD32A2CD4576A004B0DB8 /* ResizableLayer.swift */; }; + 15DFD34C2CE197F9004B0DB8 /* AppExternalLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15DFD34B2CE197F9004B0DB8 /* AppExternalLinks.swift */; }; + 15DFD34D2CE197F9004B0DB8 /* AppExternalLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15DFD34B2CE197F9004B0DB8 /* AppExternalLinks.swift */; }; 15ECAE3928C4FCE600B79453 /* WalletConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CC8A6B28C4F817001D2696 /* WalletConnectView.swift */; }; 15ECAE3A28C4FCE700B79453 /* WalletConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CC8A6B28C4F817001D2696 /* WalletConnectView.swift */; }; 15ECAE3B28C4FCEB00B79453 /* WalletConnectViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 15CC8A6C28C4F836001D2696 /* WalletConnectViewModel.swift */; }; @@ -2316,6 +2318,7 @@ 15DFD3282CD4576A004B0DB8 /* FluidGradient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FluidGradient.swift; sourceTree = ""; }; 15DFD3292CD4576A004B0DB8 /* FluidGradientView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FluidGradientView.swift; sourceTree = ""; }; 15DFD32A2CD4576A004B0DB8 /* ResizableLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResizableLayer.swift; sourceTree = ""; }; + 15DFD34B2CE197F9004B0DB8 /* AppExternalLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppExternalLinks.swift; sourceTree = ""; }; 15EC9DF1274FD1FD00F70CD9 /* FRW_App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FRW_App.swift; sourceTree = ""; }; 15EC9DF5274FD1FD00F70CD9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 15EC9DF8274FD1FD00F70CD9 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; @@ -5806,6 +5809,7 @@ 6AAD4E6828BC6E9900AEAB1F /* TransactionModels.swift */, 6AC476E728F3C993008503E6 /* WebBookmark.swift */, 6A2C560A290BE46800306A6C /* Currency.swift */, + 15DFD34B2CE197F9004B0DB8 /* AppExternalLinks.swift */, ); path = Model; sourceTree = ""; @@ -6730,6 +6734,7 @@ 6A164F742845F1CB0026B31E /* EnvironmentValues+IndexBarInsets.swift in Sources */, 15DC20CD27819C56000B187A /* VNavigationLink.swift in Sources */, 15ADAE2B28F51EBB0014B722 /* SymmetricEncryption.swift in Sources */, + 15DFD34C2CE197F9004B0DB8 /* AppExternalLinks.swift in Sources */, 4E31380B2C658FB2003A73E5 /* CappedCollection.swift in Sources */, 15DFD3312CD4576A004B0DB8 /* FluidGradientView.swift in Sources */, 15DFD3322CD4576A004B0DB8 /* FluidGradient.swift in Sources */, @@ -7526,6 +7531,7 @@ 15C58AB82868A4EE00BD4FC6 /* EnvironmentValues+IndexBarInsets.swift in Sources */, 15C58AB92868A4EE00BD4FC6 /* VNavigationLink.swift in Sources */, 15ADAE2A28F51EBB0014B722 /* SymmetricEncryption.swift in Sources */, + 15DFD34D2CE197F9004B0DB8 /* AppExternalLinks.swift in Sources */, 4E31380A2C658FB2003A73E5 /* CappedCollection.swift in Sources */, 15DFD32C2CD4576A004B0DB8 /* FluidGradientView.swift in Sources */, 15DFD32D2CD4576A004B0DB8 /* FluidGradient.swift in Sources */, diff --git a/FRW/App/AppDelegate.swift b/FRW/App/AppDelegate.swift index 683156fd..7f2877dd 100644 --- a/FRW/App/AppDelegate.swift +++ b/FRW/App/AppDelegate.swift @@ -103,28 +103,11 @@ class AppDelegate: NSObject, UIApplicationDelegate { func application(_: UIApplication, continue userActivity: NSUserActivity, restorationHandler _: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { if let url = userActivity.webpageURL { - if url.absoluteString.hasPrefix("https://fcw-link.lilico.app") { - var uri = url.absoluteString.deletingPrefix("https://fcw-link.lilico.app/wc?uri=") - uri = uri.deletingPrefix("fcw://") - WalletConnectManager.shared.onClientConnected = { - WalletConnectManager.shared.connect(link: uri) - } - WalletConnectManager.shared.connect(link: uri) - } else if url.absoluteString.hasPrefix("https://frw-link.lilico.app") { - var uri = url.absoluteString.deletingPrefix("https://frw-link.lilico.app/wc?uri=") - uri = uri.deletingPrefix("frw://") - WalletConnectManager.shared.onClientConnected = { - WalletConnectManager.shared.connect(link: uri) - } - WalletConnectManager.shared.connect(link: uri) - } else { - var uri = url.absoluteString.deletingPrefix("https://link.lilico.app/wc?uri=") - uri = uri.deletingPrefix("lilico://") - WalletConnectManager.shared.onClientConnected = { - WalletConnectManager.shared.connect(link: uri) - } + let uri = AppExternalLinks.exactWCLink(link: url.absoluteString) + WalletConnectManager.shared.onClientConnected = { WalletConnectManager.shared.connect(link: uri) } + WalletConnectManager.shared.connect(link: uri) } return true } diff --git a/FRW/Foundation/Model/AppExternalLinks.swift b/FRW/Foundation/Model/AppExternalLinks.swift new file mode 100644 index 00000000..6e6bee1a --- /dev/null +++ b/FRW/Foundation/Model/AppExternalLinks.swift @@ -0,0 +1,40 @@ +// +// AppExternalLinks.swift +// FRW +// +// Created by Hao Fu on 11/11/2024. +// + +import Foundation + +enum AppExternalLinks: String, CaseIterable { + case frw = "frw://" + case fcw = "fcw://" + case lilico = "lilico://" + case frwUL = "https://frw-link.lilico.app" + case fcwUL = "https://fcw-link.lilico.app" + + var isUniversalLink: Bool { + switch self { + case .frwUL, .fcwUL: + return true + default: + return false + } + } + + static var allLinks: [String] { + AppExternalLinks.allCases.map(\.rawValue) + } + + static func exactWCLink(link: String) -> String { + let newLink = link + .replacingOccurrences(of: "wc%2Fwc", with: "wc") + .replacingOccurrences(of: "wc/wc", with: "wc") + + return newLink + .deletingPrefixes(allLinks.map{link in "\(link)/wc?uri=" }) + .deletingPrefixes(allLinks.map{link in "\(link)wc?uri=" }) + .deletingPrefixes(allLinks) + } +} diff --git a/FRW/Modules/Browser/BrowserViewController.swift b/FRW/Modules/Browser/BrowserViewController.swift index b572cf0c..2dd1fd47 100644 --- a/FRW/Modules/Browser/BrowserViewController.swift +++ b/FRW/Modules/Browser/BrowserViewController.swift @@ -273,6 +273,26 @@ extension BrowserViewController { private func onClearCookie() { BrowserViewController.deleteCookie() } + + private func handleNavigationAction(navigationAction: WKNavigationAction) { + guard let url = navigationAction.request.url else { + return + } + + if !url.absoluteString.hasPrefixes(AppExternalLinks.allLinks) { + if navigationAction.targetFrame == nil { + UIApplication.shared.open(url) + } + return + } + + let uri = AppExternalLinks.exactWCLink(link: url.absoluteString) + WalletConnectManager.shared.onClientConnected = { + WalletConnectManager.shared.connect(link: uri) + } + WalletConnectManager.shared.connect(link: uri) + + } } // MARK: - Search Recommend @@ -318,45 +338,18 @@ extension BrowserViewController: WKNavigationDelegate { func webView(_: WKWebView, didFail _: WKNavigation!, withError _: Error) { reloadActionBarView() } - - func webView(_: WKWebView, decidePolicyFor _: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { - decisionHandler(.allow) + + func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction) async -> WKNavigationActionPolicy { + handleNavigationAction(navigationAction: navigationAction) reloadActionBarView() + return .allow } } extension BrowserViewController: WKUIDelegate { + func webView(_: WKWebView, createWebViewWith _: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures _: WKWindowFeatures) -> WKWebView? { - if navigationAction.targetFrame == nil, let url = navigationAction.request.url { - if url.absoluteString.hasPrefix("https://fcw-link.lilico.app") { - var uri = url.absoluteString.deletingPrefix("https://fcw-link.lilico.app/wc?uri=") - uri = uri.deletingPrefix("fcw://") - WalletConnectManager.shared.onClientConnected = { - WalletConnectManager.shared.connect(link: uri) - } - WalletConnectManager.shared.connect(link: uri) - } else if url.absoluteString.hasPrefix("https://frw-link.lilico.app") { - var uri = url.absoluteString.deletingPrefix("https://frw-link.lilico.app/wc?uri=") - uri = uri.deletingPrefix("frw://") - WalletConnectManager.shared.onClientConnected = { - WalletConnectManager.shared.connect(link: uri) - } - WalletConnectManager.shared.connect(link: uri) - } else if url.absoluteString.hasPrefix("https://link.lilico.app") { - var uri = url.absoluteString.deletingPrefix("https://link.lilico.app/wc?uri=") - uri = uri.deletingPrefix("lilico://") - WalletConnectManager.shared.onClientConnected = { - WalletConnectManager.shared.connect(link: uri) - } - WalletConnectManager.shared.connect(link: uri) - } else if url.description.lowercased().range(of: "http://") != nil || - url.description.lowercased().range(of: "https://") != nil || - url.description.lowercased().range(of: "mailto:") != nil - { - UIApplication.shared.openURL(url) - } - } - + handleNavigationAction(navigationAction: navigationAction) return nil } } diff --git a/FRW/UI/Extension/String.swift b/FRW/UI/Extension/String.swift index 23fbfee4..8e112c7f 100644 --- a/FRW/UI/Extension/String.swift +++ b/FRW/UI/Extension/String.swift @@ -237,10 +237,19 @@ extension String { } extension String { + + func hasPrefixes(_ prefixes: [String]) -> Bool { + prefixes.contains(where: hasPrefix) + } + func deletingPrefix(_ prefix: String) -> String { guard hasPrefix(prefix) else { return self } return String(dropFirst(prefix.count)) } + + func deletingPrefixes(_ prefixes: [String]) -> String { + prefixes.reduce(self) { $0.deletingPrefix($1) } + } } extension String {