xservice_kit 0.0.29

  • Readme
  • Changelog
  • Example
  • Installing
  • 86

xservice_kit —— 基于Channel通信的统一协议代码生成方案 #

QuikStart #

Xservice的优势 #

  • 统一标准化配置
  • 一份配置三端代码生成,告别重复手写代码工作。
  • 消息类型显示指定,方便消息定义和调用,增加类型安全性。
  • 方便支持双向一对一,一对多消息代码生成。
  • 自定义消息过滤支持,防止自定义类型序列化过程中的异常。

接入简介 #

  1. 安装命令行工具:npm install xservice -g
  2. 编写配置文件放置到 ServicesYaml(可自定义)文件夹
  3. 用命令行生成代码 例如:xservice -o out -p fleamarket.taobao.com.xservicekitexample -t yaml ServicesYaml
  4. 拷贝代码到项目中。
  5. java和Dart需要手动调用ServiceLoader启动服务。

具体可以参考项目example CodeGen文件夹下面的配置和脚本

详细步骤

  • 在Flutter工程pubspec.yaml加入xservice_kit依赖: xservice_kit:^0.0.27
  • 安装node(代码生成工具使用node开发),然后npm install xservice -g
  • 编写配置文件
  • 运行xservice命令行生成代码
  • 将生成代码移动到项目,然后在程序的开始调用Serviceloader

在工程中可以开发简单的脚本进行最后两步的动作。具体可以参考flutter_boost里面对xservice_kit的使用。

我们看一下生成代码的基本结构:

详细使用文档 #

Native向Flutter发送消息

一对一消息 , 一对一消息在配置文件里面定义好,会自动生成调用方法。

iOS

[ServiceName.service method];

Android

ServiceName.getService().method();

Dart:
在Service对应的Handler里面实现method对应逻辑即可。

一对多广播消息:广播是通用的接口。

iOS

[ServiceName.service emitEvent:@"event_name" params:@{@"key":@"value"}];

Android

ServiceName.getService().emitEvent("event_name",params);

Dart:

ServiceName.service().addEventListner("event_name",listner);

Flutter向Native发送消息

基本步骤跟前面一样,只不过由Flutter来调用方法,在Native实现Handler。

基本概念

Service

Service可以理解为是一组Handler的组织者,里面主要包含消息派发逻辑和注册到特定channel的逻辑。

Message

目前消息管道支持双向通信
消息目前分为两种:
flutter 特指 flutter 发送给 native的消息 flutter->native。
native 特指 native 发送给 flutter的小时 native->flutter。

Type

类型是消息传递的时候非常容易出错的类型,在这里我们约定以下类型。

Dart

  • basic types

    • int

    • double

    • String

    • bool

  • collections

    • List

    • Map

Dart -> OC类型影射表

  • int -> int64_t

  • double -> double

  • bool -> BOOL

  • String -> NSString

  • List -> NSArray

  • Map -> NSDictionary

Dart -> Java类型影射表

  • int -> int

  • double -> double

  • bool -> boolean

  • String -> String

  • List -> List

  • Map -> Map

使用手册

接入使用工具只需要两步

  1. 书写配置文档。

  2. 执行代码生成脚本。

配置文件

配置支持yaml和json,建议使用yaml比较简洁。

配置文件放在同一个文件夹下面 然后执行:

xservice -o out -p fleamarket.taobao.com.xservicekitexample -t yaml ServicesYaml

Yaml 配置实例

name : GeneralService #服务名称

messages: #消息

 -
  name : popNative
  returnType : String
  messageType : flutter
  channelType : method
  args : 
   - 
    name : arg1
    type : int
   - 
    name : arg2
    type : String
    
    
 -
  name : popFlutter
  returnType : String
  messageType : native
  channelType : method
  args : 
   - 
    name : arg1
    type : int
   - 
    name : arg2
    type : String

需要增加message 只需要复制即可

Json配置请参考项目example/CodeGen/Services Yaml配置请参考项目example/CodeGen/ServicesYaml

设计介绍 #

简介 #

Flutter与Native的通信是通过Channel实现的。实际上这个Channel本质是在C++层维护的一个map数据结构,由key-value的形式对channel name和handler进行映射。Dart VM通过C接口与C++对象进行通信,iOS原生对C++混编有良好的支持,而Android则是通过JNI的形式与C++进行通信。通过这种形式,Flutter能够与Native基于Channel的这种抽象进行无缝的通信。

官方实现的Channel会在通信过程当中对Dart的类型与Objective-C,Java类型进行转换。所以使用起来还是挺方便,但是对于一些自定义的类型,在转换过程当中有可能会出现一些不可预期的问题。

官方插件系统 #

官方支持的插件,实际上是基于Channel通信的简单封装。Android Studio在生成一个插件项目的时候,会分别生成Dart,OC,Java的插件类。我们大致看一下:

Java

public class FlutterPlugin implements MethodCallHandler {
  /** Plugin registration. */
  public static void registerWith(Registrar registrar) {
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_plugin");
    channel.setMethodCallHandler(new FlutterPlugin());
  }

  @Override
  public void onMethodCall(MethodCall call, Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }
}

OC

@implementation FlutterPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
  FlutterMethodChannel* channel = [FlutterMethodChannel
      methodChannelWithName:@"flutter_plugin"
            binaryMessenger:[registrar messenger]];
  FlutterPlugin* instance = [[FlutterPlugin alloc] init];
  [registrar addMethodCallDelegate:instance channel:channel];
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
  if ([@"getPlatformVersion" isEqualToString:call.method]) {
    result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
  } else {
    result(FlutterMethodNotImplemented);
  }
}

@end

Dart

class FlutterPlugin {
  static const MethodChannel _channel =
      const MethodChannel('flutter_plugin');

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

插件的基本结构其实包含以下主要几个方法:

  • invoke接口,也就是发送消息的接口
  • onMethodCall,消息处理方法
  • 注册接口

官方插件的好处 #

  • 简单,使用方便
  • 拥有良好的项目结构跟原生flutter项目兼容性很好
  • 轻量级

官方插件的一些问题 #

  • 需要手写handler,if else噩梦。
  • 插件包含三份代码:dart,java,oc。同一个消息需要手写三份重复的代码。
  • 没有统一定义和维护消息的格式和标准。
  • Channel是支持双向通信的,但是官方插件生成出来的代码没有这个支持。
  • 需要为不同的插件生成不同的包,粒度不好把握。
  • 发送消息的时候无法去做消息内容过滤和检查,可能会有类型导致的异常。

Xservice #

简介 #

为了解决官方插件存在的一些问题,我们同样是基于Flutter本身提供的Channel实现了一个更加强大的通信标准模块。最初的想法来源于protobuf此类的RPC通信标准,从广义上来说Flutter与Native的通信的抽象,也可以大致理解为RPC,只是一种特殊类型。

类似于protobuf的结构,我们开发了一个基础库xservice_kit以及xservice代码生成工具。我们定义了消息的基本结构,只需要配置一个统一配置,即可生成三端代码。

主要概念 #

这里主要有Service和Handler,Message等概念。 我们在配置文件里面去定义Message以及Message所在的Service,代码生成工具会去解析生成对应的Service以及消息处理者Handler。

Service Service可以理解为是一组Handler的组织者,里面主要包含消息派发逻辑和注册到特定channel的逻辑。

Handler 消息的最终处理者,由消息对应的Service集中管理。

Message 目前消息管道支持双向通信 消息目前分为两种,消息的类型是以消息的发送者来定义的,比如: flutter 特指 flutter 发送给 native的消息 flutter->native。 native 特指 native 发送给 flutter的消息 native->flutter。

消息也分为一对一这里有invoke的概念,一对多就是监听与广播的支持。这里一对一,一对多都是支持双向的。

我们支持Json和Yaml格式的配置文件,推荐Yaml比较直观:

一个典型的消息配置文件:

name : GeneralService 


messages: 


 -
  name : Message1
  returnType : String
  messageType : flutter
  channelType : method
  args : 
   - 
    name : arg1
    type : int
   - 
    name : arg2
    type : String
    
    
 -
  name :Message2
  returnType : String
  messageType : native
  channelType : method
  args : 
   - 
    name : arg1
    type : int
   - 
    name : arg2
    type : String


注意我们的消息里面所带的参数是统一由Dart的类型来进行书写,参数的显示类型配置也是相对于官方插件的一个优势。

接入简介 #

接入只需要几步:

  • 在Flutter工程pubspec.yaml加入xservice_kit依赖: xservice_kit:^0.0.27
  • 安装node(代码生成工具使用node开发),然后npm install xservice -g
  • 编写配置文件
  • 运行xservice命令行生成代码
  • 将生成代码移动到项目,然后在程序的开始调用Serviceloader

在工程中可以开发简单的脚本进行最后两步的动作。具体可以参考flutter_boost里面对xservice_kit的使用。

我们看一下生成代码的基本结构:

Xservice的优势 #

  • 统一标准化配置
  • 一份配置三端代码生成,告别重复手写代码工作。
  • 消息类型显示指定,方便消息定义和调用,增加类型安全性。
  • 方便支持双向一对一,一对多消息代码生成。
  • 自定义消息过滤支持,防止自定义类型序列化过程中的异常。

0.0.1 #

  • TODO: Describe initial release.

example/README.md

xservice_kit —— 基于Channel通信的统一协议代码生成方案 #

QuikStart #

Xservice的优势 #

  • 统一标准化配置
  • 一份配置三端代码生成,告别重复手写代码工作。
  • 消息类型显示指定,方便消息定义和调用,增加类型安全性。
  • 方便支持双向一对一,一对多消息代码生成。
  • 自定义消息过滤支持,防止自定义类型序列化过程中的异常。

接入简介 #

  1. 安装命令行工具:npm install xservice -g
  2. 编写配置文件放置到 ServicesYaml(可自定义)文件夹
  3. 用命令行生成代码 例如:xservice -o out -p fleamarket.taobao.com.xservicekitexample -t yaml ServicesYaml
  4. 拷贝代码到项目中。
  5. java和Dart需要手动调用ServiceLoader启动服务。

具体可以参考项目example CodeGen文件夹下面的配置和脚本

详细步骤

  • 在Flutter工程pubspec.yaml加入xservice_kit依赖: xservice_kit:^0.0.27
  • 安装node(代码生成工具使用node开发),然后npm install xservice -g
  • 编写配置文件
  • 运行xservice命令行生成代码
  • 将生成代码移动到项目,然后在程序的开始调用Serviceloader

在工程中可以开发简单的脚本进行最后两步的动作。具体可以参考flutter_boost里面对xservice_kit的使用。

我们看一下生成代码的基本结构:

详细使用文档 #

Native向Flutter发送消息

一对一消息 , 一对一消息在配置文件里面定义好,会自动生成调用方法。

iOS

[ServiceName.service method];

Android

ServiceName.getService().method();

Dart:
在Service对应的Handler里面实现method对应逻辑即可。

一对多广播消息:广播是通用的接口。

iOS

[ServiceName.service emitEvent:@"event_name" params:@{@"key":@"value"}];

Android

ServiceName.getService().emitEvent("event_name",params);

Dart:

ServiceName.service().addEventListner("event_name",listner);

Flutter向Native发送消息

基本步骤跟前面一样,只不过由Flutter来调用方法,在Native实现Handler。

基本概念

Service

Service可以理解为是一组Handler的组织者,里面主要包含消息派发逻辑和注册到特定channel的逻辑。

Message

目前消息管道支持双向通信
消息目前分为两种:
flutter 特指 flutter 发送给 native的消息 flutter->native。
native 特指 native 发送给 flutter的小时 native->flutter。

Type

类型是消息传递的时候非常容易出错的类型,在这里我们约定以下类型。

Dart

  • basic types

    • int

    • double

    • String

    • bool

  • collections

    • List

    • Map

Dart -> OC类型影射表

  • int -> int64_t

  • double -> double

  • bool -> BOOL

  • String -> NSString

  • List -> NSArray

  • Map -> NSDictionary

Dart -> Java类型影射表

  • int -> int

  • double -> double

  • bool -> boolean

  • String -> String

  • List -> List

  • Map -> Map

使用手册

接入使用工具只需要两步

  1. 书写配置文档。

  2. 执行代码生成脚本。

配置文件

配置支持yaml和json,建议使用yaml比较简洁。

配置文件放在同一个文件夹下面 然后执行:

xservice -o out -p fleamarket.taobao.com.xservicekitexample -t yaml ServicesYaml

Yaml 配置实例

name : GeneralService #服务名称

messages: #消息

 -
  name : popNative
  returnType : String
  messageType : flutter
  channelType : method
  args : 
   - 
    name : arg1
    type : int
   - 
    name : arg2
    type : String
    
    
 -
  name : popFlutter
  returnType : String
  messageType : native
  channelType : method
  args : 
   - 
    name : arg1
    type : int
   - 
    name : arg2
    type : String

需要增加message 只需要复制即可

Json配置请参考项目example/CodeGen/Services Yaml配置请参考项目example/CodeGen/ServicesYaml

设计介绍 #

简介 #

Flutter与Native的通信是通过Channel实现的。实际上这个Channel本质是在C++层维护的一个map数据结构,由key-value的形式对channel name和handler进行映射。Dart VM通过C接口与C++对象进行通信,iOS原生对C++混编有良好的支持,而Android则是通过JNI的形式与C++进行通信。通过这种形式,Flutter能够与Native基于Channel的这种抽象进行无缝的通信。

官方实现的Channel会在通信过程当中对Dart的类型与Objective-C,Java类型进行转换。所以使用起来还是挺方便,但是对于一些自定义的类型,在转换过程当中有可能会出现一些不可预期的问题。

官方插件系统 #

官方支持的插件,实际上是基于Channel通信的简单封装。Android Studio在生成一个插件项目的时候,会分别生成Dart,OC,Java的插件类。我们大致看一下:

Java

public class FlutterPlugin implements MethodCallHandler {
  /** Plugin registration. */
  public static void registerWith(Registrar registrar) {
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_plugin");
    channel.setMethodCallHandler(new FlutterPlugin());
  }

  @Override
  public void onMethodCall(MethodCall call, Result result) {
    if (call.method.equals("getPlatformVersion")) {
      result.success("Android " + android.os.Build.VERSION.RELEASE);
    } else {
      result.notImplemented();
    }
  }
}

OC

@implementation FlutterPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
  FlutterMethodChannel* channel = [FlutterMethodChannel
      methodChannelWithName:@"flutter_plugin"
            binaryMessenger:[registrar messenger]];
  FlutterPlugin* instance = [[FlutterPlugin alloc] init];
  [registrar addMethodCallDelegate:instance channel:channel];
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
  if ([@"getPlatformVersion" isEqualToString:call.method]) {
    result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
  } else {
    result(FlutterMethodNotImplemented);
  }
}

@end

Dart

class FlutterPlugin {
  static const MethodChannel _channel =
      const MethodChannel('flutter_plugin');

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

插件的基本结构其实包含以下主要几个方法:

  • invoke接口,也就是发送消息的接口
  • onMethodCall,消息处理方法
  • 注册接口

官方插件的好处 #

  • 简单,使用方便
  • 拥有良好的项目结构跟原生flutter项目兼容性很好
  • 轻量级

官方插件的一些问题 #

  • 需要手写handler,if else噩梦。
  • 插件包含三份代码:dart,java,oc。同一个消息需要手写三份重复的代码。
  • 没有统一定义和维护消息的格式和标准。
  • Channel是支持双向通信的,但是官方插件生成出来的代码没有这个支持。
  • 需要为不同的插件生成不同的包,粒度不好把握。
  • 发送消息的时候无法去做消息内容过滤和检查,可能会有类型导致的异常。

Xservice #

简介 #

为了解决官方插件存在的一些问题,我们同样是基于Flutter本身提供的Channel实现了一个更加强大的通信标准模块。最初的想法来源于protobuf此类的RPC通信标准,从广义上来说Flutter与Native的通信的抽象,也可以大致理解为RPC,只是一种特殊类型。

类似于protobuf的结构,我们开发了一个基础库xservice_kit以及xservice代码生成工具。我们定义了消息的基本结构,只需要配置一个统一配置,即可生成三端代码。

主要概念 #

这里主要有Service和Handler,Message等概念。 我们在配置文件里面去定义Message以及Message所在的Service,代码生成工具会去解析生成对应的Service以及消息处理者Handler。

Service Service可以理解为是一组Handler的组织者,里面主要包含消息派发逻辑和注册到特定channel的逻辑。

Handler 消息的最终处理者,由消息对应的Service集中管理。

Message 目前消息管道支持双向通信 消息目前分为两种,消息的类型是以消息的发送者来定义的,比如: flutter 特指 flutter 发送给 native的消息 flutter->native。 native 特指 native 发送给 flutter的消息 native->flutter。

消息也分为一对一这里有invoke的概念,一对多就是监听与广播的支持。这里一对一,一对多都是支持双向的。

我们支持Json和Yaml格式的配置文件,推荐Yaml比较直观:

一个典型的消息配置文件:

name : GeneralService 


messages: 


 -
  name : Message1
  returnType : String
  messageType : flutter
  channelType : method
  args : 
   - 
    name : arg1
    type : int
   - 
    name : arg2
    type : String
    
    
 -
  name :Message2
  returnType : String
  messageType : native
  channelType : method
  args : 
   - 
    name : arg1
    type : int
   - 
    name : arg2
    type : String


注意我们的消息里面所带的参数是统一由Dart的类型来进行书写,参数的显示类型配置也是相对于官方插件的一个优势。

接入简介 #

接入只需要几步:

  • 在Flutter工程pubspec.yaml加入xservice_kit依赖: xservice_kit:^0.0.27
  • 安装node(代码生成工具使用node开发),然后npm install xservice -g
  • 编写配置文件
  • 运行xservice命令行生成代码
  • 将生成代码移动到项目,然后在程序的开始调用Serviceloader

在工程中可以开发简单的脚本进行最后两步的动作。具体可以参考flutter_boost里面对xservice_kit的使用。

我们看一下生成代码的基本结构:

Xservice的优势 #

  • 统一标准化配置
  • 一份配置三端代码生成,告别重复手写代码工作。
  • 消息类型显示指定,方便消息定义和调用,增加类型安全性。
  • 方便支持双向一对一,一对多消息代码生成。
  • 自定义消息过滤支持,防止自定义类型序列化过程中的异常。

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  xservice_kit: ^0.0.29

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter pub get

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:xservice_kit/xservice_kit.dart';
  
Popularity:
Describes how popular the package is relative to other packages. [more]
82
Health:
Code health derived from static analysis. [more]
96
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
78
Overall:
Weighted score of the above. [more]
86
Learn more about scoring.

We analyzed this package on Oct 16, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.5.1
  • pana: 0.12.21
  • Flutter: 1.9.1+hotfix.4

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Health issues and suggestions

Document public APIs. (-1 points)

40 out of 40 API elements have no dartdoc comment.Providing good documentation for libraries, classes, functions, and other API elements improves code readability and helps developers find and use your API.

Fix lib/foundation_ext/type_converter.dart. (-1.99 points)

Analysis of lib/foundation_ext/type_converter.dart reported 4 hints:

line 2 col 6: Name non-constant identifiers using lowerCamelCase.

line 19 col 8: Name non-constant identifiers using lowerCamelCase.

line 26 col 5: Name non-constant identifiers using lowerCamelCase.

line 42 col 8: Name non-constant identifiers using lowerCamelCase.

Fix lib/ServiceTemplate.dart. (-1 points)

Analysis of lib/ServiceTemplate.dart reported 2 hints:

line 8 col 17: Name types using UpperCamelCase.

line 21 col 19: Don't explicitly initialize variables to null.

Format lib/ServiceCallHandler.dart.

Run flutter format to format lib/ServiceCallHandler.dart.

Fix additional 3 files with analysis or formatting issues.

Additional issues in the following files:

  • lib/ServiceGateway.dart (Run flutter format to format lib/ServiceGateway.dart.)
  • lib/foundation_ext/foundation_ext.dart (Run flutter format to format lib/foundation_ext/foundation_ext.dart.)
  • lib/xservice_kit.dart (Run flutter format to format lib/xservice_kit.dart.)

Maintenance suggestions

The package description is too short. (-12 points)

Add more detail to the description field of pubspec.yaml. Use 60 to 180 characters to describe the package, what it does, and its target use case.

Package is pre-v0.1 release. (-10 points)

While nothing is inherently wrong with versions of 0.0.*, it might mean that the author is still experimenting with the general direction of the API.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev.49.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.11 1.14.12
meta 1.1.7
sky_engine 0.0.99
typed_data 1.1.6
vector_math 2.0.8