如何使用我的 Flutter 应用程序从另一个应用程序打开具有自定义文件扩展名的文件?

Dav*_*woj 2 android android-intent kotlin flutter

我需要将我的 Flutter 应用程序与文件类型关联起来.foo。例如,如果用户打开本地文件管理器,然后单击文件,bar.fooandroid 会提示他们使用我的 flutter 应用程序打开该文件。

到目前为止,我了解到,这基本上是一个传入的 Android 意图,必须使用所谓的intent-filter此处所述进行注册:创建打开自定义文件扩展名的应用程序。但更进一步,我不明白如何在 Kotlin 中处理它。

因此,下一个合乎逻辑的事情是找出传入意图在 Flutter 中如何工作。然而,该文档对我没有帮助,因为它仅以Java 而非 Kotlin进行解释进行解释。我完全没有 Java 经验,但无论如何我还是想坚持使用 Kotlin,因为我还有用 Kotlin 编写的其他平台特定代码。

在这篇文章中,Deep Shah似乎也有同样的问题,但没有分享解决方案: Support custom file extension in a flutter app (Open file with extension .abc in flutter)

Shanks的这篇文章悄然消亡:用 Flutter App 打开自定义文件扩展名

我希望找到答案或指向相关资源的指示。

Dav*_*woj 5

我找到了安卓的解决方案。这篇文章应该将所有重要步骤捆绑在一起。从开始的事情YOUR_取决于你。相应地改变它们。

首先,您必须intent-filterAndroidManifest.xml. 这将告诉 android 将您的应用程序列为可能的选项。

<!-- TODO: CHANGE ICON AND LABEL HERE -->  
<intent-filter android:icon="YOUR_ICON_LOCATION"                  
               android:label="YOUR_APP_LABEL"
               android:priority="1">
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <data android:scheme="content" />
    <data android:scheme="http" />
    <data android:scheme="file" />
    <data android:mimeType="*/*" />
    <!-- TODO: CHANGE FILE EXTENSION -->  
    <data android:pathPattern=".*\\.YOUR_FILE_EXTENSION" />
</intent-filter>
Run Code Online (Sandbox Code Playgroud)

接下来,设置您的 Android 方法通道。为此,在 Kotlin 中是这样完成的:

import io.flutter.embedding.android.FlutterActivity
import android.content.Intent
import android.os.Bundle
import androidx.annotation.NonNull
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity : FlutterActivity() {
    // TODO: CHANGE METHOD CHANNEL NAME
    private val CHANNEL = "YOUR_CHANNEL_NAME"

    var openPath: String? = null
    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine)
        val channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
        channel.setMethodCallHandler { call, result ->
            when (call.method) {
                "getOpenFileUrl" -> {
                    result.success(openPath)
                }
                else -> result.notImplemented()
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        handleOpenFileUrl(intent)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        handleOpenFileUrl(intent)
    }

    private fun handleOpenFileUrl(intent: Intent?) {
        val path = intent?.data?.path
        if (path != null) {
            openPath = path
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,在 dart 方面设置一个处理程序。以下代码必须位于绘制的小部件中。我将它放入我的MainView小部件中,因为它总是在应用程序启动时绘制,并且在小部件树中相对较高。(对我来说这是 Widget 之外的第一个 Widget MaterialApp

class MainView extends StatefulWidget {
  const MainView({Key key}) : super(key: key);

  @override
  _MainViewState createState() => _MainViewState();
}

class _MainViewState extends State<MainView> with WidgetsBindingObserver {
  // TODO: CHANGE CHANNEL NAME
  static const platform = const MethodChannel("YOUR_CHANNEL_NAME");
 
  @override
  void initState() {
    super.initState();
    getOpenFileUrl();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    super.dispose();
    WidgetsBinding.instance.removeObserver(this);
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      getOpenFileUrl();
    }
  }

  @override
  Widget build(BuildContext context) {
    // TODO: Implement Build Method
  }

  void getOpenFileUrl() async {
    dynamic url = await platform.invokeMethod("getOpenFileUrl");

    if (url != null) {
      setState(() {
        // TODO: DO SOMETING WITH THE FILE URL
      });
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

完全终止并重新启动我的应用程序和外部应用程序(在我的例子中是文件管理器)后,它起作用了。