preface
The advantages of Flutter in cross-platform development are clear.
- Near-native performance
- Thermal overload
- Rich components
Given that the project has a large number of native businesses, it is not possible to refactor all businesses based on Flutter. Therefore, Flutter can only be used on an existing basis to develop new business or restructure old business. Refer to Idle Fish, Harrow, etc., who also provide the corresponding solutions for mixed development: Flutter_boost and Flutter_thrio. At present, we adopt Flutter_Boost as the solution of our TW591 project.
Flutter remix existing projects
Official Access:
-
Create a Flutter project, Flutter create -t module flutter_module, create a Flutter project, Flutter create -t module flutter_module Otherwise, you will encounter the flutter_export_environment problem described in clause 4
-
Add the created Flutter_module project to your target repository
-
Add the following script to your Podfile
Flutter_application_path = '.. flutter_application_path = '.. /.. /TWFlutter591/flutter_module' load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') target 'twhouse' do install_all_flutter_pods(flutter_application_path) endCopy the code
- Notice The flutter_export_environment.sh file path is incorrect
To handle this, delete the Flutter_module /ios file
Run this with AndoirdStudio or VSCode to generate the new flutter_export_environment.sh file
- Integrated idle fish Flutter_boost hybrid development program
- Note: The Flutter_boost version needs to correspond to our flutter version, for example, Flutter_boost :v1.17.1-hotfixes corresponding to the FLUTTER SDK: 1.17.1
- Use the Flutter –version command to view the current version
- Open pubspec.yaml in the flutter_module folder and add dependencies
Flutter_boost: git: url: 'https://github.com/alibaba/flutter_boost.git' ref: 'v1.17.1 - hotfixes'Copy the code
- Execute the command
flutter packages get
- Finally, it is implemented in the project
pod install --repo-update
- The native project Flutter directory after install is executed will package our Flutter project into a framework
Native part
- The TWFlutterUtil singleton class is used to register the FLUTTER engine and encapsulate a layer of calls to avoid direct calls from the FlutterBoostPlugin
- Based on Flutter_boost DEMO, TWFlutterPlatformRouter was adjusted according to our project business, mainly the Router that FLUTTER interacts with Native platform
- TWFlutterJumpUtil mainly deals with the business logic between Flutter and Native hop routes
- TWFlutterNativePageName Defines the page route name
- TWFlutterNativeEventUtil mainly deals with the business logic of Flutter and Native events
Sample TWFlutterUtil section
TWFlutterUtil.swift
import UIKit
import flutter_boost
@objcMembers class TWFlutterUtil: NSObject {
static let shareInstance = TWFlutterUtil(a)var router: TWFlutterPlatformRouter?
var engine: FlutterEngine?
// register the FLUTTER engine
func registerFlutter(a) {
router = TWFlutterPlatformRouter(a)guard let router = router else {return}
FlutterBoostPlugin.sharedInstance().startFlutter(with: router) {[weak self](engine) in
self?.engine = engine
HouseTool.dispatch(afterTime: 2.0) {
TWFlutterNativeEventUtil.sendConfigureInfo()
}
}
}
// MARK: - sendEvent
/** * Native layer sends events to Dart layer, eventName specified by eventName ** @param eventName eventName * @param arguments */
open class func sendEvent(_ eventName: String.arguments: [AnyHashable: Any]) {
FlutterBoostPlugin.sharedInstance().sendEvent(eventName, arguments: arguments)
}
/** * Add event listener for Dart layer to call Native layer ** @param name event name * @param listner event listener */
open class func addEventListener(_ listener: @escaping FLBEventListener.name: String) - >FLBVoidCallback {
return FlutterBoostPlugin.sharedInstance().addEventListener(listener, forName: name)
}
// MARK: - open/close Page
** @param uniqueId the uniqueId of the closed page * @param resultData the result to return from the page (for the previous page), * @param Completion * @Param Completion Note that an immediate callback is required to close the page, which will be called back once the page is closed */
open class func close(_ uniqueId: String.result resultData: [AnyHashable: Any].exts: [AnyHashable: Any].completion: @escaping (Bool) - >Void) {
FlutterBoostPlugin.close(uniqueId, result: resultData, exts: exts, completion: completion)
}
/** * Open a new page (default is push), mixing the recommended interface for operating the page; UrlParams can be set to present the page: urlParams:@{@"present":@(YES)} * * @param url url to open the page resource locator * @param urlParams passed in the page parameter; @param resultCallback The callback that is executed when the page returns at the end of the page. This callback is used to retrieve the data returned from the page. For example, in the resultData * @param completion passed in by the close function, note that the immediate callback to open the page must be passed, which will be called */ once the page is opened
open class func open(_ url: String.urlParams: [AnyHashable: Any].exts: [AnyHashable: Any].onPageFinished resultCallback: @escaping ([AnyHashable: Any]) -> Void.completion: @escaping (Bool) - >Void) {
FlutterBoostPlugin.open(url, urlParams: urlParams, exts: exts, onPageFinished: resultCallback, completion: completion)
}
** @param url = @param urlParams = @param urlParams; @param resultCallback The callback that is executed when the page returns at the end of the page. This callback is used to retrieve the data returned from the page. For example, in the resultData * @param completion passed in by the close function, note that the immediate callback to open the page must be passed, which will be called */ once the page is opened
open class func present(_ url: String.urlParams: [AnyHashable: Any].exts: [AnyHashable: Any].onPageFinished resultCallback: @escaping ([AnyHashable: Any]) -> Void.completion: @escaping (Bool) - >Void) {
FlutterBoostPlugin.present(url, urlParams: urlParams, exts: exts, onPageFinished: resultCallback, completion: completion)
}
}
Copy the code
Native opens the Flutter page
The page uses the file page class name as the registration ID
// TWFlutterUtil opens more pages in iOS
TWFlutterUtil.open("TWMorePage",
urlParams: ["isDebug":API_DEBUG = = 1 ? "1" : "0"],
exts: ["isHideNavigationBar":"1"],
onPageFinished: { (result) in
}) { (finish) in
}
Copy the code
Flutter part
- TWFlutterBoostPage is mainly the entry page for the Flutter project
- TWRouterBoost is used to register routes to native calls to flutter
- TWFlutterNativeEvent is used for flutter and native event processing
- TWRouterFlutterNative Service logic processing of route redirection
Example TWFlutterBoostPage section
TWFlutterBoostPage
import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_module/common/tw_app_color.dart';
import 'package:flutter_module/router/tw_router_boost.dart';
class TWFlutterBoostPage extends StatefulWidget {
@override
_TWFlutterBoostAppState createState() => _TWFlutterBoostAppState();
}
class _TWFlutterBoostAppState extends State<TWFlutterBoostApp> {
@override
void initState() {
super.initState();
// Initialize registration...
TWRouterBoost routerBoost = TWRouterBoost();
routerBoost.registerRouter();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Boost example'.// (2) Initialize the route
debugShowCheckedModeBanner: true,
theme: ThemeData(
primaryColor: TWAppColor.tw_ff7f00,
dividerColor: TWAppColor.tw_eeeeee,
),
builder: FlutterBoost.init(postPush: _onRoutePushed),
home: Container(
color:Colors.white
));
}
void _onRoutePushed(
String pageName,
String uniqueId,
Map<String.dynamic> params,
Route<dynamic> route,
Future<dynamic> _,) {}}Copy the code
TWRouterFlutterNative
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_module/features/mine/more/tw_more_page.dart';
class TWRouterFlutterNative {
///* * * ** * * ** * * *** Flutter to Naitive *** * * ** * * ** * * ** * * ** /
static const String tw_flutterOpenNative = 'TWFlutterOpenNative';
///* * * ** * * ** * * *** Naitive to Flutter *** * * ** * * ** * * ** * * **/
static const String tw_flutterMorePage = "TWMorePage";
/// Route hop logic processes map
static Map<String, PageBuilder> routerPageBuilder = <String, PageBuilder>{
tw_flutterMorePage: (String pageName, Map<String.dynamic> params, String _) => TWMorePage(params: params,),
};
}
Copy the code
TWRouterBoost
import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_module/router/tw_router_flutter_native.dart';
import 'package:flutter_module/util/tw_log.dart';
class TWRouterBoost extends NavigatorObserver{
// Initialize the registered route...
void registerRouter() {
FlutterBoost.singleton.registerPageBuilders(TWRouterFlutterNative.routerPageBuilder);
FlutterBoost.singleton.addBoostNavigatorObserver(this);
}
///* * * ** * * ** * * *** NavigatorObserver Method *** * * ** * * ** * * ** * * ** /
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
TWLog("flutterboost#didPush");
}
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
TWLog("flutterboost#didPop");
}
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
TWLog("flutterboost#didRemove");
}
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
TWLog("flutterboost#didReplace"); }}Copy the code
TWFlutterNativeEvent
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_module/config/tw_configure.dart';
import 'package:flutter_module/util/tw_log.dart';
class TWFlutterNativeEvent {
///* * * ** * * ** * * *** Native sends the Flutter event name *** * * ** * * ** * * ** * * ** /
static final String tw_flutterNativeEventConfigureInfo = "EventConfigureInfo";
///* * * ** * * ** * * *** The event name ** is sent to Native by *** * * ** * * ** * * ** * * **/
///* * * ** * * ** * * *** Native sends uniform processing to Flutter events *** * * ** * * ** * * ** * * ** /
/// Listen for startup configuration information
static void addConfigureInfo() {
TWLog("Start configuring startup information...");
FlutterBoost.singleton.channel.addEventListener(TWFlutterNativeEvent.tw_flutterNativeEventConfigureInfo,
(name, arguments) {
TWConfigure.singleton.configure(arguments);
return; }); }}Copy the code
Flutter opens the Native page
Open in project routing mode note: TWFlutterOpenNative ID is to mark the opening of the Native page from the Flutter page and the routing part of the exTS field on the Native page. It is suggested that the original project should unify the routing rules and standards of Android and iOS. We use MGJRouter for iOS and ARouter for Android. Define a set of routing URL standards for projects
///* * * ** * * ** * * *** Private Method *** * * ** * * ** * * ** * * ** /
void clickAction(int index) {
TWLog("Index =$index");
/// Open the evaluation,
String open_page_url = "app:///xxxx/more_page? entrance=more_evalue&pushAnimation=1";
/// Free fish library open native API
FlutterBoost.singleton.open(TWRouterFlutterNative.tw_flutterOpenNative, exts: {
"app_open_url": app_open_url
}).then((value) => print('call me when page is finished. did recieve native route result $value'));
}
Copy the code
Refactor more pages with Flutter, and the experience feels similar to native
Excellent third party library
In order to minimize native bridging and make Android and iOS as common as possible, some infrastructure needs to be built. Including network library, state management, image cache, data cache and so on…
classification | address | star |
---|---|---|
The network library | Dio | 8.2 k. |
State management | bloc | 5.3 k. |
State management | provider | 2.8 k. |
The database | sqflite | 1.8 k. |
Image cache library | flutter_cached_network_image | 1.4 k. |
Refresh the controls | flutter_easyrefresh | 2.2 k. |
Refresh the controls | flutter_pulltorefresh | 1.6 k. |
shuffling | flutter_swiper | 2.6 k. |
Local notifications | flutter_local_notifications | 1.1 k. |
Widgets | flukit | 2.6 k. |
Toast | flutter_oktoast | 288 |
Toast | FlutterToast | 818 |
The menu | flutter_slidable | 1.4 k. |
The map | flutter_amap | 137 |
The map | flutter_amap_location | 249 |
A debugging tool | flutter_slidable | 308 |
Current project Structure
Flutter_module ├ ─ ─ images # image resources ├ ─ ─ asset # local resources ├ ─ ─ lib # project code ├ ─ ─ the features # business module | ├ ─ ─ home # page | ├ ─ ─ # search search | ├ ─ ─ # # news news | └ ─ ─ mime my | └ ─ ─ more # more (example: More pages) | ├ ─ ─ the model # model | ├ ─ ─ the view # view | ├ ─ ─ tool # tools | └ ─ ─ page # page | ├ ─ ─ page # portal home page ├ ─ ─ common # general components, header files, defining constants (example: │ ├─ Utility class │ HTTP tools │ public Methods │ ├─ All kinds of Widgets │ ├─ Store │ ├ s │ State Management │ ├─ Config │ Center ├ ─ ├ ─ router # ├ ─ imp (1), imp (2), imp (2), imp (3Copy the code