Flutter插件packme的使用_PackMe是一个轻量级库,用于使用JSON描述数据协议生成所有必要的类

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

Flutter插件packme的使用_PackMe是一个轻量级库,用于使用JSON描述数据协议生成所有必要的类

什么是PackMe

PackMe是一个轻量级库,用于使用JSON描述数据协议生成所有必要的类(Flutter/Dart、JS、C++等),以实现客户端和服务器之间的二进制数据通信。它提供了一个快速的二进制序列化方法(Blazing Fast Binary Serialization, BFBS)。

示例代码

以下是一个简单的示例,展示了如何使用PackMe进行数据的打包和解包:

import 'dart:typed_data';
import 'package:packme/packme.dart';
import 'generated/manifest.generated.dart';

Future<void> main() async {
    // 简单示例
    Uint8List buffer = packMe.pack(DemandRequest(
        request: "I demand an answer!",
        deadline: DateTime.now()
    ));
    buffer = await serverQuery(buffer);
    DemandResponse myAnswer = packMe.unpack(buffer);
    myAnswer.excuses.forEach(print);
}

性能

PackMe在处理中等大小和复杂度的数据时,每秒可以完成500,000次以上的打包/解包操作。由于PackMe直接生成Dart类,无需中间步骤,因此其性能远超JSON或Protobuf。

简单性与安全性

PackMe提供了简单易用的接口,用户只需使用JSON即可声明类型、消息和请求。此外,生成的类确保了数据的一致性,增强了处理效率并加强了服务器端的安全性。

使用方法

客户端示例

首先,创建一个manifest.json文件来定义客户端与服务器间的通信协议:

{
    "get_user": [
        {
            "id": "string"
        },
        {
            "first_name": "string",
            "last_name": "string",
            "age": "uint8"
        }
    ]
}

然后,使用命令生成相应的Dart类:

dart run packme protocols generated

接下来,编写客户端代码:

import 'package:packme/packme.dart';
import 'generated/manifest.generated.dart';

void main() {
    PackMe packMe = PackMe();
    packMe.register(manifestMessageFactory);

    GetUserRequest request = GetUserRequest(id: 'a7db84cc2ef5012a6498bc64334ffa7d');
    socket.send(packMe.pack(request)); // 假设socket已经实现

    socket.listen((Uint8List data) {
        final PackMeMessage? message = packMe.unpack(data);
        if (message is GetUserResponse) {
            print('He is awesome: ${message.firstName} ${message.lastName}, ${message.age} y.o.');
        }
    });
}

服务器端示例

服务器端代码如下:

import 'package:packme/packme.dart';
import 'generated/manifest.generated.dart';

void main() {
    PackMe packMe = PackMe();
    packMe.register(manifestMessageFactory);

    server.listen((Uint8List data, SomeSocket socket) { // 假设server已经实现
        final PackMeMessage? message = packMe.unpack(data);
        if (message is GetUserRequest) {
            GetUserResponse response = message.$response(
                firstName: 'Peter',
                lastName: 'Hollens',
                age: 41,
            );
            socket.send(packMe.pack(response));
        }
    });
}

JSON节点

PackMe支持四种类型的节点:枚举、对象、消息和请求。每个节点都有特定的用途和格式。

枚举

"message_status": [
    "sent",
    "delivered",
    "read",
    "unsent"
]

这将生成一个名为MessageStatus的枚举。

对象

"user_profile": {
    "first_name": "string",
    "last_name": "string",
    "birth_date": "datetime"
}

这将生成一个名为UserProfile的类。

消息

"update": [
    {
        "field_1": "uint8",
        "field_2": "uint16",
        "field_3": "uint32"
    }
]

这将生成一个名为UpdateMessage的类。

请求

"get_something": [
    {
        "field_1": "uint8",
    }, 
    {
        "field_1": "uint16",
        "field_2": "uint32",
        "field_3": "uint64"
    }
]

这将生成两个类:GetSomethingRequestGetSomethingResponse

字段和数据类型

PackMe支持多种字段类型,包括整数类型、浮点类型、布尔值、字符串、日期时间、嵌套对象、引用和数组等。

示例性能测试

以下是一个性能测试示例,展示了PackMe的高效性:

import 'dart:async';
import 'dart:math';
import 'dart:typed_data';
import 'package:packme/packme.dart';
import 'generated/example.generated.dart';

final Random rand = Random();

String randomString() {
    const String src = 'qwertyuiopasdfghjklzxcvbnm134567890 ';
    final int length = rand.nextInt(20);
    String result = '';
    for (int i = 0; i < length; i++) {
        result += src[rand.nextInt(length)];
    }
    return result;
}

List<int> randomList([int? fixedLength]) {
    final List<int> result = <int>[];
    final int length = fixedLength ?? rand.nextInt(10);
    for (int i = 0; i < length; i++) {
        result.add(rand.nextInt(256));
    }
    return result;
}

List<Uint8List> listOfIds(int idLength) {
    final List<Uint8List> result = <Uint8List>[];
    final int length = rand.nextInt(10);
    for (int i = 0; i < length; i++) {
        result.add(Uint8List.fromList(randomList(idLength)));
    }
    return result;
}

TestMessage randomTextMessage() {
    final TestMessage message = TestMessage(
        reqId: Uint8List.fromList(randomList(12)),
        optId: rand.nextBool() ? null : Uint8List.fromList(randomList(12)),
        reqIds: listOfIds(4),
        optIds: rand.nextBool() ? null : listOfIds(4),
        reqInt8: rand.nextInt(256) - 128,
        reqUint16: rand.nextInt(65536),
        reqDouble: rand.nextDouble(),
        reqBool: rand.nextBool(),
        reqString: randomString(),
        reqList: randomList(),
        reqEnum: TypeEnum.values[rand.nextInt(TypeEnum.values.length)],
        reqNested: NestedObject(a: rand.nextInt(256), b: randomString()),
        optInt8: rand.nextBool() ? null : rand.nextInt(256) - 128,
        optUint16: rand.nextBool() ? null : rand.nextInt(65536),
        optDouble: rand.nextBool() ? null : rand.nextDouble(),
        optBool: rand.nextBool() ? null : rand.nextBool(),
        optString: rand.nextBool() ? null : randomString(),
        optList: rand.nextBool() ? null : randomList(),
        optEnum: rand.nextBool() ? null : TypeEnum.values[rand.nextInt(TypeEnum.values.length)],
        optNested: rand.nextBool() ? null : NestedObject(a: rand.nextInt(256), b: randomString()),
    );
    return message;
}

void main() {
    final PackMe packer = PackMe(onError: (String error, [StackTrace? stack]) => print(error));

    packer.register(exampleMessageFactory);

    final TestMessage message = randomTextMessage();

    Uint8List packedMessage = packer.pack(message)!;

    TestMessage unpackedMessage = packer.unpack(packedMessage)! as TestMessage;

    print('\nSource message:\n$message');
    print('\nUnpacked message:\n$unpackedMessage');
    print('\nRunning performance test in 5 seconds (1 million cycles)...');

    Timer(const Duration(seconds: 5), () {
        final DateTime dt1 = DateTime.now();
        print('Started at: $dt1');
        for (int i = 0; i < 1000000; i++) {
            packedMessage = packer.pack(message)!;
            unpackedMessage = packer.unpack(packedMessage)! as TestMessage;
        }
        final DateTime dt2 = DateTime.now();
        final double delta = (dt2.millisecondsSinceEpoch - dt1.millisecondsSinceEpoch) / 1000;
        print('Finished at: $dt2 and took ${delta.toStringAsFixed(2)} seconds.');
        print('Cycles per second: ${(1000000 / delta).round()}');
    });
}

更多关于Flutter插件packme的使用_PackMe是一个轻量级库,用于使用JSON描述数据协议生成所有必要的类的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter插件packme的使用_PackMe是一个轻量级库,用于使用JSON描述数据协议生成所有必要的类的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,针对帖子中提到的“Flutter未知功能插件packme的潜在使用”,虽然我们不能确切知道“packme”这个插件的具体功能(因为它是一个假设的或未知的插件),但我可以为你提供一个Flutter插件开发的通用框架和示例代码,这样你可以根据“packme”插件可能提供的接口或功能进行类似的集成和使用。

假设“packme”插件提供了一些与硬件交互的功能,比如读取设备传感器数据,下面是一个如何集成和使用假设的Flutter插件的示例:

1. 创建Flutter插件(假设这是packme插件的简化版)

首先,我们需要在Flutter插件项目中定义插件的接口和功能。由于这是一个假设的插件,我们将创建一个简单的插件来模拟读取设备传感器数据的功能。

iOS端实现(Swift)

ios/Classes/PackmePlugin.swift中:

import Flutter
import CoreMotion

public class PackmePlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "packme", binaryMessenger: registrar.messenger())
    let instance = PackmePlugin()
    channel.setMethodCallHandler(onMethodCall: instance.handle(_:result:))
  }

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    switch call.method {
    case "getSensorData":
      let motionManager = CMMotionManager()
      motionManager.deviceMotionUpdateInterval = 1.0

      if motionManager.isDeviceMotionAvailable {
        motionManager.startDeviceMotionUpdates(to: OperationQueue.main) { (data, error) in
          guard let data = data else {
            result(FlutterError(code: "UNAVAILABLE", message: "Device motion data is not available.", details: nil))
            return
          }

          let userAcceleration = data.userAcceleration
          let attitude = data.attitude

          let resultDictionary = [
            "userAccelerationX": userAcceleration.x,
            "userAccelerationY": userAcceleration.y,
            "userAccelerationZ": userAcceleration.z,
            "attitudePitch": attitude.pitch,
            "attitudeRoll": attitude.roll,
            "attitudeYaw": attitude.yaw
          ] as [String : Any]

          result(resultDictionary)
        }
      } else {
        result(FlutterError(code: "UNAVAILABLE", message: "Device motion is not available on this device.", details: nil))
      }
    default:
      result(FlutterMethodNotImplemented)
    }
  }
}

Android端实现(Kotlin)

android/src/main/kotlin/com/example/packme/PackmePlugin.kt中:

package com.example.packme

import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import androidx.annotation.NonNull
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

class PackmePlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
  private lateinit var channel: MethodChannel
  private lateinit var sensorManager: SensorManager
  private var sensorEventListener: SensorEventListener? = null

  override fun onAttachedToEngine(@NonNull flutterEngine: FlutterEngine) {
    channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "packme")
    channel.setMethodCallHandler(this)

    val context = flutterEngine.context
    sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
  }

  override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
    if (call.method == "getSensorData") {
      val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
      sensorEventListener = object : SensorEventListener {
        override fun onSensorChanged(event: SensorEvent) {
          val accelerationX = event.values[0]
          val accelerationY = event.values[1]
          val accelerationZ = event.values[2]

          val resultDictionary = mapOf(
            "accelerationX" to accelerationX,
            "accelerationY" to accelerationY,
            "accelerationZ" to accelerationZ
          )

          result.success(resultDictionary)
          sensorManager.unregisterListener(this)
        }

        override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
      }

      if (sensor != null) {
        sensorManager.registerListener(sensorEventListener, sensor, SensorManager.SENSOR_DELAY_NORMAL)
      } else {
        result.error("UNAVAILABLE", "Sensor is not available on this device.", null)
      }
    } else {
      result.notImplemented()
    }
  }

  override fun onDetachedFromEngine(@NonNull flutterEngine: FlutterEngine) {
    channel.setMethodCallHandler(null)
  }

  override fun onAttachedToActivity(binding: ActivityPluginBinding) {}

  override fun onDetachedFromActivityForConfigChanges() {}

  override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {}

  override fun onDetachedFromActivity() {}
}

2. 在Flutter项目中集成和使用插件

在你的Flutter项目中,你需要添加对插件的依赖(虽然这是一个假设的插件,但通常你会在pubspec.yaml中添加依赖),然后调用插件提供的方法。

pubspec.yaml中添加依赖(假设已经有该插件)

dependencies:
  flutter:
    sdk: flutter
  packme:
    path: ../path/to/your/packme/plugin  # 假设插件在本地路径

在Dart代码中调用插件

import 'package:flutter/material.dart';
import 'package:packme/packme.dart';  // 假设这是插件的包名

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

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

class _MyAppState extends State<MyApp> {
  Map<String, dynamic>? sensorData;

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

  Future<void> _getSensorData() async {
    try {
      final Map<String, dynamic> result = await Packme.getSensorData();
      setState(() {
        sensorData = result;
      });
    } catch (e) {
      print(e);
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Packme Plugin Demo'),
        ),
        body: Center(
          child: sensorData == null
              ? Text('Loading sensor data...')
              : Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Text('Acceleration X: ${sensorData!['accelerationX']}'),
                    Text('Acceleration Y: ${sensorData!['accelerationY']}'),
                    Text('Acceleration Z: ${sensorData!['accelerationZ']}'),
                    // 如果packme插件提供了更多数据,可以继续添加
                  ],
                ),
        ),
      ),
    );
  }
}

请注意,上述代码是一个假设的示例,用于展示如何创建一个Flutter插件并在Flutter项目中集成和使用它。实际中,“packme”插件的功能和接口可能完全不同,你需要根据插件的文档或源代码来调整你的集成方式。

回到顶部