1、安装Flutter环境
1、下载SDK并安装
docs.flutter.cn/get-started...
2、 配置环境
如果 ~/.zshenv
文件存在,请在文本编辑器中打开 Zsh 环境变量文件 ~/.zshenv
。如果不存在,请创建 ~/.zshenv
将export PATH=$HOME/development/flutter/bin:$PATH
加入到文件的最后面
创建Flutter项目
以Flutter为主
以Flutter为主:意思是直接创建完整的flutter项目,里面就已经包含了iOS、Android等工程。直接用即可
在需要的目录中 执行 flutter create aiflutter
配置
进入iOS文件夹
这里需要注意: 需要用到CocosPods将Flutter作为组件导入到项目,但是Flutter并没有直接生成Podfile文件。需要自己init一个
在进行 Podfile install
时,会有警告。 如果想要去掉警告,需要按照以下方式修改。但是修改之后会运行不起来

正确的应该是选中Debug.xcconfig、Release.xcconfig

直接运行会报错:
css
Command PhaseScriptExecution failed with a nonzero exit code
这是由于Run Script
的脚本找不到正确路径
需要修改 Podfile
文件
具体如下:
ruby
source 'https://github.com/CocoaPods/Specs.git'
# Uncomment this line to define a global platform for your project
platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
在使用过程中, 因为iOS工程是其他人创建后给我的,在进行pod install的时候,出现了路径找不到的报错: 修改这个路径

此时如果直接运行,将会报错
css
Unable to load contents of file list: '/Target Support Files/Pods-Runner/Pods-Runner-frameworks-Debug-input-files.xcfilelist'
需要回到Flutter项目目录下,执行flutter run
.
其实在执行flutter create flutterdemo
完成的时候,就已经提示了
bash
In order to run your application, type:
$ cd test
$ flutter run
Your application code is in test/lib/main.dart.
报错
如果报错: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
在Build Settings
中搜索ENABLE_USER_SCRIPT_SANDBOXING
将其设置为NO,如果原本是NO,设置为YES后运行一次后再改为NO
错误处理
1、确保执行过
flutter run
2、在
Build Settings
中搜索ENABLE_USER_SCRIPT_SANDBOXING
将其设置为NO3、使用
pod init
新建一个podfile文件并修改里面的内容4、
PROJECT
->info
->Configurations
中的Debug、Release 设置为对应的Debug.xcconfig、Release.xcconfig
5、确认
ios/Flutter
路径下的Generated.xcconfig
中的配置FLUTTER_ROOT、FLUTTER_APPLICATION_PATH
是否正常
总结
1、安装FlutterSDK并配置其环境
2、使用命令创建Flutter项目
flutter create flutterdemo
3、执行
cd flutterdemo
和flutter run
命令4、导入podfile文件并执行
pod install
命令
以iOS为主
以iOS为主意思是:手动创建一个iOS工程,将Flutter作为一个组件导入到iOS项目中
1、创建一个iOS工程AIIOSDemo
,并进行pod
2、在同级目录下新建Flutter项目:flutter create -t module my_flutter
\
3、在podfile中引入flutter
bash
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '12.0'
# 在文件顶部添加 flutter_application_path
flutter_application_path = '../my_flutter' #这里是刚才创建的flutter module名称
load File.join(flutter_application_path, '.ios', 'Flutter', 'podhelper.rb')
target 'AIIOSDemo' do
use_frameworks!
pod 'SnapKit'
# 集成 Flutter
install_all_flutter_pods(flutter_application_path)
end
iOS与Flutter交互
Flutter 与原生存在三种交互方式
三种 Channel 之间互相独立,各有用途,但它们在设计上却非常相近。每种 Channel 均有三个重要成员变量:
- name: 【重要参数】String类型,代表 Channel 的名字,也是其唯一标识符
需要和Fluter中的定义保持一致
- messager:【重要参数】BinaryMessenger 类型,代表消息信使,是消息的发送与接收的工具
- codec: MessageCodec 类型或 MethodCodec 类型,代表消息的编解码器
MethodChannel
一般用于传递方法调用(method invocation)通常用于Flutter调用原生中某个方法
举例:使用场景-Flutter需要获取原生生成的用户UUID,并传递UUID做存储操作
swift
// 引入Flutter
import Flutter
@objc class AppDelegate: FlutterAppDelegate {
// 枚举的方式定义方法名
enum FlutterMethodType: String {
case saveUUID = "saveUUID" ///< 保存 UUID
case getUUID = "getUUID" ///< 获取 UUID
}
let controller = window?.rootViewController as! FlutterViewController
// 初始化参数,并设置回调handle
func MethodChannelRegist(controller: FlutterViewController) {
let methodChannel_channer = FlutterMethodChannel(
name: "com.example/ai/snowflake",
binaryMessenger: controller.binaryMessenger
)
methodChannel_channer.setMethodCallHandler { [weak self] (call, result) in
guard let self = self else { return }
self.flutterMethodChanner_channer(call: call, result: result)
}
}
// flutter 调用 swift
private func flutterMethodChanner_channer(call: FlutterMethodCall, result: FlutterResult) -> Void {
if call.method == FlutterMethodType.getUUID.rawValue {
let uuid = "uuid"
result(uuid)
}else if call.method == FlutterMethodType.saveUUID.rawValue {
let success = true
result(success)
} else {
result(FlutterMethodNotImplemented)
}
}
}

BasicMessageChannel
它是可以双端通信的,Flutter 端可以给 iOS 发送消息,iOS 也可以给 Flutter 发送消息。
swift
// 全局,方便随时可以发送消息
var basicMessageChannel: FlutterBasicMessageChannel? = nil
// 其他和MethodChannel基本一致
func BasicMessageChannelRegist(controller: FlutterViewController) {
basicMessageChannel = FlutterBasicMessageChannel(name: "com.example/ai/snowflake",
binaryMessenger: controller.binaryMessenger)
basicMessageChannel?.setMessageHandler { [weak self] (call, result) in
guard let self = self else { return }
self.flutterMethodChanner_channer(call: call as! FlutterMethodCall, result: result)
}
// 相比MethodChannel 最重要的区别就是这个 可以主动向Flutter发送消息
basicMessageChannel?.sendMessage(["name":"隔壁老王","age":25])
}
// flutter 调用 swift
private func flutterMethodChanner_channer(call: FlutterMethodCall, result: FlutterResult) -> Void {
if call.method == "methodOne" {
}else if call.method == "methodTwo" {
} else {
result(FlutterMethodNotImplemented)
}
}

EventChannel
只能是原生发送消息给 Flutter 端,例如监听手机电量变化,网络变化,传感器等。
swift
func eventChannelRegist(controller: FlutterViewController) {
let eventChannel = FlutterEventChannel(
name: "com.example.demo/event",
binaryMessenger: controller.binaryMessenger
)
eventChannel.setStreamHandler(self)
}
// MARK: FlutterStreamHandler
var eventSink: FlutterEventSink? = nil
func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
self.eventSink = events
return nil
}
func onCancel(withArguments arguments: Any?) -> FlutterError? {
self.eventSink = nil
return nil
}
func sendEvent(data: Any) {
eventSink?(data) // 主动发送数据到 Flutter
}
