安卓端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.dart
import '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/