Flutter与iOS混合开发交互

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 将其设置为NO

3、使用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 flutterdemoflutter 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
      }
相关推荐
redreamSo1 小时前
房产票据价值模型:7张票拆解一套房的真正价值,推演未来涨跌
程序员
ai小鬼头5 小时前
AIStarter 3.2.0更新!一键离线导入+高速下载,熊哥教你轻松玩转AI工具
人工智能·程序员·github
古希腊被code拿捏的神5 小时前
【Flutter】面试记录
flutter·面试·职场和发展
nc_kai5 小时前
Flutter 之 table_calendar 控件
flutter
0wioiw05 小时前
Flutter基础(前端教程⑨-图片)
前端·flutter
码路工人6 小时前
【Markdown-00】前言:为什么是 Markdown?
程序员·markdown·电子书
浅忆无痕7 小时前
Flutter抓包
前端·flutter
火柴就是我7 小时前
每日见闻之尝试大白话说清Flutter的事件传递
flutter
浅墨momo7 小时前
将你的Shopify App部署到fly.io上
前端·程序员