Flutter与C/C++高效交互:实战dart:ffi与MethodChannel的深度解析

Flutter调用C++实战:手把手教你用dart:ffi绕过MethodChannel的坑(附.so文件正确存放位置) 本文详细介绍了Flutter通过dart:ffi直接调用C++代码的实战方法,对比MethodChannel的性能差异,提供.so文件存放位置指南和跨平台兼容方案。重点解析dart:ffi的核心用法,包括动态库加载、函数映射和复杂数据类型处理,帮助开发者实现高性能的Flutter与C++深度整合。 阅读详情

1. 为什么Flutter需要与C/C++“握手”?

如果你用Flutter做过一些稍微“硬核”一点的功能,比如图像处理、音频解码、硬件加密或者调用一些老牌算法库,你大概率会遇到一个灵魂拷问:Dart这语言,性能虽然不错,但真到了计算密集型的场景,还是有点力不从心。这时候,我们很自然地就会想到那些用C或C++写成的“老炮儿”库,它们经过几十年优化,又快又稳。

但问题来了,Flutter的Dart和C/C++,完全是两个世界的语言,怎么让它们顺畅地对话呢?这就是我们今天要聊的核心。我刚开始做这块的时候,也是头大,官方文档看一遍感觉懂了,一上手全是坑。最常见的两种方案就是 dart:ffi 和 MethodChannel。简单来说,ffi像是给Dart发了一张“特别通行证”,让它能直接调用C函数;而MethodChannel则像请了两位“翻译官”(Android和iOS平台),让Flutter通过它们间接和C/C++沟通。

选择哪种,可不是拍脑袋决定的。用ffi,性能直达,几乎零损耗,但平台兼容性和构建流程会让你掉不少头发。用MethodChannel,开发起来相对直观,平台的事儿交给原生端处理,但多了一层通信,性能有损耗,而且你得写双份(Android和iOS)的桥接代码。我自己的项目里,两种方案都用过,踩过的坑数不胜数,今天就把这些实战经验掰开了、揉碎了,跟你好好聊聊。

2. 直捣黄龙:用dart:ffi直接调用C/C++

2.1 ffi是什么?为什么说它“高效”?

dart:ffi 的全称是 Foreign Function Interface,翻译过来叫“外部函数接口”。你可以把它想象成Dart虚拟机开的一个“后门”,通过这个后门,Dart代码可以直接在内存里找到C/C++编译好的函数,然后调用它。这个过程没有中间商赚差价,Dart和C函数几乎是直接握手,所以性能非常高,理论上就是原生C函数的调用开销加上一点点查找函数的开销。

我第一次用ffi的时候,感觉就像发现新大陆。原来不需要经过Platform Channel那套复杂的消息编解码,就能直接让我的Flutter App跑起来那些用C写的图像滤镜算法,帧率瞬间就上去了。但是,高效往往伴随着复杂性,ffi这条路,第一步“找库”就能把人卡住。

2.2 实战第一步:.so库到底放哪儿?(巨坑预警!)

这是几乎所有ffi新手都会栽跟头的地方,包括我。按照常理,我们会把动态库(比如 libnative_add.so)放在 assets/ 或者 android/app/src/main/jniLibs/ 这类看起来“理所当然”的目录。结果运行起来,一律报错:Failed to load dynamic library。

我当时折腾了大半天,各种路径都试遍了,差点放弃。后来才发现,在Flutter的调试构建(debug)过程中,库文件需要放在一个编译产出的中间目录里。对于Android来说,典型路径是:

你的项目/build/app/intermediates/merged_native_libs/debug/out/lib/

在这个 lib/ 目录下,再按CPU架构分子目录,比如 arm64-v8a/、armeabi-v7a/、x86_64/。

为什么这么反直觉?因为Flutter的构建流程会把所有原生依赖(包括你自己的.so)合并到这个位置。build目录是编译时生成的,clean一下就没了,所以这显然不是存放源文件的地方。通常的做法是:把你的.so文件放在项目某个固定位置(比如一个 native_libs/ 目录),然后在 android/app/build.gradle 里写一段拷贝脚本,在构建时自动复制到目标位置。

android {
    sourceSets {
        main {
            jniLibs.srcDirs = ['../native_libs'] // 指定你的源库目录
        }
    }
    // 或者使用更精细的copy任务
}

对于iOS,情况更特殊。苹果App Store对动态库(.dylib)审核很严,通常要求使用静态库(.a或.framework)。通过ffi调用时,iOS端一般使用 DynamicLibrary.process() 来加载主执行程序中的符号,或者加载打包在App内的framework。

2.3 代码怎么写:从加载到调用的完整流程

假设我们有一个最简单的C函数:

// native_code.c
#include <stdint.h>

int32_t add(int32_t a, int32_t b) {
    return a + b;
}

编译成 libnative_code.so。

在Dart端,我们创建一个 native_ffi.dart 文件来专门处理FFI调用:

import 'dart:ffi'; // 核心库
import 'dart:io'; // 用于Platform判断

// 1. 加载动态库
final DynamicLibrary nativeLib = Platform.isAndroid
    ? DynamicLibrary.open('libnative_code.so') // Android加载.so
    : DynamicLibrary.process(); // iOS加载主程序符号(静态库情况)

// 2. 定义函数签名(类型映射)
// C端函数签名:int32_t (int32_t, int32_t)
// Dart端对应:int (int, int)
// 使用typedef让代码更清晰
typedef AddNative = Int32 Function(Int32 a, Int32 b);
typedef AddDart = int Function(int a, int b);

// 3. 查找并映射函数
final AddDart add = nativeLib
    .lookupFunction<AddNative, AddDart>('add');

// 使用函数
void testFFI() {
  final result = add(10, 20);
  print('FFI计算结果是:$result'); // 输出 30
}

这段代码里,lookupFunction 是关键。它第一个泛型参数 AddNative 描述的是C函数的模样,第二个参数 AddDart 描述的是我们希望得到的Dart函数的模样。FFI会在底层完成这个转换。

2.4 数据类型映射:小心“踩雷”

C和Dart的数据类型不是一一对应的,这里最容易出bug。我整理了一个常见类型的映射表,你写代码时最好放在手边:

C/C++ 类型 (ffi中)Dart 类型 (ffi中)对应的Dart语言类型说明
int8_t / charInt8int有符号8位整数
uint8_tUint8int无符号8位整数
int32_tInt32int有符号32位整数
floatFloatdouble单精度浮点数
doubleDoubledouble双精度浮点数
char* (C字符串)Pointer<Utf8>String需要手动转换,使用 .toDartString()
void*Pointer<Void>无通用指针,需根据上下文转换

特别注意字符串和结构体:

  • 字符串:C中的 char* 传到Dart是 Pointer<Utf8>,不能直接当String用。你需要这样转换:
    // C函数:const char* get_name();
    final getName = lib.lookupFunction<Pointer<Utf8> Function(), Pointer<Utf8> Function()>('get_name');
    Pointer<Utf8> namePtr = getName();
    String name = namePtr.toDartString(); // 关键转换
    
    记得,如果C端分配了内存,Dart端可能需要负责释放,否则内存泄漏。
  • 结构体:需要用在Dart中用 class 继承 Struct 来定义,且每个字段都必须用ffi类型。这个比较繁琐,建议看官方示例。

2.5 性能实测与陷阱

我做过一个简单的性能对比:用Dart和用ffi调用C,执行1000万次整数加法。

  • 纯Dart循环:约 450 ms
  • ffi调用C函数循环:约 120 ms

优势很明显,接近4倍的差距。但对于单次调用,ffi由于有查找函数和跨语言调用的固定开销,如果函数本身非常简单(比如就做一个加法),那么这个开销占比就很高,优势不明显。所以ffi更适合在循环内调用,或者调用本身计算量大的函数。

另一个陷阱是异步。dart:ffi调用是同步阻塞的。如果你调用的C函数很耗时,它会卡住你的Dart UI线程。解决方法是在Isolate(Dart的线程)中调用ffi函数,但这又会涉及如何在Isolate间传递ffi对象(Pointer 和 DynamicLibrary 不能直接传递),复杂度飙升。通常的套路是在Spawn Isolate时,在Isolate内部重新打开动态库。

3. 稳扎稳打:通过MethodChannel进行桥接

3.1 MethodChannel工作原理:为什么说它是“桥梁”?

如果你觉得ffi太“底层”,或者你的C/C++库已经由原生端(Android/iOS)封装好了,那么MethodChannel是你的菜。它的工作原理很简单:

  1. Flutter端:定义一个MethodChannel,给它起个名字(比如 'com.example/native')。
  2. Flutter端:通过这个Channel发送方法调用和参数。
  3. 原生端(Android/iOS):监听同一个名字的Channel,收到调用后,执行对应的原生代码(这里可以是Java/Kotlin或Swift/Obj-C,再由它们去调用C/C++库)。
  4. 原生端:处理完毕,将结果通过Channel回传给Flutter。

整个过程就像Flutter和原生之间打了一通“电话”,MethodChannel就是电话线,两边的“接线员”(平台代码)负责翻译和传达。我最初放弃ffi后,就是用的这个方法,先把Android端调通了。

3.2 Android端完整实现:从Flutter到Kotlin再到C++

假设我们要在Android端通过MethodChannel调用一个C++函数 encryptData。

第一步:Flutter端代码

import 'package:flutter/services.dart';

class NativeBridge {
  static const MethodChannel _channel = MethodChannel('com.example/crypto');

  static Future<String> encrypt(String data) async {
    try {
      final String result = await _channel.invokeMethod('encrypt', data);
      return result;
    } on PlatformException catch (e) {
      print("调用加密失败: ${e.message}");
      return "";
    }
  }
}

第二步:Android (Kotlin)端代码

  1. 在 MainActivity.kt 中设置Channel:
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example/crypto"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
            call, result ->
            if (call.method == "encrypt") {
                val data = call.arguments as String
                // 调用本地Native方法
                val encrypted = NativeHelper.encryptData(data)
                result.success(encrypted)
            } else {
                result.notImplemented()
            }
        }
    }
}
  1. 创建 NativeHelper.kt 来通过JNI调用C++:
// 加载我们编译好的C++库
external fun encryptData(data: String): String

companion object {
    init {
        System.loadLibrary("native_crypto") // 对应 libnative_crypto.so
    }
}

第三步:C++层代码 (native-lib.cpp)

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_NativeHelper_encryptData(JNIEnv* env, jobject /* this */, jstring input) {
    const char* nativeString = env->GetStringUTFChars(input, nullptr);
    // 这里执行你的加密逻辑...
    std::string result = "encrypted_" + std::string(nativeString);
    env->ReleaseStringUTFChars(input, nativeString);
    return env->NewStringUTF(result.c_str());
}

看到那个又长又臭的 Java_com_example_app_NativeHelper_encryptData 函数名了吗?这就是JNI的规矩,必须按照 Java_包名_类名_方法名 的格式来命名,一点不能错,否则就是 UnsatisfiedLinkError。这是我当时觉得最“椒麻”的地方。

3.3 iOS端实现:Swift/Obj-C的桥接

iOS端思路类似,但细节不同。首先,iOS不能随意使用动态库,我们一般把C++代码编译成静态库(.a)或直接放在工程里用C++混编。

第一步:Flutter端代码不变,还是调用同一个Channel。

第二步:iOS (Swift)端代码 在 AppDelegate.swift 中设置:

import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let channel = FlutterMethodChannel(name: "com.example/crypto", binaryMessenger: controller.binaryMessenger)
        
        channel.setMethodCallHandler({
            (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
            if call.method == "encrypt" {
                if let data = call.arguments as? String {
                    let encrypted = NativeHelper.encrypt(data) // 调用Swift/Obj-C方法
                    result(encrypted)
                } else {
                    result(FlutterError(code: "BAD_ARGS", message: "参数错误", details: nil))
                }
            } else {
                result(FlutterMethodNotImplemented)
            }
        })
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
}

第三步:通过Objective-C++桥接调用C++

  1. 创建一个 NativeHelper.mm 文件(.mm扩展名表示Objective-C++,可以混编C++):
// NativeHelper.mm
#import "NativeHelper.h"
#import "native_crypto.h" // 你的C++头文件

@implementation NativeHelper

+ (NSString *)encrypt:(NSString *)data {
    std::string cppData = std::string([data UTF8String]);
    std::string encrypted = ::encryptData(cppData); // 调用C++函数
    return [NSString stringWithUTF8String:encrypted.c_str()];
}

@end
  1. 你的C++头文件和实现:
// native_crypto.h
#pragma once
#include <string>
std::string encryptData(const std::string& data);

// native_crypto.cpp
#include "native_crypto.h"
std::string encryptData(const std::string& data) {
    return "encrypted_" + data;
}

iOS这边主要麻烦在于混编配置和头文件引入,对于不熟悉XCode和iOS开发的同学来说,光配环境就能耗掉半天。

3.4 MethodChannel的优缺点分析

用MethodChannel绕了一圈,感受非常明显。 优点:

  1. 开发体验相对统一:在Flutter端,你只需要关心 invokeMethod,不用管底层是C还是C++。
  2. 平台特性利用充分:所有平台相关的细节(JNI、Objective-C Runtime)都被封装在原生端,你可以充分利用Android/iOS的原生API。
  3. 异步友好:Channel调用天生是异步的(返回Future),不会阻塞UI。
  4. 安全隔离:C/C++代码的崩溃通常会被限制在原生进程内,不一定导致整个Flutter应用崩溃(取决于实现)。

缺点:

  1. 性能损耗:数据需要经过多次序列化和反序列化(Flutter -> 原生平台 -> C++),对于大量、高频的数据传输,这个开销很大。
  2. 双份工作:你需要为Android和iOS分别实现一遍桥接逻辑,虽然业务代码一样,但平台胶水代码得写两套。
  3. 类型映射麻烦:复杂的数据结构(如列表、字典、自定义对象)在Channel间传递需要手动编解码,容易出错。

4. 深度对比:ffi vs MethodChannel,我该怎么选?

光讲技术不行,得落到实际选择上。我画了一个对比表格,你可以一目了然地看到核心差异:

特性维度dart:ffiMethodChannel
性能⭐⭐⭐⭐⭐ 接近原生调用,延迟极低,吞吐量高。⭐⭐ 有显著开销,经过消息编解码和线程切换。
开发复杂度⭐⭐ 高。需处理平台库路径、内存管理、数据类型精确映射、可能需Isolate。⭐⭐⭐⭐ 中。主要复杂度在原生端桥接,但模式固定。
跨平台一致性⭐⭐ 低。Android和iOS的库格式、加载方式、甚至函数签名都可能需要调整。⭐⭐⭐⭐ 高。Flutter端接口完全一致,原生端各自实现即可。
安全性/稳定性⭐⭐ 风险高。C/C++内存错误可能导致Dart VM崩溃。⭐⭐⭐⭐ 风险较低。原生端崩溃可能被捕获,不一定会波及Flutter UI。
适用场景高性能计算、频繁调用的底层函数、已有现成.so/.a库。调用平台特定API、复杂异步任务、对性能不敏感的简单调用。
调试难度⭐⭐⭐ 难。C/C++层崩溃日志难以捕捉,需要原生调试工具。⭐⭐ 较易。可在Flutter和原生两端分别打断点调试。

怎么选?我的实战经验是:

  • 选ffi,当你:做音视频处理、游戏引擎绑定、科学计算、密码学等性能瓶颈明显的模块。或者,你的核心算法库已经是现成的C/C++动态库,不想重写。
  • 选MethodChannel,当你:需要调用摄像头、蓝牙、传感器等平台特有硬件API。或者,你的C/C++调用不频繁,且数据结构复杂,用ffi映射起来太痛苦。又或者,你的团队对Android/iOS开发更熟悉,希望把底层问题隔离在原生侧。

一个混合策略:在我的一个图像处理项目中,我采用了混合方案。核心的滤镜算法(每秒调用数百万次)用ffi实现,以获得极致性能。而像“从相册选图”、“保存图片到系统相册”这类操作,则用MethodChannel调用平台API。各取所长,效果很好。

5. 进阶话题与避坑指南

5.1 内存管理:谁分配,谁释放?

这是ffi中最容易导致崩溃的地方。一个黄金法则:尽量让内存的分配和释放在同一种语言中进行。

  • 情况一:C函数返回一个指向内部静态数据的指针(或字符串)。Dart端可以安全地读取,但绝对不能尝试释放它。
  • 情况二:C函数使用 malloc 分配内存并返回指针。Dart端在使用完毕后,必须调用C端的释放函数(如 free_result(Pointer<Void> ptr)),而不能用Dart的任何方式去释放。你需要在C端暴露这个释放函数。
  • 情况三:Dart端分配内存传给C函数使用。可以使用 allocate 或 allocate 函数。用完记得在Dart端调用 free。
// Dart分配内存给C使用示例
import 'dart:ffi';
import 'package:ffi/ffi.dart'; // 这个包提供了很多好用工具

final malloc = mallocLib.lookupFunction<...>('malloc');
final free = mallocLib.lookupFunction<...>('free');

Pointer<Int32> intPtr = allocate<Int32>();
intPtr.value = 42;
// 将 intPtr 传递给C函数...
free(intPtr); // 使用C标准库的free释放

5.2 在Isolate中使用ffi

前面提到,耗时的ffi调用会阻塞UI。解决方案是放到Isolate里。但 DynamicLibrary 和 Pointer 对象不能直接跨Isolate传递。标准做法是在Spawn Isolate时,将库的路径作为参数传入,然后在Isolate内部重新打开这个动态库。

// 主Isolate
void spawnComputeIsolate() {
  final receivePort = ReceivePort();
  Isolate.spawn(_isolateEntry, receivePort.sendPort);
}

// Isolate入口函数
static void _isolateEntry(SendPort sendPort) async {
  // 在Isolate内重新打开库
  final lib = DynamicLibrary.open('libheavy_compute.so');
  final heavyFunc = lib.lookupFunction<...>(...);
  
  // ... 执行计算 ...
  final result = heavyFunc(...);
  
  // 将结果(基本类型或可序列化对象)发送回主Isolate
  sendPort.send(result);
}

5.3 调试技巧:当调用崩溃时怎么办?

  1. Android:当ffi调用导致崩溃时,去看 adb logcat 输出,寻找 signal、SIGSEGV(段错误)等关键字。这通常是空指针或内存越界。使用Android Studio的LLDB或NDK调试工具附加到进程进行调试。
  2. iOS:在XCode中运行Flutter项目(flutter run 后按 i),当崩溃发生时,XCode会停在C/C++代码的出错行。这是最有效的调试方式。
  3. 一个有用的检查清单:
    • 库文件是否放对了位置和架构目录?
    • 函数名是否完全匹配(大小写敏感)?
    • 参数和返回值类型映射是否正确?
    • 指针是否有效(非空)?
    • 内存操作是否越界?

5.4 关于“直接调用C/C++源文件”

原始文章还提到了另一种方式:不提供编译好的.so,而是直接提供C/C++源文件,让Flutter项目在构建时通过CMake编译。这种方式在插件开发中很常见。

优点:源码集成,避免管理二进制库的麻烦,兼容性更好。 缺点:构建配置复杂(需要写CMakeLists.txt),会延长项目的构建时间。

具体做法就是在 android/ 目录下创建 CMakeLists.txt,将你的 .c/.cpp 文件添加进去,然后在 build.gradle 中配置 externalNativeBuild。这一步其实是将原生开发的工作流整合进了Flutter项目里,对于熟悉Android NDK开发的同学来说更顺手。但如果你只是想快速调用一个现成的库,我还是推荐直接管理.so文件更直接。

折腾Flutter与C/C++交互的这段时间,我最大的体会是:没有银弹。ffi和MethodChannel是两种截然不同的哲学,一个追求极致的性能和控制力,一个追求开发的便利和平台的稳定性。选择哪种,取决于你的具体场景、团队的技术栈和对性能的苛求程度。建议你先从一个小功能点开始尝试两种方案,亲自体会一下其中的麻烦和爽点,自然就能找到最适合你项目的那条路。毕竟,踩坑的过程,才是成长最快的时候。

Flutter跨平台开发全攻略:从入门到架构设计 跨平台开发框架通过单一代码库实现多平台部署,大幅提升开发效率。Flutter作为Google推出的开源UI工具包,采用独特的自绘引擎架构,通过Dart语言实现高性能渲染。其分层设计包含Platform Embedder、Flutter Engine和Framework层,支持120fps流畅体验。在移动应用、Web和桌面端开发中,Flutter的热重载、丰富组件库和状态管理方案(如Provider、Riverpod)显著提升开发效率。通过Dio网络库和Hive本地存储实现数据持久化,结合MethodChan 阅读详情

相关推荐

Flutter cryptography库OpenHarmony适配:构建金融级跨平台安全方案

现代密码学是保障移动应用数据安全的基石,其核心原理包括对称加密、非对称加密和哈希算法等,通过数学方法确保信息的机密性、完整性和不可否认性。在工程实践中,密码学技术为支付、身份认证等场景提供关键保护,而跨平台开发框架如Flutter的普及,使得在不同操作系统上实现统一且高性能的加密能力成为重要需求。OpenHarmony作为新兴操作系统,其原生加密框架cryptoFramework与现有生态存在差异,这促使了将成熟密码学库进行深度适配的必要性。通过FFI桥接和原生API集成,开发者能够在OpenHarmony

weixin_30681121的博客 391

Dart中FFI学习

Dart中如何与C语言交互

yong_19930826的博客 1725

RenderDoc实战:5分钟搞定安卓Vulkan应用抓帧(含常见连接失败排查)

本文详细介绍了如何使用RenderDoc工具对安卓Vulkan应用进行抓帧分析,包括环境配置、完整抓帧流程及常见连接问题的解决方案。通过实战案例和高级技巧,帮助开发者快速定位渲染问题和性能瓶颈,提升移动图形开发效率。

weixin_28318011的博客 282

跨语言通信——dart::ffi

ffi是一个比一般通信更底层的机制,接近于jni或者jsi。主要用来做dart和c++的interop。 方法定义和绑定 dart call c++ 官方demo是: import 'dart:ffi'; // For FFI import 'dart:io'; // For Platform.isX final DynamicLibrary nativeAddLib = Platform.isAndroid ? DynamicLibrary.open("libnative_add.so")

pouloghost的专栏 2117

四阶龙格库塔法求解一次常微分方程组(python实现)

之前在博客发布了关于使用四阶龙格库塔方法求解一次常微分方程组的文章,由于代码缺少具体的验证,部分朋友可能存在疑问,因此这里打算再重新写一篇博客来验证一下程序的正确性,另外,这里是使用python语言来实现的。

HelloWorldTM的博客 8543

程序员实战:DINOv3 权重文件下载与本地化部署全流程指南

Meta开源的DINOv3视觉大模型凭借70亿参数和17亿图像训练,在语义分割、目标检测等任务表现优异。本文详解预训练权重的获取渠道、校验方法和加载实践。开发者可通过HuggingFace或GitHub获取不同版本权重,包括针对服务器端的ViT系列和边缘设备的ConvNeXt系列。文章提供MD5校验代码确保文件完整性,并给出PyTorch和Transformers两种加载方式。特别强调7B模型需16GB GPU内存,建议根据硬件条件选择合适版本,如边缘设备使用ConvNeXt-Tiny。最后指出DINOv3

xiugou3365的博客 5906

Flutter使用C++

flutter通过dart语言和C++交互dart的ffi包完成交互ffi封装了c++的基本数据类型(包括结构体)和一些基本方法。我们可以直接在dart中访问c++的内存数据等。相对于jni更加直接。

hn_lgc的专栏 3452

envi5.3处理高分二号影像数据详细过程记录

全文根据此篇文章进行数据处理: tm影像辐射定标_高分二号影像数据预处理及裁剪过程 其他参考: 学习笔记---遥感影像辐射定标与大气校正 利用ENVI自带全球DEM数据计算区域平均高程 高分二号数据处理流程(有高分二号的数据信息) GF2有多光谱和全色两个数据,MSS是多光谱的,PAN是全色的,多光谱的分辨率低,全色的高,需要把这两个数据融合,融合之前需要做定标等处理,获取经纬度。 一、多光谱影像处理 1. 辐射定标 以这个为例: 其他路径\2022.4.2...

ligous的博客 5万+

在flutter项目集成C/C++并生成符合架构的SO文件

本方案采用NDK+Cmake在flutter实现,建议各位先看图片,我是先截图后面才补充的代码内容,按照顺序看图就好,然后具体代码只是一个参考,主要是为了防止图片看不清被压缩啥的,图片里面的描述已经很清晰了,我的项目文件目录结构在最后也都加上了注释,希望可以帮助到你们。

qq_32287935的博客 1425

分享一个完整的KANO问卷(包含正反问题和选项设置)

本文介绍了KANO模型问卷的设计与应用,用于评估功能需求优先级。问卷包含基本信息、功能评估(正反问题设计)、界面评估及开放问题,选项定义明确(如"非常喜欢"到"很不喜欢")。数据清洗规则包括剔除矛盾回答和注意力检验。通过量化编码和矩阵分析,将需求分为魅力型、期望型、必备型等类别。示例数据显示健康监测为必备型(72%),电子围栏为期望型(45%),适老化改造为无差异型(38%)。该模型为产品决策提供客观量化依据。

从技术实践立足,从项目管理方法论延伸思考 1795

【跳频通信】基于MATLAB的跳频通信系统仿真

同时,跳频通信也具有良好的抗干扰能力,即使有部分频点被干扰,仍能在其他未被干扰的频点上进行正常的通信。由于跳频通信系统是瞬时窄带系统,它易于与其他的窄带通信系统兼容,也就是说,跳频电台可以与常规的窄带电台互通,有利于设备的更新。跳频是最常用的扩频方式之一,其工作原理是指收发双方传输信号的载波频率按照预定规律进行离散变化的通信方式,也就是说,通信中使用的载波频率受伪随机变化码的控制而随机跳变。从通信技术的实现方式来说,“跳频”是一种用码序列进行多频频移键控的通信方式,也是一种码控载频跳变的通信系统。

FPGA/MATLAB学习教程/源码/项目合作开发 6267

Dart FFi

FFI: 全称Foregin Function Interface,外部函数接口,是dart sdk的一个新的语言特性,提供了一套动态库加载器,能直接查找内存中已有的函数符号,也支持将指定路径的库加加载到内存中.通在dart侧持有这个库的文件句柄,利用dart暴露的方法查找对应的native方法返回给dart调用,从而提交与native通信的效率,相比较JNI和iOS的混编,它为开发者提供了一套额外的技术方案.实例代码可以参考 https://dart.dev/guides/libraries/c-inte

jiodg45的博客 1238

Allegro如何导入芯片的Pin Delay?

Allegro在做等长时,需要导入芯片的Pin Delay才能做真正的等长。因为有些芯片内部的引脚本身就是不等长的,例如海思的部分芯片。在右栏找到芯片U1,然后在Pin Delay栏下找一个PIN脚随便输入一个数值,这一步的目的是导出Pin Delay.csv文件的格式。4、用这份文件的格式,重新编辑需要导入芯片的Pin Delay,然后选择菜单File→Import→Pin delay。2、回到PCB,选择菜单File→Export→Pin delay,导出Pin Delay。

bhxc809751502的博客 5143

Flutter for OpenHarmony:Flutter 三方库 jnigen — 自动化打通 Flutter 与原生代码的通信壁垒(适配鸿蒙 HarmonyOS Next ohos)

本文介绍了在Flutter for OpenHarmony开发中使用jnigen工具自动化打通Flutter与原生代码通信的方法。传统MethodChannel需要手动编写大量映射代码,而jnigen通过解析C头文件或Java类文件,自动生成Dart绑定类和C/C++封装代码,显著提高开发效率。文章详细讲解了jnigen的配置和使用流程,包括YAML文件编写、代码生成命令执行等,并针对鸿蒙平台提供了符号导出、内存对齐等适配建议。通过示例代码展示了生成的Dart绑定层的简洁调用方式,指出jnigen在性能优化

大山哥 4976

UE5 Niagara基础知识讲解

在UE5版本中,Niagara粒子系统引入了许多可添加的模块,分别用于控制发射器的生成和更新、粒子的生成和更新以及渲染效果。本文采用虚幻5.2.1版本,以图文方式对Niagara基础知识进行讲解。

一碗清深的博客 2470

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【高并发场景下的Flutter优化】:原生桥接、线程调度与GPU渲染深度调优

解决高并发下Flutter性能瓶颈,系统讲解跨平台移动应用的性能优化策略(Flutter + 原生),涵盖原生桥接通信、线程调度机制与GPU渲染调优,适用于复杂业务场景。提升响应速度与帧率稳定性,值得收藏。

CompiWander的博客 1000

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

鸿蒙ArkTS适配Flutter DES/3DES加密库:金融级数据安全迁移实战

数据加密是保障应用安全的核心技术,尤其在金融、硬件通信等高敏感场景,离线数据的本地加密与安全传输至关重要。DES和3DES作为经典的对称加密算法,因其在传统金融终端和遗留系统中的广泛兼容性,仍是许多项目必须实现的技术选型。其原理基于Feistel网络结构和分组密码模式,通过多轮置换与替换确保数据机密性。在跨平台开发中,Flutter应用常用的`dart_des`库提供了纯Dart实现,但在迁移至鸿蒙HarmonyOS的ArkTS环境时,会因运行时与API差异面临兼容性挑战。本文聚焦于**鸿蒙原生应用**的*

weixin_33724059的博客 448

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

如何在Flutter应用中使用 OpenCV和 CC++库进行图像流处理

本文将帮助你在 Android 和 iOS 中为 Flutter 应用程序集成 C/C++ 插件。问题1: Flutter camera 插件没有为快速复杂的图像流处理提供完整的指南。问题2: Flutter camera 插件处理图像流太慢。问题3:图像处理需要OpenCV包问题4:你当前的图像流处理实现正在阻塞 UI 并导致你的应用程序滞后和内存泄漏问题5:缺乏实现接口和使用 Dart FFI...

深度学习与计算机视觉 5471

Dart和C,C++混合编程

刚开始研究dart调用C、C++,走了很多弯路,以为char*和String转化必须通过自己写的Pointer来进行转换,熟不知,有更好的方法,flutter pub的ffi库封装了dart与C交互的所有方法,包括指针管理malloc、free等方法,以下简单说明。 参考链接 https://pub.flutter-io.cn/packages/ffi https://github.com/dar...

大谷的代码日记 3018

Flutter 使用 C、C++ 代码库,突破性能敏感和“底层”库移植能力

Flutter主要使用Dart语言,也就是说我们只要掌握了Dart语言调用C/C++的方法,就知道了如何在Flutter中调用C/C++编写的功能了。Dart的移动端、命令行和服务端应用所运行的Dart原生平台,均可以使用dart:ffi库调用原生的C语言API,用于读、写、分配和销毁原生内存。FFI(ForeignFunctionInterface)指的是外部函数接口。

洪伟的专栏 2065

Dart C/C++异步扩展

Dart和JavaScript一样,是一种单线程编程语言。如果把耗时的任务都放在Dart线程中,就会阻塞程序。Dart提供了同步和异步两种扩展方式。异步扩展可以把一个C/C++函数执行在一条工作线程上,这样就可以用于执行耗时的任务,不会阻塞程序。这里结合Dynamsoft C/C++ barcode SDK来实现一个Dart的异步扩展。 使用Visual Studio 2015创建Dar

yushulx的专栏 7407

c++ 泛型_Dart 2.5 发布,支持 Dart 与 C 相互调用

DART (计算机编程语言) Dart是谷歌开发的计算机编程语言,后来被Ecma (ECMA-408)认定为标准 。它被用于web、服务器、移动应用 和物联网等领域的开发。它是宽松开源许可证(修改的BSD证书)下的开源软件。Dart是面向对象的、类定义的、单继承的语言。它的语法类似C语言,可以转译为JavaScript,支持接口(interfaces)、混入(mixins)、抽象类(abstrac...

weixin_39816024的博客 341

在Dart中使用FFI调用Rust函数

什么是FFI 外部函数接口 (FFI) 是一种机制,通过该机制,以一种编程语言编写的程序可以调用以另一种编程语言编写的服务。当你需要额外的速度🚀或需要使用其他语言的库时,应用FFI会很方便。 为什么需要FFI Dart是Flutter底层的语言,Dart引入FFI机制很大程度上是为了帮Flutter在桌面开发领域铺路。 假设你像我一样是一个懒惰的程序员,并且你现在需要一个库来在你的计算机上播放音乐/音频。不幸的是,Flutter/Dart 中不存在这样的东西,因为它是一个相对年轻的生态系统(语言实际上并不那

whuhewei的博客 4798

flutter调用c/c++方法并在项目中使用(记录)

flutter调用c/c++方法并在项目中使用(记录) 参考 官方文档 做人要简单的帖子 1、在vscode中使用指令新建一个plugin项目:flutter create -t plugin native_add 2、在新建的native_add项目中,新建native_add.cpp文件,并放到ios/Classes/,如下图 3、native_add.cpp添加两个方法 #include ......

guawazi123321的博客 1万+

Flutter 利用 FFI,绕过 Android JNI 直接调用 C++ 层!

坏de牧羊人 | 作者承香墨影 | 校对https://juejin.cn/post/6976824832595853342 | 原文大家好,这里是承香墨影!今天和大家聊聊 Flutter...

承香墨影的博客 1万+
上一篇: Vue-Cropper实战指南:打造高效图片裁剪解决方案
下一篇: 实战指南:三菱FX3U与Xone Demo的CC-Link通讯配置详解
postgres8guard
博客等级 码龄4年 62粉丝 1443原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值