Android逆向技术59——Flutter with Rust会发生什么续篇(By LittleQ)
之前,写过一期文章,在Flutter里面使用Rust, 那一种方案是将rust和flutter绑定到了一起,这种方式,总觉得不太优雅,如果能作为一个独立的库,这个体验就好了,然后翻了一下flutter_rust_bridge的那个库的文档,实际上这个是支持插件的,那么动手尝试一下吧。
实验环境
实验环境和上一篇文章保持一致。
准备工作
-
安装melos
dart pub global activate melos
-
新建插件项目
flutter create --template=plugin_ffi --platforms=android,ios,macos,linux,windows --org=com.littleq flutter_library_rust
-
新建rust的项目
cargo new rust --lib
项目结构
这里,因为我们要集成到flutter当中,因此,这里和纯dart有些区别,需要进行一些微调。
.
├── analysis_options.yaml
├── android
├── example # 示例文件
├── ffigen.yaml
├── flutter_library_rust.iml
├── ios
├── lib # dart库文件
├── linux
├── macos
├── rust # rust库文件
├── scripts
└── windows
由于调整了部分结构,因此后续需要对脚本进行微调,注意我这脚本和官方文档的有差异。
样例代码
-
rust
// api.rs
pub fn add(left: usize, right: usize) -> usize {
left + right
}
-
dart
// src/ffi.dart
import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';
import 'bridge_generated.dart';
import 'bridge_definitions.dart';
export 'bridge_definitions.dart';
// Re-export the bridge so it is only necessary to import this file.
export 'bridge_generated.dart';
import 'dart:io' as io;
const _base = 'rust';
// On MacOS, the dynamic library is not bundled with the binary,
// but rather directly **linked** against the binary.
final _dylib = io.Platform.isWindows ? '$_base.dll' : 'lib$_base.so';
final Rust api = RustImpl(
io.Platform.isIOS || io.Platform.isMacOS
? DynamicLibrary.executable()
: DynamicLibrary.open(_dylib),
);
-
配置文件
rust_input:
- rust/src/api.rs
dart_output:
- lib/src/bridge_generated.dart
c_output:
- ios/Runner/bridge_generated.h
extra_c_output_path:
- macos/Runner
dart_decl_output: lib/src/bridge_definitions.dart
dart_format_line_length: 120
wasm: true
然后,我们直接构建代码就可以了
flutter_rust_bridge_codegen .flutter_rust_bridge.yml
到这里,准备工作就做完了,可以瞅一瞅,代码里面还有没有报错,有报错,说明哪里没执行好,检查一遍,没报错,就可以执行下一步了。
构建各个平台的代码
Android
这里,需要配置一下CMakeList.txt
set(LibraryVersion "library_name-v0.0.0") # generated; do not edit
# Unlike the Windows & Linux CMakeLists.txt, this Android equivalent is just here
# to download the Android binaries into src/main/jniLibs/ and does not build anything.
# The binary download/extraction is difficult to do concisely in Groovy/Gradle,
# at least across host platforms, so we are just reusing our Linux/Windows logic.
# The Flutter tooling requires that developers have CMake 3.10 or later
# installed. You should not increase this version, as doing so will cause
# the plugin to fail to compile for some customers of the plugin.
cmake_minimum_required(VERSION 3.10)
# Download the binaries if they are not already present.
set(LibRoot "${CMAKE_CURRENT_SOURCE_DIR}/src/main/jniLibs")
set(ArchivePath "${CMAKE_CURRENT_SOURCE_DIR}/${LibraryVersion}.tar.gz")
if (NOT EXISTS ${ArchivePath})
file(DOWNLOAD
"your download uri"
${ArchivePath}
)
endif ()
# Extract the binaries, overriding any already present.
file(REMOVE_RECURSE ${LibRoot})
file(MAKE_DIRECTORY ${LibRoot})
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xzf ${ArchivePath}
WORKING_DIRECTORY ${LibRoot}
)
这里,其实不配置也可以,编译出来的,自己放到对应的目录下也行,但是咱作为库了,自然要做的优雅一点,当然,这个配置,也可以根据自己的需要,自己改吧改吧cmake的构建文件。
然后,我们编写下构建的脚本,当然,选择手动构建也不是不行,就是麻烦点。
#!/bin/bash
# Setup
BUILD_DIR=rust
cd $BUILD_DIR
# Create the jniLibs build directory
JNI_DIR=jniLibs
mkdir -p $JNI_DIR
# Set up cargo-ndk
cargo install cargo-ndk
rustup target add
aarch64-linux-android
armv7-linux-androideabi
x86_64-linux-android
i686-linux-android
# Build the android libraries in the jniLibs directory
cargo ndk -o $JNI_DIR
--manifest-path ./Cargo.toml
-t armeabi-v7a
-t arm64-v8a
-t x86
-t x86_64
build --release
# Archive the dynamic libs
cd $JNI_DIR
tar -czvf ../android.tar.gz *
cd -
# Cleanup
rm -rf $JNI_DIR
这里,唯一需要注意的就是Cargo.toml
文件的位置,其他的和官网大差不差。
IOS
这里,同样需要微调一下构建的脚本。
#!/bin/bash
# Setup
BUILD_DIR=rust
#mkdir $BUILD_DIR
cd $BUILD_DIR
# Build static libs
for TARGET in
aarch64-apple-ios x86_64-apple-ios aarch64-apple-ios-sim
x86_64-apple-darwin aarch64-apple-darwin; do
rustup target add $TARGET
cargo build -r --target=$TARGET
done
# Create XCFramework zip
FRAMEWORK="rust.xcframework"
LIBNAME=librust.a
mkdir mac-lipo ios-sim-lipo
IOS_SIM_LIPO=ios-sim-lipo/$LIBNAME
MAC_LIPO=mac-lipo/$LIBNAME
lipo -create -output $IOS_SIM_LIPO
./target/aarch64-apple-ios-sim/release/$LIBNAME
./target/x86_64-apple-ios/release/$LIBNAME
lipo -create -output $MAC_LIPO
./target/aarch64-apple-darwin/release/$LIBNAME
./target/x86_64-apple-darwin/release/$LIBNAME
xcodebuild -create-xcframework
-library $IOS_SIM_LIPO
-library $MAC_LIPO
-library ./target/aarch64-apple-ios/release/$LIBNAME
-output $FRAMEWORK
zip -r $FRAMEWORK.zip $FRAMEWORK
# Cleanup
rm -rf ios-sim-lipo mac-lipo $FRAMEWORK
然后,需要更改一下flutter_library_rust.podspec
文件,内容如下
Pod::Spec.new do |s|
s.name = 'flutter_library_rust'
s.version = '0.0.1'
s.summary = 'A new Flutter FFI plugin project.'
s.description = <<-DESC
A new Flutter FFI plugin project.
DESC
s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => '[email protected]' }
# This will ensure the source files in Classes/ are included in the native
# builds of apps using this FFI plugin. Podspec does not support relative
# paths, so Classes contains a forwarder C file that relatively imports
# `../src/*` so that the C sources can be shared among all target platforms.
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.vendored_frameworks = 'Frameworks/**/*.xcframework'
s.static_framework = true # This allows us to use the static library we built.
s.dependency 'Flutter'
s.platform = :ios, '11.0'
# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
s.swift_version = '5.0'
end
如果想要自动下载依赖库的话呢,就自行处理下下载的逻辑,这里我手动移动进去的,因此呢对,就是这么的任性,不处理了。
MacOS
对于MacOS,具体的方法和IOS一致,这里,只需要更改对应的macos文件夹下的内容就可以了。
其他平台
对于其他平台来说,直接参考文档吧,这里不在展开描述了。
总结
目前,通过插件形式来引入rust到flutter当中,相对来说,对于主项目的入侵就变得非常低了,而且也利于不同项目进行拆分,目前来看,这是一个还不错的方案。
参考资料
-
https://cjycode.com/flutter_rust_bridge/library/dart_only.html[1]
Reference
https://cjycode.com/flutter_rust_bridge/library/dart_only.html: https://cjycode.com/flutter_rust_bridge/library/dart_only.html
原文始发于微信公众号(安全后厨):Android逆向技术59——Flutter with Rust会发生什么续篇(By LittleQ)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论