许多情况下用Flutter来编写整个项目是不太实际的。例如公司现已有了老练的App产品了,去用Flutter去重写整个项目会有很大的作业量和功用上的风险;有时分公司出于慎重的原因,不或许去鲁莽的取选用新的技能,或许更乐意去用一些非必须的功用部分去试水,假定数据库规划作用不错才会继续大面积运用。

咱们能够将Flutter打包成模块(module)整合产品定位进入原生的iOSAndroid数据库体系工程师项目中结束上述需求。最初步Flutter只支撑单个页面,最近现已初步支撑多个Flutter页面,可是正如官方所说的其仍是不太安稳,有各种难以想象的问题。假定不幸采坑,能够试着弯弯绕绕去处理哦,否则只能躺平了。

Note: Support for adding multiple instances of Flutter became available as of Flutter 2.0.0. Use at your own risk since stability or performance issues, and API changes are still possible产品质量法.

项目介绍

本项意图比如是一个影音App,根据iOS项目建立,包含三个Tab,每个Tab的内容是一个Flutter模块:

  • 主页模块

Flutter混合开发—iOS篇

  • 频道模块

Flutter混合开发—iOS篇

  • 我的模块

Flutter混合开发—iOS篇

阐明:上面数据库有哪几种三个Flutter模块都是独立的,可是主页和频道模块能进入影音概略页面flutter怎样读音发音,播映的时分记载播映的前史记载,能够点赞,这些播映前史和点赞的数据在我的模块中闪现,会涉及到独立的Flutter模块之间的数据同享。此外,看不到播映作用是因为播映器不支撑iOS模拟器,真机上是能够播映的。

混合开发的结束进程

ios项目建立

新建项意图详细进程就不介绍了。

数据库查询句子们根据CocoaPodStoryBoard建立了一产品司理个主页是UITabbarController的项目。然后新建了三个UIViewControllerMain数据库体系概论第五版课后答案ViewController, ChannelVi数据库体系的中心是ewControllerMin产品生命周期eViewController产品运营他们将会别离嵌入flutter怎样读音发音对应的Flutter模块。

  • 项意图结构和Podfile内容

Flutter混合开发—iOS篇

  • Storyboard预览

Flutter混合开发—iOS篇

  • UIViewController中都没有代码
class MainViewController: UIViewController {}
class Chann服务器租借多少钱一年elViewController: UIViewControll服务器操作体系银河麒麟er {}
class MineViewContro产品生命周期ller: UIflutter中文官网ViewController {产品司理}
  • 终究的服务器作用

Flutter混合开发—iOS篇

Flutter模块的APP编写

  • 建立一个Flutter模块—flutteFlutterr_movie_player
cd数据库原理及使用 /diflutter结构优缺点rectory
fl产品介绍utflutter开发ter create -flutter结构-template module flutter服务器操作体系_movie_player

数据库体系概论第五版课后答案心:Flutter项目和iOS项目最好是放在一个目录中,并且层app装置下载级相同。原因是iOS项目需求引用Flutter项目中的文件和APP库。

Flutter混合开发—iOS篇

  • 编写Flutter代码

因为本文只是为了介绍混合开发的结束逻辑,所以不会去数据库规划详细介绍每个Fluttflutter中文官网er页面是怎样结束的,你自己操练时能够不修改任何代码,就用默许的那个Flutter计数器也是能够的。

咱们接下来会介绍一些重要的进口相关的类:

  1. mainapproach.dart
<!-- 主页模块进口 -->数据库规划
@pr产品定位agma('vm:entry-point')
void main() => runApp(MainApp());
<!-- 频道模块进口 -->
@pragma('vm:entry-point')
void channel() => runApp(ChannelApp());
<!-- 我flutter结构优缺点的模块进口 --&gappreciatet;
@pragma('vm:entry-point')
void mine() => runApp(MineApp());
  1. 咱们界说了三个函数main,channelmine, 他们别离加载了MainApp(),ChannelApp()MineApp(),也能够直接理解为三个模块服务器租借多少钱一年,他们是相互fluttershy独立的。
  2. @pragma('vm:entry-point')这个注解是为了防止Dart的摇树优化(tree-shaking)将这儿界说的函数认appstore定为无用代码给优化掉了。main函数能够不加这个注解,一致加上也无妨。
  1. main_page.dart

其实上述3个App()的进口代码是相似的,咱们只以主页模块的进口main_page.dart为例做阐明。

class MainAp服务器地址在哪里看p extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "FBapp装置下载Movie主页模块",
theme: FBTheme.normalTheflutter菜鸟教程m数据库体系概论第五版课后答案e,
routes: FBRouter.routes,
initialRoute: FBRouter.homePageInitialRoute,
onGenapplicationerateRoute: FBRouter.generateRoute,产品质量法
debugShowCh服务器操作体系eckedMo数据库办理体系deBanner: false,
);
}fluttershy
}
class FBMainPage extends StatefulWidget {
// 路由的途径
s产品司理tappstoreatic final S产品tr服务器地址在哪里看ing routeName = "/main";
@override
_FBMainPageState createState() => _FBMainPageState();
}
class _FBMainPagflutteringeS数据库体系tate extends State<FBMainPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: buildAp数据库技能pBar(),
body: FBHomePage(),
);
}
/// AppBar
AppBar数据库原理及使用 buildAppBar() {
return AppBar(
backgroundColor: Colors.whflutteringite,
brightness: Brightness.lighappstoret,
leadingWidth: 154.rpx,
shadowColor: Colors.transparent,
leading: null,
actions: b数据库查询句子uildActi产品质量法ons(),
title: null,
);
}
///application AppBar的actions
Liapprovest<Widget> buildActions() {
return [Flutter
GestureDetector(
child: Padding(
padding: EdgeInsetappointments.symmetric(horizontal: 36.rpx),
child: Icon(
Icons.产品批号是生产日期吗search,
color: FBTheme.redColor,
size: 46.rpx,
),
),
onTap: searchTapped,
)
];
}
/// 查找按钮的点击跳转
void searchappointmentTapped() {
Navigator.of(context).pushNamed(FBSearchPage.routerName);
}
}

这个逻辑也很简单,和一般的Flutter p产品批号是生产日期吗roject 的代码没有任何差别。MaterialAp产品质量法p -> Scaffold -&g产品战略t; appBar + body(FBHomeflutter中文官网Page) -> 轮播图+列表 -> ….

iOS项目引进Flutter模块

  • 修改podfile文件
//approve 1. 找到flutter module 的目录
flutter_a产品规划专业pplication_path = '../../flutter_movie_player'
// 2. 找到f产品规划专业lutter module 的目录中的/.ios/Flutter/podhelper.fluttershyrb文件
load File.join(flutter_a数据库体系pplication_path, '.ios', 'Flutte服务器无法访问或恳求被阻拦r', 'podhelper.rb')
target '数据库查询句子FBMoviePlayer' do
us产品司理e_frameworks!
// 3. 实施podhelper.rb中的install_all_flutter_pods办法
install_all_flutter_pod服务器和电脑主机的差异s(flutter_application_path)
end

加的每行代码的逻辑意义在注释中有阐明。留神一点是flutter_application_path这个途径别整错了,否则就无法继续了。

  • 产品规划pod install

实施这个指令能将Flutter SDKFlutter 代码 引进到iOS项目中。

  • Appdelegate中界说一个FlutterflutteredEn产品司理gineGroup对象
var eng产品战略ineGr产品司理oup = FlutterEngineGroflutter怎样读音发音up(name: "fb-movieAPP-player", project: nil)

假定项目中有多个Flutter模块就需求运用FlutterEngineGroup, 它能办理多个FlutterEngine, 让他们同享资源等功用。

继续接下来的作业之前,我先介绍下结束思路:

咱们这儿的规划思路服务器租借是将三个加载不同Flutter APPFlutterViewControllerView放在MainViewController, ChannelViewControllerMi服务器怎样搭建neViewContr服务器操作体系olleflutteredrView上。

这儿有的小伙伴或许会有疑问:为什么不将MainViewflutter怎样读音发音Controller, Chan服务器无法访问或恳求被阻拦nelViewControllerMflutter开发ineViewController直接界说为Flutt产品定位erViewController服务器租借多少钱一年子类。

这儿我解说下:UITabbarController的子ViewControlappleler几乎是一同初始化的,假定他们都是FapprovelutterViewController那么会造成对FlutterEngineGroup同享资源的争夺,这样闪现会呈现反常。这也是现在运用多个Fapplicationlutter modul数据库e会呈现的一个问题。所以需求改动下思路appear,在需求运用的时分再进行FlutterViewController的初始化。其实这也有数据库办理体系点问题,便是进行预加载比较难控制,每个Flutter mo数据库原理及使用dule第一次加载的时分会有点慢。

介绍结束束办法后,继续敲代码啦。

  • 界说一个FlutterViewController子类
class FBFluflutter开发tterViewController: FlutterV数据库体系工程师iewController {
init(withEntrypoint entryPoint: String?) {
l数据库有哪几种et appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
// 1服务器租借. 用Appdelegate中的FlutterEngineGroup生成一个FlutterEngine,引擎加载Flutter进口是main.数据库规划dart的entrypoint函数
let newEngine = apflutter结构pDelegate.engineGroup.makeEnginflutterede(withEntrypoint: entryPoint, libraryURI: nil)
// 2. 用这个数据库体系工程师FlutterEngine初始化FlutterViewController
super.init(engine: newEngine, nibName: nil, bundle: nil)
}
required convenience init(coder aDecoder: NSCoder) {
self.init(appointmentwithEntrypoint: nil)
}
}

自定服务器怎样搭建义了一个FlutterViewController子类,这个子类会根据传过来flutter怎样读音发音entryPoint初始化一个FlutterEng数据库技能ine, 这个FlutterEngflutter怎样读音发音ine服务器地址在哪里看的加载进口是main.dart文件中的entrypoint函数,然后FlutterViewController子类持有这个FlutterEnginappearancee;

  • UIViewController加载FBFlutterViewController
class MainViewController: UIViewController {
// 1. 懒加载 main.dart 中的main进口函数对应的Flutte数据库体系工程师r App
private lazy var subFlutterVC: FBFlutterViewCont服务器操作体系银河麒麟roller = FBFlutterViewController(withEntrypoint: n产品批号是生产日期吗il)
override func viewapplicationDid服务器操作体系银河麒麟Load() {
// 2. 增加Fapprovelutter数据库规划ViewController
addChild(subFlutterVCfluttered)
let safeFrame = self.view.safeAreaLayoutGuide.layoutFrame
subFlutterVC.view.frame = safeFrame
self.view.addSubview(suflutter中文官网bFlutterVC.view)
subFlutterVC.didMove(toParent: self)
}
}
  1. MainVi产品运营ewController加载产品批号是生产日期吗ma服务器租借in.dart 中的main进口函数对应的Flutter App, 对应的void main() => runApp(MainApp());flutter中文官网内容;
  2. 懒加载也是为了处理资源竞赛的问题。
class ChannelViewController: UIViewController {
// 懒加载 main.dart 中的channel进口函数对应的Flutter App
private lazy var subFlutterVC: FBFlutterViewController = FBFlutappointmentterViewController(withEntrypoint: "channel")
overrflutteredide func viewDidLoflutter结构ad() {
addChappreciateild(subFlutterVC)
let safeFrame = self.v服务器iew.safeAreaLayoutGuide.flutter中文官网layoutFrame
subFlutterVC.view.frame = safeFrame
self.view.addSubview(subFlutterVC.view)
subFlutterVC.didMove(toPar产品规划ent: self)
}flutter菜鸟教程
}数据库查询句子

对应的void channel() => runApp(ChannelApp());的内apple

class MineViewController: UIViewController {
// 懒加载 main.dart 中的mine进口函数对应的Flutter App
private lazy var subFlutte服务器无法访问或恳求被阻拦rVC: FapproveBFlutterVi服务器操作体系银河麒麟ewController = FBFluttflutteringerViewController(withEntrypoint: "mine")
override func viewDidLoad() {
addChild(subFlutterVC)
let safeFrame = self.view.saflutter结构优缺点feAreaLayoutGuide.layoutFrame
subFlutterVC.view.frame = safeFrame
self.view.addSubview(subFlutterVC.view)
subFlutterVC.didMove(toParent: self)
}
}

对应的void mine() => runApp(MineApp()); 的内容

现在方位,三个Flutte数据库规划r module现已被集成到了咱们的iOS项目中了,每个模块基服务器怎样搭建本上能正常闪现。可是这个项目还有两个问题需求咱们来处理。

注册插件

我前服务器租借面提到过,主页模块频道模块 中的播映前史和点赞记载是需求在 我的模块 中展示的。可是现在他们是独立的,这就涉及到模块数据同步的问题。

这个同步的逻辑有一些通用的办法:

  1. 经过服务器网络恳求的办法;
  2. App进行内存存储;
  3. APP进行文件数据库规划存储;
  4. App进行数据库存数据库规划储;

咱们这儿用的是数据库的存储办法,可是Flutter服务器和电脑主机的差异数据库存储是经过数据库查询句子插件来结束的,咱们上面是flutter开发没有结束插件的注册,所以需求进行这方面的作业。

dependenciappearancees:
flutter:
sdk: flutter
...
fijkplayer: ^0.8.7
shared_preferences: 0.5.1数据库体系的中心是2+4
sqflite: ^1.3.0
url_launcher: ^5.7.10

其实咱们的Flutter项目顶用到了这些插件,都需求一致注appreciateFlutter Engine中。

  • 问题之一

Flutter混合开发—iOS篇

未注册插件,看不到观看前史和点赞

  • 处理方案:
// 1. 引进库
import FlutterPluginRegistrant
class FBFlutterViewController: FlutterViewControl产品运营ler {
/产品定位// ...
override func viewDidLoad() {
super.vi服务器是什么ewDidLoad()
// 2. 注册插件到FlutterEngine中
Gen服务器体系eratedPluginRegistrant.regis数据库体系的中心是ter(with: seappointmentlf.pluginRegistry())
}
}
  • 结束作用

Flutter混合开发—iOS篇

注册插件,能看到观看前史和点赞

编写插件

当集成到项目中后肯定会遇到各种问题,这时分编写插件便是很常见的需求了。咱们来看一下下面这个图:

Flutter混合开发—iOS篇

咱们看到从主页进入到二级页面,底下的TabBar没有躲藏,这是不符合一般的规划逻appreciate辑的。可是最初步服务器怎样搭建Flutter开发者或许并不了解这个问题,这时分就需求Flutter进行改代码了。

咱们需求结束的逻辑便是当Flutter二级甚至更深层级的界面的时分需求躲藏TabBar,只要一级界面闪现TabBar

Flutter端修改

  • 封装一个TabBar功用相关的插件类TabBarController
class T产品abBarController {
// 界说一个MethodChannel
static fi数据库技能nal channel = const MethodChannel("fbmovie.com/tab_switch");
/// 闪现tabbar
static Future<int> showTab() async {
final result = await channel.invokeAPPMethod("showTab");
retur数据库有哪几种n result ?? 0;
}
/// 躲藏tabbar
static Future<int> hideTab() async {
final result = await channel.invokeMethod("hideTab");
rflutter结构优缺点eturn result ?? 0;
}
}数据库查询句子

界说一个Metho服务器无法访问或恳求被阻拦dappleChannel,然后界说了一个showTab和一个hide服务器租借多少钱一年Tab办法数据库体系的中心是去调用原生代码。

  • 初始化一个路由监听器
// 路由监听器
final RouteObserver<PageRoute> rout产品生命周期e服务器Observer = RouteObserver<PageRoute>();
  • 监听路由的改动数据库有哪几种
class MainApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
// ...产品定位省掉
// 1. MaterialApp 加上路由监听器
navigatorObserversapprove: [数据库routeObse产品规划专业rver数据库体系工程师],
);
}
}
class FBMainPage extends StatefulWidget {
@override
_FBMainPageState createState() => _FBMainPageStaflutter中文官网te();
}
// 2. 混入 Rout数据库eAware
class _FBMainPageState extends State<FBMainPage> with RouteAware {
// ...省掉
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 3. 订阅路fluttering由监听器
routeappointmentObserver.subscrapp装置下载ibe(产品质量法this, ModalRoute.of(con数据库体系工程师text));
}
@override
void dispose() {
// 4. 撤销订阅路由监听器
routefluttershyObserver.unsubscribe(this);
super.dispose();
}
voi产品司理d didPopNext() {
// 5. 返回到当时页面
TabBarContro服务器地址在哪里看ller.app装置下载showTa产品生命周期b();
}
void didP产品规划ushNext() {
// 6. 跳转到下一个页面
TabBarController.hideTab();
}
}

当订阅路由监听器后,FBMainPage跳转到其他fluttering页面时会调用didPushappleNext,此刻奉告Native代码躲藏TabB产品战略ar,当其他页面跳转回FBMainPage时,此刻奉告Native代码闪现TabBar

iOS端修改

class FapproachBFlut数据库技能terViewController: F产品批号是生产日期吗lutterViewControl数据库办理体系ler {
private var channel: FlutterMethodChannel产品运营?
override func viewDidLoad() {
// ...省掉服务器和电脑主机的差异
// 1. 生成Flu服务器操作体系tterMethodChannel
channel = FlutappreciateterMetho产品批号是生产日期吗dChannelflutter中文官网(
name: "fbmovie.com/tab_s服务器操作体系witch", binaryMessenger: self.engine!.binaryMessenger)
// 2. 注册回调办法
channel!.setMethodCallHandler { [weak self] (call: FlutterMethodCall, result: @escaping Flutflutter菜鸟教程terResult) in
if call.method == "showTab" {
// 3. 闪现TabBar
self产品质量法?.showTab()
} else if call.method == "hideTab" {
// 3. 躲藏Ta服务器操作体系bBar
self?.hiflutter怎样读音发音deTab()
} else {
result(FlutterMethodNotImplemented)
}
}
}
/// 闪现TabBar
func showTab() {
self.parent?.tabBarController?.tabBar.isHidden = false
}
/// 躲藏TabBar
func hideTaAPPb() {
self.parent?.tabBarapp装置下载Controller?.tabBar.isHidden = true
}
}

iOS 端首要便是在flutteredFlutterViewController中初始化FlutterMFlutteretho产品战略dC产品战略hannel,监听Flutflutteringter端的调用,然后去控制UITabbarController

作用如下:

Flutter混合开发—iOS篇

总结

Flutter多模块集成还有一些待完善的当地,可是全体上来说Flutter混入原生仍是很不错的一个办法。因为approach自己的烘托闭环功率,做出来的作用仍是不错的。

本文介绍了Flutter混合iOS项意图结束办法,下节咱们将继续数据库技能来介绍Flutter混入And产品roid项目。