Flutter 原生路由跳转行为插件g_faraday的使用

Flutter 插件g_faraday的使用

g_faraday 是一个用于Flutter混合栈开发的解决方案,支持iOS、Android和Flutter三端的所有原生路由跳转行为,并提供了丰富的特性如页面间回调传值、自定义页面切换动画等。本文将详细介绍如何使用 g_faraday 插件。

特性

  • 支持iOS、Android、Flutter三端所有原生路由(页面切换)跳转行为
  • 支持混合栈(native -> flutter -> native)路由跳转(popTo、replace …)
  • 支持flutter页面作为root页面
  • 支持flutter作为子页面加入原生堆栈
  • 支持flutter作为弹出页面(背景透明到native层)
  • 页面间回调传值完整支持
  • iOS导航条自动隐藏/显示
  • WillPopScope拦截滑动返回(iOS)或者返回按键键(Android)
  • 发送/接收全局通知
  • 支持自定义页面切换动画
  • 支持完整的生命周期监听

快速开始

添加依赖

在你的 pubspec.yaml 文件中添加 g_faraday 依赖:

dependencies:
  g_faraday: ^0.7.0

Flutter端集成

在Flutter侧,主要是注册需要从原生打开的页面:

import 'package:flutter/cupertino.dart';
import 'package:g_faraday/g_faraday.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    // 定义 route
    final route = faraday.wrapper((settings) {
      switch (settings.name) {
        case 'first_page':
          return CupertinoPageRoute(builder: (context) => Text('First Page'));
        case 'second_page':
          return CupertinoPageRoute(builder: (context) => Text('Second Page'));
        default:
          return CupertinoPageRoute(builder: (context) => Text(settings.name));
      }
    });

    // 将 route 赋给你的app widget
    return CupertinoApp(
      onGenerateRoute: (_) => route,
    );
  }
}

注意:不管是 CupertinoApp 还是 MaterialApp 都不要设置 home

iOS集成

为了实现从Flutter端打开原生页面的应用场景,我们需要实现一个打开原生页面的protocol:

import UIKit
import g_faraday

extension AppDelegate: FaradayNavigationDelegate {

    func push(_ name: String, arguments: Any?, options: [String : Any]?, callback token: CallbackToken) {
        let isFlutter = options?["flutter"] as? Bool ?? false
        let isPresent = options?["present"] as? Bool ?? false

        let vc = isFlutter ? FaradayFlutterViewController(name, arguments: arguments) : FirstViewController(name, arguments: arguments)

        let topMost = UIViewController.fa.topMost
        if (isPresent) {
            // 此处注意
            // vc.modalPresentationStyle 不能是`pageSheet`
            // 如果的确需要这种UI效果,可以配合透明背景,在Flutter侧实现
            topMost?.present(vc, animated: true, completion: nil)
        } else {
            topMost?.navigationController?.pushViewController(vc, animated: true)
        }

        // 非常重要
        // 如果此处不调用 `enableCallback` 那么flutter侧`await Navigator`则永远不会返回
        vc.fa.enableCallback(with: token)
    }
}

// 在 `application: didFinishLaunchingWithOptions` 中启动flutter engine
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        Faraday.default.startFlutterEngine(navigatorDelegate: self)
        return true
    }
}

Android集成

为了实现从Flutter端打开原生页面的应用场景,我们需要实现一组打开原生页面的接口:

import android.content.Intent
import android.os.Bundle
import androidx.core.app.ActivityCompat
import com.gfaraday.Faraday
import com.gfaraday.FaradayActivity
import com.gfaraday.FaradayNavigator
import java.io.Serializable

class SimpleFlutterNavigator : FaradayNavigator {

    companion object {
        const val KEY_ARGS = "_args"
    }

    override fun create(name: String, arguments: Serializable?, options: HashMap<String, *>?): Intent? {
        val context = Faraday.getCurrentActivity() ?: return null

        val isFlutterRoute = options?.get("flutter") == true

        if (isFlutterRoute) {
            // singleTask 模式
            val builder = FaradayActivity.builder(name, arguments)

            // 你看到的绿色的闪屏就是这个
            builder.backgroundColor = Color.WHITE
            builder.activityClass = SingleTaskFlutterActivity::class.java

            return builder.build(context);
        }

        when (name) {
            "flutter2native" -> {
                return Intent(context, FlutterToNativeActivity::class.java)
            }
            "native2flutter" -> {
                return Intent(context, Native2FlutterActivity::class.java)
            }
            "tabContainer" -> {
                return Intent(context, TabContainerActivity::class.java)
            }
            else -> {
                val intent = Intent(Intent.ACTION_VIEW)
                intent.data = Uri.parse(name)
                intent.putExtra(KEY_ARGS, arguments)
                return intent
            }
        }
    }

    override fun pop(result: Serializable?) {
        val activity = Faraday.getCurrentActivity() ?: return
        if (result != null) {
            activity.setResult(Activity.RESULT_OK, Intent().apply { putExtra(KEY_ARGS, result) })
        }
        activity.finish()
    }

    override fun enableSwipeBack(enable: Boolean) {
    }
}

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        if (!Faraday.startFlutterEngine(this, SimpleFlutterNavigator())) {
            GeneratedPluginRegistrant.registerWith(Faraday.engine)
        }
    }
}

示例Demo

以下是一个简单的示例Demo,展示了如何使用 g_faraday 插件来实现Flutter与原生页面之间的跳转:

import 'package:flutter/cupertino.dart';
import 'package:g_faraday/g_faraday.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Map<String, RouteFactory> routes = {
    'home': (settings) => CupertinoPageRoute(
        builder: (context) => HomePage(settings.arguments), settings: settings),
    'native2flutter': (settings) => CupertinoPageRoute(
        builder: (context) => Native2FlutterPage(settings.arguments),
        settings: settings),
    'flutter2flutter': (settings) => CupertinoPageRoute(
        builder: (context) => Flutter2Flutter(index: settings.toJson.index),
        settings: settings),
    'tab1': (settings) =>
        CupertinoPageRoute(builder: (context) => TabPage(), settings: settings),
    'transparent_flutter': (settings) => CupertinoPageRoute(
          builder: (context) => TransparentPage(),
          settings: settings,
        )
  };

  [@override](/user/override)
  Widget build(BuildContext context) {
    final color = Color.fromARGB(255, 6, 210, 116);

    final route = faraday.wrapper(
      (settings) => routes[settings.name]?.call(settings),
      errorPage: _buildErrorPage,
    );

    final cupertinoApp = CupertinoApp(
      theme: CupertinoThemeData(primaryColor: color),
      debugShowCheckedModeBanner: false,
      onGenerateRoute: (_) => route,
    );

    return Directionality(
      textDirection: TextDirection.ltr,
      child: Banner(
        location: BannerLocation.topEnd,
        message: 'faraday',
        color: color,
        textStyle: TextStyle(
          color: CupertinoColors.white,
          fontSize: 12 * 0.85,
          fontWeight: FontWeight.w900,
          height: 1.0,
        ),
        child: cupertinoApp,
      ),
    );
  }

  ///
  /// 出错页面
  ///
  Widget _buildErrorPage(BuildContext context) {
    return GestureDetector(
      onTap: () => faraday.refresh(), // 刷新
      behavior: HitTestBehavior.opaque,
      child: Container(
        color: CupertinoColors.lightBackgroundGray,
        padding: EdgeInsets.only(left: 15.0, right: 15.0),
        alignment: Alignment.center,
        child: Text.rich(
          TextSpan(children: [
            TextSpan(
              text: '404',
              style: TextStyle(
                color: CupertinoColors.systemRed,
                fontSize: 64.0,
                fontWeight: FontWeight.bold,
              ),
            ),
            TextSpan(
              text: '\n出错了,点击刷新',
              style: TextStyle(
                fontSize: 16.0,
                color: CupertinoColors.placeholderText,
              ),
            ),
          ]),
          textAlign: TextAlign.center,
        ),
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  final dynamic arguments;

  HomePage(this.arguments);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('Home Page'),
      ),
      child: Center(
        child: CupertinoButton(
          child: Text('Go to Native Page'),
          onPressed: () {
            faraday.push('native2flutter', arguments: {'key': 'value'});
          },
        ),
      ),
    );
  }
}

class Native2FlutterPage extends StatelessWidget {
  final dynamic arguments;

  Native2FlutterPage(this.arguments);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text('Native to Flutter Page'),
      ),
      child: Center(
        child: Text('Arguments from Native: $arguments'),
      ),
    );
  }
}

更多关于Flutter 原生路由跳转行为插件g_faraday的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter 原生路由跳转行为插件g_faraday的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


在Flutter开发中,g_faraday 插件可能不是一个广为人知的库,但从其命名推测,它可能与网络请求拦截、调试或类似功能相关。尽管没有官方的详细文档或广泛的使用案例,我们可以尝试探索其基本用法,假设它提供了类似网络请求拦截的功能。

由于g_faraday在Flutter社区中可能不太常见,且没有具体的官方文档或示例代码,以下是一个假设性的示例,展示如何在Flutter项目中集成和使用一个假设的网络请求拦截器插件。请注意,这里的代码是基于假设的API和功能,实际使用时需要根据g_faraday的真实API进行调整。

假设性示例代码

1. 添加依赖

首先,在pubspec.yaml文件中添加g_faraday依赖(注意:这里假设它已经在pub.dev上可用):

dependencies:
  flutter:
    sdk: flutter
  g_faraday: ^x.y.z  # 替换为实际版本号

然后运行flutter pub get来安装依赖。

2. 初始化插件

在你的Flutter应用的入口文件(通常是main.dart)中初始化g_faraday插件:

import 'package:flutter/material.dart';
import 'package:g_faraday/g_faraday.dart';  // 假设的导入路径

void main() {
  WidgetsFlutterBinding.ensureInitialized();

  // 初始化g_faraday插件
  Faraday faraday = Faraday();

  // 设置请求拦截器(假设的API)
  faraday.addInterceptor((RequestOptions options) async {
    // 在这里可以修改请求选项,或者记录日志
    print('Intercepted request: ${options.path}');
    // 可以选择性地返回修改后的RequestOptions,或者抛出异常来阻止请求
    return options;
  });

  // 设置响应拦截器(假设的API)
  faraday.addResponseInterceptor((Response response, RequestOptions options) async {
    // 在这里可以修改响应数据,或者记录日志
    print('Intercepted response: ${response.statusCode} for ${options.path}');
    // 可以选择性地返回修改后的Response,或者抛出异常来处理错误
    return response;
  });

  // 配置全局HTTP客户端使用Faraday
  // 假设Faraday提供了一个方法来设置全局客户端
  faraday.configureGlobalHttpClient();

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Faraday Demo'),
        ),
        body: Center(
          child: Text('Check console for intercepted requests and responses'),
        ),
      ),
    );
  }
}

3. 使用HTTP客户端

在你的应用中,你可以像平常一样使用HTTP客户端,但所有的请求和响应都会被g_faraday拦截器处理:

import 'package:http/http.dart' as http;

// 假设在某个地方发送HTTP请求
void sendRequest() async {
  try {
    var response = await http.get(Uri.parse('https://api.example.com/data'));
    print('Response data: ${response.body}');
  } catch (e) {
    print('Request failed: $e');
  }
}

注意事项

  • 上述代码是基于假设的API和功能编写的,实际使用时需要根据g_faraday的真实API进行调整。
  • 如果g_faraday插件提供了不同的初始化或配置方法,请查阅其官方文档或源代码以获取准确的信息。
  • 如果g_faraday不是一个真实存在的Flutter插件,或者其功能与上述假设不符,那么你可能需要寻找其他网络请求拦截或调试的Flutter插件,如dio的拦截器功能等。

希望这个假设性的示例能够帮助你开始探索g_faraday插件的使用。如果有任何具体的问题或需要进一步的帮助,请查阅该插件的官方文档或联系其维护者。

回到顶部