Rust跨平台消息通道库irondash_message_channel的使用,实现高效安全的进程间通信

Rust跨平台消息通道库irondash_message_channel的使用,实现高效安全的进程间通信

完整示例demo

Dart端完整代码

import 'dart:ffi';
import 'package:flutter/services.dart';
import 'package:irondash_message_channel/irondash_message_channel.dart';

void main() async {
  // 初始化消息通道
  final nativeContext = _initNativeContext();
  final channel = NativeMethodChannel('demo_channel', context: nativeContext);
  
  // 设置消息处理器
  _setupMessageHandlers(channel);
  
  // 调用Rust方法
  final version = await channel.invokeMethod('getVersion');
  print('Received from Rust: $version');
  
  final sum = await channel.invokeMethod('calculateSum', [5, 7]);
  print('Sum from Rust: $sum');
}

// 初始化消息通道上下文
MessageChannelContext _initNativeContext() {
  final dylib = DynamicLibrary.process();
  final function = dylib.lookup<
      NativeFunction<MessageChannelContextInitFunction>>(
    "init_message_channel_context");
  return MessageChannelContext.forInitFunction(function);
}

// 设置Dart端消息处理器
void _setupMessageHandlers(NativeMethodChannel channel) {
  channel.setMethodCallHandler((call) async {
    switch (call.method) {
      case 'getPlatformInfo':
        return 'Dart running on ${Platform.operatingSystem}';
      case 'multiplyNumbers':
        final args = call.arguments as List;
        return args[0] * args[1];
      default:
        throw PlatformException(
          code: 'unimplemented',
          message: 'Method ${call.method} not implemented',
        );
    }
  });
}

Rust端完整代码

use irondash_message_channel::*;
use std::os::raw::c_void;

// 初始化函数 - 必须用#[no_mangle]标记且使用extern "C"
#[no_mangle]
pub extern "C" fn init_message_channel_context(data: *mut c_void) -> FunctionResult {
    irondash_init_message_channel_context(data)
}

// 主消息处理结构体
struct DemoHandler {
    invoker: Late<AsyncMethodInvoker>,
}

#[async_trait(?Send)]
impl AsyncMethodHandler for DemoHandler {
    // 设置调用器以便从Rust调用Dart
    fn assign_invoker(&self, invoker: AsyncMethodInvoker) {
        self.invoker.set(invoker);
    }

    // 处理来自Dart的方法调用
    async fn on_method_call(&self, call: MethodCall) -> PlatformResult {
        match call.method.as_str() {
            "getVersion" => {
                Ok(format!("Rust v{}", env!("CARGO_PKG_VERSION")).into())
            }
            "calculateSum" => {
                let args: Vec<i32> = call.args.try_into()?;
                let sum = args[0] + args[1];
                Ok(sum.into())
            }
            _ => Err(PlatformError {
                code: "unimplemented".into(),
                message: Some(format!("Method {} not implemented", call.method)),
                detail: Value::Null,
            }),
        }
    }
}

// 初始化消息通道
pub fn init_message_channel() {
    let handler = DemoHandler {
        invoker: Late::new(),
    }.register("demo_channel");
    
    // 保持handler不被丢弃,否则通道会停止工作
    std::mem::forget(handler);
}

// 从Rust调用Dart方法的示例
async fn call_dart_methods(handler: &DemoHandler) {
    if let Some(invoker) = handler.invoker.get() {
        // 调用Dart端的getPlatformInfo方法
        let platform: String = invoker.call_method("getPlatformInfo", Value::Null).await.unwrap().try_into().unwrap();
        println!("Dart platform info: {}", platform);
        
        // 调用Dart端的multiplyNumbers方法
        let args = vec![3, 4];
        let product: i32 = invoker.call_method("multiplyNumbers", args.into()).await.unwrap().try_into().unwrap();
        println!("Product from Dart: {}", product);
    }
}

使用说明

  1. 初始化流程:

    • Dart端首先加载原生库并初始化消息通道上下文
    • Rust端提供初始化函数并通过register方法注册处理器
  2. 双向通信:

    • Dart调用Rust通过invokeMethod
    • Rust调用Dart通过AsyncMethodInvokercall_method
  3. 数据类型:

    • 支持基本类型(int, double, String等)
    • 支持列表和映射
    • 自动序列化/反序列化
  4. 线程注意事项:

    • 确保Rust处理器在具有RunLoop的线程创建
    • 跨线程调用需要额外处理
  5. 错误处理:

    • 使用PlatformError传递错误信息
    • Dart端会收到PlatformException

这个完整示例展示了:

  • Dart和Rust的双向方法调用
  • 基本数据类型和复杂参数的传递
  • 错误处理机制
  • 异步通信模式
  • 线程安全考虑

使用时需要确保:

  1. 正确配置Flutter的FFI设置
  2. Rust库被正确编译为平台特定的动态库
  3. 在Dart端正确加载原生库
  4. 保持Rust端的handler不被提前释放

1 回复

Rust跨平台消息通道库irondash_message_channel使用指南

简介

irondash_message_channel是一个Rust实现的跨平台消息通道库,专门设计用于高效安全的进程间通信(IPC)。它提供了简单易用的API,支持多种数据类型传输,并能在不同平台(包括移动端)上工作。

主要特性

  • 跨平台支持(Windows, macOS, Linux, iOS, Android)
  • 线程安全的通信机制
  • 支持多种数据类型传输
  • 高性能的二进制序列化
  • 简单的错误处理机制

安装

在Cargo.toml中添加依赖:

[dependencies]
irondash_message_channel = "0.3"

基本使用方法

1. 创建消息通道

use irondash_message_channel::{MessageChannel, Value};

fn main() {
    // 创建消息通道
    let channel = MessageChannel::new("my_channel");
    
    // 设置消息处理器
    channel.set_handler(|method: String, args: Value| {
        println!("Received method: {}, args: {:?}", method, args);
        // 返回响应
        Ok(Value::String("Response from Rust".to_string()))
    });
}

2. 发送消息

// 发送简单消息
channel.send("greet", Value::String("Hello from Rust".to_string()))
    .expect("Failed to send message");

// 发送复杂数据结构
let data = Value::Map(vec![
    ("name".to_string(), Value::String("Alice".to_string())),
    ("age".to_string(), Value::I32(30)),
    ("active".to_string(), Value::Bool(true)),
]);

channel.send("user_data", data).expect("Failed to send user data");

3. 接收和处理消息

channel.set_handler(|method, args| {
    match method.as_str() {
        "greet" => {
            let name = args.as_str().unwrap_or("stranger");
            println!("Hello, {}!", name);
            Ok(Value::Null)
        }
        "calculate" => {
            let nums = args.as_list().unwrap();
            let sum: i64 = nums.iter().map(|v| v.as_i64().unwrap_or(0)).sum();
            Ok(Value::I64(sum))
        }
        _ => {
            Err(format!("Unknown method: {}", method).into())
        }
    }
});

高级用法

1. 异步消息处理

use tokio::runtime::Runtime;

channel.set_async_handler(|method, args| {
    Box::pin(async move {
        match method.as_str() {
            "async_op" => {
                tokio::time::sleep(std::time::Duration::from_secs(1)).await;
                Ok(Value::String("Async operation completed".to_string()))
            }
            _ => Err("Unknown method".into()),
        }
    })
});

2. 二进制数据传输

// 发送二进制数据
let binary_data = vec![0x01, 0x02, 0x03, 0x04];
channel.send("binary_data", Value::Binary(binary_data))
    .expect("Failed to send binary data");

// 接收二进制数据
channel.set_handler(|method, args| {
    if method == "process_binary" {
        let data = args.as_binary().unwrap();
        println!("Received binary data of length: {}", data.len());
        Ok(Value::Null)
    } else {
        Err("Unknown method".into())
    }
});

3. 跨平台集成示例

与Flutter集成的示例:

// Flutter端代码
final channel = MessageChannel('my_channel');

// 发送消息到Rust
final response = await channel.send('greet', 'Hello from Flutter');
print('Response from Rust: $response');

// 接收来自Rust的消息
channel.setMessageHandler((method, args) async {
  print('Received from Rust - Method: $method, Args: $args');
  return 'Response from Flutter';
});

错误处理

channel.set_handler(|method, args| {
    if method == "dangerous_op" {
        if some_condition {
            Ok(Value::Null)
        } else {
            Err("Operation failed".into())
        }
    } else {
        Err(format!("Unknown method: {}", method).into())
    }
});

// 发送消息时处理错误
match channel.send("dangerous_op", Value::Null) {
    Ok(response) => println!("Operation succeeded: {:?}", response),
    Err(e) => println!("Operation failed: {}", e),
}

性能优化建议

  1. 对于高频小消息,考虑批量发送
  2. 大二进制数据使用Value::Binary而不是base64编码的字符串
  3. 复杂数据结构优先使用Value::MapValue::List组合
  4. 异步处理耗时操作以避免阻塞

注意事项

  • 消息通道名称在应用中必须唯一
  • 跨平台使用时确保两端数据类型兼容
  • 大消息可能影响性能,考虑分片传输
  • 错误消息应尽量简洁,避免传输敏感信息

完整示例Demo

下面是一个完整的Rust与Flutter跨平台通信示例:

Rust端代码

use irondash_message_channel::{MessageChannel, Value};
use tokio::runtime::Runtime;

fn main() {
    // 创建Tokio运行时
    let rt = Runtime::new().unwrap();
    
    // 在Tokio运行时中执行
    rt.block_on(async {
        // 创建消息通道
        let channel = MessageChannel::new("app_channel");
        
        // 设置同步消息处理器
        channel.set_handler(|method, args| {
            match method.as_str() {
                "sync_greet" => {
                    let name = args.as_str().unwrap_or("world");
                    println!("[Rust] Received sync greeting for: {}", name);
                    Ok(Value::String(format!("Hello, {} from Rust!", name)))
                }
                "calculate_sum" => {
                    let nums = args.as_list().unwrap();
                    let sum: i64 = nums.iter().map(|v| v.as_i64().unwrap_or(0)).sum();
                    Ok(Value::I64(sum))
                }
                _ => Err("Unknown method".into())
            }
        });
        
        // 设置异步消息处理器
        channel.set_async_handler(|method, args| {
            Box::pin(async move {
                match method.as_str() {
                    "async_task" => {
                        let duration = args.as_i64().unwrap_or(1) as u64;
                        tokio::time::sleep(std::time::Duration::from_secs(duration)).await;
                        Ok(Value::String("Async task completed".to_string()))
                    }
                    _ => Err("Unknown async method".into())
                }
            })
        });
        
        // 发送初始化消息到Flutter
        channel.send("init", Value::String("Rust backend ready".to_string()))
            .expect("Failed to send init message");
            
        // 保持程序运行
        loop {
            tokio::time::sleep(std::time::Duration::from_secs(60)).await;
        }
    });
}

Flutter端代码

import 'package:flutter/material.dart';
import 'package:irondash_message_channel/irondash_message_channel.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final channel = MessageChannel('app_channel');
  String _response = '';
  String _asyncResponse = '';

  @override
  void initState() {
    super.initState();
    
    // 设置消息处理器
    channel.setMessageHandler((method, args) async {
      print('Received from Rust - Method: $method, Args: $args');
      
      if (method == 'init') {
        setState(() {
          _response = args;
        });
      }
      
      return 'Received in Flutter';
    });
  }

  Future<void> _sendMessage() async {
    final response = await channel.send('sync_greet', 'Flutter User');
    setState(() {
      _response = response.toString();
    });
  }

  Future<void> _sendAsyncTask() async {
    final response = await channel.send('async_task', 2);
    setState(() {
      _asyncResponse = response.toString();
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('Flutter-Rust IPC Demo')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: _sendMessage,
                child: Text('Send Sync Message'),
              ),
              SizedBox(height: 20),
              Text('Sync Response: $_response'),
              SizedBox(height: 40),
              ElevatedButton(
                onPressed: _sendAsyncTask,
                child: Text('Send Async Task'),
              ),
              SizedBox(height: 20),
              Text('Async Response: $_asyncResponse'),
            ],
          ),
        ),
      ),
    );
  }
}

这个完整示例展示了:

  1. Rust端创建消息通道并设置同步/异步处理器
  2. Flutter端与Rust的双向通信
  3. 不同数据类型的传输
  4. 异步操作处理
  5. 跨平台通信的基本模式

您可以根据实际需求扩展此示例,添加更多消息类型和处理逻辑。

回到顶部