Xamarin Forms如何从指定路径调用外部默认应用打开文件?
Got it, let's figure out how to open a file with the default external app in Xamarin.Forms—since Process.Start doesn't translate directly to cross-platform mobile, we need to use Xamarin's Dependency Service to tap into native platform code (Android, iOS, UWP) to get this working.
Step 1: Define a Shared Interface
First, in your shared Xamarin.Forms project, create an interface that declares the method we'll use across all platforms:
public interface IFileOpener { Task OpenFileAsync(string filePath); }
Step 2: Implement the Interface for Android
In your Android project, add this native implementation. Don't forget the dependency attribute so Xamarin can find it:
using Android.Content; using Android.Net; using System.IO; using Xamarin.Forms; [assembly: Dependency(typeof(FileOpenerAndroid))] namespace YourAppName.Droid { public class FileOpenerAndroid : IFileOpener { public async Task OpenFileAsync(string filePath) { var targetFile = new Java.IO.File(filePath); if (!targetFile.Exists()) throw new FileNotFoundException("Requested file doesn't exist", filePath); // Get the file's MIME type (fallback to "*/*" if we can't determine it) string mimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension( MimeTypeMap.GetFileExtensionFromUrl(targetFile.AbsolutePath).ToLower() ); if (string.IsNullOrEmpty(mimeType)) mimeType = "*/*"; // Create and launch the intent to open the file var openIntent = new Intent(Intent.ActionView); openIntent.SetDataAndType(Uri.FromFile(targetFile), mimeType); openIntent.SetFlags(ActivityFlags.ClearWhenTaskReset | ActivityFlags.NewTask); try { Android.App.Application.Context.StartActivity(openIntent); await Task.CompletedTask; } catch (ActivityNotFoundException) { throw new InvalidOperationException("No app installed that can open this file type."); } } } }
Heads up: For Android 7.0+,
Uri.FromFilewill trigger aFileUriExposedException. You'll need to set up aFileProviderin your Android manifest and adjust the URI creation to useFileProvider.GetUriForFile()instead.
Step 3: Implement the Interface for iOS
In your iOS project, add this native implementation:
using Foundation; using System.IO; using UIKit; using Xamarin.Forms; [assembly: Dependency(typeof(FileOpeneriOS))] namespace YourAppName.iOS { public class FileOpeneriOS : IFileOpener { public async Task OpenFileAsync(string filePath) { if (!File.Exists(filePath)) throw new FileNotFoundException("Requested file doesn't exist", filePath); var fileUrl = new NSUrl(filePath); var docController = UIDocumentInteractionController.FromUrl(fileUrl); // Find the topmost view controller to present the open-in menu var window = UIApplication.SharedApplication.KeyWindow; var topViewController = window.RootViewController; while (topViewController.PresentedViewController != null) { topViewController = topViewController.PresentedViewController; } docController.Delegate = new DocInteractionDelegate(topViewController); docController.PresentOpenInMenu(topViewController.View.Frame, topViewController.View, true); await Task.CompletedTask; } } // Helper delegate to handle preview presentation public class DocInteractionDelegate : UIDocumentInteractionControllerDelegate { private readonly UIViewController _parentViewController; public DocInteractionDelegate(UIViewController parent) { _parentViewController = parent; } public override UIViewController ViewControllerForPreview(UIDocumentInteractionController controller) { return _parentViewController; } } }
Step 4: Use the Service in Shared Code
Now, in your Xamarin.Forms shared code (like a ViewModel or Page code-behind), call the service like this:
try { var fileOpener = DependencyService.Get<IFileOpener>(); await fileOpener.OpenFileAsync(@"storage/emulated/0/DCIM/Camera/IMG_20180502_162205.jpg"); } catch (Exception ex) { // Handle errors (file missing, no app available, etc.) await DisplayAlert("Oops!", ex.Message, "Got it"); }
Bonus: UWP Implementation (If Needed)
For UWP projects, here's the native implementation:
using Windows.Storage; using Windows.System; using Xamarin.Forms; [assembly: Dependency(typeof(FileOpenerUWP))] namespace YourAppName.UWP { public class FileOpenerUWP : IFileOpener { public async Task OpenFileAsync(string filePath) { var targetFile = await StorageFile.GetFileFromPathAsync(filePath); await Launcher.LaunchFileAsync(targetFile); } } }
This approach mirrors the behavior of Process.Start but works cross-platform for mobile, letting the system pick the default app to open your file.
内容的提问来源于stack exchange,提问作者ASalameh

