首先官方文章有介绍基本的使用方法:官方文档
基本使用
1、在vscode中使用指令新建一个plugin项目:flutter create -t plugin native_add 2、在新建的native_add项目中,新建native_add.cpp文件,并放到ios/Classes/,如下图
3、native_add.cpp添加两个方法
#include <stdint.h>
extern "C" {
// __attribute__((visibility("default"))) __attribute__((used))
int32_t native_add(int32_t x, int32_t y) { return x + y; }
double double_add(double x, double y) { return x + y; }
}
4、在andriod目录下,新建CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1) # for example
add_library( native_add
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
../ios/Classes/native_add.cpp )
5、android/build.gradle文件
android{
// ...
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
6、在lib/native_add.dart下添加内容
import 'dart:async';
import 'package:flutter/services.dart';
import 'dart:ffi'; // For FFI
import 'dart:io'; // For Platform.isX
final DynamicLibrary nativeAddLib = Platform.isAndroid
? DynamicLibrary.open("libnative_add.so")
: DynamicLibrary.process();
final int Function(int x, int y) nativeAdd =
nativeAddLib
.lookup<NativeFunction<Int32 Function(Int32, Int32)>>("native_add")
.asFunction();
class NativeAdd {
static const MethodChannel _channel =
const MethodChannel('native_add');
static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
}
7、在example/lib/main.dart中使用
8、在vscode的terminal窗口,使用cd example,进入native_add项目的example目录,并执行flutter run,测试是否能成功调用nativeAdd方法
9、测试结果:nativeAdd(1,2)等于3
以上就是简单的纯ffi官方的讲解介绍使用。但是在使用的过程中数据类型不仅仅是int和double,还有其他的一些问题是我遇到了并解决了的,这里给大家一些参考,希望能帮到你。
项目使用建议结合pub.dev上面的ffi和系统的ffi方法一起使用,
扩展以及遇到的问题及修复方案:
1. 我的c文件很多,并不是只有一个,而且c文件是已存在的,我只是创建一个交互逻辑使用它。
首先c文件还是按照之前的文件放置在ios/Classes/下面:
记得在CMakeLists.txt里面补充上所有的文件,注意如果是c的文件需要在公共引入方法那里导入头文件:文章参考《C++编程报错Error:Undefined reference to的常见解决办法》
extern “C”{
#include “OOXX.h”
}
注意格式换行要正确。
否则编译会出现异常:Undefined reference to ****
2. 传参类型有二级指针char **
官方demo讲述的只有int,doubel的基本类型,但是c里面也存在char * 和char **的参数类型,需要用什么dart的类型来桥接?(已通过代码验证有效,尤其是char **,有些文章说使用Pointer<Uint8>,我却使用dart怎么也转换不成对应的样子。)
char * 使用Pointer<Utf8>来接。
char ** 使用Pointer<Pointer<Utf8>>来接
使用示例(这里使用的toNativeUtf8(),是使用的pub库里面ffi:1.1.2里面的扩展):
3. allocate.dart文件,一些博友留一手不上传,这里我整理了一下不需要c币的一份连接这个可以在ffi:0.1.2版本中找到,或则我这里给你们贴出来代码:
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:ffi';
import 'dart:io';
// Note that kernel32.dll is the correct name in both 32-bit and 64-bit.
final DynamicLibrary stdlib = Platform.isWindows
? DynamicLibrary.open("kernel32.dll")
: DynamicLibrary.process();
typedef PosixMallocNative = Pointer Function(IntPtr);
typedef PosixMalloc = Pointer Function(int);
final PosixMalloc posixMalloc =
stdlib.lookupFunction<PosixMallocNative, PosixMalloc>("malloc");
typedef PosixFreeNative = Void Function(Pointer);
typedef PosixFree = void Function(Pointer);
final PosixFree posixFree =
stdlib.lookupFunction<PosixFreeNative, PosixFree>("free");
typedef WinGetProcessHeapFn = Pointer Function();
final WinGetProcessHeapFn winGetProcessHeap = stdlib
.lookupFunction<WinGetProcessHeapFn, WinGetProcessHeapFn>("GetProcessHeap");
final Pointer processHeap = winGetProcessHeap();
typedef WinHeapAllocNative = Pointer Function(Pointer, Uint32, IntPtr);
typedef WinHeapAlloc = Pointer Function(Pointer, int, int);
final WinHeapAlloc winHeapAlloc =
stdlib.lookupFunction<WinHeapAllocNative, WinHeapAlloc>("HeapAlloc");
typedef WinHeapFreeNative = Int32 Function(
Pointer heap, Uint32 flags, Pointer memory);
typedef WinHeapFree = int Function(Pointer heap, int flags, Pointer memory);
final WinHeapFree winHeapFree =
stdlib.lookupFunction<WinHeapFreeNative, WinHeapFree>("HeapFree");
/// Allocates memory on the native heap.
///
/// For POSIX-based systems, this uses malloc. On Windows, it uses HeapAlloc
/// against the default public heap. Allocation of either element size or count
/// of 0 is undefined.
///
/// Throws an ArgumentError on failure to allocate.
Pointer<T> allocate<T extends NativeType>({int count = 1}) {
final int totalSize = count * sizeOf<T>();
Pointer<T> result;
if (Platform.isWindows) {
result = winHeapAlloc(processHeap, /*flags=*/ 0, totalSize).cast();
} else {
result = posixMalloc(totalSize).cast();
}
if (result.address == 0) {
throw ArgumentError("Could not allocate $totalSize bytes.");
}
return result;
}
/// Releases memory on the native heap.
///
/// For POSIX-based systems, this uses free. On Windows, it uses HeapFree
/// against the default public heap. It may only be used against pointers
/// allocated in a manner equivalent to [allocate].
///
/// Throws an ArgumentError on failure to free.
///
// TODO(dartbug.com/36855): Once we have a ffi.Bool type we can use it instead
// of testing the return integer to be non-zero.
void free(Pointer pointer) {
if (Platform.isWindows) {
if (winHeapFree(processHeap, /*flags=*/ 0, pointer) == 0) {
throw ArgumentError("Could not free $pointer.");
}
} else {
posixFree(pointer);
}
}
使用:
Pointer<Uint8> soureData = allocate<Uint8>(count:source.length);
如果你使用的时候和我一样遇到allocate方法的第一行的sizeOf<T>();提示错误,不妨可以将这个类型提出来,在外部使用的地方乘好穿进去int值就好了:可以改成如下:
使用的地方: