Dart 튜토리얼 26편: Native interop(C/Swift/Java) - dart:ffi·ffigen·jnigen
요약
핵심 요지
- 문제 정의: 앱에서 기존 네이티브 코드(C/ObjC/Swift/Java)를 재사용하려면 언어 경계와 메모리 경계를 넘어야 해서, 절차를 모르고 시작하면 바로 막힌다.
- 핵심 주장: Dart Native에서는
dart:ffi1로 C API 호출이 가능하고, Objective-C/Swift는package:ffigen2으로 바인딩 코드를 생성하며, Java/Kotlin은package:jnigen3 +package:jni4로 바인딩을 생성해 호출하는 흐름이 제시된다. - 주요 근거:
hello_world샘플의 빌드/실행 절차, ffigen의FfiGenerator설정/생성 예시, jnigen의jnigen.yaml설정/생성/실행 예시가 제시된다. - 실무 기준: 네이티브 interop는 “(1) 바인딩 생성(또는 작성) → (2) 네이티브 라이브러리 빌드 → (3) 런타임에서 로드/호출” 순서로 체크리스트화한다.
문서가 설명하는 범위
- Dart Native에서
dart:ffi로 C 라이브러리를 호출하는 개요와 hello_world 예시 절차 - Objective-C/Swift interop에서 ffigen 설치/설정/생성/사용 절차
- Java/Kotlin interop에서 jnigen 설정/생성/실행 절차(실험적 기능 안내 포함)
읽는 시간: 14분 | 난이도: 초급
참고 자료
문제 상황
interop는 단순히 “함수를 호출한다”가 아닙니다.
네이티브 라이브러리를 빌드해야 하고, Dart 쪽에서는 타입 서명(signature)을 맞춰야 하며, 실행 시점에 라이브러리를 로드해야 합니다.
이 단계 중 하나라도 빠지면 실행이 되지 않습니다.
그래서 이 글은 언어별로 “필수 단계”만 먼저 고정합니다.
해결 방법
단계 1: C interop은 dart:ffi로 “라이브러리 로드 → 함수 lookup → 호출”을 만든다
Why
NOTE이미 존재하는 C 라이브러리를 재사용하거나, OS/플랫폼 API가 C 형태로 제공되는 경우가 많습니다.
이때 C 호출의 기본 루틴을 먼저 익히면, 다른 언어 interop도 구조가 비슷하게 보입니다.
What
NOTE
dart:ffi는 Dart Native(모바일/CLI/서버)에서 C API를 호출하고 네이티브 메모리를 다루는 기능을 제공합니다.
예시로hello_world샘플이 소개됩니다.
How
TIP샘플에서는 네이티브 라이브러리를 빌드하고 Dart 앱을 실행하는 흐름이 제시됩니다.
Terminal window $ cd hello_library$ cmake ....$ make...$ cd ..$ dart pub get$ dart run hello.dartHello World또한
hello.dart의 핵심 단계는 다음 순서로 설명됩니다.
DynamicLibrary.open()으로 라이브러리 로드 →lookup<NativeFunction<...>>()로 함수 찾기 →asFunction()으로 Dart 함수로 변환 → 호출.
Watch out
WARNINGmacOS에서는 실행 파일(Dart VM 포함)이 “서명된 라이브러리만 로드”할 수 있다는 주의가 제시됩니다.
즉, macOS에서 라이브러리 로드 실패가 나면 서명 문제를 먼저 의심해야 합니다.
결론: C interop는 “라이브러리 로드 → 함수 lookup → 호출” 체크리스트로 접근하면 디버깅이 쉬워집니다.
단계 2: Objective-C/Swift는 ffigen으로 “바인딩 생성”을 자동화한다
Why
NOTEObjective-C도 C 기반이라
dart:ffi만으로 가능하지만, 직접 바인딩을 작성하면 반복 코드가 많아집니다.
그래서 바인딩 생성기를 사용하는 흐름이 제시됩니다.
What
NOTEObjective-C/Swift interop는
dart:ffi와package:ffigen을 함께 사용하며, ffigen이 헤더를 분석해 Dart 바인딩을 생성합니다.
또한 ffigen은 LLVM을 사용하므로 설치가 필요하다고 안내합니다.
How
TIP의존성 추가 예시는 다음과 같습니다.
Terminal window $ dart pub add dev:ffigen objective_c ffi그리고
generate_code.dart에서FfiGenerator를 구성하고.generate()를 호출하는 흐름이 제시됩니다.import 'package:ffigen/ffigen.dart';final config = FfiGenerator();void main() => config.generate();
Watch out
WARNINGffigen은 경우에 따라 Objective-C 보조 코드가 담긴
.m파일을 생성할 수 있으며, 생성되면 반드시 빌드에 포함해야 한다는 주의가 제시됩니다.
즉, “Dart 파일만 생성되겠지”라고 가정하면 런타임에서 심볼 누락 오류가 날 수 있습니다.
결론: ObjC/Swift interop는 “헤더 기준 바인딩 생성”이 핵심이므로, 생성 산출물을 빌드에 포함하는 흐름까지 같이 고정합니다.
단계 3: Java/Kotlin은 jnigen으로 바인딩을 생성하고 jni로 실행한다
Why
NOTEAndroid나 기존 JVM 생태계에서는 Java/Kotlin 코드 재사용이 필요할 수 있습니다.
하지만 JNI 호출은 보일러플레이트가 많습니다.
What
NOTE
package:jni는 JNI를 통해 Java와 상호작용하게 해주고,package:jnigen은 Java API의 Dart 바인딩을 자동 생성하는 도구로 소개됩니다.
또한 이 interop 기능은 실험적(experimental)이라는 주의가 제시됩니다.
How
TIP의존성 추가와 설정 파일 예시는 다음과 같습니다.
Terminal window $ dart pub add jni dev:jnigenoutput:dart:path: lib/example.dartstructure: single_filesource_path:- 'java/'classes:- 'dev.dart.Example'생성 명령과 실행에 앞선 준비 절차 예시는 다음과 같습니다.
Terminal window $ dart run jnigen --config jnigen.yaml$ dart run jni:setup$ javac java/dev/dart/Example.java
Watch out
WARNING실험적 기능이라는 점이 명시되어 있으므로, 운영 환경 도입 전에는 “지원 플랫폼/업데이트/제약”을 확인해야 합니다.
즉, 학습/프로토타입과 운영 도입을 같은 속도로 진행하면 위험할 수 있습니다.
결론: Java/Kotlin interop는 “바인딩 생성 → JNI 준비 → 실행” 3단계로 나눠서 진행하면 막히는 지점을 줄일 수 있습니다.
Footnotes
공유
이 글이 도움이 되었다면 다른 사람과 공유해주세요!