本篇博客会介绍如何通过第三方插件Flutter_Boost实现接入原有工程。

如果不希望引入第三方插件,可以参考博客Flutter混合开发--接入现有原生工程(iOS+Android)

一、新建原生工程和Flutter Module

1、新建Android工程

搭建一个空的Android工程FlutterDemo_Android模拟已经存在的原有工程

Android项目配置:

2、新建iOS工程

搭建一个空的iOS工程FlutterDemo_iOS模拟已经存在的原有工程

Xcode项目配置

搭建Pod:

在工程目录下执行

pod init
pod install

3、新建Flutter Module

这里使用AndroidStudio做Flutter开发环境

3.1 AndroidStudio添加Flutter插件

3.2 新建Flutter Module

第一步:File -> New Flutter Project

第二步:选择Flutter

第三步:配置Flutter Module

flutter_demo_module

完成目录结构

二、Flutter Boost 配置

1、Flutter_Module工程

1.修改pubspec.yaml文件:

dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2 # add
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: '4.1.0'

然后执行flutter pub get下载flutter_boost到module中

2.新增willpop.dart页面做为跳转目标页

import 'package:flutter/material.dart';

class WillPopRoute extends StatefulWidget {
const WillPopRoute({Key? key, this.title}) : super(key: key); final String? title; @override
State<StatefulWidget> createState() => _WillPopRouteState();
} class _WillPopRouteState extends State<WillPopRoute> {
bool shouldPop = true;
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
return shouldPop;
},
child: Scaffold(
appBar: AppBar(
title: const Text('Flutter Demo'),
),
),
);
}
}

3.修改main.dart文件,配置页面路由

import 'package:flutter/material.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter_demo_module/willpop.dart'; void main() {
CustomFlutterBinding();
runApp(const MyApp());
} class CustomFlutterBinding extends WidgetsFlutterBinding
with BoostFlutterBinding {} class MyApp extends StatefulWidget {
const MyApp({super.key}); @override
State<MyApp> createState() => _MyAppState();
} class _MyAppState extends State<MyApp> {
// 配置路由
static Map<String, FlutterBoostRouteFactory> routerMap = {
'flutterPage': (settings, uniqueId) {
return PageRouteBuilder<dynamic>(
settings: settings, pageBuilder: (_, __, ___) => const WillPopRoute());
}
}; 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);
} }

2、Android跳转Flutter:

1.setting.gralde添加:

setBinding(new Binding([gradle: this]))
evaluate(new File(
settingsDir.parentFile,
'flutter_demo_module/.android/include_flutter.groovy'
))
include ':flutter_demo_module'
project(':flutter_demo_module').projectDir = new File('../flutter_demo_module')

注意:new Binding([gradle: this])会有红色提示,不用管

2.app的AndroidManifest添加:

<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" > </activity>
<meta-data android:name="flutterEmbedding"
android:value="2">
</meta-data>

注意这一步之后执行gradle sync,如果遇到问题,可以参考文章最后的问题集锦

3.FlutterBoost初始化

自定义Application

class MyApp : Application() {
override fun onCreate() {
super.onCreate()
FlutterBoost.instance().setup(this, object : FlutterBoostDelegate {
override fun pushNativeRoute(options: FlutterBoostRouteOptions) {
// 原生跳转
} override fun pushFlutterRoute(options: FlutterBoostRouteOptions) {
// Flutter跳转
}
}, FlutterBoost.Callback { engine: FlutterEngine? -> })
}
}

配置app的AndroidManifest

<application
android:name=".MyApp"
...
</application>

4.Android跳转代码

val params: Map<String, Any> = HashMap()
val intent: Intent = FlutterBoostActivity.CachedEngineIntentBuilder(
FlutterBoostActivity::class.java
)
.backgroundMode(FlutterActivityLaunchConfigs.BackgroundMode.opaque)
.destroyEngineWithActivity(false)
.url("flutterPage")
.urlParams(params)
.build(context)
startActivity(intent)

3、iOS跳转Flutter:

1.修改Pod文件

step1. load file

flutter_application_path = '../flutter_demo_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')

step2. install function

install_all_flutter_pods(flutter_application_path)

step3 post_install

post_install do |installer|
flutter_post_install(installer) if defined?(flutter_post_install)
end

完整pod文件

# Flutter Module Path
# step1 load file
flutter_application_path = '../flutter_demo_module'
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb') target 'FlutterDemo_iOS' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks! # step2 install function
install_all_flutter_pods(flutter_application_path)
end # step3 post_install
post_install do |installer|
flutter_post_install(installer) if defined?(flutter_post_install)
end

执行pod install,podhelper.rb 脚本会把你的 plugins, Flutter.framework,和 App.framework 集成到你的项目中。

备注:

Flutter.framework 是 Flutter engine 的框架, App.framework 是你的 Dart 代码的编译产物。

2.添加Delegate

定义FlutterDelegate

import UIKit
import Flutter
import flutter_boost
import FlutterPluginRegistrant class MyBoostAppDelegate: NSObject,FlutterBoostDelegate { static let shared = MyBoostAppDelegate() ///您用来push的导航栏
var navigationController:UINavigationController? ///用来存返回flutter侧返回结果的表
var resultTable:Dictionary<String,([AnyHashable:Any]?)->Void> = [:]; func pushNativeRoute(_ pageName: String!, arguments: [AnyHashable : Any]!) { //可以用参数来控制是push还是pop
let isPresent = arguments["isPresent"] as? Bool ?? false
let isAnimated = arguments["isAnimated"] as? Bool ?? true
//这里根据pageName来判断生成哪个vc,这里给个默认的了
let targetViewController = UIViewController() if(isPresent){
self.navigationController?.present(targetViewController, animated: isAnimated, completion: nil)
}else{
self.navigationController?.pushViewController(targetViewController, animated: isAnimated)
}
} func pushFlutterRoute(_ options: FlutterBoostRouteOptions!) {
let vc:FBFlutterViewContainer = FBFlutterViewContainer()
vc.setName(options.pageName, uniqueId: options.uniqueId, params: options.arguments,opaque: options.opaque) //用参数来控制是push还是pop
let isPresent = (options.arguments?["isPresent"] as? Bool) ?? false
let isAnimated = (options.arguments?["isAnimated"] as? Bool) ?? true //对这个页面设置结果
resultTable[options.pageName] = options.onPageFinished; //如果是present模式 ,或者要不透明模式,那么就需要以present模式打开页面
if(isPresent || !options.opaque){
self.navigationController?.present(vc, animated: isAnimated, completion: nil)
}else{
self.navigationController?.pushViewController(vc, animated: isAnimated)
}
} func popRoute(_ options: FlutterBoostRouteOptions!) {
//如果当前被present的vc是container,那么就执行dismiss逻辑
if let vc = self.navigationController?.presentedViewController as? FBFlutterViewContainer,vc.uniqueIDString() == options.uniqueId{ //这里分为两种情况,由于UIModalPresentationOverFullScreen下,生命周期显示会有问题
//所以需要手动调用的场景,从而使下面底部的vc调用viewAppear相关逻辑
if vc.modalPresentationStyle == .overFullScreen { //这里手动beginAppearanceTransition触发页面生命周期
self.navigationController?.topViewController?.beginAppearanceTransition(true, animated: false) vc.dismiss(animated: true) {
self.navigationController?.topViewController?.endAppearanceTransition()
}
}else{
//正常场景,直接dismiss
vc.dismiss(animated: true, completion: nil)
}
}else{
self.navigationController?.popViewController(animated: true)
}
//否则直接执行pop逻辑
//这里在pop的时候将参数带出,并且从结果表中移除
if let onPageFinshed = resultTable[options.pageName] {
onPageFinshed(options.arguments)
resultTable.removeValue(forKey: options.pageName)
}
}
}

修改AppDelegate

import UIKit
import flutter_boost @main
class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { //创建代理,做初始化操作
let delegate = MyBoostAppDelegate.shared
FlutterBoost.instance().setup(application, delegate: delegate) { engine in }
return true
}
}

跳转Flutter页面代码

    @IBAction func clickButton(_ sender: Any) {
MyBoostAppDelegate.shared.navigationController = self.navigationController
let options = FlutterBoostRouteOptions()
options.pageName = "flutterPage"
FlutterBoost.instance().open(options)
}

问题集锦

1.Android导入Flutter Module报错Failed to apply plugin class ‘FlutterPlugin’

setting.gradle修改Model值为RepositoriesMode.PREFER_PROJECT

dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.PREFER_PROJECT)
repositories {
google()
mavenCentral()
}
}

Flutter(六):Flutter_Boost接入现有原生工程(iOS+Android)的更多相关文章

  1. 封装 React Native 原生组件(iOS / Android)

    封装 React Native 原生组件(iOS / Android) 在 React Native中,有很多种丰富的组件了,例如 ScrollView.FlatList.SectionList.Bu ...

  2. 使用新版本5+SDK创建最简Android原生工程(Android studio)http://ask.dcloud.net.cn/article/13232

    1 使用Android Studio创建一个工程 2 删除原生工程中Java目录下系统默认创建的源代码 3 复制SDK->libs->lib.5plus.base-release.aar文 ...

  3. 原生工程接入Flutter实现混编

    前言 上半年我定的OKR目标是帮助团队将App切入Flutter,实现统一技术栈,变革成多端融合开发模式.Flutter目前是跨平台方案中最有潜力实现我们这个目标的,不管是Hybird还是React ...

  4. unity导出工程导入到iOS原生工程中详细步骤

    一直想抽空整理一下unity原生工程导入iOS原生工程中的详细步骤.做iOS+vuforia+unity开发这么长时间了.从最初的小小白到现在的小白.中间趟过了好多的坑.也有一些的小小收货.做一个喜欢 ...

  5. 如何在原生工程中引入Cordova工程-for iOS 【转】

    http://blog.csdn.net/e20914053/article/details/50170487 如今混合开发方兴未艾,有的项目可能一开始是原生开发的,后期需要加入混合开发,如将Cord ...

  6. 【Flutter 混合开发】嵌入原生View-Android

    Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-IOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...

  7. 【Flutter 混合开发】嵌入原生View-iOS

    Flutter 混合开发系列 包含如下: 嵌入原生View-Android 嵌入原生View-iOS 与原生通信-MethodChannel 与原生通信-BasicMessageChannel 与原生 ...

  8. 现有新的iOS更新可用,请从iOS12 beta版进行更新.解决方案

    问题描述: ios系统一直弹出“现有新的iOS更新可用,请从iOS12 beta版进行更新”的提示,很烦的. 应该只出现在安装测试版ios12的手机上. 解决方案: 删除描述文件无法解决. 有网友机制 ...

  9. 基于Mui与H5+开发webapp的Android原生工程打包步骤(使用新版本5+SDK与Android studio)(部分内容转自dcloud官网)

    文章背景: dcloud官网给出的打包步骤对于有一定安卓打包基础的同学来说比较容易掌握,但是对于webapp小白来讲有的地方可能没有说的太具体.下面我给大家介绍的详细一点,保证大家按照步骤就能学会打包 ...

  10. 移动端热更新方案(iOS+Android)

    PPT资源包含iOS+Android 各种方案分析:https://github.com/qiyer/Share/blob/master/%E7%83%AD%E6%9B%B4%E6%96%B0%E5% ...

随机推荐

  1. pySpark-merge多个dataframe

    当需要merge多个spark datafame的时候: from functools import reduce buff = [] for pdfs in [pdf1, pdf1,pdf3...] ...

  2. UE4下实现HTC Vive手柄拾取物品蓝图编程

    UE4下实现Vive手柄拾取物品 标签: UE4Vive游戏引擎 目录(?) [-] 创建拾取接口 实现接口 定义拾取 简单说下思路,首先定义拾取接口,然后在需要拾取的物品的蓝图类中实现该接口,最后在 ...

  3. node nvm使用

    背景 node 经过了一次大的改变,直接从8到了10,差别很大,但是有的项目又需要用到8,这个时候不能完全升级. 所以我们需要一个管理虚拟环境的工具. 安装 https://github.com/co ...

  4. redis和memcached的区别和使用场景

    Redis 和 Memcached 都是基于内存的数据存储系统.Memcached是高性能分布式内存缓存服务,其本质上就是一个内存key-value数据库.Redis是一个开源的key-value存储 ...

  5. 力扣54(java)-螺旋矩阵(中等)

    题目: 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素. 示例 1: 提示: m == matrix.lengthn == matrix[i].leng ...

  6. 力扣171(java)-Excel表列序号(简单)

    题目: 给你一个字符串 columnTitle ,表示 Excel 表格中的列名称.返回 该列名称对应的列序号 . 例如: A -> 1B -> 2C -> 3...Z -> ...

  7. IOT设备连接上云

    如何让我的设备连接上云?参考如下路径. 云 [![](http://static-aliyun-doc.oss-cn-hangzhou.aliyuncs.com/assets/img/974556/1 ...

  8. 基于信通院 Serverless 工具链模型的实践:Serverless Devs

    简介: Serverless Devs 作为开源开放的开发者工具,参编中国信通院<基于无服务器架构的工具链能力要求>标准,为行业统一规范发挥助推作用!​ 作者 | 江昱(阿里云 Serve ...

  9. StarLake:汇量科技云原生数据湖的探索和实践

    简介: 快速了解汇量科技在云原生数据湖领域的探索和实践,详解 StarLake 的架构及业务应用案例. 作者:陈绪(汇量科技资深算法架构师,EnginePlus 2.0 产品负责人) 内容框架: 互联 ...

  10. Metasploit 实现木马生成、捆绑及免杀

    ​简介: 在渗透测试的过程中,避免不了使用到社会工程学的方式来诱骗对方运行我们的木马或者点击我们准备好的恶意链接.木马的捆绑在社会工程学中是我们经常使用的手段,而为了躲避杀毒软件的查杀,我们又不得不对 ...