Commit 787c847a authored by XinLei's avatar XinLei Committed by GitHub

Merge pull request #12 from alibaba/master

[sync] 2020/3/2
parents a08e481b dfed0646
......@@ -57,6 +57,37 @@ bool isTopContainer = FlutterBoost.BoostContainer.of(context).onstage
同时FlutterBoost也提供了一次性创建混合工程的命令:flutterboot。代码参考:https://github.com/alibaba-flutter/flutter-boot
### 如果我需要通过FlutterViewController再弹出一个新的但frame比较小的FlutterViewController,应该怎么实现?
### 7. 如果我需要通过FlutterViewController再弹出一个新的但frame比较小的FlutterViewController,应该怎么实现?
回答:如果不加处理会遇到window大小变化的问题,但可以解决。具体可以参考这个issue:https://github.com/alibaba/flutter_boost/issues/435
### 8. Flutter ViewController如何设置横屏
VC设置横屏依赖于NavigationController或者rootVC。可以通过一下方式来设置:
1. dart层的SystemChrome.setPreferredOrientations函数并非直接设置转向,而是设置页面优先使用的转向(preferred)
2. app的转向控制除了info.plist的设置外,主要受UIWindow.rootViewController控制。大概过程是这样的:硬件检测到转向,就会调用UIWindow的转向函数,然后调用其rootViewController的shouldAutorotate判断是否需要自动转,然后取supportedInterfaceOrientations和info.plist中设置的交集来判断可否转
3. 对于UIViewController中的转向,也只在rootviewcontroller中才有效
举例如下,实现步骤可以这样:
1. 重写NavigationController:
```objc
-(BOOL)shouldAutorotate
{
// id currentViewController = self.topViewController;
//
//
// if ([currentViewController isKindOfClass:[FlutterViewController class]])
// return [currentViewController shouldAutorotate];
return YES;
}
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
id currentViewController = self.topViewController;
if ([currentViewController isKindOfClass:[FlutterViewController class]]){
NSLog(@"[XDEBUG]----fvc supported:%ld\n",[currentViewController supportedInterfaceOrientations]);
return [currentViewController supportedInterfaceOrientations];
}
return UIInterfaceOrientationMaskAll;
}
```
2. 改dart层:因为SystemChrome.setPreferredOrientations的设置是全局的,但混合栈是多页面,所以在main函数中设置,后面在新建一个FlutterViewController时会被冲掉。为了解决这个问题,需要在每个dart页面的build处都加上这语句来设置每个页面能支持哪些转向类型
......@@ -33,14 +33,16 @@
| Flutter Boost 分支 | 支持的 Flutter SDK 版本 | Description | 是否支持 AndroidX? |
| v1.9.1-hotfixes | 1.9.1-hotfixes | 支持androidx,修复bug后会定期发布新版本 | Yes |
| task/task_v1.9.1_support_hotfixes| 1.9.1-hotfixes | 支持support包,不支持androidx | NO |
| v1.12.13-hotfixes | 1.12.13-hotfixes | 支持androidx,目前还没发布的版本,用分支形式引入 | Yes |
| task/task_v1.12.13_support_hotfixes| 1.12.13-hotfixes | 支持support包,不支持androidx | NO |
.
| Flutter Boost 分支 | 支持的 Flutter SDK 版本 | 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 |
# 安装
......
......@@ -7,6 +7,7 @@
//
#import "PlatformRouterImp.h"
#import "UIViewControllerDemo.h"
#import <flutter_boost/FlutterBoost.h>
@interface PlatformRouterImp()
......@@ -14,12 +15,30 @@
@implementation PlatformRouterImp
- (void)openNativeVC:(NSString *)name
urlParams:(NSDictionary *)params
exts:(NSDictionary *)exts{
UIViewController *vc = UIViewControllerDemo.new;
BOOL animated = [exts[@"animated"] boolValue];
if([params[@"present"] boolValue]){
[self.navigationController presentViewController:vc animated:animated completion:^{
}];
}else{
[self.navigationController pushViewController:vc animated:animated];
}
}
#pragma mark - Boost 1.5
- (void)open:(NSString *)name
urlParams:(NSDictionary *)params
exts:(NSDictionary *)exts
completion:(void (^)(BOOL))completion
{
if ([name isEqualToString:@"native"]) {//模拟打开native页面
[self openNativeVC:name urlParams:params exts:exts];
return;
}
BOOL animated = [exts[@"animated"] boolValue];
FLBFlutterViewContainer *vc = FLBFlutterViewContainer.new;
[vc setName:name params:params];
......
......@@ -16,6 +16,17 @@ class FirstRouteWidget extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
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 second route result $value");
});
},
),
RaisedButton(
child: Text('Open second route'),
onPressed: () {
......
......@@ -87,7 +87,8 @@ class BoostContainer extends Navigator {
}
},
observers: <NavigatorObserver>[
ContainerNavigatorObserver.bindContainerManager()
ContainerNavigatorObserver.bindContainerManager(),
HeroController(),
],
onUnknownRoute: navigator.onUnknownRoute);
......
......@@ -16,6 +16,7 @@ dev_dependencies:
flutter_test:
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
......
import 'package:flutter_test/flutter_test.dart';
import 'unit/boost_channel_test.dart' as boost_channel;
//import 'unit/boost_container_test.dart' as boost_container;
import 'unit/boost_page_route_test.dart' as boost_page_route;
import 'unit/container_coordinator_test.dart'
as container_coordinator;
import 'unit/container_manager_test.dart'
as container_manager;
import 'unit/flutter_boost_test.dart' as flutter_boost;
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
// group('all_test', () {
// boost_channel.main();
//// boost_container.main();
// boost_page_route.main();
// container_coordinator.main();
// container_manager.main();
// flutter_boost.main();
// });
}
import 'package:flutter_boost/container/container_coordinator.dart';
import 'dart:ui';
import 'package:flutter/services.dart';
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;
EventListener get testEventListener => _testEventListener;
MethodHandler _testHandler;
EventListener _testEventListener;
VoidCallback addEventListener(String name, EventListener listener) {
_testEventListener = listener;
super.addEventListener(name, listener);
}
VoidCallback addMethodHandler(MethodHandler handler) {
_testHandler = handler;
super.addMethodHandler(handler);
}
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
const MessageCodec<dynamic> jsonMessage = JSONMessageCodec();
test('test onMethodCall', () async {
// Initialize all bindings because defaultBinaryMessenger.send() needs a window.
TestWidgetsFlutterBinding.ensureInitialized();
MockBoostChannel boostChannel = MockBoostChannel();
ContainerCoordinator(boostChannel);
final Map arguments = {};
arguments["pageName"] = "pageName";
arguments["params"] = {};
arguments["uniqueId"] = "xxxxx";
MethodCall call = MethodCall('didInitPageContainer', arguments);
try {
boostChannel.testHandler(call);
} catch (e) {
expect(e, isAssertionError);
}
MethodCall call2 = MethodCall('willShowPageContainer', arguments);
try {
boostChannel.testHandler(call2);
} catch (e) {
expect(e, isNoSuchMethodError);
}
MethodCall call3 = MethodCall('didShowPageContainer', arguments);
try {
boostChannel.testHandler(call3);
} catch (e) {
expect(e, isNoSuchMethodError);
}
MethodCall call4 = MethodCall('willDisappearPageContainer', arguments);
try {
boostChannel.testHandler(call4);
} catch (e) {
expect(e, isNoSuchMethodError);
}
MethodCall call5 = MethodCall('onNativePageResult', arguments);
try {
boostChannel.testHandler(call5);
} catch (e) {
expect(e, isNoSuchMethodError);
}
MethodCall call6 = MethodCall('didDisappearPageContainer', arguments);
try {
boostChannel.testHandler(call6);
} catch (e) {
expect(e, isNoSuchMethodError);
}
MethodCall call7 = MethodCall('willDeallocPageContainer', arguments);
try {
boostChannel.testHandler(call7);
} catch (e) {
expect(e, isNoSuchMethodError);
}
Map arg = {'type': 'backPressedCallback'};
try {
boostChannel.testEventListener("lifecycle", arg);
} catch (e) {
expect(e, isNoSuchMethodError);
}
Map arg2 = {'type': 'foreground'};
try {
boostChannel.testEventListener("lifecycle", arg2);
} catch (e) {
expect(e, isNoSuchMethodError);
}
group('container_coordinator', () {
Map arg3 = {'type': 'background'};
try {
boostChannel.testEventListener("lifecycle", arg3);
} catch (e) {
expect(e, isNoSuchMethodError);
}
Map arg4 = {'type': 'scheduleFrame'};
try {
boostChannel.testEventListener("lifecycle", arg4);
} catch (e) {
expect(e, isNoSuchMethodError);
}
});
}
\ No newline at end of file
}
import 'package:flutter/material.dart';
import 'package:flutter_boost/container/container_manager.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_boost/flutter_boost.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
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
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");
return FlutterRouteWidget(params: params);
},
});
FlutterBoost.singleton
.addBoostNavigatorObserver(TestBoostNavigatorObserver());
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Boost example',
builder: FlutterBoost.init(postPush: _onRoutePushed),
home: Container());
}
void _onRoutePushed(
String pageName, String uniqueId, Map params, Route route, Future _) {}
}
class TestBoostNavigatorObserver extends NavigatorObserver {
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didPush");
}
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didPop");
}
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didRemove");
}
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
print("flutterboost#didReplace");
}
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
......@@ -67,84 +10,39 @@ void main() {
testWidgets('test iOS edge swipe then drop back at starting point works',
(WidgetTester tester) async {
//push app
await tester.pumpWidget(
MyApp(),
);
//open firt page
ContainerCoordinator.singleton
.nativeContainerDidShow("first", {}, "1000000");
await tester.pump(const Duration(seconds: 1));
expect(find.text('First'), findsOneWidget);
//open second page firt(1000000)->second(2000000)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", {}, "2000000");
await tester.pump(const Duration(seconds: 1));
expect(find.text('Second'), findsOneWidget);
await tester.pump(const Duration(seconds: 1));
//close sencod page firt(1000000)
FlutterBoost.containerManager?.remove("2000000");
await tester.pump(const Duration(seconds: 1));
expect(find.text('First'), findsOneWidget);
// second page ,but pageId is 2000001 firt(1000000)->second(2000001)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", {}, "2000001");
await tester.pump(const Duration(seconds: 1));
expect(find.text('Second'), findsOneWidget);
await tester.pump(const Duration(seconds: 1));
//reopen firt page second(2000001)->firt(1000000)
ContainerCoordinator.singleton
.nativeContainerDidShow("first", {}, "1000000");
await tester.pump(const Duration(seconds: 1));
expect(find.text('First'), findsOneWidget);
//reopen firt page second(2000001)->firt(1000000)
// reopen second page and pageId is 2000001 firt(1000000)->second(2000001)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", {}, "2000001");
await tester.pump(const Duration(seconds: 1));
expect(find.text('Second'), findsOneWidget);
await tester.pump(const Duration(seconds: 1));
//close firt(1000000) page second(2000001)
FlutterBoost.containerManager?.remove("1000000");
await tester.pump(const Duration(seconds: 1));
expect(find.text('Second'), findsOneWidget);
// open second(2000003)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", {}, "2000003");
await tester.idle();
expect(find.text('Second'), findsOneWidget);
});
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, isNoSuchMethodError);
}
try {
FlutterBoost.singleton.close("url");
} catch (e) {
expect(e, isNoSuchMethodError);
}
try {
FlutterBoost.singleton.closeCurrent(result: {}, exts: {});
} catch (e) {
expect(e, isNoSuchMethodError);
}
try {
FlutterBoost.singleton.closeByContext(null, result: {}, exts: {});
} 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_test/flutter_test.dart';
import 'page_widgets.dart';
import 'package:flutter_boost/container/container_coordinator.dart';
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
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");
return FlutterRouteWidget(params: params);
},
});
FlutterBoost.singleton
.addBoostNavigatorObserver(TestBoostNavigatorObserver());
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Boost example',
builder: FlutterBoost.init(postPush: _onRoutePushed),
home: Container());
}
void _onRoutePushed(
String pageName, String uniqueId, Map params, Route route, Future _) {}
}
class TestBoostNavigatorObserver extends NavigatorObserver {
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didPush");
}
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didPop");
}
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didRemove");
}
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
print("flutterboost#didReplace");
}
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
testWidgets('test iOS edge swipe then drop back at starting point works',
(WidgetTester tester) async {
//push app
await tester.pumpWidget(
MyApp(),
);
//open firt page
ContainerCoordinator.singleton
.nativeContainerDidShow("first", {}, "1000000");
await tester.pump(const Duration(seconds: 1));
expect(find.text('First'), findsOneWidget);
//open second page firt(1000000)->second(2000000)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", {}, "2000000");
await tester.pump(const Duration(seconds: 1));
expect(find.text('Second'), findsOneWidget);
await tester.pump(const Duration(seconds: 1));
//close sencod page firt(1000000)
FlutterBoost.containerManager?.remove("2000000");
await tester.pump(const Duration(seconds: 1));
expect(find.text('First'), findsOneWidget);
// second page ,but pageId is 2000001 firt(1000000)->second(2000001)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", {}, "2000001");
await tester.pump(const Duration(seconds: 1));
expect(find.text('Second'), findsOneWidget);
await tester.pump(const Duration(seconds: 1));
//reopen firt page second(2000001)->firt(1000000)
ContainerCoordinator.singleton
.nativeContainerDidShow("first", {}, "1000000");
await tester.pump(const Duration(seconds: 1));
expect(find.text('First'), findsOneWidget);
//reopen firt page second(2000001)->firt(1000000)
// reopen second page and pageId is 2000001 firt(1000000)->second(2000001)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", {}, "2000001");
await tester.pump(const Duration(seconds: 1));
expect(find.text('Second'), findsOneWidget);
await tester.pump(const Duration(seconds: 1));
//close firt(1000000) page second(2000001)
FlutterBoost.containerManager?.remove("1000000");
await tester.pump(const Duration(seconds: 1));
expect(find.text('Second'), findsOneWidget);
// open second(2000003)
ContainerCoordinator.singleton
.nativeContainerDidShow("second", {}, "2000003");
await tester.idle();
expect(find.text('Second'), findsOneWidget);
});
}
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