本篇博客会介绍如何通过第三方插件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. 重新整理.net core 计1400篇[六] (.net core 一个简易版的依赖注入容器 )

    前言 我们了解到一个依赖注入的形式是: 注入依赖服务:var root = new Cat().Register<IFoo, Foo>(Lifetime.Transient); 获取对应的 ...

  2. js es6 map weakmap

    前言 这里介绍一些map和weakmap的一些属性和他们不同之处. 正文 map JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键.这 ...

  3. 房屋设计H51图纸

  4. Django框架——ORM执行SQL语句、神奇的双下划线、外键字段的创建、跨表查询、进阶操作

    ORM执行SQL语句 有时候ORM的操作效率可能偏低 我们是可以自己编写SQL的 方式一: models.User.objects.raw('select * from app01_user') 方式 ...

  5. 力扣166(java)-分数到小数(中等)

    题目: 给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以 字符串形式返回小数 . 如果小数部分为循环小数,则将循环的部分括在括号内. 如果存在多个答案,只需返回 ...

  6. Java 应用压测性能问题定位经验分享

    简介: 问题千千万,但只要修练了足够深厚的内功,形成一套属于自己的排查问题思路和打法,再加上一套支撑问题排查的工具,凭借已有的经验还有偶发到来的那一丝丝灵感,相信所有的问题都会迎刃而解. 作者:凡勇 ...

  7. 行业实战 | 5G+边缘计算+“自由视角” 让体育赛事更畅快

    简介: 世界本是多维的.进入5G时代,观众对多维度视觉体验的需求日益增长,5G MEC网络与边缘计算的结合,具备大带宽.低延迟特性,使视频多维视觉呈现成为现实.在第二十三届CUBA中国大学生篮球联赛期 ...

  8. hyengine - 面向移动端的高性能通用编译/解释引擎

    ​简介:手机淘宝客户端在历史上接过多种多样的脚本引擎,用于支持的语言包括:js/python/wasm/lua,其中js引擎接过的就有:javascriptcore/duktape/v8/quickj ...

  9. Flink 和 Iceberg 如何解决数据入湖面临的挑战

    简介: 4.17 上海站 Meetup 胡争老师分享内容:数据入湖的挑战有哪些,以及如何用 Flink + Iceberg 解决此类问题. 一.数据入湖的核心挑战 数据实时入湖可以分成三个部分,分别是 ...

  10. Python静态类型解析工具简介和实践

    简介: Python是一门强类型的动态类型语言,开发者可以给对象动态指定类型,但类型不匹配的操作是不被允许的.动态类型帮助开发者写代码轻松愉快,然而,俗话说:动态一时爽,重构火葬场.动态类型也带来了许 ...