ffi_native_only_classes_extending_nativefieldwrapperclass1_can_be_pointer 진단: Pointer로 넘길 수 있는 건 NativeFieldWrapperClass1을 상속한 클래스뿐이에요

ffi_native_only_classes_extending_nativefieldwrapperclass1_can_be_pointer 진단: Pointer로 넘길 수 있는 건 NativeFieldWrapperClass1을 상속한 클래스뿐이에요

Dart 분석기가 내보내는 진단에는 이름이 있어요. ffi_native_only_classes_extending_nativefieldwrapperclass1_can_be_pointer@Native 시그니처에서 파라미터를 Pointer로 넘기도록 했는데, 대응하는 Dart 파라미터 타입이 NativeFieldWrapperClass1을 상속한 클래스가 아닐 때 분석기가 알려주는 컴파일 타임 진단이에요. 포인터로 넘길 대상은 특정 조건을 갖춘 클래스만 될 수 있어요.

출처: ffi_native_only_classes_extending_nativefieldwrapperclass1_can_be_pointer

본문

설명

분석기는 @Native 애노테이션이 붙은 함수나 메서드의 FFI 시그니처에 Pointer 파라미터가 있는데, 대응하는 Dart 파라미터 타입이 NativeFieldWrapperClass1을 상속하지 않는 클래스 인스턴스(PointerTypedData가 아닌)일 때 이 진단을 만들어요.

예시

아래 코드는 MyServiceNativeFieldWrapperClass1을 상속하지 않는데, process 메서드의 @Native 시그니처가 수신자(receiver)를 Pointer<Void>로 넘기라고 나타내고 있어서 이 진단을 만들어요.

import 'dart:ffi';

// MyService does not extend NativeFieldWrapperClass1
class MyService {
  @Native<Void Function(Pointer<Void>, Int8)>(symbol: 'MyService_process')
  external void process(int data);
}

흔한 해결 방법

Dart 클래스가 네이티브 객체를 감싸는(wrap) 용도라면: Dart 클래스가 NativeFieldWrapperClass1을 상속하게 만들어요. 이는 Dart 클래스 인스턴스가 대응하는 네이티브 객체를 갖고 있고 그 객체의 포인터를 넘겨야 하는 상황에 맞는 방법이에요.

import 'dart:ffi';

class MyService extends NativeFieldWrapperClass1 {
  @Native<Void Function(Pointer<Void>, Int8)>(symbol: 'MyService_process')
  external void process(int data);
}

Dart 객체에 불투명 핸들(opaque handle)을 넘기려는 경우라면: @Native 애노테이션의 FFI 시그니처에서 파라미터를 Pointer 대신 Handle을 쓰도록 바꿔요. 그러면 네이티브 코드가 Dart C API를 통해 상호작용할 수 있는, Dart 객체 자체에 대한 참조를 넘길 수 있어요.

import 'dart:ffi';

class MyService {
  @Native<Void Function(Handle, Int8)>(symbol: 'MyService_process')
  external void process(int data);
}

더 알아보기