A hybrid solution between Flutter and Native. FlutterBoost is a Flutter plugin that allows Flutter integration for your existing native apps with minimal effort. The FlutterBoost philosophy is that using Flutter is as easy as using a WebView. Managing Native UIs and Flutter UIs at the same time is not uncommon in an existing application. FlutterBoost manages pages for you. The only thing you need to care about is the name of the page (usually a URL).
Prerequisites:
- Before continuing, you need to integrate Flutter into your existing project.
- The Flutter SDK supported by Boost 3.0 is> = 1.22
Begin
Add dependencies to your Flutter project.
Open your pubspec.yaml and add the following line to the dependencies:
1 2 3 4 5 | flutter_boost: git: url: 'https://github.com/alibaba/flutter_boost.git' ref: 'v3.0-hotfixes' |
FlutterBoost integration
Integration into Flutter project
- Initialize :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | void main() { runApp(MyApp()); } class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { static Map<String, FlutterBoostRouteFactory> routerMap = { '/': (settings, uniqueId) { return PageRouteBuilder<dynamic>( settings: settings, pageBuilder: (_, __, ___) => Container()); }, 'embedded': (settings, uniqueId) { return PageRouteBuilder<dynamic>( settings: settings, pageBuilder: (_, __, ___) => EmbeddedFirstRouteWidget()); }, 'presentFlutterPage': (settings, uniqueId) { return PageRouteBuilder<dynamic>( settings: settings, pageBuilder: (_, __, ___) => FlutterRouteWidget( params: settings.arguments, uniqueId: uniqueId, )); }}; Route<dynamic> routeFactory(RouteSettings settings, String uniqueId) { FlutterBoostRouteFactory func =routerMap[settings.name]; if (func == null) { return null; } return func(settings, uniqueId); } @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return FlutterBoostApp( routeFactory ); } |
- Boost Lifecycle monitoring:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | class SimpleWidget extends StatefulWidget { final Map params; final String messages; final String uniqueId; const SimpleWidget(this.uniqueId, this.params, this.messages); @override _SimpleWidgetState createState() => _SimpleWidgetState(); } class _SimpleWidgetState extends State<SimpleWidget> with PageVisibilityObserver { static const String _kTag = 'xlog'; @override void didChangeDependencies() { super.didChangeDependencies(); print('$_kTag#didChangeDependencies, ${widget.uniqueId}, $this'); } @override void initState() { super.initState(); PageVisibilityBinding.instance.addObserver(this, ModalRoute.of(context)); print('$_kTag#initState, ${widget.uniqueId}, $this'); } @override void dispose() { PageVisibilityBinding.instance.removeObserver(this); print('$_kTag#dispose, ${widget.uniqueId}, $this'); super.dispose(); } @override void onForeground() { print('$_kTag#onForeground, ${widget.uniqueId}, $this'); } @override void onBackground() { print('$_kTag#onBackground, ${widget.uniqueId}, $this'); } @override void onAppear(ChangeReason reason) { print('$_kTag#onAppear, ${widget.uniqueId}, $reason, $this'); } void onDisappear(ChangeReason reason) { print('$_kTag#onDisappear, ${widget.uniqueId}, $reason, $this'); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('tab_example'), ), body: SingleChildScrollView( physics: BouncingScrollPhysics(), child: Container( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Container( margin: const EdgeInsets.only(top: 80.0), child: Text( widget.messages, style: TextStyle(fontSize: 28.0, color: Colors.blue), ), alignment: AlignmentDirectional.center, ), Container( margin: const EdgeInsets.only(top: 32.0), child: Text( widget.uniqueId, style: TextStyle(fontSize: 22.0, color: Colors.red), ), alignment: AlignmentDirectional.center, ), InkWell( child: Container( padding: const EdgeInsets.all(8.0), margin: const EdgeInsets.all(30.0), color: Colors.yellow, child: Text( 'open flutter page', style: TextStyle(fontSize: 22.0, color: Colors.black), )), onTap: () => BoostNavigator.of().push("flutterPage", arguments: <String, String>{'from': widget.uniqueId}), ) Container( height: 300, width: 200, child: Text( '', style: TextStyle(fontSize: 22.0, color: Colors.black), ), ) ], ))), ); } } |
- Page jump
Open the page:
1 2 3 | String result = await BoostNavigator.of() .push("flutterPage", withContainer: true); |
Close the page
1 2 | BoostNavigator.of().pop('I am result for popping.'); |
Integrate into Android project
- Initialize
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | public class MyApplication extends FlutterApplication { @Override public void onCreate() { super.onCreate(); FlutterBoost.instance().setup(this, new FlutterBoostDelegate() { @Override public void pushNativeRoute(String pageName, HashMap<String, String> arguments) { Intent intent = new Intent(FlutterBoost.instance().currentActivity(), NativePageActivity.class); FlutterBoost.instance().currentActivity().startActivity(intent); } @Override public void pushFlutterRoute(String pageName, HashMap<String, String> arguments) { Intent intent = new FlutterBoostActivity.CachedEngineIntentBuilder(FlutterBoostActivity.class, FlutterBoost.ENGINE_ID) .backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.opaque) .destroyEngineWithActivity(false) .url(pageName) .urlParams(arguments) .build(FlutterBoost.instance().currentActivity()); FlutterBoost.instance().currentActivity().startActivity(intent); } },engine->{ engine.getPlugins(); } ); } } |
- AndroidManifest.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.idlefish.flutterboost.example"> <application android:name="com.idlefish.flutterboost.example.MyApplication" android:label="flutter_boost_example" android:icon="@mipmap/ic_launcher"> <activity android:name="com.idlefish.flutterboost.containers.FlutterBoostActivity" android:theme="@style/Theme.AppCompat" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" > <meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/launch_background"/> </activity> <meta-data android:name="flutterEmbedding" android:value="2"> </meta-data> </application> </manifest> |
- Open and close Flutter page
1 2 3 4 | FlutterBoost.instance().open("flutterPage",params); FlutterBoost.instance().close("uniqueId"); |
Integration into iOS project
- AppDelegate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { MyFlutterBoostDelegate* delegate=[[MyFlutterBoostDelegate alloc ] init]; [[FlutterBoost instance] setup:application delegate:delegate callback:^(FlutterEngine *engine) { } ]; return YES; } @end |
- FlutterBoostDelegate
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | @interface MyFlutterBoostDelegate : NSObject<FlutterBoostDelegate> @property (nonatomic,strong) UINavigationController *navigationController; @end @implementation MyFlutterBoostDelegate - (void) pushNativeRoute:(FBCommonParams*) params{ BOOL animated = [params.arguments[@"animated"] boolValue]; BOOL present= [params.arguments[@"present"] boolValue]; UIViewControllerDemo *nvc = [[UIViewControllerDemo alloc] initWithNibName:@"UIViewControllerDemo" bundle:[NSBundle mainBundle]]; if(present){ [self.navigationController presentViewController:nvc animated:animated completion:^{ }]; }else{ [self.navigationController pushViewController:nvc animated:animated]; } } - (void) pushFlutterRoute:(FBCommonParams*)params { FlutterEngine* engine = [[FlutterBoost instance ] getEngine]; engine.viewController = nil; FBFlutterViewContainer *vc = FBFlutterViewContainer.new ; [vc setName:params.pageName params:params.arguments]; BOOL animated = [params.arguments[@"animated"] boolValue]; BOOL present= [params.arguments[@"present"] boolValue]; if(present){ [self.navigationController presentViewController:vc animated:animated completion:^{ }]; }else{ [self.navigationController pushViewController:vc animated:animated]; } } - (void) popRoute:(FBCommonParams*)params result:(NSDictionary *)result{ FBFlutterViewContainer *vc = (id)self.navigationController.presentedViewController; if([vc isKindOfClass:FBFlutterViewContainer.class] && [vc.uniqueIDString isEqual: params.uniqueId]){ [vc dismissViewControllerAnimated:YES completion:^{}]; }else{ [self.navigationController popViewControllerAnimated:YES]; } } @end |
- Open and close Flutter page
1 2 3 4 | [[FlutterBoost instance] open:@"flutterPage" arguments:@{@"animated":@(YES)}]; [[FlutterBoost instance] open:@"secondStateful" arguments:@{@"present":@(YES)}]; |