flutter 专题 一百零三

embedded/2025/3/20 7:39:11/

前不久,谷歌官方正式发布了Flutter的首个发布预览版(Release Preview 1),这标志着谷歌进入了Flutter正式版(1.0)发布前的最后阶段,同时作为Google的重量级跨平台开发方案,此次更新也吸引了多数的移动开发者的关注。使用 Flutter从头开始写一个 App是一件非常轻松惬意的事情,但在原生APP中接入 Flutter会是什么效果呢,似乎并不是一件容易的事情,下面就讲解在iOS原生应用中如何接入Flutter。

开发环境
  • Flutter:0.5.7
  • Xcode 9.4.1
  • Flutter工程:flutter/examples/hello_world

项目实例

Flutter(engine) 基础库

首先,在你的项目里面拖入Flutter.framework,这个库是 Flutter的Engine库,承载了 Dart运行时和绘图引擎。Flutter.framework和命令行工具版本是一一对应的,如果你不知道从哪里找这个文件,可以直接在 Flutter源码项目里面进行一次 flutter run 命令,然后你就能在 /<project>/ios/Flutter/ 目录下面就能找到Flutter.framework了,然后直接将它拖进项目即可。

接下来需要把 Flutter的基础代码引入现有工程,有了基础的 Flutter ViewController才可以显示 Flutter视图。然后,只需要在你现有的 ViewController中 Push过去就可以。例如:

 - (void)jumpToFlutter {FlutterViewController *viewController = [FlutterViewController new];[self.navigationController pushViewController:viewController animated:YES];
}

需要注意的是,在使用的时候还需要把 AppDelegate里面的生命周期事件传递给 Flutter。实现的思路如下:
直接让现有的 AppDelegate继承 FlutterAppDelegate即可,但这带来的负面影响是 root ViewController会被设置为Flutter ViewController。
改造 AppDelegate实现。例如:

// AppDelegate 或者模块的 Delegate@interface DemoFlutterBaseAppDelegate : NSObject <ModularApplicationDelegate, FlutterPluginRegistry>/**FlutterBinaryMessengerthis determines which view controller is the flutter view controllernomally, flutter view controller provides the binary messages@return root Flutter ViewController*/
- (NSObject<FlutterBinaryMessenger> *)binaryMessenger;/**FlutterTextureRegistrythis determines which view controller is the flutter view controllernomally, flutter view controller provides the custom textures@return root Flutter ViewController*/
- (NSObject<FlutterTextureRegistry> *)textures;@end

然后在实现中添加Flutter messenger 和 texture。

// Registrar 声明和实现@interface DemoFlutterAppDelegateRegistrar : NSObject<FlutterPluginRegistrar>@property(nonatomic, copy) NSString *pluginKey;
@property(nonatomic, strong) DemoFlutterBaseAppDelegate *appDelegate;- (instancetype)initWithPlugin:(NSString*)pluginKey appDelegate:(DemoFlutterBaseAppDelegate*)delegate;@end@implementation DemoFlutterAppDelegateRegistrar
- (instancetype)initWithPlugin:(NSString*)pluginKey appDelegate:(DemoFlutterBaseAppDelegate*)appDelegate {self = [super init];NSAssert(self, @"Super init cannot be nil");_pluginKey = [pluginKey copy];_appDelegate = appDelegate;return self;
}- (NSObject<FlutterBinaryMessenger>*)messenger {return [_appDelegate binaryMessenger];
}- (NSObject<FlutterTextureRegistry>*)textures {return [_appDelegate textures];
}- (void)publish:(NSObject*)value {_appDelegate.pluginPublications[_pluginKey] = value;
}- (void)addMethodCallDelegate:(NSObject<FlutterPlugin>*)delegatechannel:(FlutterMethodChannel*)channel {[channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {[delegate handleMethodCall:call result:result];}];
}- (void)addApplicationDelegate:(NSObject<FlutterPlugin>*)delegate {[_appDelegate.pluginDelegates addObject:delegate];
}- (NSString*)lookupKeyForAsset:(NSString*)asset {return [FlutterDartProject lookupKeyForAsset:asset];
}- (NSString*)lookupKeyForAsset:(NSString*)asset fromPackage:(NSString*)package {return [FlutterDartProject lookupKeyForAsset:asset fromPackage:package];
}@end// AppDelegate实现@interface DemoFlutterBaseAppDelegate ()@property(nonatomic, strong) DemoFlutterBaseViewController *rootController;
@property(readonly, nonatomic) NSMutableArray* pluginDelegates;
@property(readonly, nonatomic) NSMutableDictionary* pluginPublications;@end@implementation DemoFlutterBaseAppDelegate/** ... 这里写转发各种声明周期事件给 plugin*/
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {for (id<FlutterPlugin> plugin in _pluginDelegates) {if ([plugin respondsToSelector:_cmd]) {[plugin application:application didFinishLaunchingWithOptions:launchOptions];}}return YES;
}#pragma mark - getters for flutter// 返回 FlutterViewController实例
- (FlutterViewController *)rootController {// ...
}- (NSObject<FlutterBinaryMessenger> *)binaryMessenger
{if ([self.rootController conformsToProtocol:@protocol(FlutterBinaryMessenger)]) {return (NSObject<FlutterBinaryMessenger> *)self.rootController;}return nil;
}- (NSObject<FlutterTextureRegistry> *)textures
{if ([self.rootController conformsToProtocol:@protocol(FlutterTextureRegistry)]) {return (NSObject<FlutterTextureRegistry> *)self.rootController;}return nil;
}- (NSObject<FlutterPluginRegistrar>*)registrarForPlugin:(NSString*)pluginKey {NSAssert(self.pluginPublications[pluginKey] == nil, @"Duplicate plugin key: %@", pluginKey);self.pluginPublications[pluginKey] = [NSNull null];return [[DemoFlutterAppDelegateRegistrar alloc] initWithPlugin:pluginKey appDelegate:self];
}- (BOOL)hasPlugin:(NSString*)pluginKey {return _pluginPublications[pluginKey] != nil;
}- (NSObject*)valuePublishedByPlugin:(NSString*)pluginKey {return _pluginPublications[pluginKey];
}@end

到此,Flutter的运行环境其实就准备好了,无论是 Hot Restart还是 AOT都可以支持。接下来我们实现 Debug Hot Restart,即Flutter中最重要特性之一:特重载。

首先在你的 Flutter代码目录下执行一遍 Flutter build bundle,这可以帮助我们打包出一个 Flutter Asset,然后把这个 flutter_assets 目录拖入项目。

对你的项目进行一次 build,确保能够得到一个 .app 文件。然后新建一个文件夹叫做 Payload,把 .app文件放入 Payload文件夹,然后压缩成 zip文件。然后执行如下的命令:

flutter run --use-application-binary /path/to/Payload.zip

如有要打包到真机上运行,需要做如下的一些替换操作。

  1. 把 Flutter.framework替换成flutter/bin/cache/artifacts/engine/ios-release/Flutter.framework,因为上一步我们用的库其实是JIT Runtime。
  2. 在 Flutter代码项目下面执行 flutter build aot –release –target-platform ios –ios-arch armv7,arm64 然后我们可以在 build目录下拿到一个打包好的 App.framework,不过别忘记在里面放一个 Info.plist。并且把这个库拖到工程里面。
  3. 删除工程里面的 flutter_assets文件夹下的 isolate_snapshot_data、kernel_blob.bin、platform.dill、vm_snapshot_data这几个文件。
  4. 编译打包给真机运行。

其实 Flutter官方有支持现有 App 集成的计划,并且现在文档也有一部分介绍,但其实整体工具链还没支持上来,目前所支持的程度和上文的方法也大同小异,所以还需要更多的摸索。


http://www.ppmy.cn/embedded/174081.html

相关文章

分页优化之——游标分页

游标分页&#xff08;Cursor-based Pagination&#xff09; 是一种高效的分页方式&#xff0c;特别适用于大数据集和无限滚动的场景。与传统的基于页码的分页&#xff08;如 page1&size10&#xff09;不同&#xff0c;游标分页通过一个唯一的游标&#xff08;通常是时间戳或…

三分钟掌握视频分辨率修改 | 在 Rust 中优雅地使用 FFmpeg

前言 在视频处理领域&#xff0c;调整视频分辨率是一个绕不过去的需求。比如&#xff0c;你可能需要将一段视频适配到手机、平板或大屏电视上&#xff0c;或者为了节省存储空间和网络带宽而压缩视频尺寸。然而&#xff0c;传统的FFmpeg命令行工具虽然功能强大&#xff0c;但复…

centos 7误删/bash 拯救方法

进入救援模式 1. 插入CentOS 7安装光盘&#xff0c;重启系统。在开机时按BIOS设置对应的按键&#xff08;通常是F2等&#xff09;&#xff0c;将启动顺序调整为CD - ROM优先。 2. 系统从光盘启动后&#xff0c;选择“Troubleshooting”&#xff0c;然后选择“Rescue a Cent…

C语言 第五章 指针(3)

目录 指针常用运算 定义&#xff1a; 指针与整数值的加减运算 格式&#xff1a; 举例&#xff1a; 说明&#xff1a; 实例 举例&#xff1a; 实例 指针的自增、自减运算 定义 实例1&#xff1a; 实例2&#xff1a; 指针常用运算 定义&#xff1a; 指针本质上就是一…

免费看付费电影网站制作,高清电影集合搜索引擎网站

引言 在当今数字化时代&#xff0c;电影已经成为人们日常生活中不可或缺的一部分。然而&#xff0c;随着各大视频平台推出付费会员制度&#xff0c;许多用户开始寻找免费观看付费电影的途径。本文将详细介绍如何制作一个免费看付费电影的网站&#xff0c;并打造一个高清电影集…

东隆科技携手PRIMES成立中国校准实验室,开启激光诊断高精度新时代

3月12日&#xff0c;上海慕尼黑光博会期间&#xff0c;东隆科技正式宣布与德国PRIMES共同成立“中国校准实验室”。这一重要合作标志着东隆科技在本地化服务领域的优势与PRIMES在激光光束诊断领域的顶尖技术深度融合&#xff0c;旨在为中国客户提供更快速、更高精度的服务以及本…

python:music21 与 AI 结合应用探讨

Python 的 music21 库与人工智能&#xff08;AI&#xff09;技术结合应用具有广泛的可能性&#xff0c;尤其是在音乐生成、分析和风格模拟等领域。以下是具体的结合方向与示例&#xff1a; 1. 音乐生成与 AI AI 模型驱动音乐生成&#xff1a; 使用深度学习模型&#xff08;如 …

DeepSeek私有化部署与安装浏览器插件内网穿透远程访问实战

文章目录 前言1. 本地部署OllamaDeepSeek2. Page Assist浏览器插件安装与配置3. 简单使用演示4. 远程调用大模型5. 安装内网穿透6. 配置固定公网地址 前言 最近&#xff0c;国产AI大模型Deepseek成了网红爆款&#xff0c;大家纷纷想体验它的魅力。但随着热度的攀升&#xff0c…