安卓端flutter通过ffi调用so动态库
背景
自从抖音上线web版后不久,旧版的无水印接口就开始失效了,需要找新的官方接口。
但是新的官方接口开始接入x-bogus算法,需要用golang的一个js虚拟机来生成x-bogus签名,这里就需要将golang打包到flutter中使用。
资料
embed库可以将资源文件一起打包成二进制,比如js、image等。import "C"作用于将golang函数导出给外部调用,部分入参和返回的数据类型也要用这个库进行转换,比如字符串。github.com/dop251/goja这个库用于运行js文件,作为一个js虚拟机。
编码
package main
import "C"
func main() {}
//export hello
func hello(name *C.char) *C.char {
msg := "hello " + name
return C.CString(msg)
}打包脚本
演示系统是windows环境
set ANDROID_NDK_HOME=D:\Android\SDK\ndk\22.0.7026061
set GOARCH=arm
set GOOS=android
set CGO_ENABLED=1
set CC=%ANDROID_NDK_HOME%\toolchains\llvm\prebuilt\windows-x86_64\bin\armv7a-linux-androideabi21-clang
go build -ldflags "-w -s" -buildmode=c-shared -o ./bin/armeabi-v7a/libhello.so ./main.go
echo Build armeabi-v7a finish
set GOARCH=arm64
set GOOS=android
set CGO_ENABLED=1
set CC=%ANDROID_NDK_HOME%\toolchains\llvm\prebuilt\windows-x86_64\bin\aarch64-linux-android21-clang
go build -ldflags "-w -s" -buildmode=c-shared -o ./bin/arm64-v8a/libhello.so ./main.go
echo Build arm64-v8a finish
set GOARCH=amd64
set GOOS=android
set CGO_ENABLED=1
set CC=%ANDROID_NDK_HOME%\toolchains\llvm\prebuilt\windows-x86_64\bin\x86_64-linux-android24-clang
go build -ldflags "-w -s" -buildmode=c-shared -o ./bin/x86_64/libhello.so ./main.go
echo Build x86_64 finish
set GOARCH=386
set GOOS=android
set CGO_ENABLED=1
set CC=%ANDROID_NDK_HOME%\toolchains\llvm\prebuilt\windows-x86_64\bin\i686-linux-android24-clang
go build -ldflags "-w -s" -buildmode=c-shared -o ./bin/x86/libhello.so ./main.go
echo Build x86 finish- 修改
ANDROID_NDK_HOME变量为你的ndk目录 - 实际上如果没有其他平台兼容打算的话,比如不去兼容一些老设备,这时只需要编译
arm64-v8a即可。
执行完脚本后会在bin目录中生成对应平台的so动态库文件。
flutter项目配置
添加依赖
dart pub add -d ffigen将
golang代码生成的.h头文件复制到flutter工程目录中,可以自由放置。比如我将其放置在lib/ffi目录。将
golang代码生成的bin目录下的所有内容复制到flutter工程的android/libs目录中。然后在app/bild.gradle文件中加入以下代码// 放入android节点下 sourceSets { main { jniLibs.srcDirs = ["libs"] } }修改
pubspec.yaml,增加以下配置ffigen: output: 'lib/ffi/libhello.h.dart' # 根据上述的路径填入 headers: entry-points: - 'lib/ffi/libhello.h' # 根据上述的路径填入运行
dart run ffigen,此时会生成一个libhello.h.dart文件。接下来编写dart快捷代码新建dart文件
lib/ffi/HelloFFi.dartimport 'dart:ffi'; import 'package:ffi/ffi.dart' as ffi; import './hello.h.dart'; class HelloFFi { HelloFFi._(); final _native = NativeLibrary(DynamicLibrary.open('libhello.so')); static final HelloFFi _instant = HelloFFi._(); factory HelloFFi() => _instant; /// 和golang代码同名的方法名 String hello(String name) { // input final raw = name.codeUnits; final buffer = ffi.malloc.allocate<Int8>(raw.length + 1); buffer.asTypedList(raw.length + 1) ..setAll(0, raw) ..[raw.length] = 0; return _native.hello(buffer).cast<ffi.Utf8>().toDartString(); } }踩坑
so文件名必须以lib开头,否则release模式下会找不到so文件,而debug模式下正常使用
//export导出函数时,//不能有空格。
安卓端flutter通过ffi调用so动态库
http://blog.icy8.cn/posts/43743/