将带有绑定 Rust 二进制文件的 Flutter 应用程序发布到 AppStore 时出现问题

Iva*_*del 9 ffi app-store ios rust flutter

语境

我们有一个功能齐全的Flutter应用程序,并且它已经发布到 PlayStore 和 AppStore。

我们正在尝试向应用程序添加Rust 二进制文件,以便我们可以使用一些用该语言编写的 SDK。

为了实现这一目标,我们使用Flutter 的 FFI 系统,通过该系统我们可以对已编译的二进制文件执行本机调用并使用这些执行的结果。

在 Android 中,我们没有遇到任何问题,它在开发模式和生产模式下都可以工作,编译时二进制文件会添加到捆绑包中,并与应用程序一起发布到 PlayStore。

问题

我们遇到的问题是iOS。当我们在开发模式下本地运行应用程序时,应用程序运行得很好,它可以无缝编译,我们可以从 iOS 模拟器和物理设备执行对 Rust 的本机调用。现在,当我们尝试编译应用程序以部署到 AppStore 时,就会出现问题

编译过程分为2步,首先我们构建Runner.app包:

flutter build ios
Run Code Online (Sandbox Code Playgroud)

这会生成 Runner.app,然后将其用作Xcode的输入以生成将上传到 AppStore 的存档:

Xcode 存档

我们面临的问题是,当我们归档Runner.app 时,二进制文件会被编译器剥离,并且 Rust 函数不会被打包。这意味着当应用程序到达 AppStore(TestFlight 和 Production)时,二进制文件不存在。

我们的设置

我们的应用程序是使用以下内容构建的:

  • Flutter 2.8.1-稳定版
  • 生锈 1.58.1

我们尝试捆绑的二进制文件是编译的静态库:library.a。该二进制文件是使用Cargo-lipo作为通用库构建的。(我们知道cargo-lipo处于维护状态,但我们也尝试过捆绑直接使用cargo build构建的二进制文件,结果是相同的)。

这是我们的Podfile

# Uncomment this line to define a global platform for your project

platform :ios, '10.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!

  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))

end

post_install do |installer|

  installer.pods_project.targets.each do |target|

    flutter_additional_ios_build_settings(target)

  end

end
Run Code Online (Sandbox Code Playgroud)

这是具有 Rust 二进制文件的 Dart 插件的podspec :

#

# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.

# Run `pod lib lint defiant_core.podspec` to validate before publishing.

#

Pod::Spec.new do |s|

  s.name             = 'defiant_core'

  s.version          = '0.0.1'

  s.summary          = 'A new flutter plugin project.'

  s.description      = <<-DESC

A new flutter plugin project.

                       DESC

  s.homepage         = 'http://example.com'

  s.license          = { :file => '../LICENSE' }

  s.author           = { 'Your Company' => 'email@example.com' }

  s.source           = { :path => '.' }

  s.source_files = 'Classes/**/*'

  s.public_header_files = 'Classes**/*.h'

  s.vendored_libraries = "**/*.a"

  s.static_framework = true

  s.dependency 'Flutter'

  s.platform = :ios, '9.0'

  # Flutter.framework does not contain a i386 slice.

  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }

  s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/**/*.a" }

  s.swift_version = '5.0'

end
Run Code Online (Sandbox Code Playgroud)

到目前为止我们已经尝试过并得到了相同的结果(或更糟)

  • cargo build使用而不是编译二进制文件cargo-lipo
  • 在 Podfile 和 podspec 中使用 iOS 版本
  • 拆除use_frameworks!线路
  • 根据不同的 Github 问题建议更改这两行:
# ...
  s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
  s.pod_target_xcconfig = { "OTHER_LDFLAGS" => "-force_load $(PODS_TARGET_SRCROOT)/**/*.a" }
# ...
Run Code Online (Sandbox Code Playgroud)
  • 删除这一行 s.static_framework = true
  • .a设置文件在行中的确切位置s.vendored_libraries = "**/*.a"
  • 更改 Xcode 中 Runner Target 的 Build Settings 中的代码条带化配置:

Xcode Runner 目标构建设置

  • 在 Xcode 的 Runner Target 中的构建阶段编译头文件 ( .h) 并链接二进制文件 ( ):.a

标头和二进制构建阶段

  • 在 Xcode 的 Runner Build Settings 中更改目标架构:

更改架构运行器构建设置

结论

到目前为止,没有任何效果......我们已经没有想法了,所以如果有人能够为我们指明正确的方向,我们将不胜感激。

干杯!