本篇博客会介绍如何通过第三方插件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. ES6~ES9

    ES6 1. let 1.1 let 变量声明及声明特性 let 用来声明变量,具有以下特性: 一.相较于 var ,let 变量不能重复声明 let a = 'a'; let a = 'a'; // ...

  2. android 找不到设备

    前言 当我们安装android studio的时候,测试的时候,你可能找不到设备. 我遇到的有两种情况,一种是本身就需要安装插件,如一些低端机或者有些小米机. 还有一种情况需要去触发一下,有些华为手机 ...

  3. redis 面试题整理

    前言 前天面试了一家公司,平时看一本redis书的也使用redis,对里面的东西也基本了解,结果回答的时候居然回答了只是使用了(因为认为是redis是运维的东西,做的东西多,所以忘了,好吧这是借口), ...

  4. Scratch3自定义积木块之新增积木块

    在Scratch3.0的二次开发中,新功能的研发和扩展离不开积木块的添加,这篇主要讲解Scratch3.0中新增积木块部分 Scratch3.0中对于新增积木块有两种方式: 1. 初始化积木块方式   ...

  5. Flutter开发技巧集锦

    flutter中单例的写法 class AccountManager { factory AccountManager() => _instance ??= AccountManager._() ...

  6. 构建RAG应用-day01: 词向量和向量数据库 文档预处理

    词向量和向量数据库 词向量(Embeddings)是一种将非结构化数据,如单词.句子或者整个文档,转化为实数向量的技术. 词向量搜索和关键词搜索的比较 优势1:词向量可以语义搜索 比如百度搜索,使用的 ...

  7. vue2.0中watch用法

    watch:观测Vue实例上的数据变动,对应一个对象,键:就是需要监测的那个东西,值:1.可以是当键变化时执行的函数,有两个参数,第一个是变化前的值,第二个是变化后的值.2.可以是函数名,得用单引号包 ...

  8. 使用 Docker 部署 Draw.io 在线流程图系统

    1)介绍 Draw.io GitHub:https://github.com/jgraph/drawio Draw.io 是一款开源的绘制流程图的工具,拥有大量免费素材和模板.程序本身支持中文在内的多 ...

  9. 浏览器端实现类似input限制输入两位小数,输入时光标从输入位置移动到最后

    1.问题描述展示 示例代码所做限制为不允许输入字母d,其他限制规则可以根据需求自己调整,使用React编写,其他框架或原生均可根据该代码理解原理进行转变,特意使用了中文键盘可以看到输入框下面白色框闪出 ...

  10. echarts使用与踩坑

    0.踩坑点 1.当图表不显示在页面(display:none)执行resize可能会导致图表样式混乱 1. 官网示例 import * as echarts from 'echarts'; // 基于 ...