С небольшой настройкой один и тот же код охватывает Android и IOS, что более эффективно, чем решение React Native. Кроме того, благодаря кроссплатформенности Rust, некоторый код Rust можно повторно использовать в различных случаях.
Этот пост предназначен для документирования попытки автора объединить Rust и Flutter и является лишь предварительной попыткой. Это не будет включать такие вещи, как:
- Как создать среду разработки Flutter и как использовать язык Dart
- Как создать среду разработки на Rust и как выучить язык Rust
Environment
- Flutter: инструменты Android, IOS настроены правильно
- Rust: Stable — это нормально
Rust Part
Prepare cross-platform toolchains & deps
IOS
# Download targets for IOS ( 64 bit targets (real device & simulator) )
rustup target add aarch64-apple-ios x86_64-apple-ios
# Install cargo-lipo to generate the iOS universal library
cargo install cargo-lipo
Android
здесьЕсть несколько хорошо зарекомендовавших себя вспомогательных скриптов для более быстрой настройки инструментов кросс-компиляции.
-
Получить Android NDK
sdkmanager --verbose ndk-bundleЕсли Android NDK готов, установите переменную среды
$ANDROID_NDK_HOME# example: export ANDROID_NDK_HOME=/Users/yinsiwei/Downloads/android-ndk-r20b -
Create the standalone NDK
# $(pwd) == ~/Downloads git clone https://github.com/kennytm/rust-ios-android.git cd rust-ios-android ./create-ndk-standalone.sh -
Настройте инструменты кросс-компиляции Android в конфигурации Cargo по умолчанию VS
cat cargo-config.toml >> ~/.cargo/configПосле выполнения вышеуказанной команды связанные кроссплатформенные цели Android (цели,
aarch64-linux-android,armv7-linux-androideabi,i686-linux-android) информация об инструменте, указывающая на только что созданныйstandalone NDK.[target.aarch64-linux-android] ar = ... linker = .. [target.armv7-linux-androideabi] ... [target.i686-linux-android] .. -
Загрузите зависимости Rust для поддержки кросс-компиляции Android
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android ```
Start a simple rust library
-
Создайте проект Rust
cargo init my-app-base --lib ```
-
редактировать
Cargo.tomlИсправлятьcrate-type
[библиотека]
имя = "my_app_base"
crate-type = ["staticlib", "cdylib"]
````
Бинарная библиотека, созданная Rust, статически связана с окончательной программой в IOS, и ее необходимо собрать.staticlibподдержка; на Android он заносится в пространство выполнения программы во время выполнения через динамическую линковку, и необходимо строитьcdylibслужба поддержки.
-
Напишите несколько функций, которые соответствуют C ABI
src/lib.rsuse std::os::raw::c_char; use std::ffi::CString; #[no_mangle] pub unsafe extern fn hello() -> *const c_char { let s = CString::new("world").unwrap(); s.into_raw() }В приведенном выше коде каждый раз, когда внешний вызов
helloфункция, строка (CString) и передать право собственности (право на освобождение пространства кучи, занятого строкой)абонент.
Build libraries
# IOS
cargo lipo --release
# Android
cargo build --target aarch64-linux-android --release
cargo build --target armv7-linux-androideabi --release
cargo build --target i686-linux-android --release
затем вtargetПо каталогу вы получите следующие полезные материалы.
target
├── aarch64-linux-android
│ └── release
│ ├── libmy_app_base.a
│ └── libmy_app_base.so
├── armv7-linux-androideabi
│ └── release
│ ├── libmy_app_base.a
│ └── libmy_app_base.so
├── i686-linux-android
│ └── release
│ ├── libmy_app_base.a
│ └── libmy_app_base.so
├── universal
│ └── release
│ └── libmy_app_base.a
Слишком далеко,RustЧасть его заканчивается абзацами.
Flutter Part
Copy build artifacts to flutter project
from: target/universal/release/libmy_app_base.a
to: ios/
from: target/aarch64-linux-android/release/libmy_app_base.so
to: android/app/src/main/jniLibs/arm64-v8a/
from: target/armv7-linux-androideabi/release/libmy_app_base.so
to: android/app/src/main/jniLibs/armeabi-v7a/
from: target/i686-linux-android/release/libmy_app_base.so
to: android/app/src/main/jniLibs/x86/
Call FFI function in Dart
-
добавить зависимости
pubspec.yaml->dev_dependencies:+=ffi: ^0.1.3 -
добавить код
(Измените непосредственно в сгенерированном проекте, не принимая во внимание проблему дизайна кода, просто сначала запустите проект)
import 'dart:ffi'; import 'package:ffi/ffi.dart'; // ... final dylib = Platform.isAndroid ? DynamicLibrary.open('libmy_app_base.so') :DynamicLibrary.process(); var hello = dylib.lookupFunction<Pointer<Utf8> Function(),Pointer<Utf8> Function()>('hello'); // ... hello(); // -> world
Build Android Project
flutter run # 如果连接着 Android 设备就直接运行了起来
Build IOS Project
(гораздо сложнее)
- следить
Flutterофициальная документация, настроитьXCodeпроект. - существует
Build PhasesсерединаLink Binary With LibrariesДобавить кlibmy_app_base.aдокумент (По стрелке на карте...) - существует
Build SettingsсерединаOther Linker Flagsдобавлено вforce_loadпараметр.
Это связано с тем, что в Dart связанные функции библиотеки вызываются динамически, но при статическом анализе при компиляции это бесполезные функции, которые ни разу не вызывались и обрезаются. пройтиforce_loadспособ решить эту проблему.
Result
Troubleshooting
XCode & IOS
Error getting attached iOS device: ideviceinfo could not find device
sudo xattr -d com.apple.quarantine ~/flutter/bin/cache/artifacts/libimobiledevice/ideviceinfo
Замените конечный путь на свой
dyld: Library not loaded
dyld: Library not loaded: /b/s/w/ir/k/homebrew/Cellar/libimobiledevice-flutter/HEAD-398c120_3/lib/libimobiledevice.6.dylib
Referenced from: /Users/hey/flutter/bin/cache/artifacts/libimobiledevice/idevice_id
Reason: image not found
удалить и заново скачать
rm -rf /Users/hey/flutter/bin/cache && flutter doctor -v
Реальная машина не может запустить программу Flutter
видетьGitHub.com/flutter/Appendix…Не обновляйтесь до системы IOS 13.3.1
What's next
-
Как эффективно реализовать взаимодействие частей Rust и Dart
Мы знаем, что Flutter похож на большинство графических библиотек, относится к однопоточной модели в сочетании с системой событий, поэтому код, использующий FFI для вызова Rust-части в основном потоке, не может блокировать поток. Язык Dart предоставляет функции синтаксиса async/await для обработки блокирующих задач, таких как сетевые запросы во Flutter. Кроме того, в последних версиях Rust поддерживает синтаксис async/await, но как элегантно объединить эти две части — проблема.
-
Поддержка рабочего стола MacOS Windows Linux
Flutter уже имеет экспериментальную поддержку для настольных компьютеров, и вы можете изучить, как объединить их для совместного использования кода на 6 терминалах.
References
-
Описывает, как собрать библиотеки Android, IOS и предоставляет примеры.
-
для создания универсальной библиотеки
Адрес блога:Ограничение идентификатора 0.Dev/2020/02/15/…