The feature to open the spice connection file was disabled in iOS and
was only available in Android. To support iOS, a new native channel
implementation for iOS has been added.

For the iOS implementation, use the `UIActivityViewController` [0] to
show the share sheet with the suggested apps that can open the file.
Alternatively, users can also save the file to the device storage.

The `getExternalChacheDirectories` function has been replaced with
`getTemporaryDirectory` as the external cache directories function is
not supported [1] in iOS.

[0] - https://developer.apple.com/documentation/uikit/uiactivityviewcontroller
[1] - 
https://developer.apple.com/documentation/bundleresources/information-property-list/utimportedtypedeclarations

References:
- 
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures#Trailing-Closures
- 
https://medium.com/@dinesh.kachhot/different-ways-to-share-data-between-apps-de75a0a46d4a
- 
https://docs.flutter.dev/platform-integration/platform-channels#step-4-add-an-ios-platform-specific-implementation
- 
https://stackoverflow.com/questions/25644054/uiactivityviewcontroller-crashing-on-ios-8-ipads

Signed-off-by: Shan Shaji <s.sh...@proxmox.com>
---
 changes since v1:
 - Fixed commit message

 Tested:
 - The above changes are tested on iPad simulator and a real iPhone in
   debug mode. 

 ios/Runner/AppDelegate.swift             | 64 +++++++++++++++++++++---
 lib/widgets/pve_console_menu_widget.dart | 10 ++--
 2 files changed, 60 insertions(+), 14 deletions(-)

diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift
index 6266644..115e1fd 100644
--- a/ios/Runner/AppDelegate.swift
+++ b/ios/Runner/AppDelegate.swift
@@ -3,11 +3,61 @@ import UIKit
 
 @main
 @objc class AppDelegate: FlutterAppDelegate {
-  override func application(
-    _ application: UIApplication,
-    didFinishLaunchingWithOptions launchOptions: 
[UIApplication.LaunchOptionsKey: Any]?
-  ) -> Bool {
-    GeneratedPluginRegistrant.register(with: self)
-    return super.application(application, didFinishLaunchingWithOptions: 
launchOptions)
-  }
+    override func application(
+        _ application: UIApplication,
+        didFinishLaunchingWithOptions launchOptions: 
[UIApplication.LaunchOptionsKey: Any]?
+    ) -> Bool {
+        let controller: FlutterViewController = window?.rootViewController as! 
FlutterViewController
+        let channel: FlutterMethodChannel = FlutterMethodChannel(
+            name: "com.proxmox.app.pve_flutter_frontend/filesharing",
+            binaryMessenger: controller.binaryMessenger)
+        
+        channel.setMethodCallHandler({
+            [weak self] (call: FlutterMethodCall, result: @escaping 
FlutterResult) -> Void in
+            
+            guard call.method == "shareFile" else {
+                result(FlutterMethodNotImplemented)
+                return
+            }
+            
+            let arguments = call.arguments as? [String: Any]
+            let path = arguments?["path"] as? String
+            let type = arguments?["type"] as? String
+            
+            if let filePath = path, let _ = type  {
+                self?.shareFile(atPath: filePath, from: controller, result: 
result)
+            } else {
+                result(FlutterError(code: "FileNotFoundException", message: 
"File not found", details: nil))
+            }
+        })
+        
+        GeneratedPluginRegistrant.register(with: self)
+        return super.application(application, didFinishLaunchingWithOptions: 
launchOptions)
+    }
+    
+    private func shareFile(atPath path: String, from controller: 
UIViewController, result: @escaping FlutterResult) {
+        let fileURL = URL(fileURLWithPath: path)
+        let activityVC = UIActivityViewController(
+            activityItems: [fileURL],
+            applicationActivities: nil,
+        )
+
+      // To avoid crashing in iPad
+      if let popover = activityVC.popoverPresentationController {
+        popover.sourceView = controller.view
+        popover.sourceRect = CGRect(
+            x: controller.view.bounds.midX,
+            y: controller.view.bounds.midY,
+            width: 0,
+            height: 0,
+        )
+      }
+
+        
+    controller.present(activityVC, animated: true) {
+            result(nil)
+        }
+    }
+    
+    
 }
diff --git a/lib/widgets/pve_console_menu_widget.dart 
b/lib/widgets/pve_console_menu_widget.dart
index cd8c314..8fa5538 100644
--- a/lib/widgets/pve_console_menu_widget.dart
+++ b/lib/widgets/pve_console_menu_widget.dart
@@ -38,7 +38,7 @@ class PveConsoleMenu extends StatelessWidget {
         child: Column(
           mainAxisSize: MainAxisSize.min,
           children: [
-            if (Platform.isAndroid && (allowSpice ?? true))
+            if ((Platform.isAndroid || Platform.isIOS) && (allowSpice ?? true))
               ListTile(
                 title: const Text(
                   "SPICE",
@@ -47,8 +47,7 @@ class PveConsoleMenu extends StatelessWidget {
                 subtitle:
                     const Text("Open SPICE connection file with external App"),
                 onTap: () async {
-                  if (Platform.isAndroid) {
-                    final tempDir = await getExternalCacheDirectories();
+                    final tempDir = await getTemporaryDirectory();
 
                     String apiPath;
                     if (['qemu', 'lxc'].contains(type)) {
@@ -67,7 +66,7 @@ class PveConsoleMenu extends StatelessWidget {
                       }
                       return;
                     }
-                    var filePath = await writeSpiceFile(data, 
tempDir![0].path);
+                    var filePath = await writeSpiceFile(data, tempDir.path);
 
                     try {
                       await platform.invokeMethod('shareFile', {
@@ -98,9 +97,6 @@ class PveConsoleMenu extends StatelessWidget {
                         }
                       }
                     }
-                  } else {
-                    print('not implemented for current platform');
-                  }
                 },
               ),
             if (Platform.isAndroid) // web_view is only available for mobile :(
-- 
2.39.5 (Apple Git-154)



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to