flutter open file externally such as on ios "open in" flutter open file externally such as on ios "open in" flutter flutter

flutter open file externally such as on ios "open in"


To do this in iOS you first define the Document Types and Imported UTIs in XCode as described in the guide you mentioned, and then in your AppDelegate.m file you do:

- (BOOL)application:(UIApplication *)application    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    /* custom code begin */    FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;    FlutterMethodChannel* myChannel = [FlutterMethodChannel                                          methodChannelWithName:@"my/file"                                          binaryMessenger:controller];    __block NSURL *initialURL = launchOptions[UIApplicationLaunchOptionsURLKey];    [myChannel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {        if ([@"checkintent" isEqualToString:call.method]) {            if (initialURL) {                [myChannel invokeMethod:@"loaded" arguments: [initialURL absoluteString]];                initialURL = nil;                result(@TRUE);            }        }    }];    /* custom code end */    [GeneratedPluginRegistrant registerWithRegistry:self];    // Override point for customization after application launch.    return [super application:application didFinishLaunchingWithOptions:launchOptions];}

On the Dart side:

class PlayTextPageState extends State<MyHomePage> with WidgetsBindingObserver{  static const platform = const MethodChannel('my/file');  void initState() {    super.initState();    WidgetsBinding.instance.addObserver(this);    platform.setMethodCallHandler((MethodCall call) async {      String method = call.method;      if (method == 'loaded') {        String path = call.arguments; // this is the path        ...      }    });  }  @override  void didChangeAppLifecycleState(AppLifecycleState state) {    super.didChangeAppLifecycleState(state);    if (state == AppLifecycleState.paused) {      ...    } else if (state == AppLifecycleState.resumed) {      platform.invokeMethod("checkintent")        .then((result) {          // result == 1 if the app was opened with a file        });    }  }}


Adding on to lastant's answer, you actually also need to override application(_:open:options:) in AppDelegate.swift for this to work.

So the idea is to use UIActivityViewController in iOS to open a file in Flutter (eg: restore a backup of the SQL DB into the Flutter app from an email).

First, you need to set the UTIs in the info.plist. Here's a good link to explain how that works. https://www.raywenderlich.com/813044-uiactivityviewcontroller-tutorial-sharing-data

Second, add the channel controller code in AppDelegate.swift.

We also need to override application(:open:options:) in AppDelegate.swift because iOS will invoke application(:open:options:) when an external application wants to send your application a file. Hence we store the filename as a variable inside AppDelegate.

Here we are have a 2-way channel controller between iOS and Flutter. Everytime the Flutter app enter the AppLifecycleState.resumed state, it will invoke "checkIntent" to check back into AppDelegate to see if the filename has been set. If a filename has been set, AppDelegate will invoke the "load" method in flutter whereby you do your required processing with the file.

Remember to delete the file given to you from AppDelegate after you are done with your processing. Otherwise, it will bloat up your application.

@UIApplicationMain@objc class AppDelegate: FlutterAppDelegate {var initialURL: URL?override func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions:    [UIApplication.LaunchOptionsKey: Any]?) -> Bool {/* channel controller code */let controller: FlutterViewController = self.window?.rootViewController as! FlutterViewControllerlet myChannel = FlutterMethodChannel(name: "my/file", binaryMessenger: controller.binaryMessenger)myChannel.setMethodCallHandler({(call: FlutterMethodCall, result: @escaping FlutterResult)-> Void in    if(call.method == "checkintent"){        if(self.initialURL != nil){            myChannel.invokeMethod("loaded", arguments: self.initialURL?.absoluteString );            self.initialURL = nil;            result(true);        } else{            print("initialURL is null");        }    } else{        print("no such channel method");    }});  GeneratedPluginRegistrant.register(with: self)  return super.application(application, didFinishLaunchingWithOptions: launchOptions)}override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {    print("import URL: \(url)");    initialURL = url;    // should not remove here.. remove after i get into flutter...   // try? FileManager.default.removeItem(at: url);    return true;  }}