Флаттер открытый файл внешне такой как на ios "open in"
Из того, что я могу сказать, большинство руководств по флаттеру могут открываться из локального хранилища, но ничего о совместном использовании файлов. Кто-нибудь знает, как это сделать. Это руководство по включению его специально для ios https://developer.apple.com/library/archive/qa/qa1587/_index.html.
Я имею в виду, что есть расширение https://pub.dartlang.org/packages/open_file, но открывается из файлового хранилища.
Чтобы прояснить этот вопрос, речь идет не о том, чтобы поделиться файлом из приложения с другим, а о том, чтобы поделиться с внешним приложением, когда ему предлагается открыть его в этом приложении.
0 ответов
Для этого в iOS вы сначала определяете типы документов и импортированные UTI в XCode, как описано в упомянутом вами руководстве, а затем в своем файле AppDelegate.m вы делаете:
- (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];
}
На стороне дротика:
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
});
}
}
}
В дополнение к последнему ответу вам на самом деле также необходимо переопределить application(_:open:options:) в AppDelegate.swift, чтобы это работало.
Итак, идея состоит в том, чтобы использовать UIActivityViewController в iOS для открытия файла во Flutter (например: восстановить резервную копию базы данных SQL в приложении Flutter из электронной почты).
Во-первых, вам нужно установить UTI в info.plist. Вот хорошая ссылка, чтобы объяснить, как это работает. https://www.raywenderlich.com/813044-uiactivityviewcontroller-tutorial-sharing-data
Во-вторых, добавьте код контроллера канала в AppDelegate.swift.
Нам также необходимо переопределить application (: open: options:) в AppDelegate.swift, потому что iOS будет вызывать application (: open: options:), когда внешнее приложение хочет отправить вашему приложению файл. Следовательно, мы сохраняем имя файла как переменную внутри AppDelegate.
Здесь у нас есть контроллер двустороннего канала между iOS и Flutter. Каждый раз, когда приложение Flutter переходит в состояние AppLifecycleState.resumed, оно вызывает "checkIntent", чтобы снова проверить в AppDelegate, установлено ли имя файла. Если имя файла было установлено, AppDelegate вызовет метод "load" во флаттере, посредством чего вы выполните необходимую обработку файла.
Не забудьте удалить файл, предоставленный вам в AppDelegate, после того, как вы закончите обработку. В противном случае это приведет к раздуванию вашего приложения.
@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! FlutterViewController
let 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;
}
}