hybrid_stack_plugin 0.0.4

hybrid_stack_plugin #

A Flutter plugin for page manage between push/pop native and flutter

  • 此plugin主要参考自闲鱼发布的hybrid_stack_manager和voiddog的hybrid_stack_manager
  • 闲鱼的hybrid_stack_manager提供了完整的思路和实现
  • voiddog的hybrid_stack_manager中Android版本的优雅实现,提供了很大的帮助

使用 #

flutter版本要求: 1.2

在pubspec.yaml添加依赖

hybrid_stack_plugin: ^0.0.4

在执行"flutter packages get"后,您可以查看包中的example,了解如何使用它。

flutter #

初始化

void main() {
  //初始化plugin,必须创建navKey,用于监听flutter页面路由跳转(push和pop)
  GlobalKey<NavigatorState> navKey = GlobalKey<NavigatorState>();
  HybridStackPlugin.init(key: navKey);
  //添加会被Native端调用的路由,id可以是任意字符串
  HybridStackPlugin.addRoute('demo', (BuildContext context, Map args) {
    return MyApp(pageId: args['id'],);
  });
  HybridStackPlugin.addRoute('demo2', (BuildContext context, Map args) {
    return Demo2(pageId: args['id'],);
  });
  // 必须添加navigatorKey,使得前面初始化的plugin可以监听路由跳转
  // 建议home是一个空白页
  runApp(MaterialApp(
    navigatorKey: navKey,
    home: EmptyPage(),
  ));
  // 必须告诉plugin启动成功,并跳转Native指定的页面
  HybridStackPlugin.startInitRoute();
}

跳转到Native页面

onTap: () async {
  //跳到Native页面,pageId是在Native端注册好的路由,args是要传到Native端的参数
  var result = await HybridStackPlugin.pushNativePage("demo", {'key':'hybrid_stack','age':9});
  //使用async/await可以得到Native页面返回时的结果
  print("main native result: $result");
},

Flutter内部的页面跳转,依旧使用Navigator.push/pop

Android #

集成配置参见下面的 关于混合开发/Android打包

初始化,在Application的onCreate中添加

  //初始化Flutter
  FlutterMain.startInitialization(this);
  //注册路由到plugin
  HybridStackPlugin.addRoute("demo", DemoActivity.class);
  HybridStackPlugin.addRoute("demo2", Demo2Activity.class);

跳转到Flutter页面

  HashMap<String, Object> args = new HashMap<>();
  args.put("id", pageId);
  HybridStackPlugin.pushFlutterPage(DemoActivity.this, "demo", args);

接收Flutter启动Native页面是传过来的参数,在onCreate中添加

  Intent data = getIntent();
  if (data != null) {
    Serializable initArgs = data.getSerializableExtra("args");
    if (initArgs instanceof HashMap) {
      HashMap<String, Object> args = (HashMap<String, Object>)initArgs;
      JSONObject json = new JSONObject(args);
      //包含了pageId和args为key的数据
      Toast.makeText(this, "初始化参数:"+json.toString(), Toast.LENGTH_LONG).show();
    }
  }

接收Flutter返回回来的参数,在onActivityResult添加

  if (requestCode == HybridStackPlugin.NATIVE_REQUEST) {
    Serializable dataArgs = data.getSerializableExtra(HybridStackPlugin.EXTRA_KEY);
    if (dataArgs instanceof HashMap) {
      HashMap<String, Object> args = (HashMap<String, Object>)dataArgs;
      JSONObject json = new JSONObject(args);
      Toast.makeText(this, json.toString(), Toast.LENGTH_LONG).show();
    }
}

给Flutter返回结果

@Override
public void onBackPressed() {
//super.onBackPressed();
  Intent intent = new Intent();
  HashMap<String, Object> result = new HashMap<>();
  result.put("key", "demo");
  result.put("age", 13);
  intent.putExtra("args", result);
  setResult(918, intent);
  finish();
}

iOS #

集成配置参见下面的 关于混合开发/iOS打包

初始化,在application初始化时,注册页面路由

  //必须至少调用一次addRoute,它会初始化FlutterEngine
  [HybridStackPlugin addRoute:@"demo" clazz:DemoViewController.class];

跳转到Flutter页面

  NSMutableDictionary* args = [NSMutableDictionary dictionary];
  [args setObject:@12 forKey:@"id"];
  [HybridStackPlugin pushFlutterPage:@"demo" args:args block:^(NSDictionary* dict) {
    NSLog(@"返回结果:%@", [self convertToJsonData:dict]);
  }];

(可选)接收Flutter传过来的参数

  //定义成员变量
  @property (nonatomic, strong) NSDictionary* args;
//在viewWillAppear就可以获得Flutter传过来的参数

(可选)给Flutter返回结果

  //定义成员变量
  @property (nonatomic, strong) FlutterResult channelResult;
  //在pop的前调用_channelResult
  if (_channelResult != nil) {
    NSMutableDictionary* args = [NSMutableDictionary dictionary];
    [args setObject:@"我是结果" forKey:@"result"];
    _channelResult(args);
  }
  [self.navigationController popViewControllerAnimated:YES];

已知问题 #

  1. iOS真机调试时,从Native调用Flutter,只有第一次进入图片能正常显示,模拟器测试正常。不使用本plugin也有同样问题,待Flutter官方解决。 已通过全局FlutterViewController规避
  2. MaterialPageRoute中不要执行复杂操作
Navigator.push(context, MaterialPageRoute(builder: (context) {
  //pid = pid+1; 运算不能在这里,从Native返回时,iOS上会再执行(Android不会)
  return MyApp(pageId: pid,);
}));

关于混合开发 #

在现有工程的基础上引入Flutter做混合开发有两种方式:

  1. 以现有工程作为主工程,引入flutter模块。
  2. 新建flutter工程作为主工程,将现有Android和iOS代码分别替换到flutter工程中的Android和iOS目录下。

对于方式2,flutter官方支持的更好,相当于把原生项目加到flutter中,要做一些迁移的工作。 对于方式1,在引入flutter模块时,可采用源码依赖和包依赖两种方式。

  1. 源码依赖,参考官网的Add2App
  2. 包依赖,打包成Android下的aar和iOS下的framework。

这里只讨论方式1的包依赖。

包依赖的好处:对于原生开发者而言,只是多引入了一个第三方的包,没有任何flutter的环境依赖

缺点:原生和flutter的联调不方便,增加了包管理负担。

Android打包 #

打包aar #

以flutter module为例,

flutter run //生成debug.aar,不去执行,调试时会自动生成
flutter build apk //生成release.aar

在执行以上后,会在.android/Flutter/build/outputs/aar目录下,生成flutter-debug.aar和flutter-release.aar包。

在Android Studio中复制External Libraries -> Flutter Plugins下各个依赖plugin的aar,如

  • hybrid_stack_plugin #本plugin
  • path_provider #flutter必要的plugin
  • shared_preferences #flutter必要的plugin

在各个plugin的android/build/outputs/aar下,有各自的debug.aar和release.aar

集成到原生项目 #

复制以上所有的aar到原生项目的libs目录下。

在app的build.gradle中引入依赖即可

    debugImplementation fileTree(includes: ['*-debug.aar'], dir: 'libs')
    releaseImplementation fileTree(includes: ['*-release.aar'], dir: 'libs')

iOS打包 #

flutter build ios //生成App.framework和Flutter.framework

复制App.framework,Flutter.framework,GeneratedPluginRegistrant.h/m以及相关的plugin的源码添加到Native工程中。

各plugin的源码在Android Studio中External Libraries -> Flutter Plugins各个plugin的ios/Classes目录下

GeneratedPluginRegistrant.m引用的plugin目录根据需要调整

在项目设置的General页下,把App.framework和Flutter.framework加入到Embedded Binaries中

0.0.4 - 2019-03-14 #

  • bug fix iOS: 从Android Studio调试时,首次不会进入到指定Flutter页面的问题(XCode调试时无此问题)
  • 优化 iOS: debug模式下黑屏闪烁,默认改成白色背景

0.0.3 - 2019-03-12 #

  • 接口改用静态方式调用
  • bug fix iOS: 解决0.0.2版本引入的页面间跳转异常的问题

0.0.2 - 2019-03-12 #

  • bug fix Android: Flutter页面没有全屏。模块开发时,返回键异常和不显示初始页面。
  • bug fix iOS: 非UINavigationController的rootViewController导致崩溃的bug。

0.0.1 - 2019-03-11 #

  • 初步支持混合栈开发

example/README.md

hybrid_stack_plugin_example #

Demonstrates how to use the hybrid_stack_plugin plugin.

使用 #

在pubspec.yaml添加依赖

hybrid_stack_plugin: ^0.0.4

在执行"flutter packages get"后,您可以查看包中的example,了解如何使用它。

flutter #

初始化

void main() {
  //初始化plugin,必须创建navKey,用于监听flutter页面路由跳转(push和pop)
  GlobalKey<NavigatorState> navKey = GlobalKey<NavigatorState>();
  HybridStackPlugin.init(key: navKey);
  //添加会被Native端调用的路由,id可以是任意字符串
  HybridStackPlugin.addRoute('demo', (BuildContext context, Map args) {
    return MyApp(pageId: args['id'],);
  });
  HybridStackPlugin.addRoute('demo2', (BuildContext context, Map args) {
    return Demo2(pageId: args['id'],);
  });
  // 必须添加navigatorKey,使得前面初始化的plugin可以监听路由跳转
  // 建议home是一个空白页
  runApp(MaterialApp(
    navigatorKey: navKey,
    home: EmptyPage(),
  ));
  // 必须告诉plugin启动成功,并跳转Native指定的页面
  HybridStackPlugin.startInitRoute();
}

跳转到Native页面

onTap: () async {
  //跳到Native页面,pageId是在Native端注册好的路由,args是要传到Native端的参数
  var result = await HybridStackPlugin.pushNativePage("demo", {'key':'hybrid_stack','age':9});
  //使用async/await可以得到Native页面返回时的结果
  print("main native result: $result");
},

Flutter内部的页面跳转,依旧使用Navigator.push/pop

Native使用参见:https://github.com/xbo1/hybrid_stack_plugin

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  hybrid_stack_plugin: ^0.0.4

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:hybrid_stack_plugin/hybrid_stack_plugin.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
0
Health:
Code health derived from static analysis. [more]
100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
90
Overall:
Weighted score of the above. [more]
48
Learn more about scoring.

We analyzed this package on Aug 22, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.4.0
  • pana: 0.12.19
  • Flutter: 1.7.8+hotfix.4

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Maintenance suggestions

Package is pre-v0.1 release. (-10 points)

While nothing is inherently wrong with versions of 0.0.*, it might mean that the author is still experimenting with the general direction of the API.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.1.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.6 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8
Dev dependencies
flutter_test