We have a Flutter application that is fully functional and it's already published to both the PlayStore and the AppStore.
We're trying to add a Rust binary to the app so that we can use some SDKs that are written in that language.
In order to achive this, we're using Flutter's FFI system with which we can execute native calls to the compiled binary and consume the results from those executions.
In Android we haven't had any problems, it works both in development mode and in production, the binary is added to the bundle when compiling and published with the app to the PlayStore.
The problem we are having is with iOS. When we run the app locally in development mode, the app works just fine, it compiles seamlessly and we can execute native calls to Rust both from an iOS emulator and from a physical device. Now, when we try compiling the app for deployment to the AppStore is when the problems arise.
The compiling process is divided in 2 steps, first we build the Runner.app package:
flutter build ios
This generates the Runner.app that is then used as input for the Xcode to generate the Archive that will be uploaded to the AppStore:
Xcode Archive
The problem we are facing is that when we archive the Runner.app, the binary gets stripped away by the compiler and the Rust functions are not packaged. This means that when the app reaches the AppStore (both TestFlight and Production) the binary is not there.
Our app is built using:
The binary we're trying to bundle is a Compiled static libary: library.a. This binary was built using cargo-lipo as a universal library. (We know cargo-lipo is in maintainance status, but we've also tried bundling binaries built directly with cargo build and the results are the same).
This is our 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
This is the podspec of the Dart plugin that has the Rust binary:
#
# 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 protected]' }
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
cargo build instead of cargo-lipouse_frameworks! line# ...
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.static_framework = true.a file in the line s.vendored_libraries = "**/*.a"Xcode Runner Target Build Settings
.h) and linking the binary (.a) in the Build Phase in the Runner Target in Xcode:Headers and Binary Build Phase
Changing architecture Runner Build Settings
So far, nothing has worked... We're running out of ideas, so we'd be more than grateful if anyone could point us in the right direction.
Cheers!
I met the same problem, and fixed by following:
I think the reason is the release build will strip the symbols which aren't used, and the symbols generated by Rust are directly used by Dart not the App. So you need to use them directly in the App.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With