Commit fb8519f8 authored by justin's avatar justin

Merge branch 'master' into v1.12.13-hotfixes

# Conflicts:
#	example/lib/simple_page_widgets.dart
#	lib/container/container_coordinator.dart
parents 802756a1 eeebe1d6
......@@ -30,7 +30,7 @@ bool isTopContainer = FlutterBoost.BoostContainer.of(context).onstage
回答:无障碍模式下目前Flutter Engine有bug,已经提交issue和PR给flutter啦。请参考这个issue:https://github.com/alibaba/flutter_boost/issues/488及其分析。提交给flutter的PR见这里:https://github.com/flutter/engine/pull/14155
### 5. 在ios模拟器下运行最新的flutter boost会闪退
回答:如上面第4条所说的,最新的flutter engine在voice over下有bug,会导致crash。因为模拟器下flutter默认会将voice over模式打开,所以其实就是辅助模式,这触发上面的bug:“在ios中voice over打开,demo在点击交互会crash”。
回答:如上面第4条所说的,最新的flutter engine在voice over下有bug,会导致crash。因为模拟器下flutter默认会将voice over模式打开,所以其实就是辅助模式,这触发上面的bug:“在ios中voice over打开,demo在点击交互会crash”。
可参考Engine的代码注释:
```c++
#if TARGET_OS_SIMULATOR
......
1、为何使用flutter_boost?
官方的集成方案有诸多弊病:
- 日志不能输出到原生端;
- 存在内存泄漏的问题,使用boost可以让内存稳定;
- native调用flutter,flutter调用native,通道的封装,使开发更加简便;
- 同时对于页面生命周期的管理,也梳理的比较整齐
2、集成流程IOS
在delegate中做flutter初始化的工作
```
在appDelegate中引入,PlatformRouterImp,用于实现平台侧的页面打开和关闭,不建议直接使用用于页面打开,建议使用FlutterBoostPlugin中的open和close方法来打开或关闭页面;
PlatformRouterImp内部实现打开各种native页面的映射。
self.router = [PlatformRouterImp new];
//初始化FlutterBoost混合栈环境。应在程序使用混合栈之前调用。如在AppDelegate中。本函数默认需要flutter boost来注册所有插件。
[FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:self.router
onStart:^(FlutterEngine *engine) {
}];
```
PlatformRouterImp,内部实现打开native页面的路由代码截图
```
- (void)open:(NSString *)name
urlParams:(NSDictionary *)params
exts:(NSDictionary *)exts
completion:(void (^)(BOOL))completion
{
if ([name isEqualToString:@"page1"]) {//打开页面1
// 打开页面1的vc
return;
}
BOOL animated = [exts[@"animated"] boolValue];
FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
[vc setName:name params:params];
[self.navigationController pushViewController:vc animated:animated];
if(completion) completion(YES);
}
```
如何打开,关闭flutter页面,直接调用FlutterBoostPlugin的类方法即可。
```
/**
* 关闭页面,混合栈推荐使用的用于操作页面的接口
*
* @param uniqueId 关闭的页面唯一ID符
* @param resultData 页面要返回的结果(给上一个页面),会作为页面返回函数的回调参数
* @param exts 额外参数
* @param completion 关闭页面的即时回调,页面一旦关闭即回调
*/
+ (void)close:(NSString *)uniqueId
result:(NSDictionary *)resultData
exts:(NSDictionary *)exts
completion:(void (^)(BOOL))completion;
/**
* 打开新页面(默认以push方式),混合栈推荐使用的用于操作页面的接口;通过urlParams可以设置为以present方式打开页面:urlParams:@{@"present":@(YES)}
*
* @param url 打开的页面资源定位符
* @param urlParams 传人页面的参数; 若有特殊逻辑,可以通过这个参数设置回调的id
* @param exts 额外参数
* @param resultCallback 当页面结束返回时执行的回调,通过这个回调可以取得页面的返回数据,如close函数传入的resultData
* @param completion 打开页面的即时回调,页面一旦打开即回调
*/
+ (void)open:(NSString *)url
urlParams:(NSDictionary *)urlParams
exts:(NSDictionary *)exts
onPageFinished:(void (^)(NSDictionary *))resultCallback
completion:(void (^)(BOOL))completion;
/**
* Present方式打开新页面,混合栈推荐使用的用于操作页面的接口
*
* @param url 打开的页面资源定位符
* @param urlParams 传人页面的参数; 若有特殊逻辑,可以通过这个参数设置回调的id
* @param exts 额外参数
* @param resultCallback 当页面结束返回时执行的回调,通过这个回调可以取得页面的返回数据,如close函数传入的resultData
* @param completion 打开页面的即时回调,页面一旦打开即回调
*/
+ (void)present:(NSString *)url
urlParams:(NSDictionary *)urlParams
exts:(NSDictionary *)exts
onPageFinished:(void (^)(NSDictionary *))resultCallback
completion:(void (^)(BOOL))completion;
```
IOS如何传递数据给flutter
```
//name是事件的名称,arguments中是一个NSDictionary,OC代码
[FlutterBoostPlugin.sharedInstance sendEvent:@"name" arguments:@{}];
//flutter部分接收数据,dart代码
FlutterBoost.singleton.channel.addEventListener('name',
(name, arguments){
//todo
return;
});
```
flutter如何传递数据给native
```
//flutter代码,ChannelName是通道名称与native部分一致即可,tmp是map类型的参数
Map<String,dynamic> tmp = Map<String,dynamic>();
try{
FlutterBoost.singleton.channel.sendEvent(ChannelName, tmp);
}catch(e){
}
//IOS侧代码
[FlutterBoostPlugin.sharedInstance addEventListener:^(NSString *name, NSDictionary *arguments) {
} forName:@"statistic"];
```
flutter中页面的生命周期管理
```
enum ContainerLifeCycle {
Init,
Appear,//已经出现,很遗憾的是如果在native部分present页面,这里是不会回调的。
WillDisappear,
Disappear,
Destroy,
Background,
Foreground
}
FlutterBoost.singleton.addBoostContainerLifeCycleObserver(//这个类是单例,再每个页面的initState方法中添加即可监听
(ContainerLifeCycle state, BoostContainerSettings settings) {
//setttings是配置,name表示页面的名称,建议一定要等到当前页面Appear状态的时候再做操作,
print(
'FlutterBoost.singleton.addBoostContainerLifeCycleObserver '+state.toString()+' '+settings.name);
},
);
```
关于flutter部分打开新页面的回调的一些坑。
```
FlutterBoost.singleton
.open(CoursePage.routeName, urlParams: {
}).then((Map<dynamic, dynamic> value) {
print(
'call me when page is finished. did recieve second route result $value');
//这个方法会优先于addBoostContainerLifeCycleObserver中的appear方法调用,所以说有些方法在这里调用,如果appear还没有出现的话就会有问题。
});
```
3、集成流程Android(待补充)
\ No newline at end of file
......@@ -5,18 +5,19 @@
<b></b><br>
<a href="README_CN.md">中文文档</a>
<a href="https://mp.weixin.qq.com/s?__biz=MzU4MDUxOTI5NA==&mid=2247484367&idx=1&sn=fcbc485f068dae5de9f68d52607ea08f&chksm=fd54d7deca235ec86249a9e3714ec18be8b2d6dc580cae19e4e5113533a6c5b44dfa5813c4c3&scene=0&subscene=131&clicktime=1551942425&ascene=7&devicetype=android-28&version=2700033b&nettype=ctnet&abtest_cookie=BAABAAoACwASABMABAAklx4AVpkeAMSZHgDWmR4AAAA%3D&lang=zh_CN&pass_ticket=1qvHqOsbLBHv3wwAcw577EHhNjg6EKXqTfnOiFbbbaw%3D&wx_header=1">中文介绍</a>
<a href="INTEGRATION.md">集成相关</a>
</p>
# Release Note
Please checkout the release note for the latest 0.1.64 to see changes [0.1.64 release note](https://github.com/alibaba/flutter_boost/releases)
Please checkout the release note for the latest 1.12.13+1 to see changes [1.12.13+1 release note](https://github.com/alibaba/flutter_boost/releases)
# FlutterBoost
A next-generation Flutter-Native hybrid solution. FlutterBoost is a Flutter plugin which enables hybrid integration of Flutter for your existing native apps with minimum efforts.The philosophy of FlutterBoost is to use Flutter as easy as using a WebView. Managing Native pages and Flutter pages at the same time is non-trivial in an existing App. FlutterBoost takes care of page resolution for you. The only thing you need to care about is the name of the page(usually could be an URL). 
<a name="bf647454"></a>
# Prerequisites
You need to add Flutter to your project before moving on.The version of the flutter SDK requires v1.9.1+hotfixes, or it will compile error.
You need to add Flutter to your project before moving on.The version of the flutter SDK requires to match boost's version, or it will compile error.
......@@ -24,13 +25,8 @@ You need to add Flutter to your project before moving on.The version of the flut
| Flutter Boost Version | Support Flutter SDK Version | Description | Support AndroidX? |
| --------------------- | --------------------------- | ------------------------------------------------------------ | ------------------ |
| 0.1.50 | 1.5.4-hotfixes | android if other flutter versions or branches will compile incorrectly. | No |
| 0.1.51-0.1.59 | 1.5.4-hotfixes | bugfix for 0.1.50. | No |
| 0.1.60 | 1.9.1-hotfixes | Android does not support andriodx if other flutter branches will compile incorrectly. | No |
| 0.1.61-0.1.69 | 1.9.1-hotfixes | bugfix for 0.1.60. | No |
| 0.1.63 | 1.9.1-hotfixes | If other branches will compile incorrectly. Synchronize with the 0.1.60 code, and bugfix also merge to this branch. | No |
| 1.9.1+2 | 1.9.1-hotfixes | Rename the version number and start supporting androidx by default | Yes |
| 1.12.13 | 1.12.13-hotfixes | supporting androidx | Yes |
| 1.12.13+1 | 1.12.13-hotfixes | supporting androidx | Yes |
......@@ -39,10 +35,7 @@ You need to add Flutter to your project before moving on.The version of the flut
| Flutter Boost branch | Support Flutter SDK Version | Description | Support AndroidX? |
| --------------------- | --------------------------- | ------------------------------------------------------------ | ------------------ |
| v1.9.1-hotfixes | 1.9.1-hotfixes | for androidx | Yes |
| task/task_v1.9.1_support_hotfixes| 1.9.1-hotfixes | for support | NO |
| v1.12.13-hotfixes | 1.12.13-hotfixes | for androidx | Yes |
| task/task_v1.12.13_support_hotfixes| 1.12.13-hotfixes | for support | NO |
# Getting Started
......@@ -56,14 +49,7 @@ androidx branch
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: ' 1.12.13'
```
support branch
```json
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: 'task/task_v1.12.13_support_hotfixes'
ref: '1.12.13+1'
```
......
......@@ -5,7 +5,7 @@
# Release Note
请查看最新版本0.1.64的release note 确认变更,[0.1.64 release note](https://github.com/alibaba/flutter_boost/releases)
请查看最新版本1.12.13+1的release note 确认变更,[1.12.13+1 release note](https://github.com/alibaba/flutter_boost/releases)
# FlutterBoost
......@@ -14,7 +14,7 @@
# 前置条件
在继续之前,您需要将Flutter集成到你现有的项目中。flutter sdk 的版本需要 v1.9.1-hotfixes,否则会编译失败.
在继续之前,您需要将Flutter集成到你现有的项目中。flutter sdk 的版本需要和boost版本适配,否则会编译失败.
# FAQ
请阅读这篇文章:
......@@ -24,25 +24,17 @@
| Flutter Boost 版本 | 支持的 Flutter SDK 版本 | Description | 是否支持 AndroidX? |
| ----------------------- | ----------------------- | ------------------------------------------------------------ | ------------------- |
| 0.1.50 | 1.5.4-hotfixes | android 如果其他 flutter 版本或者分支会编译错误。 | No |
| 0.1.51-0.1.59 | 1.5.4-hotfixes | 0.1.50 的 bugfix。 | No |
| 0.1.60 | 1.9.1-hotfixes | android 如果其他 flutter 分支会编译错误。 | No |
| 0.1.63 | 1.9.1-hotfixes | 和 0.1.60 代码同步, bugfix 也会合入该分支,如果其他分支会编译错误。 | No |
| 0.1.61-0.1.69 | 1.9.1-hotfixes | 0.1.60 的 bugfix。 | No |
| 1.9.1+2 | 1.9.1-hotfixes | 版本号重新命名,开始默认支持androidx | Yes |
| 1.12.13 | 1.12.13 -hotfixes | 支持androidx | Yes |
| 1.12.13+1 | 1.12.13 -hotfixes | 支持androidx | Yes |
| Flutter Boost 分支 | 支持的 Flutter SDK 版本 | Description | Support AndroidX? |
| Flutter Boost 分支 | 支持的 Flutter SDK 版本 | Description | 是否支持 AndroidX? |
| --------------------- | --------------------------- | ------------------------------------------------------------ | ------------------ |
| v1.9.1-hotfixes | 1.9.1-hotfixes | for androidx | Yes |
| task/task_v1.9.1_support_hotfixes| 1.9.1-hotfixes | for support | NO |
| v1.12.13-hotfixes | 1.12.13-hotfixes | for androidx | Yes |
| task/task_v1.12.13_support_hotfixes| 1.12.13-hotfixes | for support | NO |
# 安装
......@@ -56,15 +48,7 @@ androidx branch
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: '1.12.13'
```
support branch
```json
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: 'task/task_v1.12.13_support_hotfixes'
ref: '1.12.13+1'
```
......
......@@ -20,6 +20,7 @@
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
errors:
# treat missing required parameters as a warning (not a hint)
......@@ -38,9 +39,7 @@ analyzer:
# see https://github.com/dart-lang/sdk/issues/28463
- "lib/i18n/messages_*.dart"
- "lib/src/http/**"
- "example/**"
- "example_swift/**"
- "test/**"
linter:
rules:
# these rules are documented on and in the same order as
......@@ -60,6 +59,7 @@ linter:
- avoid_classes_with_only_static_members
# - avoid_double_and_int_checks # only useful when targeting JS runtime
- avoid_empty_else
- avoid_equals_and_hash_code_on_mutable_classes
- avoid_field_initializers_in_const_classes
- avoid_function_literals_in_foreach_calls
# - avoid_implementing_value_types # not yet tested
......@@ -67,7 +67,9 @@ linter:
# - avoid_js_rounded_ints # only useful when targeting JS runtime
- avoid_null_checks_in_equality_operators
# - avoid_positional_boolean_parameters # not yet tested
# - avoid_print # not yet tested
# - avoid_private_typedef_functions # we prefer having typedef (discussion in https://github.com/flutter/flutter/pull/16356)
# - avoid_redundant_argument_values # not yet tested
- avoid_relative_lib_imports
- avoid_renaming_method_parameters
- avoid_return_types_on_setters
......@@ -77,13 +79,16 @@ linter:
# - avoid_returning_this # there are plenty of valid reasons to return this
# - avoid_setters_without_getters # not yet tested
# - avoid_shadowing_type_parameters # not yet tested
# - avoid_single_cascade_in_expression_statements # not yet tested
- avoid_single_cascade_in_expression_statements
- avoid_slow_async_io
- avoid_types_as_parameter_names
# - avoid_types_on_closure_parameters # conflicts with always_specify_types
# - avoid_unnecessary_containers # not yet tested
- avoid_unused_constructor_parameters
- avoid_void_async
# - avoid_web_libraries_in_flutter # not yet tested
- await_only_futures
- camel_case_extensions
- camel_case_types
- cancel_subscriptions
# - cascade_invocations # not yet tested
......@@ -109,8 +114,11 @@ linter:
# - lines_longer_than_80_chars # not yet tested
- list_remove_unrelated_type
# - literal_only_boolean_expressions # too many false positives: https://github.com/dart-lang/sdk/issues/34181
# - missing_whitespace_between_adjacent_strings # not yet tested
- no_adjacent_strings_in_list
- no_duplicate_case_values
# - no_logic_in_create_state # not yet tested
# - no_runtimeType_toString # not yet tested
- non_constant_identifier_names
# - null_closures # not yet tested
# - omit_local_variable_types # opposite of always_specify_types
......@@ -136,9 +144,9 @@ linter:
- prefer_equal_for_default_values
# - prefer_expression_function_bodies # conflicts with https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#consider-using--for-short-functions-and-methods
- prefer_final_fields
# - prefer_final_in_for_each # not yet tested
- prefer_final_in_for_each
- prefer_final_locals
# - prefer_for_elements_to_map_fromIterable # not yet tested
- prefer_for_elements_to_map_fromIterable
- prefer_foreach
# - prefer_function_declarations_over_variables # not yet tested
- prefer_generic_function_type_aliases
......@@ -150,9 +158,11 @@ linter:
# - prefer_interpolation_to_compose_strings # not yet tested
- prefer_is_empty
- prefer_is_not_empty
- prefer_is_not_operator
- prefer_iterable_whereType
# - prefer_mixin # https://github.com/dart-lang/language/issues/32
# - prefer_null_aware_operators # disable until NNBD, see https://github.com/flutter/flutter/pull/32711#issuecomment-492930932
# - prefer_relative_imports # not yet tested
- prefer_single_quotes
- prefer_spread_collections
- prefer_typing_uninitialized_variables
......@@ -173,6 +183,7 @@ linter:
# - unnecessary_await_in_return # not yet tested
- unnecessary_brace_in_string_interps
- unnecessary_const
# - unnecessary_final # conflicts with prefer_final_locals
- unnecessary_getters_setters
# - unnecessary_lambdas # has false positives: https://github.com/dart-lang/linter/issues/498
- unnecessary_new
......@@ -181,14 +192,16 @@ linter:
- unnecessary_overrides
- unnecessary_parenthesis
- unnecessary_statements
# - unnecessary_string_interpolations
- unnecessary_this
- unrelated_type_equality_checks
# - unsafe_html # not yet tested
- use_full_hex_values_for_flutter_colors
# - use_function_type_syntax_for_parameters # not yet tested
# - use_key_in_widget_constructors # not yet tested
- use_rethrow_when_possible
# - use_setters_to_change_properties # not yet tested
# - use_string_buffers # has false positives: https://github.com/dart-lang/sdk/issues/34182
# - use_to_and_as_if_applicable # has false positives, so we prefer to catch this by code-review
- valid_regexps
# - void_checks # not yet tested
- void_checks
\ No newline at end of file
......@@ -176,7 +176,7 @@ public class FlutterBoost {
}
DartExecutor.DartEntrypoint entrypoint = new DartExecutor.DartEntrypoint(
FlutterMain.findAppBundlePath(),
"main"
mPlatform.dartEntrypoint()
);
flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
......@@ -265,6 +265,9 @@ public class FlutterBoost {
return ConfigBuilder.this.isDebug;
}
@Override
public String dartEntrypoint() { return ConfigBuilder.this.dartEntrypoint; }
@Override
public String initialRoute() {
return ConfigBuilder.this.initialRoute;
......
......@@ -38,6 +38,8 @@ public abstract class Platform {
public abstract boolean isDebug();
public abstract String dartEntrypoint();
public abstract String initialRoute();
public FlutterBoost.BoostLifecycleListener lifecycleListener;
......
......@@ -3,9 +3,11 @@ package com.taobao.idlefish.flutterboostexample;
import android.app.Application;
import android.content.Context;
import android.os.Build;
import android.util.Log;
import com.idlefish.flutterboost.*;
import java.util.HashMap;
import java.util.Map;
import com.idlefish.flutterboost.interfaces.INativeRouter;
......@@ -13,7 +15,7 @@ import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugin.common.StandardMessageCodec;
public class MyApplication extends Application {
......@@ -41,6 +43,26 @@ public class MyApplication extends Application {
@Override
public void onEngineCreated() {
// 注册MethodChannel,监听flutter侧的getPlatformVersion调用
MethodChannel methodChannel = new MethodChannel(FlutterBoost.instance().engineProvider().getDartExecutor(), "flutter_native_channel");
methodChannel.setMethodCallHandler((call, result) -> {
if (call.method.equals("getPlatformVersion")) {
result.success(Build.VERSION.RELEASE);
} else {
result.notImplemented();
}
});
// 注册PlatformView viewTypeId要和flutter中的viewType对应
FlutterBoost
.instance()
.engineProvider()
.getPlatformViewsController()
.getRegistry()
.registerViewFactory("plugins.test/view", new TextPlatformViewFactory(StandardMessageCodec.INSTANCE));
}
@Override
......
package com.taobao.idlefish.flutterboostexample;
import io.flutter.app.FlutterPluginRegistry;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.StandardMessageCodec;
public class TextPlatformViewPlugin {
public static void register(PluginRegistry.Registrar registrar) {
registrar.platformViewRegistry().registerViewFactory("plugins.test/view",
new TextPlatformViewFactory(StandardMessageCodec.INSTANCE));
}
}
......@@ -23,8 +23,22 @@
PlatformRouterImp *router = [PlatformRouterImp new];
[FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:router
onStart:^(FlutterEngine *engine) {
}];
// 注册MethodChannel,监听flutter侧的getPlatformVersion调用
FlutterMethodChannel *flutterMethodChannel = [FlutterMethodChannel methodChannelWithName:@"flutter_native_channel" binaryMessenger:engine.binaryMessenger];
[flutterMethodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
NSString *method = call.method;
if ([method isEqualToString:@"getPlatformVersion"]) {
NSString *sysVersion = [[UIDevice currentDevice] systemVersion];
result(sysVersion);
} else {
result(FlutterMethodNotImplemented);
}
}];
}];
self.window = [[UIWindow alloc] initWithFrame: [UIScreen mainScreen].bounds];
......
......@@ -16,20 +16,26 @@ class _MyAppState extends State<MyApp> {
void initState() {
super.initState();
FlutterBoost.singleton.registerPageBuilders({
'embeded': (pageName, params, _)=>EmbededFirstRouteWidget(),
'first': (pageName, params, _) => FirstRouteWidget(),
'firstFirst': (pageName, params, _) => FirstFirstRouteWidget(),
'second': (pageName, params, _) => SecondRouteWidget(),
'secondStateful': (pageName, params, _) => SecondStatefulRouteWidget(),
'tab': (pageName, params, _) => TabRouteWidget(),
'platformView': (pageName, params, _) => PlatformRouteWidget(),
'flutterFragment': (pageName, params, _) => FragmentRouteWidget(params),
FlutterBoost.singleton.registerPageBuilders(<String, PageBuilder>{
'embeded': (String pageName, Map<String, dynamic> params, String _) =>
EmbeddedFirstRouteWidget(),
'first': (String pageName, Map<String, dynamic> params, String _) => FirstRouteWidget(),
'firstFirst': (String pageName, Map<String, dynamic> params, String _) =>
FirstFirstRouteWidget(),
'second': (String pageName, Map<String, dynamic> params, String _) => SecondRouteWidget(),
'secondStateful': (String pageName, Map<String, dynamic> params, String _) =>
SecondStatefulRouteWidget(),
'tab': (String pageName, Map<String, dynamic> params, String _) => TabRouteWidget(),
'platformView': (String pageName, Map<String, dynamic> params, String _) =>
PlatformRouteWidget(),
'flutterFragment': (String pageName, Map<String, dynamic> params, String _) =>
FragmentRouteWidget(params),
///可以在native层通过 getContainerParams 来传递参数
'flutterPage': (pageName, params, _) {
print("flutterPage params:$params");
'flutterPage': (String pageName, Map<String, dynamic> params, String _) {
print('flutterPage params:$params');
return FlutterRouteWidget(params:params);
return FlutterRouteWidget(params: params);
},
});
FlutterBoost.singleton.addBoostNavigatorObserver(TestBoostNavigatorObserver());
......@@ -40,31 +46,36 @@ class _MyAppState extends State<MyApp> {
return MaterialApp(
title: 'Flutter Boost example',
builder: FlutterBoost.init(postPush: _onRoutePushed),
home: Container(
color:Colors.white
));
home: Container(color: Colors.white));
}
void _onRoutePushed(
String pageName, String uniqueId, Map params, Route route, Future _) {
}
String pageName,
String uniqueId,
Map<String, dynamic> params,
Route<dynamic> route,
Future<dynamic> _,
) {}
}
class TestBoostNavigatorObserver extends NavigatorObserver{
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didPush");
class TestBoostNavigatorObserver extends NavigatorObserver {
@override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
print('flutterboost#didPush');
}
@override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didPop");
print('flutterboost#didPop');
}
@override
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didRemove");
print('flutterboost#didRemove');
}
@override
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
print("flutterboost#didReplace");
print('flutterboost#didReplace');
}
}
......@@ -3,7 +3,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
typedef void TextViewCreatedCallback(TextViewController controller);
typedef TextViewCreatedCallback = void Function(TextViewController controller);
class TextView extends StatefulWidget {
const TextView({
......@@ -34,13 +34,13 @@ class _TextViewState extends State<TextView> {
if (widget.onTextViewCreated == null) {
return;
}
widget.onTextViewCreated(new TextViewController._(id));
widget.onTextViewCreated(TextViewController._(id));
}
}
class TextViewController {
TextViewController._(int id)
: _channel = new MethodChannel('plugins.felix.angelov/textview_$id');
: _channel = MethodChannel('plugins.felix.angelov/textview_$id');
final MethodChannel _channel;
......@@ -48,4 +48,4 @@ class TextViewController {
assert(text != null);
return _channel.invokeMethod('setText', text);
}
}
\ No newline at end of file
}
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_boost_example/platform_view.dart';
class FirstRouteWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new _FirstRouteWidgetState();
}
State<StatefulWidget> createState() => _FirstRouteWidgetState();
}
class _FirstRouteWidgetState extends State<FirstRouteWidget>{
class _FirstRouteWidgetState extends State<FirstRouteWidget> {
_FirstRouteWidgetState();
// flutter 侧MethodChannel配置,channel name需要和native侧一致
static const MethodChannel _methodChannel = MethodChannel('flutter_native_channel');
String _systemVersion = '';
Future<dynamic> _getPlatformVersion() async {
try {
final String result = await _methodChannel.invokeMethod('getPlatformVersion');
print('getPlatformVersion:' + result);
setState(() {
_systemVersion = result;
});
} on PlatformException catch (e) {
print(e.message);
}
}
@override
void initState() {
print('initState');
......@@ -45,80 +63,90 @@ class _FirstRouteWidgetState extends State<FirstRouteWidget>{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
appBar: AppBar(title: const Text('First Route')),
body: Center(
child:
Column(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children:
<Widget>[
children: <Widget>[
RaisedButton(
child: Text('Open native page'),
onPressed: () {
print("open natve page!");
FlutterBoost.singleton.open("native").then((Map value) {
print(
"call me when page is finished. did recieve native route result $value");
});
},
),
RaisedButton(
child: Text('Open FF route'),
onPressed: () {
print("open FF page!");
FlutterBoost.singleton.open("firstFirst").then((Map value) {
print(
"call me when page is finished. did recieve FF route result $value");
});
},
),
RaisedButton(
child: Text('Open second route1'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print(
"call me when page is finished. did recieve second route result $value");
});
},
),
RaisedButton(
child: Text('Present second stateful route'),
onPressed: () {
print("Present second stateful page!");
FlutterBoost.singleton.open("secondStateful",urlParams:<dynamic,dynamic>{"present":true}).then((Map value) {
print(
"call me when page is finished. did recieve second stateful route result $value");
});
},
),
RaisedButton(
child: Text('Present second route'),
onPressed: () {
print("Present second page!");
FlutterBoost.singleton.open("second",urlParams:<dynamic,dynamic>{"present":true}).then((Map value) {
print(
"call me when page is finished. did recieve second route result $value");
});
},
),
],
child: const Text('Open native page'),
onPressed: () {
print('open natve page!');
FlutterBoost.singleton
.open('native')
.then((Map<dynamic, dynamic> value) {
print(
'call me when page is finished. did recieve native route result $value');
});
},
),
RaisedButton(
child: const Text('Open FF route'),
onPressed: () {
print('open FF page!');
FlutterBoost.singleton
.open('firstFirst')
.then((Map<dynamic, dynamic> value) {
print(
'call me when page is finished. did recieve FF route result $value');
});
},
),
RaisedButton(
child: const Text('Open second route1'),
onPressed: () {
print('open second page!');
FlutterBoost.singleton
.open('second')
.then((Map<dynamic, dynamic> value) {
print(
'call me when page is finished. did recieve second route result $value');
});
},
),
RaisedButton(
child: const Text('Present second stateful route'),
onPressed: () {
print('Present second stateful page!');
FlutterBoost.singleton.open('secondStateful',
urlParams: <String, dynamic>{
'present': true
}).then((Map<dynamic, dynamic> value) {
print(
'call me when page is finished. did recieve second stateful route result $value');
});
},
),
RaisedButton(
child: const Text('Present second route'),
onPressed: () {
print('Present second page!');
FlutterBoost.singleton.open('second',
urlParams: <String, dynamic>{
'present': true
}).then((Map<dynamic, dynamic> value) {
print(
'call me when page is finished. did recieve second route result $value');
});
},
),
RaisedButton(
child: Text('Get system version by method channel:' + _systemVersion),
onPressed: () => _getPlatformVersion(),
),
],
),
),
);
}
}
class FirstFirstRouteWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return new _FirstFirstRouteWidgetState();
}
State<StatefulWidget> createState() => _FirstFirstRouteWidgetState();
}
class _FirstFirstRouteWidgetState extends State<FirstFirstRouteWidget>{
class _FirstFirstRouteWidgetState extends State<FirstFirstRouteWidget> {
_FirstFirstRouteWidgetState();
@override
......@@ -154,20 +182,18 @@ class _FirstFirstRouteWidgetState extends State<FirstFirstRouteWidget>{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
appBar: AppBar(title: const Text('First Route')),
body: Center(
child: RaisedButton(
child: Text('Open first route'),
child: const Text('Open first route'),
onPressed: () {
print("open first page again!");
FlutterBoost.singleton.open("first").then((Map value){
print("did recieve first route result");
print("did recieve first route result $value");
print('open first page again!');
FlutterBoost.singleton
.open('first')
.then((Map<dynamic, dynamic> value) {
print('did recieve first route result');
print('did recieve first route result $value');
});
},
),
),
......@@ -175,34 +201,33 @@ class _FirstFirstRouteWidgetState extends State<FirstFirstRouteWidget>{
}
}
class EmbededFirstRouteWidget extends StatefulWidget {
class EmbeddedFirstRouteWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _EmbededFirstRouteWidgetState();
}
State<StatefulWidget> createState() => _EmbeddedFirstRouteWidgetState();
}
class _EmbededFirstRouteWidgetState extends State<EmbededFirstRouteWidget> {
class _EmbeddedFirstRouteWidgetState extends State<EmbeddedFirstRouteWidget> {
@override
Widget build(BuildContext context) {
print('_EmbededFirstRouteWidgetState build called!');
return Scaffold(
body: Center(
child: RaisedButton(
child: Text('Open second route2'),
child: const Text('Open second route2'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print('open second page!');
FlutterBoost.singleton
.open('second')
.then((Map<dynamic, dynamic> value) {
print(
"call me when page is finished. did recieve second route result $value");
'call me when page is finished. did recieve second route result $value');
});
},
),
),
);
}
@override
void dispose() {
print('[XDEBUG]:_EmbededFirstRouteWidgetState disposing~');
......@@ -212,29 +237,24 @@ class _EmbededFirstRouteWidgetState extends State<EmbededFirstRouteWidget> {
class SecondStatefulRouteWidget extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return _SecondStatefulRouteWidgetState();
}
State<StatefulWidget> createState() => _SecondStatefulRouteWidgetState();
}
class _SecondStatefulRouteWidgetState extends State<SecondStatefulRouteWidget>{
class _SecondStatefulRouteWidgetState extends State<SecondStatefulRouteWidget> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("SecondStateful Route"),
),
appBar: AppBar(title: const Text('SecondStateful Route')),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
BoostContainerSettings settings =
final BoostContainerSettings settings =
BoostContainer.of(context).settings;
FlutterBoost.singleton.close(settings.uniqueId,
result: <dynamic,dynamic>{"result": "data from second"});
result: <String, dynamic>{'result': 'data from second'});
},
child: Text('Go back with result!'),
child: const Text('Go back with result!'),
),
),
);
......@@ -251,20 +271,19 @@ class SecondRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
appBar: AppBar(title: const Text('Second Route')),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
BoostContainerSettings settings =
final BoostContainerSettings settings =
BoostContainer.of(context).settings;
FlutterBoost.singleton.close(settings.uniqueId,
result: <dynamic,dynamic>{"result": "data from second"});
FlutterBoost.singleton.close(
settings.uniqueId,
result: <String, dynamic>{'result': 'data from second'},
);
},
child: Text('Go back with result!'),
child: const Text('Go back with result!'),
),
),
);
......@@ -275,15 +294,13 @@ class TabRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Tab Route"),
),
appBar: AppBar(title: const Text('Tab Route')),
body: Center(
child: RaisedButton(
onPressed: () {
FlutterBoost.singleton.open("second");
FlutterBoost.singleton.open('second');
},
child: Text('Open second route3'),
child: const Text('Open second route3'),
),
),
);
......@@ -294,17 +311,17 @@ class PlatformRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Text("Platform Route"),
),
appBar: AppBar(title: const Text('Platform Route')),
body: Center(
child: RaisedButton(
child: TextView(),
child: const TextView(),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print('open second page!');
FlutterBoost.singleton
.open('second')
.then((Map<dynamic, dynamic> value) {
print(
"call me when page is finished. did recieve second route result $value");
'call me when page is finished. did recieve second route result $value');
});
},
),
......@@ -312,9 +329,11 @@ class PlatformRouteWidget extends StatelessWidget {
);
}
}
class FlutterRouteWidget extends StatefulWidget {
FlutterRouteWidget({this.params,this.message});
final Map params;
const FlutterRouteWidget({this.params, this.message});
final Map<String, dynamic> params;
final String message;
@override
......@@ -322,190 +341,229 @@ class FlutterRouteWidget extends StatefulWidget {
}
class _FlutterRouteWidgetState extends State<FlutterRouteWidget> {
final TextEditingController _usernameController = TextEditingController();
// flutter 侧MethodChannel配置,channel name需要和native侧一致
static const MethodChannel _methodChannel = MethodChannel('flutter_native_channel');
String _systemVersion = '';
Future<dynamic> _getPlatformVersion() async {
try {
final String result = await _methodChannel.invokeMethod('getPlatformVersion');
print('getPlatformVersion:' + result);
setState(() {
_systemVersion = result;
});
} on PlatformException catch (e) {
print(e.message);
}
}
@override
Widget build(BuildContext context) {
final String message=widget.message;
final String message = widget.message;
return Scaffold(
appBar: AppBar(
brightness:Brightness.light,
brightness: Brightness.light,
backgroundColor: Colors.white,
textTheme:new TextTheme(title: TextStyle(color: Colors.black)) ,
title: Text('flutter_boost_example'),
textTheme: const TextTheme(title: TextStyle(color: Colors.black)),
title: const Text('flutter_boost_example'),
),
body: SingleChildScrollView(
child:Container(
margin: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 10.0,bottom: 20.0),
child: Text(
message ?? "This is a flutter activity \n params:${widget.params}",
style: TextStyle(fontSize: 28.0, color: Colors.blue),
child: Container(
margin: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 10.0, bottom: 20.0),
child: Text(
message ??
'This is a flutter activity \n params:${widget.params}',
style: TextStyle(fontSize: 28.0, color: Colors.blue),
),
alignment: AlignmentDirectional.center,
),
const CupertinoTextField(
prefix: Icon(
CupertinoIcons.person_solid,
color: CupertinoColors.lightBackgroundGray,
size: 28.0,
),
padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 12.0),
clearButtonMode: OverlayVisibilityMode.editing,
textCapitalization: TextCapitalization.words,
autocorrect: false,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 0.0, color: CupertinoColors.inactiveGray),
),
alignment: AlignmentDirectional.center,
),
// Expanded(child: Container()),
const CupertinoTextField(
prefix: Icon(
CupertinoIcons.person_solid,
color: CupertinoColors.lightBackgroundGray,
size: 28.0,
),
padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 12.0),
clearButtonMode: OverlayVisibilityMode.editing,
textCapitalization: TextCapitalization.words,
),
new TextField(
enabled: true,
autocorrect: true,
style: const TextStyle(
fontSize: 20.0,
color: const Color(0xFF222222),
fontWeight: FontWeight.w500),
), new TextField(
controller: new TextEditingController(),
focusNode:FocusNode(),
enabled: true,
autocorrect: false,
style: const TextStyle(
fontSize: 20.0,
color: const Color(0xFF222222),
fontWeight: FontWeight.w500),
placeholder: 'Name',
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: const Text(
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton
.open("sample://nativePage", urlParams: <dynamic,dynamic>{
"query": {"aaa": "bbb"}
}),
/// 后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
/// 例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton.open(
'sample://nativePage',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'}
},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open first',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton
.open("first", urlParams: <dynamic,dynamic>{
"query": {"aaa": "bbb"}
}),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: const Text(
'open first',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
/// 后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
/// 例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton.open(
'first',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'}
},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open second',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton
.open("second", urlParams:<dynamic,dynamic> {
"query": {"aaa": "bbb"}
}),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: const Text(
'open second',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open tab',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton
.open("tab", urlParams:<dynamic,dynamic> {
"query": {"aaa": "bbb"}
}),
/// 后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
/// 例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton.open(
'second',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'}
},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton
.open("sample://flutterPage", urlParams:<String,dynamic> {
"query": {"aaa": "bbb"}
}),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: const Text(
'open tab',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'push flutter widget',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () {
Navigator.push<dynamic>(context,
MaterialPageRoute<dynamic>(builder: (_) => PushWidget()));
/// 后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
/// 例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton.open(
'tab',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'}
},
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: const Text(
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
/// 后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
/// 例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton.open(
'sample://flutterPage',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'}
},
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: const Text(
'push flutter widget',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () {
Navigator.push<dynamic>(
context,
MaterialPageRoute<dynamic>(builder: (_) => PushWidget()),
);
},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: const Text(
'push Platform demo',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () {
Navigator.push<dynamic>(
context,
MaterialPageRoute<dynamic>(
builder: (_) => PlatformRouteWidget()),
);
},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: const Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () =>
FlutterBoost.singleton.open('sample://flutterFragmentPage'),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'push Platform demo',
'get system version by method channel:' + _systemVersion,
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () {
Navigator.push<dynamic>(context,
MaterialPageRoute<dynamic>(builder: (_) => PlatformRouteWidget()));
},
onTap: () => _getPlatformVersion(),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton
.open("sample://flutterFragmentPage"),
),
],
),
],
),
),
),
);
......@@ -513,23 +571,21 @@ class _FlutterRouteWidgetState extends State<FlutterRouteWidget> {
}
class FragmentRouteWidget extends StatelessWidget {
final Map params;
const FragmentRouteWidget(this.params);
FragmentRouteWidget(this.params);
final Map<String, dynamic> params;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutter_boost_example'),
),
appBar: AppBar(title: const Text('flutter_boost_example')),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 80.0),
child: Text(
"This is a flutter fragment",
'This is a flutter fragment',
style: TextStyle(fontSize: 28.0, color: Colors.blue),
),
alignment: AlignmentDirectional.center,
......@@ -537,7 +593,7 @@ class FragmentRouteWidget extends StatelessWidget {
Container(
margin: const EdgeInsets.only(top: 32.0),
child: Text(
params['tag'] ?? '',
'${params['tag']}' ?? '',
style: TextStyle(fontSize: 28.0, color: Colors.red),
),
alignment: AlignmentDirectional.center,
......@@ -545,37 +601,40 @@ class FragmentRouteWidget extends StatelessWidget {
Expanded(child: Container()),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton.open("sample://nativePage"),
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: const Text(
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () => FlutterBoost.singleton.open('sample://nativePage'),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton.open("sample://flutterPage"),
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: const Text(
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () => FlutterBoost.singleton.open('sample://flutterPage'),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 80.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 80.0),
color: Colors.yellow,
child: const Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () =>
FlutterBoost.singleton.open("sample://flutterFragmentPage"),
FlutterBoost.singleton.open('sample://flutterFragmentPage'),
)
],
),
......@@ -591,15 +650,8 @@ class PushWidget extends StatefulWidget {
class _PushWidgetState extends State<PushWidget> {
VoidCallback _backPressedListenerUnsub;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
// if (_backPressedListenerUnsub == null) {
......@@ -615,7 +667,6 @@ class _PushWidgetState extends State<PushWidget> {
@override
void dispose() {
// TODO: implement dispose
print('[XDEBUG] - PushWidget is disposing~');
super.dispose();
_backPressedListenerUnsub?.call();
......@@ -623,6 +674,6 @@ class _PushWidgetState extends State<PushWidget> {
@override
Widget build(BuildContext context) {
return FlutterRouteWidget(message: "Pushed Widget");
return const FlutterRouteWidget(message: 'Pushed Widget');
}
}
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget {
TestPage({Key key, this.title = "Input Test"}) : super(key: key);
const TestPage({
Key key,
this.title = 'Input Test',
}) : super(key: key);
final String title;
......@@ -18,95 +21,82 @@ class _TestPageState extends State<TestPage> {
});
}
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
appBar: AppBar(title: Text(widget.title)),
body: SafeArea(
bottom: false,
child: ListView(
children: <Widget>[
Container(
child: Text(
'You have pushed the button this many times:',
bottom: false,
child: ListView(
children: <Widget>[
Container(
child: const Text(
'You have pushed the button this many times:',
),
margin: const EdgeInsets.all(8.0),
alignment: Alignment.center,
),
margin: const EdgeInsets.all(8.0),
alignment: Alignment.center,
),
Container(
child: Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
Container(
child: Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
margin: const EdgeInsets.all(8.0),
alignment: Alignment.center,
),
margin: const EdgeInsets.all(8.0),
alignment: Alignment.center,
),
Container(
child: TextField(
minLines: 2,
maxLines: 10,
Container(
child: const TextField(minLines: 2, maxLines: 10),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
TestTextField(),
Container(
child: Container(
color: Colors.red,
width: double.infinity,
height: 128.0,
TestTextField(),
Container(
child: Container(
color: Colors.red,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.orange,
width: double.infinity,
height: 128.0,
Container(
child: Container(
color: Colors.orange,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.green,
width: double.infinity,
height: 128.0,
Container(
child: Container(
color: Colors.green,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.blue,
width: double.infinity,
height: 128.0,
Container(
child: Container(
color: Colors.blue,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.yellow,
width: double.infinity,
height: 128.0,
Container(
child: Container(
color: Colors.yellow,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: TextField(
minLines: 2,
maxLines: 10,
Container(
child: const TextField(minLines: 2, maxLines: 10),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
TestTextField(),
],
)),
TestTextField(),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
......@@ -123,22 +113,22 @@ class TestTextField extends StatefulWidget {
class _TestTextFieldState extends State<TestTextField> {
FocusNode _node;
PersistentBottomSheetController _controller;
PersistentBottomSheetController<dynamic> _controller;
@override
void initState() {
// TODO: implement initState
super.initState();
_node = FocusNode();
_node.addListener(() {
if (_node.hasFocus) {
print('showBottomSheet');
_controller = Scaffold.of(context)
.showBottomSheet<dynamic>((BuildContext ctx) => Container(
width: double.infinity,
height: 36.0,
color: Colors.deepPurple,
));
_controller = Scaffold.of(context).showBottomSheet<dynamic>(
(BuildContext ctx) => Container(
width: double.infinity,
height: 36.0,
color: Colors.deepPurple,
),
);
} else {
if (_controller != null) {
//Navigator.of(context).pop();
......
......@@ -6,13 +6,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import '../lib/main.dart';
import 'package:flutter_boost_example/main.dart';
void main() {
testWidgets('Verify Platform version', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(new MyApp());
await tester.pumpWidget(MyApp());
// Verify that platform version is retrieved.
expect(
......
......@@ -16,17 +16,22 @@ class _MyAppState extends State<MyApp> {
void initState() {
super.initState();
FlutterBoost.singleton.registerPageBuilders({
'first': (pageName, params, _) => FirstRouteWidget(),
'second': (pageName, params, _) => SecondRouteWidget(),
'tab': (pageName, params, _) => TabRouteWidget(),
'flutterFragment': (pageName, params, _) => FragmentRouteWidget(params),
FlutterBoost.singleton.registerPageBuilders(<String, PageBuilder>{
'first': (String pageName, Map<String, dynamic> params, String _) =>
FirstRouteWidget(),
'second': (String pageName, Map<String, dynamic> params, String _) =>
SecondRouteWidget(),
'tab': (String pageName, Map<String, dynamic> params, String _) =>
TabRouteWidget(),
'flutterFragment':
(String pageName, Map<String, dynamic> params, String _) =>
FragmentRouteWidget(params),
///可以在native层通过 getContainerParams 来传递参数
'flutterPage': (pageName, params, _) {
print("flutterPage params:$params");
'flutterPage': (String pageName, Map<String, dynamic> params, String _) {
print('flutterPage params:$params');
return FlutterRouteWidget();
return const FlutterRouteWidget();
},
});
}
......@@ -34,12 +39,17 @@ class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Boost example',
builder: FlutterBoost.init(postPush: _onRoutePushed),
home: Container());
title: 'Flutter Boost example',
builder: FlutterBoost.init(postPush: _onRoutePushed),
home: Container(),
);
}
void _onRoutePushed(
String pageName, String uniqueId, Map params, Route route, Future _) {
}
String pageName,
String uniqueId,
Map<String, dynamic> params,
Route<dynamic> route,
Future<dynamic> _,
) {}
}
......@@ -6,15 +6,18 @@ class FirstRouteWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
title: const Text('First Route'),
),
body: Center(
child: RaisedButton(
child: Text('Open second route'),
child: const Text('Open second route'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print("call me when page is finished. did recieve second route result $value");
print('open second page!');
FlutterBoost.singleton
.open('second')
.then((Map<dynamic, dynamic> value) {
print(
'call me when page is finished. did recieve second route result $value');
});
},
),
......@@ -28,19 +31,21 @@ class SecondRouteWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
title: const Text('Second Route'),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
BoostContainerSettings settings =
final BoostContainerSettings settings =
BoostContainer.of(context).settings;
FlutterBoost.singleton.close(settings.uniqueId,
result: <dynamic,dynamic>{"result": "data from second"});
FlutterBoost.singleton.close(
settings.uniqueId,
result: <String, dynamic>{'result': 'data from second'},
);
},
child: Text('Go back with result!'),
child: const Text('Go back with result!'),
),
),
);
......@@ -51,15 +56,13 @@ class TabRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Tab Route"),
),
appBar: AppBar(title: const Text('Tab Route')),
body: Center(
child: RaisedButton(
onPressed: () {
FlutterBoost.singleton.open("second");
FlutterBoost.singleton.open('second');
},
child: Text('Open second route'),
child: const Text('Open second route'),
),
),
);
......@@ -67,15 +70,15 @@ class TabRouteWidget extends StatelessWidget {
}
class FlutterRouteWidget extends StatelessWidget {
final String message;
const FlutterRouteWidget({this.message});
FlutterRouteWidget({this.message});
final String message;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutter_boost_example'),
title: const Text('flutter_boost_example'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
......@@ -83,7 +86,7 @@ class FlutterRouteWidget extends StatelessWidget {
Container(
margin: const EdgeInsets.only(top: 80.0),
child: Text(
message ?? "This is a flutter activity",
message ?? 'This is a flutter activity',
style: TextStyle(fontSize: 28.0, color: Colors.blue),
),
alignment: AlignmentDirectional.center,
......@@ -101,10 +104,12 @@ class FlutterRouteWidget extends StatelessWidget {
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () =>
FlutterBoost.singleton.open("sample://nativePage", urlParams: <dynamic,dynamic>{
"query": {"aaa": "bbb"}
}),
onTap: () => FlutterBoost.singleton.open(
'sample://nativePage',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'}
},
),
),
InkWell(
child: Container(
......@@ -118,36 +123,42 @@ class FlutterRouteWidget extends StatelessWidget {
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () =>
FlutterBoost.singleton.open("sample://flutterPage", urlParams: <dynamic,dynamic>{
"query": {"aaa": "bbb"}
}),
onTap: () => FlutterBoost.singleton.open(
'sample://flutterPage',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'},
},
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'push flutter widget',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'push flutter widget',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () {
Navigator.push<dynamic>(
context, MaterialPageRoute<dynamic>(builder: (_) => PushWidget()));
context,
MaterialPageRoute<dynamic>(builder: (_) => PushWidget()),
);
},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () =>
FlutterBoost.singleton.open("sample://flutterFragmentPage"),
FlutterBoost.singleton.open('sample://flutterFragmentPage'),
),
],
),
......@@ -156,15 +167,15 @@ class FlutterRouteWidget extends StatelessWidget {
}
class FragmentRouteWidget extends StatelessWidget {
final Map params;
const FragmentRouteWidget(this.params);
FragmentRouteWidget(this.params);
final Map<String, dynamic> params;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutter_boost_example'),
title: const Text('flutter_boost_example'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
......@@ -172,7 +183,7 @@ class FragmentRouteWidget extends StatelessWidget {
Container(
margin: const EdgeInsets.only(top: 80.0),
child: Text(
"This is a flutter fragment",
'This is a flutter fragment',
style: TextStyle(fontSize: 28.0, color: Colors.blue),
),
alignment: AlignmentDirectional.center,
......@@ -180,7 +191,7 @@ class FragmentRouteWidget extends StatelessWidget {
Container(
margin: const EdgeInsets.only(top: 32.0),
child: Text(
params['tag'] ?? '',
'${params['tag']}' ?? '',
style: TextStyle(fontSize: 28.0, color: Colors.red),
),
alignment: AlignmentDirectional.center,
......@@ -188,37 +199,40 @@ class FragmentRouteWidget extends StatelessWidget {
Expanded(child: Container()),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton.open("sample://nativePage"),
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () => FlutterBoost.singleton.open('sample://nativePage'),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton.open("sample://flutterPage"),
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () => FlutterBoost.singleton.open('sample://flutterPage'),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 80.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 80.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
onTap: () =>
FlutterBoost.singleton.open("sample://flutterFragmentPage"),
FlutterBoost.singleton.open('sample://flutterFragmentPage'),
)
],
),
......@@ -234,15 +248,8 @@ class PushWidget extends StatefulWidget {
class _PushWidgetState extends State<PushWidget> {
VoidCallback _backPressedListenerUnsub;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
super.didChangeDependencies();
// if (_backPressedListenerUnsub == null) {
......@@ -258,13 +265,12 @@ class _PushWidgetState extends State<PushWidget> {
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_backPressedListenerUnsub?.call();
}
@override
Widget build(BuildContext context) {
return FlutterRouteWidget(message: "Pushed Widget");
return const FlutterRouteWidget(message: 'Pushed Widget');
}
}
import 'package:flutter/material.dart';
class TestPage extends StatefulWidget {
TestPage({Key key, this.title = "Input Test"}) : super(key: key);
const TestPage({
Key key,
this.title = 'Input Test',
}) : super(key: key);
final String title;
......@@ -18,100 +21,87 @@ class _TestPageState extends State<TestPage> {
});
}
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
appBar: AppBar(title: Text(widget.title)),
body: SafeArea(
bottom: false,
child: ListView(
children: <Widget>[
Container(
child: Text(
'You have pushed the button this many times:',
bottom: false,
child: ListView(
children: <Widget>[
Container(
child: const Text(
'You have pushed the button this many times:',
),
margin: const EdgeInsets.all(8.0),
alignment: Alignment.center,
),
margin: const EdgeInsets.all(8.0),
alignment: Alignment.center,
),
Container(
child: Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
Container(
child: Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
margin: const EdgeInsets.all(8.0),
alignment: Alignment.center,
),
margin: const EdgeInsets.all(8.0),
alignment: Alignment.center,
),
Container(
child: TextField(
minLines: 2,
maxLines: 10,
Container(
child: const TextField(minLines: 2, maxLines: 10),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
TestTextField(),
Container(
child: Container(
color: Colors.red,
width: double.infinity,
height: 128.0,
TestTextField(),
Container(
child: Container(
color: Colors.red,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.orange,
width: double.infinity,
height: 128.0,
Container(
child: Container(
color: Colors.orange,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.green,
width: double.infinity,
height: 128.0,
Container(
child: Container(
color: Colors.green,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.blue,
width: double.infinity,
height: 128.0,
Container(
child: Container(
color: Colors.blue,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: Container(
color: Colors.yellow,
width: double.infinity,
height: 128.0,
Container(
child: Container(
color: Colors.yellow,
width: double.infinity,
height: 128.0,
),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
Container(
child: TextField(
minLines: 2,
maxLines: 10,
Container(
child: const TextField(minLines: 2, maxLines: 10),
padding: const EdgeInsets.all(8.0),
),
padding: const EdgeInsets.all(8.0),
),
TestTextField(),
],
)),
TestTextField(),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
),
);
}
}
......@@ -123,25 +113,24 @@ class TestTextField extends StatefulWidget {
class _TestTextFieldState extends State<TestTextField> {
FocusNode _node;
PersistentBottomSheetController _controller;
PersistentBottomSheetController<dynamic> _controller;
@override
void initState() {
// TODO: implement initState
super.initState();
_node = FocusNode();
_node.addListener(() {
if (_node.hasFocus) {
print('showBottomSheet');
_controller = Scaffold.of(context)
.showBottomSheet<dynamic>((BuildContext ctx) => Container(
width: double.infinity,
height: 36.0,
color: Colors.deepPurple,
));
_controller = Scaffold.of(context).showBottomSheet<dynamic>(
(BuildContext ctx) => Container(
width: double.infinity,
height: 36.0,
color: Colors.deepPurple,
),
);
} else {
if (_controller != null) {
//Navigator.of(context).pop();
print('closeBottomSheet');
_controller.close();
}
......
......@@ -24,30 +24,30 @@
import 'dart:async';
import 'dart:ui';
import 'package:flutter/services.dart';
typedef Future<dynamic> EventListener(String name, Map arguments);
typedef Future<dynamic> MethodHandler(MethodCall call);
import 'package:flutter/services.dart';
class BoostChannel {
final MethodChannel _methodChannel = MethodChannel("flutter_boost");
typedef EventListener = Future<dynamic> Function(
String name, Map<String, dynamic> arguments);
final Map<String, List<EventListener>> _eventListeners = Map();
final Set<MethodHandler> _methodHandlers = Set();
typedef MethodHandler = Future<dynamic> Function(MethodCall call);
class BoostChannel {
BoostChannel() {
_methodChannel.setMethodCallHandler((MethodCall call) {
if (call.method == "__event__") {
String name = call.arguments["name"];
Map arg = call.arguments["arguments"];
List<EventListener> list = _eventListeners[name];
if (call.method == '__event__') {
final String name = call.arguments['name'] as String;
final Map<String, dynamic> arg =
(call.arguments['arguments'] as Map<dynamic, dynamic>)
?.cast<String, dynamic>();
final List<EventListener> list = _eventListeners[name];
if (list != null) {
for (EventListener l in list) {
for (final EventListener l in list) {
l(name, arg);
}
}
} else {
for (MethodHandler handler in _methodHandlers) {
for (final MethodHandler handler in _methodHandlers) {
handler(call);
}
}
......@@ -56,37 +56,41 @@ class BoostChannel {
});
}
void sendEvent(String name, Map arguments) {
final MethodChannel _methodChannel = const MethodChannel('flutter_boost');
final Map<String, List<EventListener>> _eventListeners =
<String, List<EventListener>>{};
final Set<MethodHandler> _methodHandlers = <MethodHandler>{};
void sendEvent(String name, Map<String, dynamic> arguments) {
if (name == null) {
return;
}
if (arguments == null) {
arguments = Map<dynamic, dynamic>();
}
arguments ??= <String, dynamic>{};
Map msg = Map<dynamic, dynamic>();
msg["name"] = name;
msg["arguments"] = arguments;
_methodChannel.invokeMethod<dynamic>("__event__", msg);
final Map<String, dynamic> msg = <String, dynamic>{};
msg['name'] = name;
msg['arguments'] = arguments;
_methodChannel.invokeMethod<dynamic>('__event__', msg);
}
Future<T> invokeMethod<T>(String method, [dynamic arguments]) async {
assert(method != "__event__");
assert(method != '__event__');
return _methodChannel.invokeMethod<T>(method, arguments);
}
Future<List<T>> invokeListMethod<T>(String method,
[dynamic arguments]) async {
assert(method != "__event__");
assert(method != '__event__');
return _methodChannel.invokeListMethod<T>(method, arguments);
}
Future<Map<K, V>> invokeMapMethod<K, V>(String method,
[dynamic arguments]) async {
assert(method != "__event__");
assert(method != '__event__');
return _methodChannel.invokeMapMethod<K, V>(method, arguments);
}
......@@ -94,9 +98,11 @@ class BoostChannel {
VoidCallback addEventListener(String name, EventListener listener) {
assert(name != null && listener != null);
List<EventListener> list = _eventListeners[name];
List<EventListener> list;
list = _eventListeners[name];
if (list == null) {
list = List();
list = <EventListener>[];
_eventListeners[name] = list;
}
......
......@@ -22,10 +22,11 @@
* THE SOFTWARE.
*/
import 'package:flutter/material.dart';
import 'container_manager.dart';
import '../flutter_boost.dart';
import 'boost_page_route.dart';
import '../support/logger.dart';
import 'boost_page_route.dart';
import 'container_manager.dart';
enum ContainerLifeCycle {
Init,
......@@ -37,28 +38,31 @@ enum ContainerLifeCycle {
Foreground
}
typedef void BoostContainerLifeCycleObserver(
ContainerLifeCycle state, BoostContainerSettings settings);
typedef BoostContainerLifeCycleObserver = void Function(
ContainerLifeCycle state,
BoostContainerSettings settings,
);
class BoostContainer extends Navigator {
final BoostContainerSettings settings;
const BoostContainer(
{GlobalKey<BoostContainerState> key,
this.settings = const BoostContainerSettings(),
String initialRoute,
RouteFactory onGenerateRoute,
RouteFactory onUnknownRoute,
List<NavigatorObserver> observers})
: super(
key: key,
initialRoute: initialRoute,
onGenerateRoute: onGenerateRoute,
onUnknownRoute: onUnknownRoute,
observers: observers);
factory BoostContainer.copy(Navigator navigator,
[BoostContainerSettings settings = const BoostContainerSettings()]) =>
const BoostContainer({
GlobalKey<BoostContainerState> key,
this.settings = const BoostContainerSettings(),
String initialRoute,
RouteFactory onGenerateRoute,
RouteFactory onUnknownRoute,
List<NavigatorObserver> observers,
}) : super(
key: key,
initialRoute: initialRoute,
onGenerateRoute: onGenerateRoute,
onUnknownRoute: onUnknownRoute,
observers: observers,
);
factory BoostContainer.copy(
Navigator navigator, [
BoostContainerSettings settings = const BoostContainerSettings(),
]) =>
BoostContainer(
key: GlobalKey<BoostContainerState>(),
settings: settings,
......@@ -69,28 +73,34 @@ class BoostContainer extends Navigator {
);
factory BoostContainer.obtain(
Navigator navigator, BoostContainerSettings settings) =>
Navigator navigator,
BoostContainerSettings settings,
) =>
BoostContainer(
key: GlobalKey<BoostContainerState>(),
settings: settings,
onGenerateRoute: (RouteSettings routeSettings) {
if (routeSettings.name == '/') {
return BoostPageRoute<dynamic>(
pageName: settings.name,
params: settings.params,
uniqueId: settings.uniqueId,
animated: false,
settings: routeSettings,
builder: settings.builder);
} else {
return navigator.onGenerateRoute(routeSettings);
}
},
observers: <NavigatorObserver>[
ContainerNavigatorObserver.bindContainerManager(),
HeroController(),
],
onUnknownRoute: navigator.onUnknownRoute);
key: GlobalKey<BoostContainerState>(),
settings: settings,
onGenerateRoute: (RouteSettings routeSettings) {
if (routeSettings.name == '/') {
return BoostPageRoute<dynamic>(
pageName: settings.name,
params: settings.params,
uniqueId: settings.uniqueId,
animated: false,
settings: routeSettings,
builder: settings.builder,
);
} else {
return navigator.onGenerateRoute(routeSettings);
}
},
observers: <NavigatorObserver>[
ContainerNavigatorObserver.bindContainerManager(),
HeroController(),
],
onUnknownRoute: navigator.onUnknownRoute,
);
final BoostContainerSettings settings;
@override
BoostContainerState createState() => BoostContainerState();
......@@ -121,7 +131,7 @@ class BoostContainerState extends NavigatorState {
String get name => widget.settings.name;
Map get params => widget.settings.params;
Map<String, dynamic> get params => widget.settings.params;
BoostContainerSettings get settings => widget.settings;
......@@ -138,7 +148,7 @@ class BoostContainerState extends NavigatorState {
ContainerNavigatorObserver findContainerNavigatorObserver(
Navigator navigator) {
for (NavigatorObserver observer in navigator.observers) {
for (final NavigatorObserver observer in navigator.observers) {
if (observer is ContainerNavigatorObserver) {
return observer;
}
......@@ -153,11 +163,6 @@ class BoostContainerState extends NavigatorState {
backPressedHandler = () => maybePop();
}
@override
void didUpdateWidget(Navigator oldWidget) {
super.didUpdateWidget(oldWidget);
}
@override
void dispose() {
routerHistory.clear();
......@@ -172,7 +177,7 @@ class BoostContainerState extends NavigatorState {
@override
Future<bool> maybePop<T extends Object>([T result]) async {
final Route<T> route = routerHistory.last;
final Route<T> route = routerHistory.last as Route<T>;
final RoutePopDisposition disposition = await route.willPop();
if (mounted) {
switch (disposition) {
......@@ -199,7 +204,7 @@ class BoostContainerState extends NavigatorState {
}
if (canPop()) {
super.pop<T>(result);
super.pop<T>(result);
} else {
if (T is Map<String, dynamic>) {
FlutterBoost.singleton
......@@ -216,10 +221,10 @@ class BoostContainerState extends NavigatorState {
Route<T> newRoute;
if (FlutterBoost.containerManager.prePushRoute != null) {
newRoute = FlutterBoost.containerManager
.prePushRoute(name, uniqueId, params, route);
.prePushRoute<T>(name, uniqueId, params, route);
}
Future<T> future = super.push<T>(newRoute ?? route);
final Future<T> future = super.push<T>(newRoute ?? route);
routerHistory.add(route);
......@@ -233,25 +238,30 @@ class BoostContainerState extends NavigatorState {
VoidCallback addLifeCycleObserver(BoostContainerLifeCycleObserver observer) {
return FlutterBoost.singleton.addBoostContainerLifeCycleObserver(
(ContainerLifeCycle state, BoostContainerSettings settings) {
if (settings.uniqueId == uniqueId) {
observer(state, settings);
}
});
(
ContainerLifeCycle state,
BoostContainerSettings settings,
) {
if (settings.uniqueId == uniqueId) {
observer(state, settings);
}
},
);
}
}
class BoostContainerSettings {
const BoostContainerSettings({
this.uniqueId = 'default',
this.name = 'default',
this.params,
this.builder,
});
final String uniqueId;
final String name;
final Map params;
final Map<String, dynamic> params;
final WidgetBuilder builder;
const BoostContainerSettings(
{this.uniqueId = 'default',
this.name = 'default',
this.params,
this.builder});
}
class ContainerElement extends StatefulElement {
......@@ -259,13 +269,13 @@ class ContainerElement extends StatefulElement {
}
class ContainerNavigatorObserver extends NavigatorObserver {
static final Set<NavigatorObserver> boostObservers = Set<NavigatorObserver>();
ContainerNavigatorObserver();
factory ContainerNavigatorObserver.bindContainerManager() =>
ContainerNavigatorObserver();
static final Set<NavigatorObserver> boostObservers = <NavigatorObserver>{};
VoidCallback addBoostNavigatorObserver(NavigatorObserver observer) {
boostObservers.add(observer);
......@@ -278,28 +288,28 @@ class ContainerNavigatorObserver extends NavigatorObserver {
@override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
for (NavigatorObserver observer in boostObservers) {
for (final NavigatorObserver observer in boostObservers) {
observer.didPush(route, previousRoute);
}
}
@override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
for (NavigatorObserver observer in boostObservers) {
for (final NavigatorObserver observer in boostObservers) {
observer.didPop(route, previousRoute);
}
}
@override
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
for (NavigatorObserver observer in boostObservers) {
for (final NavigatorObserver observer in boostObservers) {
observer.didRemove(route, previousRoute);
}
}
@override
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
for (NavigatorObserver observer in boostObservers) {
for (final NavigatorObserver observer in boostObservers) {
observer.didReplace(newRoute: newRoute, oldRoute: oldRoute);
}
}
......
......@@ -25,26 +25,25 @@
import 'package:flutter/widgets.dart';
import 'package:flutter/material.dart';
typedef Widget PageBuilder(String pageName, Map params, String uniqueId);
typedef PageBuilder = Widget Function(
String pageName, Map<String, dynamic> params, String uniqueId);
class BoostPageRoute<T> extends MaterialPageRoute<T> {
BoostPageRoute({
this.pageName,
this.params,
this.uniqueId,
this.animated,
WidgetBuilder builder,
RouteSettings settings,
}) : super(builder: builder, settings: settings);
final String pageName;
final String uniqueId;
final Map params;
final Map<String, dynamic> params;
final bool animated;
final WidgetBuilder builder;
final RouteSettings settings;
final Set<VoidCallback> backPressedListeners = Set<VoidCallback>();
BoostPageRoute(
{this.pageName,
this.params,
this.uniqueId,
this.animated,
this.builder,
this.settings})
: super(builder: builder, settings: settings);
final Set<VoidCallback> backPressedListeners = <VoidCallback>{};
static BoostPageRoute<T> of<T>(BuildContext context) {
final Route<T> route = ModalRoute.of(context);
......
......@@ -27,12 +27,25 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';
import 'package:flutter/services.dart';
import '../channel/boost_channel.dart';
import 'boost_container.dart';
import '../flutter_boost.dart';
import '../support/logger.dart';
import 'boost_container.dart';
class ContainerCoordinator {
ContainerCoordinator(BoostChannel channel) : assert(_instance == null) {
_instance = this;
channel
..addEventListener(
'lifecycle',
(String name, Map<String, dynamic> arguments) =>
_onChannelEvent(arguments),
)
..addMethodHandler((MethodCall call) => _onMethodCall(call));
}
static ContainerCoordinator get singleton => _instance;
static ContainerCoordinator _instance;
......@@ -40,19 +53,11 @@ class ContainerCoordinator {
final Map<String, PageBuilder> _pageBuilders = <String, PageBuilder>{};
PageBuilder _defaultPageBuilder;
ContainerCoordinator(BoostChannel channel) {
assert(_instance == null);
_instance = this;
channel.addEventListener("lifecycle",
(String name, Map arguments) => _onChannelEvent(arguments));
channel.addMethodHandler((MethodCall call) => _onMethodCall(call));
}
BoostContainerSettings _createContainerSettings(
String name, Map params, String pageId) {
String name,
Map<String, dynamic> params,
String pageId,
) {
Widget page;
final BoostContainerSettings routeSettings = BoostContainerSettings(
......@@ -60,12 +65,12 @@ class ContainerCoordinator {
name: name,
params: params,
builder: (BuildContext ctx) {
//Try to build a page using keyed builder.
// Try to build a page using keyed builder.
if (_pageBuilders[name] != null) {
page = _pageBuilders[name](name, params, pageId);
}
//Build a page using default builder.
// Build a page using default builder.
if (page == null && _defaultPageBuilder != null) {
page = _defaultPageBuilder(name, params, pageId);
}
......@@ -79,12 +84,12 @@ class ContainerCoordinator {
return routeSettings;
}
//Register a default page builder.
/// Register a default page builder.
void registerDefaultPageBuilder(PageBuilder builder) {
_defaultPageBuilder = builder;
}
//Register page builder for a key.
/// Register page builder for a key.
void registerPageBuilder(String pageName, PageBuilder builder) {
if (pageName != null && builder != null) {
_pageBuilders[pageName] = builder;
......@@ -98,41 +103,35 @@ class ContainerCoordinator {
}
Future<dynamic> _onChannelEvent(dynamic event) {
if (event is Map) {
Map map = event;
final String type = map['type'];
if (event is Map<String, dynamic>) {
final Map<String, dynamic> map = event;
final String type = map['type'] as String;
Logger.log('onEvent $type');
switch (type) {
//Handler back key pressed event.
// Handler back key pressed event.
case 'backPressedCallback':
{
final String id = map['uniqueId'];
FlutterBoost.containerManager
?.containerStateOf(id)
?.performBackPressed();
}
final String id = map['uniqueId'] as String;
FlutterBoost.containerManager
?.containerStateOf(id)
?.performBackPressed();
break;
//Enter foregroud
// Enter foreground
case 'foreground':
{
FlutterBoost.containerManager?.setForeground();
}
FlutterBoost.containerManager?.setForeground();
break;
//Enter background
// Enter background
case 'background':
{
FlutterBoost.containerManager?.setBackground();
}
FlutterBoost.containerManager?.setBackground();
break;
//Schedule a frame.
// Schedule a frame.
case 'scheduleFrame':
{
WidgetsBinding.instance.scheduleForcedFrame();
Future<dynamic>.delayed(Duration(milliseconds: 250),
() => WidgetsBinding.instance.scheduleFrame());
}
WidgetsBinding.instance.scheduleForcedFrame();
Future<dynamic>.delayed(
const Duration(milliseconds: 250),
() => WidgetsBinding.instance.scheduleFrame(),
);
break;
}
}
......@@ -141,72 +140,52 @@ class ContainerCoordinator {
}
Future<dynamic> _onMethodCall(MethodCall call) {
Logger.log("onMetohdCall ${call.method}");
Logger.log('onMetohdCall ${call.method}');
final String pageName = call.arguments['pageName'] as String;
final Map<String, dynamic> params =
(call.arguments['params'] as Map<dynamic, dynamic>)
?.cast<String, dynamic>();
final String uniqueId = call.arguments['uniqueId'] as String;
switch (call.method) {
case "didInitPageContainer":
{
String pageName = call.arguments["pageName"];
Map params = call.arguments["params"];
String uniqueId = call.arguments["uniqueId"];
_nativeContainerDidInit(pageName, params, uniqueId);
}
case 'didInitPageContainer':
_nativeContainerDidInit(pageName, params, uniqueId);
break;
case "willShowPageContainer":
{
String pageName = call.arguments["pageName"];
Map params = call.arguments["params"];
String uniqueId = call.arguments["uniqueId"];
_nativeContainerWillShow(pageName, params, uniqueId);
}
case 'willShowPageContainer':
_nativeContainerWillShow(pageName, params, uniqueId);
break;
case "didShowPageContainer":
{
String pageName = call.arguments["pageName"];
Map params = call.arguments["params"];
String uniqueId = call.arguments["uniqueId"];
nativeContainerDidShow(pageName, params, uniqueId);
}
case 'didShowPageContainer':
nativeContainerDidShow(pageName, params, uniqueId);
break;
case "willDisappearPageContainer":
{
String pageName = call.arguments["pageName"];
Map params = call.arguments["params"];
String uniqueId = call.arguments["uniqueId"];
_nativeContainerWillDisappear(pageName, params, uniqueId);
}
case 'willDisappearPageContainer':
_nativeContainerWillDisappear(pageName, params, uniqueId);
break;
case "didDisappearPageContainer":
{
String pageName = call.arguments["pageName"];
Map params = call.arguments["params"];
String uniqueId = call.arguments["uniqueId"];
_nativeContainerDidDisappear(pageName, params, uniqueId);
}
case 'didDisappearPageContainer':
_nativeContainerDidDisappear(pageName, params, uniqueId);
break;
case "willDeallocPageContainer":
{
String pageName = call.arguments["pageName"];
Map params = call.arguments["params"];
String uniqueId = call.arguments["uniqueId"];
_nativeContainerWillDealloc(pageName, params, uniqueId);
}
case 'willDeallocPageContainer':
_nativeContainerWillDealloc(pageName, params, uniqueId);
break;
case "onNativePageResult":
{}
case 'onNativePageResult':
break;
}
return Future<dynamic>(() {});
}
bool _nativeContainerWillShow(String name, Map params, String pageId) {
bool _nativeContainerWillShow(
String name,
Map<String, dynamic> params,
String pageId,
) {
if (FlutterBoost.containerManager?.containsContainer(pageId) != true) {
FlutterBoost.containerManager
?.pushContainer(_createContainerSettings(name, params, pageId));
FlutterBoost.containerManager?.pushContainer(
_createContainerSettings(name, params, pageId),
);
}
//TODO, 需要验证android代码是否也可以移到这里
// TODO(unknown): 需要验证android代码是否也可以移到这里
if (Platform.isIOS) {
try {
final SemanticsOwner owner =
......@@ -221,72 +200,114 @@ class ContainerCoordinator {
return true;
}
bool nativeContainerDidShow(String name, Map params, String pageId) {
bool nativeContainerDidShow(
String name,
Map<String, dynamic> params,
String pageId,
) {
FlutterBoost.containerManager
?.showContainer(_createContainerSettings(name, params, pageId));
//对无障碍辅助模式的兼容
try {
final SemanticsOwner owner =
WidgetsBinding.instance.pipelineOwner?.semanticsOwner;
final SemanticsNode root = owner?.rootSemanticsNode;
root?.detach();
root?.attach(owner);
} catch (e) {
assert(false, e.toString());
// Compatible to accessibility mode on Android.
if (Platform.isAndroid) {
try {
final SemanticsOwner owner =
WidgetsBinding.instance.pipelineOwner?.semanticsOwner;
final SemanticsNode root = owner?.rootSemanticsNode;
root?.detach();
root?.attach(owner);
} catch (e) {
assert(false, e.toString());
}
}
performContainerLifeCycle(_createContainerSettings(name, params, pageId),
ContainerLifeCycle.Appear);
performContainerLifeCycle(
_createContainerSettings(name, params, pageId),
ContainerLifeCycle.Appear,
);
Logger.log(
'native containner did show-$name,\nmanager dump:\n${FlutterBoost.containerManager?.dump()}');
'native containner did show-$name,\n'
'manager dump:\n'
'${FlutterBoost.containerManager?.dump()}',
);
return true;
}
bool _nativeContainerWillDisappear(String name, Map params, String pageId) {
performContainerLifeCycle(_createContainerSettings(name, params, pageId),
ContainerLifeCycle.WillDisappear);
bool _nativeContainerWillDisappear(
String name,
Map<String, dynamic> params,
String pageId,
) {
performContainerLifeCycle(
_createContainerSettings(name, params, pageId),
ContainerLifeCycle.WillDisappear,
);
return true;
}
bool _nativeContainerDidDisappear(String name, Map params, String pageId) {
performContainerLifeCycle(_createContainerSettings(name, params, pageId),
ContainerLifeCycle.Disappear);
bool _nativeContainerDidDisappear(
String name,
Map<String, dynamic> params,
String pageId,
) {
performContainerLifeCycle(
_createContainerSettings(name, params, pageId),
ContainerLifeCycle.Disappear,
);
return true;
}
bool _nativeContainerDidInit(String name, Map params, String pageId) {
performContainerLifeCycle(_createContainerSettings(name, params, pageId),
ContainerLifeCycle.Init);
bool _nativeContainerDidInit(
String name,
Map<String, dynamic> params,
String pageId,
) {
performContainerLifeCycle(
_createContainerSettings(name, params, pageId),
ContainerLifeCycle.Init,
);
return true;
}
bool _nativeContainerWillDealloc(String name, Map params, String pageId) {
bool _nativeContainerWillDealloc(
String name, Map<String, dynamic> params, String pageId) {
try {
performContainerLifeCycle(_createContainerSettings(name, params, pageId),
ContainerLifeCycle.Destroy);
performContainerLifeCycle(
_createContainerSettings(name, params, pageId),
ContainerLifeCycle.Destroy,
);
} catch (e) {
Logger.log('nativeContainerWillDealloc error: $e');
}
FlutterBoost.containerManager?.remove(pageId);
Logger.log(
'native containner dealloc for $name, \n manager dump:\n${FlutterBoost.containerManager?.dump()}');
'native containner dealloc for $name, \n'
'manager dump:\n'
'${FlutterBoost.containerManager?.dump()}',
);
return true;
}
static void performContainerLifeCycle(
BoostContainerSettings settings, ContainerLifeCycle lifeCycle) {
for (BoostContainerLifeCycleObserver observer in FlutterBoost
BoostContainerSettings settings,
ContainerLifeCycle lifeCycle,
) {
final Set<BoostContainerLifeCycleObserver> observers = FlutterBoost
.singleton.observersHolder
.observersOf<BoostContainerLifeCycleObserver>()) {
.observersOf<BoostContainerLifeCycleObserver>();
for (final BoostContainerLifeCycleObserver observer in observers) {
observer(lifeCycle, settings);
}
Logger.log(
'BoostContainerLifeCycleObserver container:${settings.name} lifeCycle:$lifeCycle');
'BoostContainerLifeCycleObserver'
'container:${settings.name}'
'lifeCycle:$lifeCycle',
);
}
}
......@@ -23,10 +23,11 @@
*/
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'boost_container.dart';
import 'container_coordinator.dart';
import '../flutter_boost.dart';
import '../support/logger.dart';
import 'boost_container.dart';
import 'container_coordinator.dart';
enum ContainerOperation { Push, Onstage, Pop, Remove }
......@@ -35,12 +36,16 @@ typedef BoostContainerObserver = void Function(
@immutable
class BoostContainerManager extends StatefulWidget {
const BoostContainerManager({
Key key,
this.initNavigator,
this.prePushRoute,
this.postPushRoute,
}) : super(key: key);
final Navigator initNavigator;
final PrePushRoute prePushRoute;
final PostPushRoute postPushRoute;
const BoostContainerManager(
{Key key, this.initNavigator, this.prePushRoute, this.postPushRoute})
: super(key: key);
@override
ContainerManagerState createState() => ContainerManagerState();
......@@ -76,15 +81,15 @@ class ContainerManagerState extends State<BoostContainerManager> {
bool get foreground => _foreground;
//Number of containers.
// Number of containers.
int get containerCounts => _offstage.length;
List<BoostContainer> get offstage => _offstage;
//Setting for current visible container.
// Setting for current visible container.
BoostContainerSettings get onstageSettings => _onstage.settings;
//Current visible container.
// Current visible container.
BoostContainerState get onstageContainer => _stateOf(_onstage);
BoostContainerState get subContainer =>
......@@ -118,8 +123,7 @@ class ContainerManagerState extends State<BoostContainerManager> {
}
BoostContainerState _stateOf(BoostContainer container) {
if (container.key != null &&
container.key is GlobalKey<BoostContainerState>) {
if (container.key is GlobalKey<BoostContainerState>) {
final GlobalKey<BoostContainerState> globalKey =
container.key as GlobalKey<BoostContainerState>;
return globalKey.currentState;
......@@ -133,7 +137,7 @@ class ContainerManagerState extends State<BoostContainerManager> {
void _onShownContainerChanged(String old, String now) {
Logger.log('onShownContainerChanged old:$old now:$now');
Map<String, dynamic> properties = new Map<String, dynamic>();
final Map<String, dynamic> properties = <String, dynamic>{};
properties['newName'] = now;
properties['oldName'] = old;
......@@ -149,7 +153,7 @@ class ContainerManagerState extends State<BoostContainerManager> {
}
if (_leastEntries != null && _leastEntries.isNotEmpty) {
for (_ContainerOverlayEntry entry in _leastEntries) {
for (final _ContainerOverlayEntry entry in _leastEntries) {
entry.remove();
}
}
......@@ -223,7 +227,7 @@ class ContainerManagerState extends State<BoostContainerManager> {
setState(() {});
for (BoostContainerObserver observer in FlutterBoost
for (final BoostContainerObserver observer in FlutterBoost
.singleton.observersHolder
.observersOf<BoostContainerObserver>()) {
observer(ContainerOperation.Onstage, _onstage.settings);
......@@ -265,7 +269,7 @@ class ContainerManagerState extends State<BoostContainerManager> {
setState(() {});
for (BoostContainerObserver observer in FlutterBoost
for (final BoostContainerObserver observer in FlutterBoost
.singleton.observersHolder
.observersOf<BoostContainerObserver>()) {
observer(ContainerOperation.Push, _onstage.settings);
......@@ -280,9 +284,11 @@ class ContainerManagerState extends State<BoostContainerManager> {
_onstage = _offstage.removeLast();
setState(() {});
for (BoostContainerObserver observer in FlutterBoost
final Set<BoostContainerObserver> observers = FlutterBoost
.singleton.observersHolder
.observersOf<BoostContainerObserver>()) {
.observersOf<BoostContainerObserver>();
for (final BoostContainerObserver observer in observers) {
observer(ContainerOperation.Pop, old.settings);
}
......@@ -294,32 +300,34 @@ class ContainerManagerState extends State<BoostContainerManager> {
pop();
} else {
final BoostContainer container = _offstage.firstWhere(
(BoostContainer container) => container.settings.uniqueId == uniqueId,
orElse: () => null);
(BoostContainer container) => container.settings.uniqueId == uniqueId,
orElse: () => null,
);
if (container != null) {
_offstage.remove(container);
setState(() {});
for (BoostContainerObserver observer in FlutterBoost
final Set<BoostContainerObserver> observers = FlutterBoost
.singleton.observersHolder
.observersOf<BoostContainerObserver>()) {
.observersOf<BoostContainerObserver>();
for (final BoostContainerObserver observer in observers) {
observer(ContainerOperation.Remove, container.settings);
}
Logger.log('ContainerObserver#2 didRemove');
}
}
return null;
}
bool canPop() => _offstage.isNotEmpty;
String dump() {
String info = 'onstage#:\n ${_onstage?.desc()}\noffstage#:';
String info;
info = 'onstage#:\n ${_onstage?.desc()}\noffstage#:';
for (BoostContainer container in _offstage.reversed) {
for (final BoostContainer container in _offstage.reversed) {
info = '$info\n ${container?.desc()}';
}
......@@ -328,21 +336,21 @@ class ContainerManagerState extends State<BoostContainerManager> {
}
class _ContainerOverlayEntry extends OverlayEntry {
bool _removed = false;
_ContainerOverlayEntry(BoostContainer container)
: super(
builder: (BuildContext ctx) => container,
opaque: true,
maintainState: true);
builder: (BuildContext ctx) => container,
opaque: true,
maintainState: true,
);
bool _removed = false;
@override
void remove() {
assert(!_removed);
if (_removed) {
return;
}
_removed = true;
super.remove();
}
......
......@@ -25,58 +25,79 @@ import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'container/boost_container.dart';
import 'container/container_manager.dart';
import 'channel/boost_channel.dart';
import 'container/boost_container.dart';
import 'container/container_coordinator.dart';
import 'container/container_manager.dart';
import 'observers_holders.dart';
export 'container/boost_container.dart';
export 'container/container_manager.dart';
typedef Widget PageBuilder(String pageName, Map params, String uniqueId);
typedef PageBuilder = Widget Function(
String pageName, Map<String, dynamic> params, String uniqueId);
typedef Route PrePushRoute(
String url, String uniqueId, Map params, Route route);
typedef PrePushRoute = Route<T> Function<T>(String url, String uniqueId,
Map<String, dynamic> params, Route<dynamic> route);
typedef void PostPushRoute(
String url, String uniqueId, Map params, Route route, Future result);
typedef PostPushRoute = void Function(
String url,
String uniqueId,
Map<String, dynamic> params,
Route<dynamic> route,
Future<dynamic> result,
);
class FlutterBoost {
FlutterBoost() {
ContainerCoordinator(_boostChannel);
}
static final FlutterBoost _instance = FlutterBoost();
final GlobalKey<ContainerManagerState> containerManagerKey =
GlobalKey<ContainerManagerState>();
final ObserversHolder _observersHolder = ObserversHolder();
final BoostChannel _boostChannel = BoostChannel();
static FlutterBoost get singleton => _instance;
static ContainerManagerState get containerManager =>
_instance.containerManagerKey.currentState;
static void onPageStart() {
WidgetsBinding.instance.addPostFrameCallback((_) {
singleton.channel.invokeMethod<Map>('pageOnStart').then((Map pageInfo) {
if (pageInfo == null || pageInfo.isEmpty) return;
final GlobalKey<ContainerManagerState> containerManagerKey =
GlobalKey<ContainerManagerState>();
final ObserversHolder _observersHolder = ObserversHolder();
final BoostChannel _boostChannel = BoostChannel();
if (pageInfo.containsKey("name") &&
pageInfo.containsKey("params") &&
pageInfo.containsKey("uniqueId")) {
static void onPageStart() {
WidgetsBinding.instance.addPostFrameCallback((Duration _) {
singleton.channel
.invokeMethod<Map<dynamic, dynamic>>('pageOnStart')
.then((Map<dynamic, dynamic> _pageInfo) {
final Map<String, dynamic> pageInfo = _pageInfo?.cast<String, dynamic>();
if (pageInfo?.isEmpty ?? true) {
return;
}
if (pageInfo.containsKey('name') &&
pageInfo.containsKey('params') &&
pageInfo.containsKey('uniqueId')) {
ContainerCoordinator.singleton.nativeContainerDidShow(
pageInfo["name"], pageInfo["params"], pageInfo["uniqueId"]);
pageInfo['name'] as String,
(pageInfo['params'] as Map<dynamic, dynamic>)
?.cast<String, dynamic>(),
pageInfo['uniqueId'] as String,
);
}
});
});
}
static TransitionBuilder init(
{TransitionBuilder builder,
PrePushRoute prePush,
PostPushRoute postPush}) {
static TransitionBuilder init({
TransitionBuilder builder,
PrePushRoute prePush,
PostPushRoute postPush,
}) {
if (Platform.isAndroid) {
onPageStart();
} else if (Platform.isIOS) {
// TODO(AlexVincent525): 未解之谜
assert(() {
() async {
onPageStart();
......@@ -89,10 +110,11 @@ class FlutterBoost {
assert(child is Navigator, 'child must be Navigator, what is wrong?');
final BoostContainerManager manager = BoostContainerManager(
key: _instance.containerManagerKey,
initNavigator: child,
prePushRoute: prePush,
postPushRoute: postPush);
key: _instance.containerManagerKey,
initNavigator: child as Navigator,
prePushRoute: prePush,
postPushRoute: postPush,
);
if (builder != null) {
return builder(context, manager);
......@@ -106,94 +128,95 @@ class FlutterBoost {
BoostChannel get channel => _boostChannel;
FlutterBoost() {
ContainerCoordinator(_boostChannel);
}
///Register a default page builder.
/// Register a default page builder.
void registerDefaultPageBuilder(PageBuilder builder) {
ContainerCoordinator.singleton.registerDefaultPageBuilder(builder);
}
///Register a map builders
/// Register a map builders
void registerPageBuilders(Map<String, PageBuilder> builders) {
ContainerCoordinator.singleton.registerPageBuilders(builders);
}
Future<Map<dynamic, dynamic>> open(String url,
{Map<dynamic, dynamic> urlParams, Map<dynamic, dynamic> exts}) {
Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>();
properties["url"] = url;
properties["urlParams"] = urlParams;
properties["exts"] = exts;
Future<Map<dynamic, dynamic>> open(
String url, {
Map<String, dynamic> urlParams,
Map<String, dynamic> exts,
}) {
final Map<String, dynamic> properties = <String, dynamic>{};
properties['url'] = url;
properties['urlParams'] = urlParams;
properties['exts'] = exts;
return channel.invokeMethod<Map<dynamic, dynamic>>('openPage', properties);
}
Future<bool> close(String id,
{Map<dynamic, dynamic> result, Map<dynamic, dynamic> exts}) {
Future<bool> close(
String id, {
Map<String, dynamic> result,
Map<String, dynamic> exts,
}) {
assert(id != null);
BoostContainerSettings settings = containerManager?.onstageSettings;
Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>();
final BoostContainerSettings settings = containerManager?.onstageSettings;
final Map<String, dynamic> properties = <String, dynamic>{};
if (exts == null) {
exts = Map<dynamic, dynamic>();
}
exts ??= <String, dynamic>{};
exts["params"] = settings.params;
exts['params'] = settings.params;
if (!exts.containsKey("animated")) {
exts["animated"] = true;
if (!exts.containsKey('animated')) {
exts['animated'] = true;
}
properties["uniqueId"] = id;
properties['uniqueId'] = id;
if (result != null) {
properties["result"] = result;
properties['result'] = result;
}
if (exts != null) {
properties["exts"] = exts;
properties['exts'] = exts;
}
return channel.invokeMethod<bool>('closePage', properties);
}
Future<bool> closeCurrent(
{Map<String, dynamic> result, Map<String, dynamic> exts}) {
BoostContainerSettings settings = containerManager?.onstageSettings;
if (exts == null) {
exts = Map<String, dynamic>();
}
exts["params"] = settings.params;
if (!exts.containsKey("animated")) {
exts["animated"] = true;
Future<bool> closeCurrent({
Map<String, dynamic> result,
Map<String, dynamic> exts,
}) {
final BoostContainerSettings settings = containerManager?.onstageSettings;
exts ??= <String, dynamic>{};
exts['params'] = settings.params;
if (!exts.containsKey('animated')) {
exts['animated'] = true;
}
return close(settings.uniqueId, result: result, exts: exts);
}
Future<bool> closeByContext(BuildContext context,
{Map<String, dynamic> result, Map<String, dynamic> exts}) {
BoostContainerSettings settings = containerManager?.onstageSettings;
if (exts == null) {
exts = Map<String, dynamic>();
}
exts["params"] = settings.params;
if (!exts.containsKey("animated")) {
exts["animated"] = true;
Future<bool> closeByContext(
BuildContext context, {
Map<String, dynamic> result,
Map<String, dynamic> exts,
}) {
final BoostContainerSettings settings = containerManager?.onstageSettings;
exts ??= <String, dynamic>{};
exts['params'] = settings.params;
if (!exts.containsKey('animated')) {
exts['animated'] = true;
}
return close(settings.uniqueId, result: result, exts: exts);
}
///register for Container changed callbacks
/// Register for Container changed callbacks
VoidCallback addContainerObserver(BoostContainerObserver observer) =>
_observersHolder.addObserver<BoostContainerObserver>(observer);
///register for Container lifecycle callbacks
/// Register for Container lifecycle callbacks
VoidCallback addBoostContainerLifeCycleObserver(
BoostContainerLifeCycleObserver observer) =>
_observersHolder.addObserver<BoostContainerLifeCycleObserver>(observer);
///register callbacks for Navigators push & pop
/// Register callbacks for [Navigator.push] & [Navigator.pop]
void addBoostNavigatorObserver(NavigatorObserver observer) =>
ContainerNavigatorObserver.boostObservers.add(observer);
}
......@@ -24,10 +24,10 @@
import 'dart:ui';
class ObserversHolder {
final Map<String, Set<dynamic>> _observers = Map<String, Set<dynamic>>();
final Map<String, Set<dynamic>> _observers = <String, Set<dynamic>>{};
VoidCallback addObserver<T>(T observer) {
final Set<T> set = _observers[T.toString()] ?? Set<T>();
final Set<T> set = _observers[T.toString()] as Set<T> ?? <T>{};
set.add(observer);
_observers[T.toString()] = set;
......@@ -40,5 +40,5 @@ class ObserversHolder {
void cleanObservers<T>(T observer) => _observers[T.toString()]?.clear();
Set<T> observersOf<T>() => _observers[T.toString()] ?? Set<T>();
Set<T> observersOf<T>() => _observers[T.toString()] as Set<T> ?? <T>{};
}
......@@ -27,7 +27,6 @@ class Logger {
print('FlutterBoost#$msg');
return true;
}());
//print('FlutterBoost=>$msg');
}
static void error(String msg) {
......
......@@ -17,42 +17,7 @@ dev_dependencies:
sdk: flutter
mockito: 4.1.1
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
plugin:
androidPackage: com.idlefish.flutterboost
pluginClass: FlutterBoostPlugin
# To add assets to your plugin package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.io/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# To add custom fonts to your plugin package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.io/custom-fonts/#from-packages
import 'package:flutter_boost/channel/boost_channel.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_boost/channel/boost_channel.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
......@@ -22,13 +23,12 @@ void main() {
response = null;
test('sendEvent successfully', () async {
Map msg1 = Map<dynamic,dynamic>();
BoostChannel().sendEvent("name", msg1);
Map msg = Map<dynamic,dynamic>();
msg["name"] = "name";
msg["arguments"] = msg1;
final Map<String, dynamic> msg1 = <String, dynamic>{};
BoostChannel().sendEvent('name', msg1);
final Map<String, dynamic> msg = <String, dynamic>{};
msg['name'] = 'name';
msg['arguments'] = msg1;
expect(
log,
......@@ -36,13 +36,10 @@ void main() {
);
});
test('invokeMethod successfully', () async {
Map msg = <dynamic,dynamic>{};
msg["test"] = "test";
BoostChannel().invokeMethod<dynamic>("__event__1", msg);
// expect(e, isException);
final Map<String, dynamic> msg = <String, dynamic>{};
msg['test'] = 'test';
BoostChannel().invokeMethod<dynamic>('__event__1', msg);
expect(
log,
......@@ -50,11 +47,10 @@ void main() {
);
});
test('invokeListMethod successfully', () async {
Map msg = <dynamic,dynamic>{};
msg["test"] = "test";
var bb = await BoostChannel().invokeListMethod<dynamic>("__event__1", msg);
final Map<String, dynamic> msg = <String, dynamic>{};
msg['test'] = 'test';
await BoostChannel().invokeListMethod<dynamic>('__event__1', msg);
expect(
log,
......@@ -62,11 +58,10 @@ void main() {
);
});
test('invokeMapMethod successfully', () async {
Map msg = <dynamic,dynamic>{};
msg["test"] = "test";
BoostChannel().invokeMapMethod<dynamic,dynamic>("__event__1", msg);
final Map<String, dynamic> msg = <String, dynamic>{};
msg['test'] = 'test';
BoostChannel().invokeMapMethod<dynamic, dynamic>('__event__1', msg);
expect(
log,
......@@ -75,9 +70,9 @@ void main() {
});
test('invokeMapMethod successfully', () async {
Map msg = <dynamic,dynamic>{};
msg["test"] = "test";
BoostChannel().invokeMapMethod<dynamic,dynamic>("__event__1", msg);
final Map<String, dynamic> msg = <String, dynamic>{};
msg['test'] = 'test';
BoostChannel().invokeMapMethod<dynamic, dynamic>('__event__1', msg);
expect(
log,
......@@ -86,22 +81,24 @@ void main() {
});
test('addEventListener successfully', () async {
Function test = BoostChannel().addEventListener(
"addEventListener", (String name, Map arguments) async => "test");
print("xxx" + test.toString());
final VoidCallback test = BoostChannel().addEventListener(
'addEventListener',
(String name, Map<String, dynamic> arguments) async => 'test',
);
print('xxx' + test.toString());
expect(
test.toString(),
"Closure: () => Null",
'Closure: () => Null',
);
});
test('addMethodHandler successfully', () async {
Function test = BoostChannel().addMethodHandler((
MethodCall call) async => "test");
final VoidCallback test = BoostChannel().addMethodHandler(
(MethodCall call) async => 'test',
);
expect(
test.toString(),
"Closure: () => Null",
'Closure: () => Null',
);
});
});
......
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_boost/container/boost_container.dart';
// import 'package:flutter_boost/container/boost_container.dart';
import 'package:flutter_test/flutter_test.dart';
class FirstWidget extends StatelessWidget {
......@@ -149,11 +149,11 @@ void main() {
);
await tester.pumpWidget(widget);
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
await tester.tap(find.byKey(targetKey));
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
expect(exception, isInstanceOf<FlutterError>());
expect('$exception',
......
......@@ -49,8 +49,8 @@ void main() {
testWidgets(
'obtain BoostPageRoute through the BoostPageRoute.of(context) method',
(WidgetTester tester) async {
dynamic boostPageRoute;
dynamic boostPageRouteFindByOfMethod;
BoostPageRoute<dynamic> boostPageRoute;
BoostPageRoute<dynamic> boostPageRouteFindByOfMethod;
await tester.pumpWidget(
MaterialApp(
......@@ -58,10 +58,11 @@ void main() {
boostPageRoute = BoostPageRoute<void>(
settings: settings,
builder: (BuildContext context) => Builder(
builder: (context) {
builder: (BuildContext context) {
return FloatingActionButton(
onPressed: () {
boostPageRouteFindByOfMethod = BoostPageRoute.of<dynamic>(context);
boostPageRouteFindByOfMethod =
BoostPageRoute.of<dynamic>(context);
},
);
},
......@@ -74,7 +75,7 @@ void main() {
await tester.tap(find.byType(FloatingActionButton));
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
// The route obtained from the ancestor node through the `of` method should be the same BoostPageRoute
// as the originally created BoostPageRoute
......@@ -85,15 +86,15 @@ void main() {
'try to find BoostPageRoute through the BoostPageRoute.of(context) method, '
'but it doesn\'t exist, the method should throw an Exception',
(WidgetTester tester) async {
dynamic contextCache;
BuildContext contextCache;
await tester.pumpWidget(
MaterialApp(
onGenerateRoute: (RouteSettings settings) {
return MaterialPageRoute<dynamic>(
settings: settings,
builder: (context) => Builder(
builder: (context) => FloatingActionButton(
builder: (BuildContext context) => Builder(
builder: (BuildContext context) => FloatingActionButton(
onPressed: () {
contextCache = context;
},
......@@ -104,7 +105,7 @@ void main() {
),
);
await tester.tap(find.byType(FloatingActionButton));
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
expect(() => BoostPageRoute.of<dynamic>(contextCache), throwsException);
});
......@@ -112,8 +113,8 @@ void main() {
testWidgets(
'obtain BoostPageRoute through the BoostPageRoute.tryOf(context) method',
(WidgetTester tester) async {
dynamic boostPageRoute;
dynamic boostPageRouteFindByOfMethod;
BoostPageRoute<dynamic> boostPageRoute;
BoostPageRoute<dynamic> boostPageRouteFindByOfMethod;
await tester.pumpWidget(
MaterialApp(
......@@ -121,7 +122,7 @@ void main() {
boostPageRoute = BoostPageRoute<void>(
settings: settings,
builder: (BuildContext context) => Builder(
builder: (context) {
builder: (BuildContext context) {
return FloatingActionButton(
onPressed: () {
boostPageRouteFindByOfMethod =
......@@ -137,7 +138,7 @@ void main() {
);
await tester.tap(find.byType(FloatingActionButton));
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
// The route obtained from the ancestor node through the `tryOf` method should be the same BoostPageRoute
// as the originally created BoostPageRoute
......@@ -149,7 +150,7 @@ void main() {
'try to find BoostPageRoute through the BoostPageRoute.tryOf(context) method, '
'but it doesn\'t exist, the method should return null',
(WidgetTester tester) async {
dynamic boostPageRouteFindByOfMethod;
BoostPageRoute<dynamic> boostPageRouteFindByOfMethod;
await tester.pumpWidget(
MaterialApp(
......@@ -157,7 +158,7 @@ void main() {
return MaterialPageRoute<dynamic>(
settings: settings,
builder: (BuildContext context) => Builder(
builder: (context) {
builder: (BuildContext context) {
return FloatingActionButton(
onPressed: () {
boostPageRouteFindByOfMethod =
......@@ -172,7 +173,7 @@ void main() {
);
await tester.tap(find.byType(FloatingActionButton));
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
expect(boostPageRouteFindByOfMethod, null);
});
......
......@@ -6,9 +6,6 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_boost/channel/boost_channel.dart';
import 'package:flutter_boost/container/container_coordinator.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'dart:typed_data';
class MockBoostChannel extends BoostChannel implements Mock {
MethodHandler get testHandler => _testHandler;
......@@ -17,40 +14,42 @@ class MockBoostChannel extends BoostChannel implements Mock {
MethodHandler _testHandler;
EventListener _testEventListener;
@override
VoidCallback addEventListener(String name, EventListener listener) {
_testEventListener = listener;
return super.addEventListener(name, listener);
}
@override
VoidCallback addMethodHandler(MethodHandler handler) {
_testHandler = handler;
return super.addMethodHandler(handler);
return super.addMethodHandler(handler);
}
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
// const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
test('test onMethodCall', () async {
// Initialize all bindings because defaultBinaryMessenger.send() needs a window.
TestWidgetsFlutterBinding.ensureInitialized();
MockBoostChannel boostChannel = MockBoostChannel();
final MockBoostChannel boostChannel = MockBoostChannel();
ContainerCoordinator(boostChannel);
final Map arguments =<dynamic,dynamic> {};
arguments["pageName"] = "pageName";
arguments["params"] = <dynamic,dynamic>{};
arguments["uniqueId"] = "xxxxx";
final Map<String, dynamic> arguments = <String, dynamic>{};
arguments['pageName'] = 'pageName';
arguments['params'] = <dynamic, dynamic>{};
arguments['uniqueId'] = 'xxxxx';
MethodCall call = MethodCall('didInitPageContainer', arguments);
final MethodCall call = MethodCall('didInitPageContainer', arguments);
try {
boostChannel.testHandler(call);
} catch (e) {
expect(e, isAssertionError);
}
MethodCall call2 = MethodCall('willShowPageContainer', arguments);
final MethodCall call2 = MethodCall('willShowPageContainer', arguments);
try {
boostChannel.testHandler(call2);
......@@ -58,7 +57,7 @@ void main() {
expect(e, isNoSuchMethodError);
}
MethodCall call3 = MethodCall('didShowPageContainer', arguments);
final MethodCall call3 = MethodCall('didShowPageContainer', arguments);
try {
boostChannel.testHandler(call3);
......@@ -66,7 +65,8 @@ void main() {
expect(e, isNoSuchMethodError);
}
MethodCall call4 = MethodCall('willDisappearPageContainer', arguments);
final MethodCall call4 =
MethodCall('willDisappearPageContainer', arguments);
try {
boostChannel.testHandler(call4);
......@@ -74,7 +74,7 @@ void main() {
expect(e, isNoSuchMethodError);
}
MethodCall call5 = MethodCall('onNativePageResult', arguments);
final MethodCall call5 = MethodCall('onNativePageResult', arguments);
try {
boostChannel.testHandler(call5);
......@@ -82,14 +82,14 @@ void main() {
expect(e, isNoSuchMethodError);
}
MethodCall call6 = MethodCall('didDisappearPageContainer', arguments);
final MethodCall call6 = MethodCall('didDisappearPageContainer', arguments);
try {
boostChannel.testHandler(call6);
} catch (e) {
expect(e, isNoSuchMethodError);
}
MethodCall call7 = MethodCall('willDeallocPageContainer', arguments);
final MethodCall call7 = MethodCall('willDeallocPageContainer', arguments);
try {
boostChannel.testHandler(call7);
......@@ -97,35 +97,36 @@ void main() {
expect(e, isNoSuchMethodError);
}
Map arg = <dynamic,dynamic>{'type': 'backPressedCallback'};
final Map<String, dynamic> arg = <String, dynamic>{
'type': 'backPressedCallback'
};
try {
boostChannel.testEventListener("lifecycle", arg);
boostChannel.testEventListener('lifecycle', arg);
} catch (e) {
expect(e, isNoSuchMethodError);
}
Map arg2 = <dynamic,dynamic>{'type': 'foreground'};
final Map<String, dynamic> arg2 = <String, dynamic>{'type': 'foreground'};
try {
boostChannel.testEventListener("lifecycle", arg2);
boostChannel.testEventListener('lifecycle', arg2);
} catch (e) {
expect(e, isNoSuchMethodError);
}
Map arg3 = <dynamic,dynamic>{'type': 'background'};
final Map<String, dynamic> arg3 = <String, dynamic>{'type': 'background'};
try {
boostChannel.testEventListener("lifecycle", arg3);
boostChannel.testEventListener('lifecycle', arg3);
} catch (e) {
expect(e, isNoSuchMethodError);
}
Map arg4 = <dynamic,dynamic>{'type': 'scheduleFrame'};
final Map<String, dynamic> arg4 = <String, dynamic>{
'type': 'scheduleFrame'
};
try {
boostChannel.testEventListener("lifecycle", arg4);
boostChannel.testEventListener('lifecycle', arg4);
} catch (e) {
expect(e, isNoSuchMethodError);
}
});
}
......@@ -12,19 +12,21 @@ class FirstRouteWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
title: const Text('First Route'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('First'),
child: const Text('First'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print('open second page!');
FlutterBoost.singleton
.open('second')
.then((Map<dynamic, dynamic> value) {
print(
"call me when page is finished. did recieve second route result $value");
'call me when page is finished. did recieve second route result $value');
});
},
),
......@@ -40,19 +42,21 @@ class SecondRouteWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Route'),
title: const Text('Second Route'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Second'),
child: const Text('Second'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print('open second page!');
FlutterBoost.singleton
.open('second')
.then((Map<dynamic, dynamic> value) {
print(
"call me when page is finished. did recieve second route result $value");
'call me when page is finished. did recieve second route result $value');
});
},
),
......@@ -73,9 +77,11 @@ class _MyAppState extends State<MyApp> {
void initState() {
super.initState();
FlutterBoost.singleton.registerPageBuilders({
'first': (pageName, params, _) => FirstRouteWidget(),
'second': (pageName, params, _) => SecondRouteWidget(),
FlutterBoost.singleton.registerPageBuilders(<String, PageBuilder>{
'first': (String pageName, Map<String, dynamic> params, String _) =>
FirstRouteWidget(),
'second': (String pageName, Map<String, dynamic> params, String _) =>
SecondRouteWidget(),
});
}
......@@ -88,7 +94,7 @@ class _MyAppState extends State<MyApp> {
assert(child is Navigator, 'child must be Navigator, what is wrong?');
final BoostContainerManager manager = BoostContainerManager(
initNavigator: child,
initNavigator: child as Navigator,
);
return manager;
......@@ -113,19 +119,23 @@ void main() {
testWidgets(
'through the `BoostContainerManager.of(context)` method',
(WidgetTester tester) async {
var builderContext;
FlutterBoost.singleton.registerPageBuilders({
'context': (pageName, params, _) => Builder(
builder: (context) {
return FloatingActionButton(
onPressed: () {
builderContext = context;
},
);
},
),
});
BuildContext builderContext;
FlutterBoost.singleton.registerPageBuilders(
<String, PageBuilder>{
'context':
(String pageName, Map<String, dynamic> params, String _) =>
Builder(
builder: (BuildContext context) {
return FloatingActionButton(
onPressed: () {
builderContext = context;
},
);
},
),
},
);
await tester.pumpWidget(
MaterialApp(
......@@ -135,28 +145,34 @@ void main() {
);
//open context page
ContainerCoordinator.singleton
.nativeContainerDidShow("context", {}, "1000000");
ContainerCoordinator.singleton.nativeContainerDidShow(
'context',
<String, dynamic>{},
'1000000',
);
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
expect(find.byType(FloatingActionButton), findsOneWidget);
//get the context of the Builder
await tester.tap(find.byType(FloatingActionButton));
final isFind = BoostContainerManager.of(builderContext) != null;
final bool isFind = BoostContainerManager.of(builderContext) != null;
expect(isFind, true,
reason: '`BoostContainerManager.of` should be able to '
'find `ContainerManagerState` in `FlutterBoost.init()` based on the context of the `Builder`');
expect(
isFind,
true,
reason: '`BoostContainerManager.of` should be able to '
'find `ContainerManagerState` in `FlutterBoost.init()` based on the context of the `Builder`',
);
},
);
// testWidgets(
// 'through the `BoostContainerManager.of(context)` method',
// (WidgetTester tester) async {
// var builderContext;
// BuildContext builderContext;
//
// await tester.pumpWidget(
// MaterialApp(
......@@ -184,19 +200,22 @@ void main() {
testWidgets(
'through the `BoostContainerManager.tryOf(context)` method',
(WidgetTester tester) async {
var builderContext;
FlutterBoost.singleton.registerPageBuilders({
'context': (pageName, params, _) => Builder(
builder: (context) {
return FloatingActionButton(
onPressed: () {
builderContext = context;
},
);
},
),
});
BuildContext builderContext;
FlutterBoost.singleton.registerPageBuilders(
<String, PageBuilder>{
'context': (String pageName, Map<String, dynamic> params, _) =>
Builder(
builder: (BuildContext context) {
return FloatingActionButton(
onPressed: () {
builderContext = context;
},
);
},
),
},
);
await tester.pumpWidget(
MaterialApp(
......@@ -206,21 +225,25 @@ void main() {
);
//open context page
ContainerCoordinator.singleton
.nativeContainerDidShow("context", {}, "1000000");
ContainerCoordinator.singleton.nativeContainerDidShow(
'context', <String, dynamic>{}, '1000000');
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
expect(find.byType(FloatingActionButton), findsOneWidget);
//get the context of the Builder
await tester.tap(find.byType(FloatingActionButton));
final isFind = BoostContainerManager.tryOf(builderContext) != null;
final bool isFind =
BoostContainerManager.tryOf(builderContext) != null;
expect(isFind, true,
reason: '`BoostContainerManager.tryOf` should be able to '
'find `ContainerManagerState` in `FlutterBoost.init()` based on the context of the `Builder`');
expect(
isFind,
true,
reason: '`BoostContainerManager.tryOf` should be able to '
'find `ContainerManagerState` in `FlutterBoost.init()` based on the context of the `Builder`',
);
},
);
},
......@@ -230,19 +253,22 @@ void main() {
testWidgets(
'containerCounts should change based on the number of pages',
(WidgetTester tester) async {
var builderContext;
FlutterBoost.singleton.registerPageBuilders({
'context': (pageName, params, _) => Builder(
builder: (context) {
return FloatingActionButton(
onPressed: () {
builderContext = context;
},
);
},
),
});
BuildContext builderContext;
FlutterBoost.singleton.registerPageBuilders(
<String, PageBuilder>{
'context': (String pageName, Map<String, dynamic> params, _) =>
Builder(
builder: (BuildContext context) {
return FloatingActionButton(
onPressed: () {
builderContext = context;
},
);
},
),
},
);
await tester.pumpWidget(
MaterialApp(
......@@ -253,23 +279,24 @@ void main() {
//open first context page
ContainerCoordinator.singleton
.nativeContainerDidShow("context", {}, "1000000");
.nativeContainerDidShow('context', <String, dynamic>{}, '1000000');
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
//get the context of the Builder
await tester.tap(find.byType(FloatingActionButton));
final containerManagerState = BoostContainerManager.of(builderContext);
final ContainerManagerState containerManagerState =
BoostContainerManager.of(builderContext);
expect(containerManagerState.containerCounts, 1,
reason: '1 page shown');
//open second context page
ContainerCoordinator.singleton
.nativeContainerDidShow("context", {}, "2000000");
.nativeContainerDidShow('context', <String, dynamic>{}, '2000000');
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
expect(containerManagerState.containerCounts, 2,
reason: '2 page shown');
......@@ -277,7 +304,7 @@ void main() {
//pop second context page
containerManagerState.pop();
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
expect(containerManagerState.containerCounts, 1,
reason: 'second context page closed, Only one page left');
......@@ -285,7 +312,7 @@ void main() {
//pop last context page
containerManagerState.pop();
await tester.pump(Duration(seconds: 1));
await tester.pump(const Duration(seconds: 1));
expect(containerManagerState.containerCounts, 0,
reason: 'last context page closed, no page left');
......
import 'package:flutter_boost/container/container_manager.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_boost/container/container_manager.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
test('test onMethodCall', () async {
FlutterBoost.singleton.registerDefaultPageBuilder(
(String pageName, Map<String, dynamic> params, String _) =>
Container());
FlutterBoost.singleton.addContainerObserver(
(ContainerOperation operation, BoostContainerSettings settings) {},
);
FlutterBoost.singleton.addBoostContainerLifeCycleObserver(
(ContainerLifeCycle state, BoostContainerSettings settings) {},
);
FlutterBoost.singleton.addBoostNavigatorObserver(NavigatorObserver());
try {
FlutterBoost.singleton.open('url');
} catch (e) {
expect(e, isException);
}
try {
FlutterBoost.singleton.close('url');
} catch (e) {
expect(e, isNoSuchMethodError);
}
try {
FlutterBoost.singleton.closeCurrent(
result: <String, dynamic>{},
exts: <String, dynamic>{},
);
} catch (e) {
expect(e, isNoSuchMethodError);
}
// test('test onMethodCall', () async {
// FlutterBoost.singleton
// .registerDefaultPageBuilder((pageName, params, _) => Container());
// FlutterBoost.singleton.addContainerObserver(
// (ContainerOperation operation, BoostContainerSettings settings) {});
//
// FlutterBoost.singleton.addBoostContainerLifeCycleObserver(
// (ContainerLifeCycle state, BoostContainerSettings settings) {});
//
// FlutterBoost.singleton.addBoostNavigatorObserver(NavigatorObserver());
//
// try {
// FlutterBoost.singleton.open("url");
// } catch (e) {
// expect(e, isException);
// }
// try {
// FlutterBoost.singleton.close("url");
// } catch (e) {
// expect(e, isNoSuchMethodError);
// }
// try {
// FlutterBoost.singleton.closeCurrent(result: <String,dynamic>{}, exts: <String,dynamic>{});
// } catch (e) {
// expect(e, isNoSuchMethodError);
// }
//
// try {
// FlutterBoost.singleton.closeByContext(null, result: <String,dynamic>{}, exts: <String,dynamic>{});
// } catch (e) {
// expect(e, isNoSuchMethodError);
// }
// });
try {
FlutterBoost.singleton.closeByContext(
null,
result: <String, dynamic>{},
exts: <String, dynamic>{},
);
} catch (e) {
expect(e, isNoSuchMethodError);
}
});
}
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_boost/container/container_coordinator.dart';
import 'package:flutter_test/flutter_test.dart';
import 'page_widgets.dart';
import 'package:flutter_boost/container/container_coordinator.dart';
class MyApp extends StatefulWidget {
@override
......@@ -15,14 +16,19 @@ class _MyAppState extends State<MyApp> {
void initState() {
super.initState();
FlutterBoost.singleton.registerPageBuilders({
'embeded': (pageName, params, _) => EmbededFirstRouteWidget(),
'first': (pageName, params, _) => FirstRouteWidget(),
'second': (pageName, params, _) => SecondRouteWidget(),
'tab': (pageName, params, _) => TabRouteWidget(),
'flutterFragment': (pageName, params, _) => FragmentRouteWidget(params),
'flutterPage': (pageName, params, _) {
print("flutterPage params:$params");
FlutterBoost.singleton.registerPageBuilders(<String, PageBuilder>{
'embeded': (String pageName, Map<String, dynamic> params, _) =>
EmbededFirstRouteWidget(),
'first': (String pageName, Map<String, dynamic> params, _) =>
FirstRouteWidget(),
'second': (String pageName, Map<String, dynamic> params, _) =>
SecondRouteWidget(),
'tab': (String pageName, Map<String, dynamic> params, _) =>
TabRouteWidget(),
'flutterFragment': (String pageName, Map<String, dynamic> params, _) =>
FragmentRouteWidget(params),
'flutterPage': (String pageName, Map<String, dynamic> params, _) {
print('flutterPage params:$params');
return FlutterRouteWidget(params: params);
},
......@@ -40,24 +46,33 @@ class _MyAppState extends State<MyApp> {
}
void _onRoutePushed(
String pageName, String uniqueId, Map params, Route route, Future _) {}
String pageName,
String uniqueId,
Map<String, dynamic> params,
Route<dynamic> route,
Future<dynamic> _,
) {}
}
class TestBoostNavigatorObserver extends NavigatorObserver {
@override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didPush");
print('flutterboost#didPush');
}
@override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didPop");
print('flutterboost#didPop');
}
@override
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didRemove");
print('flutterboost#didRemove');
}
@override
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
print("flutterboost#didReplace");
print('flutterboost#didReplace');
}
}
......@@ -72,7 +87,7 @@ void main() {
);
//open firt page
ContainerCoordinator.singleton
.nativeContainerDidShow("first", <dynamic,dynamic>{}, "1000000");
.nativeContainerDidShow('first', <String, dynamic>{}, '1000000');
await tester.pump(const Duration(seconds: 1));
......@@ -80,7 +95,7 @@ void main() {
//open second page firt(1000000)->second(2000000)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", <dynamic,dynamic>{}, "2000000");
.nativeContainerDidShow('second', <String, dynamic>{}, '2000000');
await tester.pump(const Duration(seconds: 1));
......@@ -89,7 +104,7 @@ void main() {
await tester.pump(const Duration(seconds: 1));
//close sencod page firt(1000000)
FlutterBoost.containerManager?.remove("2000000");
FlutterBoost.containerManager?.remove('2000000');
await tester.pump(const Duration(seconds: 1));
......@@ -97,7 +112,7 @@ void main() {
// second page ,but pageId is 2000001 firt(1000000)->second(2000001)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", <dynamic,dynamic>{}, "2000001");
.nativeContainerDidShow('second', <String, dynamic>{}, '2000001');
await tester.pump(const Duration(seconds: 1));
......@@ -107,7 +122,7 @@ void main() {
//reopen firt page second(2000001)->firt(1000000)
ContainerCoordinator.singleton
.nativeContainerDidShow("first",<dynamic,dynamic> {}, "1000000");
.nativeContainerDidShow('first', <String, dynamic>{}, '1000000');
await tester.pump(const Duration(seconds: 1));
......@@ -117,7 +132,7 @@ void main() {
// reopen second page and pageId is 2000001 firt(1000000)->second(2000001)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", <dynamic,dynamic>{}, "2000001");
.nativeContainerDidShow('second', <String, dynamic>{}, '2000001');
await tester.pump(const Duration(seconds: 1));
......@@ -126,24 +141,18 @@ void main() {
await tester.pump(const Duration(seconds: 1));
//close firt(1000000) page second(2000001)
FlutterBoost.containerManager?.remove("1000000");
FlutterBoost.containerManager?.remove('1000000');
await tester.pump(const Duration(seconds: 1));
expect(find.text('Second'), findsOneWidget);
// open second(2000003)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", <dynamic,dynamic>{}, "2000003");
.nativeContainerDidShow('second', <String, dynamic>{}, '2000003');
await tester.idle();
expect(find.text('Second'), findsOneWidget);
});
}
......@@ -7,36 +7,38 @@ class FirstRouteWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
title: const Text('First Route'),
),
body: Center(
child:
Column(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children:
<Widget>[
children: <Widget>[
RaisedButton(
child: Text('First'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print(
"call me when page is finished. did recieve second route result $value");
});
},
),
RaisedButton(
child: Text('Present second route'),
onPressed: () {
print("Present second page!");
FlutterBoost.singleton.open("second",urlParams:<dynamic,dynamic>{"present":true}).then((Map value) {
print(
"call me when page is finished. did recieve second route result $value");
});
},
),
],
child: const Text('First'),
onPressed: () {
print('open second page!');
FlutterBoost.singleton
.open('second')
.then((Map<dynamic, dynamic> value) {
print(
'call me when page is finished. did recieve second route result $value');
});
},
),
RaisedButton(
child: const Text('Present second route'),
onPressed: () {
print('Present second page!');
FlutterBoost.singleton.open('second',
urlParams: <String, dynamic>{
'present': true
}).then((Map<dynamic, dynamic> value) {
print(
'call me when page is finished. did recieve second route result $value');
});
},
),
],
),
),
);
......@@ -49,12 +51,14 @@ class EmbededFirstRouteWidget extends StatelessWidget {
return Scaffold(
body: Center(
child: RaisedButton(
child: Text('Open second route'),
child: const Text('Open second route'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print('open second page!');
FlutterBoost.singleton
.open('second')
.then((Map<dynamic, dynamic> value) {
print(
"call me when page is finished. did recieve second route result $value");
'call me when page is finished. did recieve second route result $value');
});
},
),
......@@ -68,19 +72,19 @@ class SecondRouteWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second"),
title: const Text('Second'),
),
body: Center(
child: RaisedButton(
onPressed: () {
// Navigate back to first route when tapped.
BoostContainerSettings settings =
final BoostContainerSettings settings =
BoostContainer.of(context).settings;
FlutterBoost.singleton.close(settings.uniqueId,
result:<dynamic,dynamic>{"result": "data from second"});
result: <String, dynamic>{'result': 'data from second'});
},
child: Text('Go back with result!'),
child: const Text('Go back with result!'),
),
),
);
......@@ -92,14 +96,14 @@ class TabRouteWidget extends StatelessWidget {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Tab Route"),
title: const Text('Tab Route'),
),
body: Center(
child: RaisedButton(
onPressed: () {
FlutterBoost.singleton.open("second");
FlutterBoost.singleton.open('second');
},
child: Text('Open second route'),
child: const Text('Open second route'),
),
),
);
......@@ -107,8 +111,9 @@ class TabRouteWidget extends StatelessWidget {
}
class FlutterRouteWidget extends StatefulWidget {
FlutterRouteWidget({this.params,this.message});
final Map params;
const FlutterRouteWidget({this.params, this.message});
final Map<String, dynamic> params;
final String message;
@override
......@@ -116,176 +121,190 @@ class FlutterRouteWidget extends StatefulWidget {
}
class _FlutterRouteWidgetState extends State<FlutterRouteWidget> {
final TextEditingController _usernameController = TextEditingController();
@override
Widget build(BuildContext context) {
final String message=widget.message;
final String message = widget.message;
return Scaffold(
appBar: AppBar(
brightness:Brightness.light,
brightness: Brightness.light,
backgroundColor: Colors.white,
textTheme:new TextTheme(title: TextStyle(color: Colors.black)) ,
title: Text('flutter_boost_example'),
textTheme: TextTheme(title: TextStyle(color: Colors.black)),
title: const Text('flutter_boost_example'),
),
body: SingleChildScrollView(
child:Container(
margin: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 10.0,bottom: 20.0),
child: Text(
message ?? "This is a flutter activity \n params:${widget.params}",
style: TextStyle(fontSize: 28.0, color: Colors.blue),
),
alignment: AlignmentDirectional.center,
child: Container(
margin: const EdgeInsets.all(24.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
margin: const EdgeInsets.only(top: 10.0, bottom: 20.0),
child: Text(
message ??
'This is a flutter activity \n params:${widget.params}',
style: TextStyle(fontSize: 28.0, color: Colors.blue),
),
// Expanded(child: Container()),
const CupertinoTextField(
prefix: Icon(
CupertinoIcons.person_solid,
color: CupertinoColors.lightBackgroundGray,
size: 28.0,
alignment: AlignmentDirectional.center,
),
const CupertinoTextField(
prefix: Icon(
CupertinoIcons.person_solid,
color: CupertinoColors.lightBackgroundGray,
size: 28.0,
),
padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 12.0),
clearButtonMode: OverlayVisibilityMode.editing,
textCapitalization: TextCapitalization.words,
autocorrect: false,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
width: 0.0, color: CupertinoColors.inactiveGray),
),
padding: EdgeInsets.symmetric(horizontal: 6.0, vertical: 12.0),
clearButtonMode: OverlayVisibilityMode.editing,
textCapitalization: TextCapitalization.words,
autocorrect: false,
decoration: BoxDecoration(
border: Border(bottom: BorderSide(width: 0.0, color: CupertinoColors.inactiveGray)),
),
placeholder: 'Name',
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
placeholder: 'Name',
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton
.open("sample://nativePage", urlParams: <dynamic,dynamic>{
"query": {"aaa": "bbb"}
}),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton.open(
'sample://nativePage',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'},
},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open first',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton
.open("first", urlParams: <dynamic,dynamic>{
"query": {"aaa": "bbb"}
}),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open first',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open second',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton
.open("second", urlParams: <dynamic,dynamic>{
"query": {"aaa": "bbb"}
}),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton.open(
'first',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'},
},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open tab',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton
.open("tab", urlParams: <dynamic,dynamic>{
"query": {"aaa": "bbb"}
}),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open second',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton
.open("sample://flutterPage", urlParams:<dynamic,dynamic> {
"query": {"aaa": "bbb"}
}),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton.open(
'second',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'},
},
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open tab',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'push flutter widget',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () {
Navigator.push<dynamic>(context,
MaterialPageRoute<dynamic>(builder: (_) => PushWidget()));
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton.open(
'tab',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'}
},
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
),
),
///后面的参数会在native的IPlatform.startActivity方法回调中拼接到url的query部分。
///例如:sample://nativePage?aaa=bbb
onTap: () => FlutterBoost.singleton.open(
'sample://flutterPage',
urlParams: <String, dynamic>{
'query': <String, dynamic>{'aaa': 'bbb'}
},
),
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'push Platform demo',
'push flutter widget',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () {
Navigator.push<dynamic>(
context,
MaterialPageRoute<dynamic>(builder: (_) => PushWidget()),
);
},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton
.open("sample://flutterFragmentPage"),
),
],
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'push Platform demo',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () {},
),
InkWell(
child: Container(
padding: const EdgeInsets.all(8.0),
margin: const EdgeInsets.all(8.0),
color: Colors.yellow,
child: Text(
'open flutter fragment page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () =>
FlutterBoost.singleton.open('sample://flutterFragmentPage'),
),
],
),
),
),
);
......@@ -293,15 +312,15 @@ class _FlutterRouteWidgetState extends State<FlutterRouteWidget> {
}
class FragmentRouteWidget extends StatelessWidget {
final Map params;
const FragmentRouteWidget(this.params);
FragmentRouteWidget(this.params);
final Map<String, dynamic> params;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('flutter_boost_example'),
title: const Text('flutter_boost_example'),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
......@@ -309,7 +328,7 @@ class FragmentRouteWidget extends StatelessWidget {
Container(
margin: const EdgeInsets.only(top: 80.0),
child: Text(
"This is a flutter fragment",
'This is a flutter fragment',
style: TextStyle(fontSize: 28.0, color: Colors.blue),
),
alignment: AlignmentDirectional.center,
......@@ -317,7 +336,7 @@ class FragmentRouteWidget extends StatelessWidget {
Container(
margin: const EdgeInsets.only(top: 32.0),
child: Text(
params['tag'] ?? '',
'${params['tag']}' ?? '',
style: TextStyle(fontSize: 28.0, color: Colors.red),
),
alignment: AlignmentDirectional.center,
......@@ -332,7 +351,7 @@ class FragmentRouteWidget extends StatelessWidget {
'open native page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton.open("sample://nativePage"),
onTap: () => FlutterBoost.singleton.open('sample://nativePage'),
),
InkWell(
child: Container(
......@@ -343,7 +362,7 @@ class FragmentRouteWidget extends StatelessWidget {
'open flutter page',
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () => FlutterBoost.singleton.open("sample://flutterPage"),
onTap: () => FlutterBoost.singleton.open('sample://flutterPage'),
),
InkWell(
child: Container(
......@@ -355,7 +374,7 @@ class FragmentRouteWidget extends StatelessWidget {
style: TextStyle(fontSize: 22.0, color: Colors.black),
)),
onTap: () =>
FlutterBoost.singleton.open("sample://flutterFragmentPage"),
FlutterBoost.singleton.open('sample://flutterFragmentPage'),
)
],
),
......@@ -373,13 +392,13 @@ class _PushWidgetState extends State<PushWidget> {
@override
void initState() {
// TODO: implement initState
// TODO(unknown): implement initState
super.initState();
}
@override
void didChangeDependencies() {
// TODO: implement didChangeDependencies
// TODO(unknown): implement didChangeDependencies
super.didChangeDependencies();
// if (_backPressedListenerUnsub == null) {
......@@ -395,13 +414,13 @@ class _PushWidgetState extends State<PushWidget> {
@override
void dispose() {
// TODO: implement dispose
// TODO(unknown): implement dispose
super.dispose();
_backPressedListenerUnsub?.call();
}
@override
Widget build(BuildContext context) {
return FlutterRouteWidget(message: "Pushed Widget");
return const FlutterRouteWidget(message: 'Pushed Widget');
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment