First, the official article introduces the basic usage methods: Official documents
Basic use
Reference article: Using c code on Fluent - (I) projects with source code_ Simplecoder's blog CSDN blog_ Fluent calls c code
1. Create a new plugin project using the instruction in vscode: fluent create - t plugin native_ add
2. In the new native_ In the add project, create a new native_add.cpp file and put it into ios/Classes /, as shown in the following figure
3,native_add.cpp adds two methods
#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. Under the Android directory, create a new 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 file
android{ // ... externalNativeBuild { cmake { path "CMakeLists.txt" } } }
6. In lib / native_ add. Add content under 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. In example / lib / main Used in dart
8. In the terminal window of vscode, use cd example to enter native_add the example directory of the project and execute fluent run to test whether the nativeAdd method can be successfully called
9. Test result: nativeAdd (1, 2) equals 3
The above is a simple official explanation of pure ffi. However, in the process of using, the data types are not only int and double, but also some other problems I have encountered and solved. Here are some references for you, hoping to help you.
It is recommended to use the project in combination with pub The ffi above dev is used together with the ffi method of the system,
Problems encountered in expansion and repair solutions:
1. I have many c files, not only one, and the c file already exists. I just create an interactive logic to use it.
First, the c file is placed under ios/Classes / according to the previous file:
Remember at cmakelists Txt. Note that if it is a c file, you need to import the header file in the public import method: article reference Common solutions to C + + programming Error: Undefined reference to
extern "C"{ #include "OOXX.h" } Note that the format should be correct.
Otherwise, an exception will occur during compilation: Undefined reference to****
2. The parameter type has a secondary pointer char**
The official demo only describes the basic types of int and double, but there are also parameter types of char * and char * * in c. what kind of dart should be used to bridge? (it has been verified by the code, especially char * *. Some articles say that point < uint8 >, but I can't convert it into the corresponding appearance by using dart.)
char * use Pointer<Utf8>Pick it up. char ** use Pointer<Pointer<Utf8>>Pick it up
3. allocate.dart file. Some bloggers don't upload it. Here I sorted out a connection that doesn't need c currency: Fluent and c call allocation Dart file - other document resources - CSDN Downloadhttps://download.csdn.net/download/BUG_delete/76844837 , this can be found in ffi:0.1.2, or I'll post the code here:
// 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); } }
use:
Pointer<Uint8> soureData = allocate<Uint8>(count:source.length);
If you encounter sizeof < T > () in the first line of the allocate method as I do when using it; If you are prompted with an error, you might as well raise this type and multiply it by the int value where it is used externally: it can be changed to the following:
Place of use: