flutter使用dart ffi调用cc++

简介

flutter使用dart:ffi调用c/c++的插件开发

创建项目

创建flutter_ffi项目,平台勾选Android,Web,Windows。

添加c/c++源码

libs/native_add/native_add.cpp

#include <stdint.h>

#ifdef WIN32
#define DART_API extern "C" __declspec(dllexport)
#else
#define DART_API extern "C" __attribute__((visibility("default"))) __attribute__((used))
#endif

DART_API int32_t native_add(int32_t x, int32_t y) {
    return x + y;
}

Dart

lib/flutter_native_demo.dart 中添加动态库的调用代码

import 'dart:async';
import 'dart:ffi';
import 'dart:io';

import 'package:flutter/services.dart';

final DynamicLibrary nativeAddLib = Platform.isMacOS || Platform.isIOS
    ? DynamicLibrary.process()
    : DynamicLibrary.open('libNativeAdd.${Platform.isWindows ? 'dll' : 'so'}');

final int Function(int x, int y) nativeAdd = nativeAddLib
    .lookup<NativeFunction<Int32 Function(Int32, Int32)>>('native_add')
    .asFunction();

class FlutterNativeDemo {
  static const MethodChannel _channel = MethodChannel('flutter_native_demo');

  static Future<String?> get platformVersion async {
    final String? version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }
}

修改main.dart

添加

platformVersion = nativeAdd(1, 2).toString();
import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_c_ffi/flutter_native_demo.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _platformVersion = 'Unknown';

  @override
  void initState() {
    super.initState();
    initPlatformState();
  }

  // Platform messages are asynchronous, so we initialize in an async method.
  Future<void> initPlatformState() async {
    String platformVersion;
    // Platform messages may fail, so we use a try/catch PlatformException.
    // We also handle the message potentially returning null.
    try {
      // platformVersion =
      //     await FlutterNativeDemo.platformVersion ?? 'Unknown platform version';
      platformVersion = nativeAdd(1, 2).toString();
    } on PlatformException {
      platformVersion = 'Failed to get platform version.';
    }

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() {
      _platformVersion = platformVersion;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: Center(
          child: Text('Running on: $_platformVersion\n'),
        ),
      ),
    );
  }
}

windows 配置

libs/native_add 目录中添加一个 CMakeLists.txt ,用来编译 动态库。

cmake_minimum_required(VERSION 3.4)

# 项目名称
set(PROJECT_NAME "libNativeAdd")
project(${PROJECT_NAME} LANGUAGES CXX)

# 源文件
add_library(${PROJECT_NAME} SHARED
    "./native_add.cpp"
)

# 动态库的输出目录
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<$<CONFIG:DEBUG>:Debug>$<$<CONFIG:RELEASE>:Release>")
# 安装动态库的目标目录
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
# 安装动态库,到执行目录
install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${PROJECT_NAME}.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime)

windows 目录下面的 CMakeLists.txt 中添加相应的子目录

add_subdirectory("../libs/native_add" native_add)

android配置

修改 libs/native_add/CMakeLists.txt 让他兼容windows和 android

cmake_minimum_required(VERSION 3.10)

# 项目名称
if (${CMAKE_SYSTEM_NAME} EQUAL "Windows") 
    set(PROJECT_NAME "libNativeAdd")
else()
    set(PROJECT_NAME "NativeAdd")
endif()

project(${PROJECT_NAME} LANGUAGES CXX)

# 源文件
add_library(${PROJECT_NAME} SHARED
    "./native_add.cpp"
)

# Windows 需要把dll拷贝到bin目录
IF (WIN32)
    # 动态库的输出目录
    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/$<$<CONFIG:DEBUG>:Debug>$<$<CONFIG:RELEASE>:Release>")
    # 安装动态库的目标目录
    set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
    # 安装动态库,到执行目录
    install(FILES "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${PROJECT_NAME}.dll" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" COMPONENT Runtime)
ENDIF()

在 android/build.gradle 文件中的buildscript中添加 CMakeList.txt 路径


//声明为 application
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

android {
    compileSdkVersion 29

    defaultConfig {
        // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
        applicationId "com.xzhongwei.ffi"
        namespace ""
        minSdkVersion 16
        targetSdkVersion 29
        //赋值为上面从pubspec.yaml读取到的相关值
        //versionCode flutterVersionCode.toInteger()
        //versionName flutterVersionName
        versionCode 1
        versionName ""
    }
    externalNativeBuild {
        // Encapsulates your CMake build configurations.
        cmake {
            // 指定一个CMake 编译脚本的相对目录。
            path "../libs/native_add/CMakeLists.txt"
        }
    }
}
/*
task clean(type: Delete) {
    delete rootProject.buildDir
}*/

下面的task clean老报错我就把它干掉了

找不到动态库的问题

  • 我发现libflutter.so 在D:\xzw\demo\flutter\flutter_c_ffi\build\app\intermediates\stripped_native_libs\debug\out\lib目录下,而我们的so在D:\xzw\demo\flutter\flutter_c_ffi\android\build\intermediates\merged_native_libs\debug\out\lib目录下所以不会打包进去
  • 解决办法就是手动放进去,或者修改CMakeLists.tx

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×