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 的存档:
我们面临的问题是,当我们归档Runner.app 时,二进制文件会被编译器剥离,并且 Rust 函数不会被打包。这意味着当应用程序到达 AppStore(TestFlight 和 Production)时,二进制文件不存在。
我们的应用程序是使用以下内容构建的:
我们尝试捆绑的二进制文件是编译的静态库: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
use_frameworks!
线路# ...
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"
.h
) 并链接二进制文件 ( ):.a
到目前为止,没有任何效果......我们已经没有想法了,所以如果有人能够为我们指明正确的方向,我们将不胜感激。
干杯!
小智 1
我遇到了同样的问题,并通过以下方式修复:
我认为原因是发布版本会去除未使用的符号,而 Rust 生成的符号直接由 Dart 使用,而不是由 App 使用。所以你需要直接在App中使用它们。