使用 dart::ffi 的 Flutter C++ 绑定
Flutter C++ bindings with dart::ffi
我正在尝试为在我们的应用程序中进行一些数据分析的 C++ 代码编写包装程序包。
我发现此 显示了执行此操作所需的主要步骤。我更像是一个 C/C++ 编码员,所以我有点卡住了,我不明白我做错了什么?
这是analyses.hpp
#include <memory>
#include <vector>
struct int_array
{
int* array;
int len;
};
class cpp_analyses
{
public:
cpp_analyses();
~cpp_analyses() = default;
int_array get_header_index(int_array idx_list_input);
};
对应analyses.cpp
#include "analyses.hpp"
cpp_analyses::cpp_analyses()
{
}
int_array cpp_analyses::get_header_index(int_array idx_list_input)
{
int_array out;
out.array = new int[2];
out.len = 2;
out.array[0] = 1;
out.array[1] = 2;
return out;
}
这是分析-adapter.hpp
#include "analyses.hpp"
#define EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((used))
EXPORT void* initialize_analyses();
EXPORT int_array analyses_get_index(void *ptr, struct int_array in_idx);
对应的源文件analyses_adapter.cpp
#include "analyses-adapter.hpp"
void* initialize_analyses()
{
return new cpp_analyses;
}
int_array analyses_get_index(void *ptr, struct int_array in_idx)
{
auto typed_ptr = static_cast<cpp_analyses*>(ptr);
return typed_ptr->get_header_index(in_idx);
}
飞镖方面:
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class IntArray extends Struct {
external Pointer<Int32> data;
@Int32()
external int length;
}
typedef _example_init_analyses = Pointer<Void> Function();
typedef _analyses_get_saccades_index = IntArray Function(Pointer<Void> obj, IntArray input);
class Analyses {
static late DynamicLibrary nativeApiLib;
external Pointer<Void> _nativeInstance;
external _analyses_index analyses_index;
Analyses() {
nativeApiLib =(DynamicLibrary.open('libanalyses.so')); // android and linux
_example_init_analyses _initialize_analyses = nativeApiLib.lookup<NativeFunction<_example_init_analyses>>('initialize_analyses').asFunction();
_nativeInstance = _initialize_analyses();
analyses_index = nativeApiLib.lookup<NativeFunction<_analyses_index>>('analyses_get_index').asFunction();
}
IntArray get_saccades_index(IntArray input)
{
return analyses_index(_nativeInstance, input);
}
}
终于在main.dart
import 'package:flutter/material.dart';
import 'package:analyses/analyses.dart';
void main() {
Analyses OBJ = new Analyses();
IntArray TMP = IntArray();
TMP.length = 2;
IntArray TMP_second = OBJ.get_index(TMP);
}
整个代码构建没有问题。但是,当我尝试 运行 代码时,它抱怨
#0 NoSuchMethodError._throwNew (dart:core-patch/errors_patch.dart:222:5)
#1 Analyses._nativeInstance= (package:analyses/ncapp_analyses.dart)
我看不出我哪里做错了。任何帮助将不胜感激!
谢谢
编辑
根据要求,请查看完整的堆栈跟踪
Tried calling: _nativeInstance=
#0 NoSuchMethodError._throwNew (dart:core-patch/errors_patch.dart:222:5)
#1 Analyses._nativeInstance= (package:analyses/analyses.dart)
#2 new Analyses (package:analyses/analyses.dart:22:17)
#3 main (package:analyses/main.dart:5:33)
#4 _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:130:25)
#5 _rootRun (dart:async/zone.dart:1426:13)
#6 _CustomZone.run (dart:async/zone.dart:1328:19)
#7 _runZoned (dart:async/zone.dart:1861:10)
#8 runZonedGuarded (dart:async/zone.dart:1849:12)
#9 _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:126:5)
#10 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#11 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
如果我去掉Pointer _nativeInstance;前面的external,我无法编译:
ERROR: lib/ncapp_analyses.dart:16:23: Error: Field '_nativeInstance' should be initialized because its type 'Pointer<Void>' doesn't allow null.
ERROR: - 'Pointer' is from 'dart:ffi'.
ERROR: - 'Void' is from 'dart:ffi'.
ERROR: Pointer<Void> _nativeInstance;
ERROR: ^^^^^^^^^^^^^^^
首先,您需要将代表共享对象的 Dart class 与代表 C++ class.
的 Dart class 分开
第一个包含共享库引用和查找的函数;第二个将仅包含 Pointer<Void>
到您的 C++ class 实例 - 每个实例将有一个(并且将是您在完成特定 C++ [=18= 后释放的东西) ]实例)。
例如:
import 'dart:ffi';
class SoLibrary {
factory SoLibrary() {
// make it a singleton
_instance ??= SoLibrary._();
return _instance!;
}
SoLibrary._() {
// todo - check for Platform type
_nativeApiLib = DynamicLibrary.open('libanalyses.so');
}
static SoLibrary? _instance;
late DynamicLibrary _nativeApiLib;
late final Pointer<Void> Function() _newAnalyses = _nativeApiLib
.lookupFunction<Pointer<Void> Function(), Pointer<Void> Function()>(
'initialize_analyses');
}
class Analyses {
Pointer<Void> _nativeInstance;
Analyses() : _nativeInstance = SoLibrary()._newAnalyses();
}
我正在尝试为在我们的应用程序中进行一些数据分析的 C++ 代码编写包装程序包。
我发现此
这是analyses.hpp
#include <memory>
#include <vector>
struct int_array
{
int* array;
int len;
};
class cpp_analyses
{
public:
cpp_analyses();
~cpp_analyses() = default;
int_array get_header_index(int_array idx_list_input);
};
对应analyses.cpp
#include "analyses.hpp"
cpp_analyses::cpp_analyses()
{
}
int_array cpp_analyses::get_header_index(int_array idx_list_input)
{
int_array out;
out.array = new int[2];
out.len = 2;
out.array[0] = 1;
out.array[1] = 2;
return out;
}
这是分析-adapter.hpp
#include "analyses.hpp"
#define EXPORT extern "C" __attribute__((visibility("default"))) __attribute__((used))
EXPORT void* initialize_analyses();
EXPORT int_array analyses_get_index(void *ptr, struct int_array in_idx);
对应的源文件analyses_adapter.cpp
#include "analyses-adapter.hpp"
void* initialize_analyses()
{
return new cpp_analyses;
}
int_array analyses_get_index(void *ptr, struct int_array in_idx)
{
auto typed_ptr = static_cast<cpp_analyses*>(ptr);
return typed_ptr->get_header_index(in_idx);
}
飞镖方面:
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class IntArray extends Struct {
external Pointer<Int32> data;
@Int32()
external int length;
}
typedef _example_init_analyses = Pointer<Void> Function();
typedef _analyses_get_saccades_index = IntArray Function(Pointer<Void> obj, IntArray input);
class Analyses {
static late DynamicLibrary nativeApiLib;
external Pointer<Void> _nativeInstance;
external _analyses_index analyses_index;
Analyses() {
nativeApiLib =(DynamicLibrary.open('libanalyses.so')); // android and linux
_example_init_analyses _initialize_analyses = nativeApiLib.lookup<NativeFunction<_example_init_analyses>>('initialize_analyses').asFunction();
_nativeInstance = _initialize_analyses();
analyses_index = nativeApiLib.lookup<NativeFunction<_analyses_index>>('analyses_get_index').asFunction();
}
IntArray get_saccades_index(IntArray input)
{
return analyses_index(_nativeInstance, input);
}
}
终于在main.dart
import 'package:flutter/material.dart';
import 'package:analyses/analyses.dart';
void main() {
Analyses OBJ = new Analyses();
IntArray TMP = IntArray();
TMP.length = 2;
IntArray TMP_second = OBJ.get_index(TMP);
}
整个代码构建没有问题。但是,当我尝试 运行 代码时,它抱怨
#0 NoSuchMethodError._throwNew (dart:core-patch/errors_patch.dart:222:5)
#1 Analyses._nativeInstance= (package:analyses/ncapp_analyses.dart)
我看不出我哪里做错了。任何帮助将不胜感激! 谢谢
编辑 根据要求,请查看完整的堆栈跟踪
Tried calling: _nativeInstance=
#0 NoSuchMethodError._throwNew (dart:core-patch/errors_patch.dart:222:5)
#1 Analyses._nativeInstance= (package:analyses/analyses.dart)
#2 new Analyses (package:analyses/analyses.dart:22:17)
#3 main (package:analyses/main.dart:5:33)
#4 _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:130:25)
#5 _rootRun (dart:async/zone.dart:1426:13)
#6 _CustomZone.run (dart:async/zone.dart:1328:19)
#7 _runZoned (dart:async/zone.dart:1861:10)
#8 runZonedGuarded (dart:async/zone.dart:1849:12)
#9 _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:126:5)
#10 _delayEntrypointInvocation.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:297:19)
#11 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:192:12)
如果我去掉Pointer _nativeInstance;前面的external,我无法编译:
ERROR: lib/ncapp_analyses.dart:16:23: Error: Field '_nativeInstance' should be initialized because its type 'Pointer<Void>' doesn't allow null.
ERROR: - 'Pointer' is from 'dart:ffi'.
ERROR: - 'Void' is from 'dart:ffi'.
ERROR: Pointer<Void> _nativeInstance;
ERROR: ^^^^^^^^^^^^^^^
首先,您需要将代表共享对象的 Dart class 与代表 C++ class.
的 Dart class 分开第一个包含共享库引用和查找的函数;第二个将仅包含 Pointer<Void>
到您的 C++ class 实例 - 每个实例将有一个(并且将是您在完成特定 C++ [=18= 后释放的东西) ]实例)。
例如:
import 'dart:ffi';
class SoLibrary {
factory SoLibrary() {
// make it a singleton
_instance ??= SoLibrary._();
return _instance!;
}
SoLibrary._() {
// todo - check for Platform type
_nativeApiLib = DynamicLibrary.open('libanalyses.so');
}
static SoLibrary? _instance;
late DynamicLibrary _nativeApiLib;
late final Pointer<Void> Function() _newAnalyses = _nativeApiLib
.lookupFunction<Pointer<Void> Function(), Pointer<Void> Function()>(
'initialize_analyses');
}
class Analyses {
Pointer<Void> _nativeInstance;
Analyses() : _nativeInstance = SoLibrary()._newAnalyses();
}