Flutter Meteor DDP插件dart_meteor的使用

发布于 1周前 作者 htzhanglong 最后一次编辑是 5天前 来自 Flutter

Flutter Meteor DDP插件dart_meteor的使用

简介

dart_meteor 是一个用于 Dart 和 Flutter 开发者的 Meteor DDP 库。它使得在 Flutter 应用中与 Meteor 后端建立连接变得简单,并且可以无缝地与 StreamBuilderFutureBuilder 一起使用。

版本变更

  • 3.0.0 版本变更

    • meteor.collection('collectionName') 的流现在在初始时返回 snapshot.hasData == true,并且包含一个空的映射。
  • 2.0.0 版本变更

    • 调用 Meteor 方法和订阅时传递参数变为可选。例如:
      // 旧版本
      meteor.call('your_method_name', [param1, param2]);
      
      // 新版本
      meteor.call('your_method_name', args: [param1, param2]);
      
    • 订阅也类似:
      // 旧版本
      meteor.subscribe('your_pub', [param1, param2]);
      
      // 新版本
      meteor.subscribe('your_pub', args: [param1, param2]);
      
    • 不再需要调用 meteor.prepareCollection('your_collection_name'),可以直接通过 meteor.collection('messages').listen((value) { ... }) 访问集合。
    • 支持 DateTime 类型,可以直接传递和接收 DateTime 变量。

使用示例

1. 创建 MeteorClient 实例

首先,在应用的全局作用域中创建一个 MeteorClient 实例,以便在整个项目中使用。

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

// 创建 MeteorClient 实例
MeteorClient meteor = MeteorClient.connect(url: 'https://yourdomain.com');

void main() => runApp(MyApp());
2. 使用 StreamBuilder 构建 UI

StatefulWidgetStatelessWidget 中,可以使用 StreamBuilderFutureBuilder 来根据来自 Meteor DDP 服务器的响应构建 UI。

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

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

  // 调用 Meteor 方法
  void _callMethod() {
    meteor.call('helloMethod').then((result) {
      setState(() {
        _methodResult = result.toString();
      });
    }).catchError((err) {
      if (err is MeteorError) {
        setState(() {
          _methodResult = err.message;
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Package dart_meteor Example'),
        ),
        body: Container(
          padding: EdgeInsets.all(8.0),
          child: Column(
            children: <Widget>[
              // 显示连接状态并提供连接/断开按钮
              StreamBuilder<DdpConnectionStatus>(
                stream: meteor.status(),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    if (snapshot.data.status == DdpConnectionStatusValues.connected) {
                      return ElevatedButton(
                        child: Text('Disconnect'),
                        onPressed: () {
                          meteor.disconnect();
                        },
                      );
                    }
                    return ElevatedButton(
                      child: Text('Connect'),
                      onPressed: () {
                        meteor.reconnect();
                      },
                    );
                  }
                  return Container();
                },
              ),
              // 显示当前连接状态
              StreamBuilder<DdpConnectionStatus>(
                stream: meteor.status(),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return Text('Meteor Status ${snapshot.data.toString()}');
                  }
                  return Text('Meteor Status: ---');
                },
              ),
              // 用户登录/登出按钮
              StreamBuilder(
                stream: meteor.userId(),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return ElevatedButton(
                      child: Text('Logout'),
                      onPressed: () {
                        meteor.logout();
                      },
                    );
                  }
                  return ElevatedButton(
                    child: Text('Login'),
                    onPressed: () {
                      meteor.loginWithPassword('yourusername', 'yourpassword');
                    },
                  );
                },
              ),
              // 显示当前用户信息
              StreamBuilder(
                stream: meteor.user(),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return Text(snapshot.data.toString());
                  }
                  return Text('User: ----');
                },
              ),
              // 调用 Meteor 方法的按钮
              ElevatedButton(
                child: Text('Method Call'),
                onPressed: _callMethod,
              ),
              // 显示方法调用结果
              Text(_methodResult),
            ],
          ),
        ),
      ),
    );
  }
}
3. 调用 Meteor 方法

调用 Meteor 方法会返回一个 Future,必须处理 catchError 以防止应用程序崩溃。

meteor.call('helloMethod').then((result) {
  setState(() {
    _methodResult = result.toString();
  });
}).catchError((err) {
  if (err is MeteorError) {
    setState(() {
      _methodResult = err.message;
    });
  }
});

你也可以使用 FutureBuilder 来调用方法:

FutureBuilder<int>(
  future: meteor.call('sumMethod', args: [5, 10]),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      // 你的 snapshot.data 应该是 5 + 10 = 15
      return Text('Answer is: ${snapshot.data}');
    }
  },
),
4. 集合与订阅

你可以通过调用 meteor.collection('your_collection_name') 来访问集合。它返回一个 Stream,可以与 StreamBuilder 一起使用来监听集合的更新。

meteor.collection('your_collections');

要使集合在 Flutter 应用中可用,可以通过订阅服务器上的数据:

class YourWidget extends StatefulWidget {
  YourWidget() {}

  @override
  _YourWidgetState createState() => _YourWidgetState();
}

class _YourWidgetState extends State<YourWidget> {
  SubscriptionHandler? _subscriptionHandler;

  @override
  void initState() {
    super.initState();
    _subscriptionHandler = meteor.subscribe('your_pub', args: ['param_1', 'param_2']);
  }

  @override
  void dispose() {
    _subscriptionHandler?.stop();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return StreamBuilder(
      stream: meteor.collection('your_collection'),
      builder: (context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
        int docCount = 0;
        if (snapshot.hasData) {
          docCount = snapshot.data!.length;
        }
        return Text('Total document count: $docCount');
      },
    );
  }
}

集合以 Map<String, dynamic> 的形式返回,键是文档的 _id,值是整个文档。

例如:

{
  "DGbsysgxzSf7Cr8Jg": {
    "_id": "DGbsysgxzSf7Cr8Jg", 
    "field1": 0, 
    "field2": "a", 
    "field3": true, 
    "field4": SomeDate
  }
}
5. 直接访问最新数据

如果你不想通过流来访问数据,可以直接使用 meteor.collectionCurrentValue('your_collection_name')meteor.userCurrentValue()meteor.userIdCurrentValue() 来获取最新的值。

例如,通过 _id 访问文档:

// 非响应式
final id = 'DGbsysgxzSf7Cr8Jg';
final doc = meteor.collectionCurrentValue('your_collection_name')[id];
if (doc != null) {
  // do something
}

// 非响应式
final userId = 'Sf7Cr8JgDGbsysgxz';
final user = meteor.collectionCurrentValue('users')[userId];
if (user != null) {
  // do something
}

更多关于Flutter Meteor DDP插件dart_meteor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter Meteor DDP插件dart_meteor的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


关于Flutter中的dart_meteor插件,虽然它不是一个广泛知名的官方或主流插件,但假设它是一个用于与Meteor平台交互的Flutter库(Meteor是一个全栈JavaScript平台,用于构建实时Web和移动应用)。以下是一个基于假设的代码案例,展示如何在Flutter项目中使用dart_meteor(注意:实际代码可能需要根据dart_meteor的具体实现和API进行调整)。

首先,确保你已经在pubspec.yaml文件中添加了dart_meteor依赖:

dependencies:
  flutter:
    sdk: flutter
  dart_meteor: ^x.y.z  # 替换为实际版本号

然后运行flutter pub get来安装依赖。

接下来,我们编写一个示例代码来展示如何使用dart_meteor连接到Meteor服务器并执行一些基本操作。以下代码是假设性的,因为dart_meteor的具体API和实现细节可能有所不同。

import 'package:flutter/material.dart';
import 'package:dart_meteor/dart_meteor.dart';  // 假设的导入路径

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

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

class _MyAppState extends State<MyApp> {
  MeteorClient? _meteorClient;

  @override
  void initState() {
    super.initState();
    // 初始化Meteor客户端并连接到服务器
    _meteorClient = MeteorClient('wss://your-meteor-server-url/websocket');

    _meteorClient!.onConnect!.listen((_) {
      print('Connected to Meteor server');
      // 登录Meteor(假设需要登录)
      _meteorClient!.loginWithPassword('username', 'password').then((result) {
        if (result) {
          print('Logged in successfully');
          // 订阅数据
          _meteorClient!.subscribe('yourPublicationName', {}).then((subscriptionHandle) {
            print('Subscribed to publication');
            // 监听实时数据更新
            subscriptionHandle.onReady!.listen((_) {
              print('Subscription ready');
              // 获取数据
              _meteorClient!.find('yourCollectionName', {}).then((data) {
                print('Data retrieved: $data');
              });
            });
            subscriptionHandle.onChanged!.listen((changes) {
              print('Data changed: $changes');
            });
          });
        } else {
          print('Login failed');
        }
      });
    });

    _meteorClient!.onError!.listen((error) {
      print('Error: $error');
    });

    _meteorClient!.onDisconnect!.listen((_) {
      print('Disconnected from Meteor server');
    });
  }

  @override
  void dispose() {
    _meteorClient?.disconnect();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Meteor Demo'),
        ),
        body: Center(
          child: Text('Connecting to Meteor...'),
        ),
      ),
    );
  }
}

class MeteorClient {
  final String url;
  WebSocket? _socket;
  // 假设的回调和状态管理
  final ValueNotifier<bool> _isConnected = ValueNotifier(false);
  final StreamController<void> _onConnect = StreamController<void>();
  final StreamController<dynamic> _onError = StreamController<dynamic>();
  final StreamController<void> _onDisconnect = StreamController<void>();

  MeteorClient(this.url);

  Stream<void> get onConnect => _onConnect.stream;
  Stream<dynamic> get onError => _onError.stream;
  Stream<void> get onDisconnect => _onDisconnect.stream;

  bool get isConnected => _isConnected.value;

  Future<void> connect() async {
    _socket = await WebSocket.connect(url);
    _socket!.listen(
      (data) {
        // 处理服务器消息
      },
      onError: (error) {
        _onError.add(error);
      },
      onDone: () {
        _isConnected.value = false;
        _onDisconnect.add(null);
      },
    );
    _isConnected.value = true;
    _onConnect.add(null);
  }

  Future<void> disconnect() async {
    if (_socket!.closeCode == null) {
      await _socket!.close();
    }
  }

  // 假设的登录方法
  Future<bool> loginWithPassword(String username, String password) async {
    // 构造登录消息并发送
    Map<String, dynamic> loginMessage = {
      'msg': 'method',
      'method': 'login',
      'params': [
        {'username': username, 'password': password},
      ],
      'id': '1',
    };
    _socket!.add(jsonEncode(loginMessage));
    // 等待响应并处理
    // ...(此处省略详细实现)
    return false; // 假设登录失败,实际应根据响应处理
  }

  // 假设的订阅方法
  Future<SubscriptionHandle> subscribe(String publicationName, Map<String, dynamic> params) async {
    // 构造订阅消息并发送
    // ...(此处省略详细实现)
    return SubscriptionHandle(); // 假设的SubscriptionHandle实例
  }

  // 假设的查找数据方法
  Future<dynamic> find(String collectionName, Map<String, dynamic> selector) async {
    // 构造查找消息并发送
    // ...(此处省略详细实现)
    return {}; // 假设返回空数据
  }
}

class SubscriptionHandle {
  final StreamController<void> _onReady = StreamController<void>();
  final StreamController<dynamic> _onChanged = StreamController<dynamic>();

  Stream<void> get onReady => _onReady.stream;
  Stream<dynamic> get onChanged => _onChanged.stream;

  // 假设的ready和change触发方法(实际应根据服务器消息触发)
  void triggerReady() {
    _onReady.add(null);
  }

  void triggerChanged(dynamic changes) {
    _onChanged.add(changes);
  }
}

注意

  1. 上述代码是一个高度假设性的示例,用于展示如何使用一个假设的dart_meteor插件。
  2. 实际的dart_meteor插件可能有完全不同的API和实现。
  3. 在使用任何第三方库之前,请务必查阅其官方文档和示例代码。
  4. 实时通信和数据同步是复杂的功能,确保在生产环境中充分测试和优化。
回到顶部