streams_channel 0.2.2

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • new50

StreamsChannel for Flutter plugin development

StreamsChannel is inspired from EventChannel. It allows to create streams of events between Flutter and platform side.

Rationale

EventChannel allows to only create a single open stream per channel. On the first subscription, the stream will be open and it's possible to pass arguments from Flutter to platform side. Subsequent subscriptions will either re-use the open stream or override it with a new one.

In order to have multiple streams open at the same time, with different parameters for stream initialization, one has to create multiple EventChannel. And it gets complicated if the number of streams is dynamic.

Installation

Add streams_channel to your pubspec.yaml:

dependencies:
  streams_channel: ^0.2.2

How it works

StreamsChannel works in a similar way than EventChannel. The difference is that it supports multiple open streams at the same time.

On the platform side, the channel takes a stream handler factory:

let channel = FlutterStreamsChannel(name: "my_channel", binaryMessenger: plugin.registrar.messenger())
channel.setStreamHandlerFactory { arguments in
  return MyHandler(arguments) // MyHandler is an instance FlutterStreamHandler
}

On the flutter side, each call to receiveBroadcastStream(args) will create a new stream, that won't replace any previous one that is still running.

  1. The first subscription to the stream will create a new stream handler using the factory on the platform side, then trigger onListen on the handler;
  2. The last subscription to the stream will trigger onCancel on the handler, then destroy the handler instance
  3. If a new first subscription happens afterwards, repeat step 1.

Under the hood, StreamsChannel tracks each stream with a simple auto-incremented unique id.

Example

Flutter side

final StreamsChannel channel = new StreamsChannel('some_channel');

// continuous stream of events from platform side, match some args
channel.receiveBroadcastStream('some args')
  .listen((data) {
    // do something
  });

// another continuous stream of events from platform side, matching some other args
channel.receiveBroadcastStream('some other args')
  .listen((data) {
    // do something
  });

Platform side

Android

public class DemoPlugin {
  public static void registerWith(PluginRegistry.Registrar registrar) {
    final StreamsChannel channel = new StreamsChannel(registrar.messenger(), "streams_channel_test");
    channel.setStreamHandlerFactory(new StreamsChannel.StreamHandlerFactory() {
      @Override
      public EventChannel.StreamHandler create(Object arguments) {
        return new StreamHandler();
      }
    });
  }

  // Send "Hello" 10 times, every second, then ends the stream
  public static class StreamHandler implements EventChannel.StreamHandler {

    private final Handler handler = new Handler();
    private final Runnable runnable = new Runnable() {
      @Override
      public void run() {
        if (count > 10) {
            eventSink.endOfStream();
        } else {
            eventSink.success("Hello " + count + "/10");
        }
        count++;
        handler.postDelayed(this, 1000);
      }
    };

    private EventChannel.EventSink eventSink;
    private int count = 1;

    @Override
    public void onListen(Object o, final EventChannel.EventSink eventSink) {
      this.eventSink = eventSink;
      runnable.run();
    }

    @Override
    public void onCancel(Object o) {
      handler.removeCallbacks(runnable);
    }
  }
}

iOS

@interface StreamHandler : NSObject<FlutterStreamHandler>
  @property(strong, nonatomic) NSTimer *timer;
  @property(assign, nonatomic) NSInteger count;
@end

@implementation DemoPlugin

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {

  FlutterStreamsChannel *channel = [FlutterStreamsChannel streamsChannelWithName:@"streams_channel_test" binaryMessenger:registrar.messenger];
  [channel setStreamHandlerFactory:^NSObject<FlutterStreamHandler> *(id arguments) {
    return [StreamHandler new];
  }];
}

@end

// Send "Hello" 10 times, every second, then ends the stream
@implementation StreamHandler

- (FlutterError *)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)events {
  self.count = 1;
  self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
    if(self.count > 10) {
      events(FlutterEndOfEventStream);
    } else {
      events([NSString stringWithFormat:@"Hello %ld/10", (long)self.count]);
      self.count++;
    }
  }];

  return nil;
}

- (FlutterError *)onCancelWithArguments:(id)arguments {
  [self.timer invalidate];
  self.timer = nil;
  return nil;
}
@end

Author

Beacons plugin is developed by Loup, a mobile development studio based in Montreal and Paris.
You can contact us at hello@intheloup.io

License

Apache License 2.0

0.2.2

  • Internal improvements

0.2.1

  • Fix: Cocoapods podspec for iOS side

0.2.0

  • New: Refactor API into using a factory to create stream handler on demand, one for each active stream

0.1.0

  • New: StreamsChannel (iOS side)

0.0.1

  • New: StreamsChannel (Android side)

example/lib/main.dart

//  Copyright (c) 2018 Loup Inc.
//  Licensed under Apache License v2.0

import 'dart:async';

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

final StreamsChannel testChannel = new StreamsChannel('streams_channel_test');

void main() => runApp(new MyApp());

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

class _MyAppState extends State<MyApp> {
  StreamSubscription<dynamic> _subscriptionA;
  StreamSubscription<dynamic> _subscriptionB;

  void _start(bool a) {
    // ignore: cancel_subscriptions
    StreamSubscription<dynamic> subscription =
        a ? _subscriptionA : _subscriptionB;

    if (subscription != null) {
      subscription.cancel();
      subscription = null;
    } else {
      final streamId = 'Stream ${a ? 'A' : 'B'}';
      subscription = testChannel
          .receiveBroadcastStream(streamId)
          .listen((data) => debugPrint('Received from $streamId: $data'));

      subscription.onDone(() {
        setState(() {
          if (a) {
            _subscriptionA = null;
          } else {
            _subscriptionB = null;
          }
        });
      });
    }

    setState(() {
      if (a) {
        _subscriptionA = subscription;
      } else {
        _subscriptionB = subscription;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Demo'),
        ),
        body: new Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              new FlatButton(
                onPressed: () => _start(true),
                child: Text(_subscriptionA != null ? 'Stop A' : 'Start A'),
              ),
              new FlatButton(
                onPressed: () => _start(false),
                child: Text(_subscriptionB != null ? 'Stop B' : 'Start B'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Use this package as a library

1. Depend on it

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


dependencies:
  streams_channel: "^0.2.2"

2. Install it

You can install packages from the command line:

with Flutter:


$ flutter packages get

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

3. Import it

Now in your Dart code, you can use:


      import 'package:streams_channel/streams_channel.dart';
  
Version Uploaded Documentation Archive
0.2.2 May 25, 2018 Go to the documentation of streams_channel 0.2.2 Download streams_channel 0.2.2 archive
0.2.1 May 25, 2018 Go to the documentation of streams_channel 0.2.1 Download streams_channel 0.2.1 archive
0.2.0 May 24, 2018 Go to the documentation of streams_channel 0.2.0 Download streams_channel 0.2.0 archive
0.1.0 May 24, 2018 Go to the documentation of streams_channel 0.1.0 Download streams_channel 0.1.0 archive
0.0.1 May 24, 2018 Go to the documentation of streams_channel 0.0.1 Download streams_channel 0.0.1 archive

Analysis

We analyzed this package on Jun 12, 2018, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.0.0-dev.60.0
  • pana: 0.11.3
  • Flutter: 0.5.2

Scores

Popularity:
Describes how popular the package is relative to other packages. [more]
0 / 100
Health:
Code health derived from static analysis. [more]
100 / 100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100 / 100
Overall score:
Weighted score of the above. [more]
50
Learn more about scoring.

Platforms

Detected platforms: Flutter

References Flutter, and has no conflicting libraries.

Suggestions

  • Package is pre-v1 release.

    While there is nothing inherently wrong with versions of 0.*.*, it usually means that the author is still experimenting with the general direction API.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.19.0 <3.0.0
flutter 0.0.0
Transitive dependencies
collection 1.14.6 1.14.10
meta 1.1.5
sky_engine 0.0.99
typed_data 1.1.5
vector_math 2.0.6 2.0.7