diff --git a/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift b/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift index d488825dcc..353ff41653 100644 --- a/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift +++ b/frontends/ios/BitBoxApp/BitBoxApp/BitBoxAppApp.swift @@ -38,10 +38,11 @@ protocol SetMessageHandlersProtocol { func setMessageHandlers(handlers: MessageHandlersProtocol) } -class GoEnvironment: NSObject, MobileserverGoEnvironmentInterfaceProtocol { - func getSaveFilename(_ p0: String?) -> String { - // TODO - return "" +class GoEnvironment: NSObject, MobileserverGoEnvironmentInterfaceProtocol, UIDocumentInteractionControllerDelegate { + func getSaveFilename(_ fileName: String?) -> String { + let cacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! + let fileURL = cacheDirectory.appendingPathComponent(fileName!) + return fileURL.path() } func auth() { @@ -75,10 +76,47 @@ class GoEnvironment: NSObject, MobileserverGoEnvironmentInterfaceProtocol { func setDarkTheme(_ p0: Bool) { } - func systemOpen(_ url: String?) throws { - guard let url = URL(string: url!) else { return } - if UIApplication.shared.canOpenURL(url) { - UIApplication.shared.open(url) + // Helper method to get the root view controller + private func getRootViewController() -> UIViewController? { + guard let scene = UIApplication.shared.connectedScenes + .filter({ $0.activationState == .foregroundActive }) + .first as? UIWindowScene else { + return nil + } + + return scene.windows.first(where: { $0.isKeyWindow })?.rootViewController + } + + func systemOpen(_ urlString: String?) throws { + guard let urlString = urlString else { return } + // Check if it's a local file path (not a URL) + var url: URL + if urlString.hasPrefix("/") { + // This is a local file path, construct a file URL + url = URL(fileURLWithPath: urlString) + } else if let potentialURL = URL(string: urlString), potentialURL.scheme != nil { + // This is already a valid URL with a scheme + url = potentialURL + } else { + // Invalid URL or path + return + } + // Ensure all UIKit actions run on the main thread + DispatchQueue.main.async { + if url.isFileURL { + // Local file path, use UIDocumentInteractionController + if let rootViewController = self.getRootViewController() { + //let documentController = UIDocumentInteractionController(url: url) + //documentController.delegate = self // Ensure GoEnvironment conforms to UIDocumentInteractionControllerDelegate + //documentController.presentOptionsMenu(from: rootViewController.view.frame, in: rootViewController.view, animated: true) + let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil) + rootViewController.present(activityViewController, animated: true, completion: nil) + } + } else { + if UIApplication.shared.canOpenURL(url) { + UIApplication.shared.open(url) + } + } } } diff --git a/util/config/appdir.go b/util/config/appdir.go index 625f448b8f..65afb09353 100644 --- a/util/config/appdir.go +++ b/util/config/appdir.go @@ -83,8 +83,8 @@ func AppDir() string { // ExportsDir returns the absolute path to the folder which can be used to export files. func ExportsDir() (string, error) { - if runtime.GOOS == "android" { - // Android apps are sandboxed, we don't need to specify a folder. + if runtime.GOOS == "android" || runtime.GOOS == "ios" { + // Android/iOS apps are sandboxed, we don't need to specify a folder. return "", nil } homeFolder := os.Getenv("HOME")