使用 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();
}