Flutter入门——面向Android开发者——Intents

581 阅读3分钟

Flutter中的Intent等价于什么?

在Android中,对于Intent有两个最主要用例:在Activity之间导航,以及与组件通信。另一个方面,Flutter没有Intent的概念,尽管您仍然可以通过通过native调用Intent。

Flutter并没有直接等同于Activity和Fragment;相反,在Flutter中,您可以使用NavigatorRoute在屏幕之间导航,所有这些都在同一个Activity。

Route是应用程序“屏幕”或“页面”的抽象,而Navigator是管理路由的小部件。路线大致映射到Activity,但它不具有相同的含义。Navigator的工作方式就像一个堆栈,您可以用push()导航要导航到新路线,也可以在用pop()“返回”。

在Android中,您在AndroidManifest.xml定义activity。

在Flutter中,您有几个选项可以在页面之间导航:

  • 置顶一个Map路由名称。(使用MaterialApp
  • 直接导航到路线。(使用WidgetsApp)

下面例子构建一个Map

void main() {
    runApp(MaterialApp(
        home: const MyAppHome(), // Becomes the route named `/`
        routes: <String, WidgetBuilder>{
           '/a': (context) => const MyPage(title: 'page A'),
           '/b': (context) => const MyPage(title: 'page B'),
           '/c': (context) => consr MyPage(title: 'page C'),
        },
    ));
}

通过push将其名称添加到Navigator

Navigator.of(context).pushNamed('/b');

另一个使用Intent调用外部组件,例如调用相机或文件选择器。为此,你需要创建原生平台集成(或使用现有插件)。

要了解如何构建原生平台集成,请参阅开发包和插件

如何在Flutter中处理来自外部应用程序的传入Intent

Flutter可以通过直接与Android层对话并请求共享数据来处理来自Android传入的Intent。

以下示例在运行我们的Flutter代码的,在Activity上注册了一个文本共享Intent filter,因此其他应用程序可以与我们的Flutter应用程序共享文本。

基本流程意味着我们首先在Android端处理共享文本数据(在ActivityMethodChannel

首先,在AndroidManifest.xml注册intent filter

<activity
    android:name=".MainActivity"
    android:launchMode="@style/LaunchTheme"
    abdroid:confirChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection"
    android:hardwareAccelerated="true"
    android:windowSoftInputMode="adjustResize">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

然后在MainActivity处理Intent,从Intent中提取共享文本并保存它。当Flutter准备好处理时,它使用platform channel,并从native端发送:

package com.example.shared;

import android.content.Intent;
impoort android.os.Bundle;

import androidx.annotation.NonNull;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {
    
    private String sharedText;
    private static final String CHANNEL = "app.channel.shared.data";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent intent = getIntent();
        String action = intent.getAction();
        String type = intent.getType();
        
        if (Intent.ACTION_SEND.equals(action) && type != null) {
            if ("text/plain".equals(type)) {
                handleSendText(intent);// Handle text being sent
            }
        }
    }
    
    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine);
        
        new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
            .setMethodCallHandler(
                (call, result) -> {
                    if (call.method.contentEquals("getSharedText") {
                        result.success(sharedText);
                        sharedText = null;
                    }
                }
            );
    }
    
    void handleSendText(Intent intent) {
        sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
    }
}

最后,在widget渲染时向Flutter端请求数据:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
    runApp(const SampleApp());
}

class SampleApp extends StatelessWidget {
    const SampleApp({Key? key}) : super(key: key);
    
    // This widget is the root of your appliation.
    @override
    Widget build(BuildContext context) {
        return MaterialApp(
            title: 'Sample Shared App Handler',
            theme: ThemeData(
                primarySwatch: Colors.blue,
            ),
            home: const SampleAppPage(),
        );
    }
}

class SampleAppPage extends StatefulWidget {
    const SampleAppPage({Key? key}) : super(key: key);
    
    @override
    State<SampleAppPage> createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
    static const platform = MethodChannel('app.channel.shared.data');
    String dataShared = 'No data';
    
    @override
    void initState() {
        supter.initState();
        getSHaredText();
    }
    
    @override
    Widget build(BuildContext context) {
        return Scaffold(body: Center(child: Text(dataShared)));
    }
    
    Future<void> getSharedText() async {
        var sharedData = await platform.invokeMethod('getSharedText');
        if (sharedData != null) {
            setState(() {
                dataShared = sharedData;
            });
        }
    }
}

startActivityForResult()的等价物是什么?

该类Navigator处理Flutter中的路由,并用于从您已经push到对战的路由中获取结果。这是通过await Future push()的返回值。

例如,要启动一个位置路由让用户选择他们的为智慧,你可以执行以下操作:

Object? coordinates = await Navigator.of(context).pushNamed('/location');

然后,在您的位置路线中,一旦用户选择了他们的位置,你就可以pop讲结果返回来。

Navigator.of(context).pop({'lat': 43.821757, 'long': -79.226392});