Post

Dart ffi認識與應用

使用dart:ffi與C語言進行溝通

前情提要

某次需求要在手機上開啟文件,而文件本身有經透過C/C++來做加密,這時候dart:ffi就派上用場了。

什麼是dart:ffi

首先要講一下FFI(Foreign Function Interface),作為編寫程式的人來說,它是一種通用術語,所表達的是開發者可以透過某種語言去呼叫或橋接另一種語言,而Dart也不例外,它可以在Dart Native平台上(Dart Web目前不支援)使用dart:ffi函式庫和ffi包來達到這個目的,讓我們來橋接Dart code與Native code吧。

建立ffi plugin

這邊建議用官方推薦的方式來使用,透過create plugin新增插件後在裡面加入你的代碼。

1
$ flutter create --platforms=android,ios --template=plugin_ffi native_add

建立一個C++檔案

  1. 找到ios/Classes路徑,並在底下新增native_test.cpp
1
2
3
4
5
6
#include <stdint.h>
extern "C" __attribute__((visibility("default"))) __attribute__((used))
// Todo: FFI綁定C symbols,表示他會照C語言的方式進行編譯跟鏈結,並允許他被外部程序訪問。
int32_t native_add(int32_t x, int32_t y) {
    return x + y;
}

指定C語言代碼目錄。

  • ios配置

    Classes為預設路徑,如果要更改可以到.podspec去調整

  • Android配置

  1. 在android底下新增CMakeList.txt,並輸入這段做指定目錄。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
     # 專案的名稱
     add_library( native_add 
        
     # Sets the library as a shared library.
     SHARED
    
     # 指定Code目錄
     ../ios/Classes/native_test.cpp
     )
    
  2. 到build.gradle 在android底下加一行

package

在pubspec.yaml中dependencies配置底下新增ffi

1
ffi: ^1.2.1

開始寫ffi

到lib目錄底下新增ffi.bridge.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import 'dart:ffi';
import 'dart:io';
import 'package:ffi/ffi.dart';

typedef AddFunction = Int32 Function(Int32 x, Int32 y);
typedef AddFunctionDart = int Function(int x, int y);
// Todo: typedef 聲明往這邊加

class FFIBridge {
  late AddFunctionDart _addFunc;

  FFIBridge() {
    final dl = Platform.isAndroid
        ? DynamicLibrary.open('libnative_add.so')
        : DynamicLibrary.process();
    // Todo: Android 因為JVM的關係,只支援動態鏈結,在執行時會生成.so(ELF)名稱為"lib"+"pluginName"+".so",IOS則支援靜態鏈結

    _addFunc = dl.lookup<NativeFunction<AddFunction>>('native_add').asFunction();
  }


  int calc(int a, int b) => _addFunc(a, b);
  // Todo: 這邊新增一個calc Func,提供外部呼叫時使用
}

使用方法

跟平常使用別人的package一樣,在pubspec.yaml新增這個plugin,改一下Path後pub get,就可以直接import了。

結語

簡單的ffi就大功告成了!,其他部分還有資料類型對應等的問題,可以在C interop using dart:ffi去查詢。

This post is licensed under CC BY 4.0 by the author.