aws_ivs_realtime 0.1.4 copy "aws_ivs_realtime: ^0.1.4" to clipboard
aws_ivs_realtime: ^0.1.4 copied to clipboard

Flutter plugin for Amazon IVS Real-Time (Stages): native stage video grid, optional SigV4 control-plane helpers, and IVS Chat WebSocket session utilities.

aws_ivs_realtime #

Flutter plugin for Amazon IVS Real-Time: low-latency multi-participant live video (stage / “broadcast” grid) on Android and iOS, plus optional Amazon IVS Chat for room-style text messages alongside the stream.

What you get:

  • Real-time live streaming (Stages) — native participant grid (host and viewers), camera/mic publish, mute, leave; bridged with a MethodChannel and platform view (IvsRealtimePlatform, AwsIvsRealtimePlatformView.viewType).
  • Control plane in Dart (optional) — create/list/delete stages, mint participant tokens, create/delete chat rooms, mint chat tokens — either by implementing one backend-facing interface (IvsLiveControlPlane) or by using the built-in SigV4-on-device implementation (IvsAwsSigV4ControlPlane) for prototypes only.
  • IVS Chat WebSocketIvsChatSession after you obtain a chat token.
  • Runtime permissionspermission_handler before join/publish.

Live streaming only vs live + chat #

  • Streaming only (no chat): use IvsRealtimePlatform + the platform view (AwsIvsRealtimePlatformView.viewType) and a participant token from mintParticipantToken / your backend. Do not create IvsChatSession, do not call mintChatToken / createChatRoom, and do not add chat UI widgets. The native stage never shows a chat pane by itself—there is no plugin-wide “chat on/off” flag; chat appears only if your app wires it up.
  • Streaming + chat: additionally connect IvsChatSession and build your own message list / composer.
  • IvsLiveControlPlane lists chat APIs alongside Real-Time APIs so one implementation can power both products; you may still call only the stage-related methods from your UI—unused chat methods stay unused (no extra change inside this package).
  • The example/ app demonstrates both together for convenience; a minimal integration can be video only.

Source repository, pub.dev, and where to run the demo #

What URL / path
GitHub (browse source) https://github.com/vipulbansal/aws_ivs_realtime
Clone git clone https://github.com/vipulbansal/aws_ivs_realtime.git
Issues https://github.com/vipulbansal/aws_ivs_realtime/issues
Runnable example app Folder example/ in that repository — open example/ on GitHub
Published package https://pub.dev/packages/aws_ivs_realtime
Sample app (app-only, no backend) aws_ivs_realtime_usage — standalone Flutter repo: use the package from the app only (no separate backend) as a reference for integration

Reference — app-only sample: vipulbansal/aws_ivs_realtime_usage is a standalone Flutter project (not the in-repo example/) that shows how to wire aws_ivs_realtime without a backend—ideal if you depend on pub.dev and want a full app tree to copy from. Clone: https://github.com/vipulbansal/aws_ivs_realtime_usage.


Two layers (do not confuse them) #

Layer Purpose Key type
Native stage Render tiles + send/receive real-time A/V IvsRealtimePlatform.join needs only the IVS participant token (opaque string from AWS CreateParticipantToken). Never pass IAM access key / secret here.
Control plane (Dart) Create stages, list stages, mint participant/chat tokens, delete resources Either your backend (implement IvsLiveControlPlane) or IAM credentials inside the app via IvsAwsSigV4ControlPlane (non-production pattern).

Backend integration: implement IvsLiveControlPlane #

If your AWS keys and SigV4 signing live only on your servers, the Flutter side should implements IvsLiveControlPlane.

What you must do (no ambiguity) #

  1. Create a Dart class that implements IvsLiveControlPlane (see lib/ivs_live_control_plane.dart for exact signatures).
  2. Implement every method in that abstract class. Each method corresponds one-to-one to an AWS operation listed below. Your implementation typically:
    • forwards the method arguments to your HTTP/gRPC/mobile-BFF API using your URLs and auth; then
    • parses your API’s JSON into the Dart return type shown.
  3. Your server performs the real AWS call (with an IAM role or temporary credentials). The app never receives long-lived IAM user keys in this model.
  4. Reference: IvsAwsSigV4ControlPlane in this repo is the same interface already implemented using SigV4 from the device — use its source as a behavioral reference for what each operation is supposed to accomplish (then replace networking with calls to your backend).

This README does not define your REST paths or JSON field names; only the Dart contract is fixed.

Methods you must implement (full contract) #

You implement AWS operation (your backend must honor this semantics) Dart return type
mintParticipantToken CreateParticipantToken Future<String>only the participant token string (same value as participantToken.token in the AWS JSON).
listStages ListStages Future<List<Map<String, dynamic>>> — one map per stage summary (same information you would map from AWS stageList items).
createStage CreateStage Future<Map<String, dynamic>> — stage object / metadata as maps (equivalent to parsing AWS stage + related fields your UI needs).
deleteStage DeleteStage Future<void>
createChatRoom CreateRoom (IVS Chat) Future<Map<String, dynamic>> — room resource (same semantics as AWS room in the response).
deleteChatRoom DeleteRoom Future<void>
mintChatToken CreateChatToken Future<Map<String, dynamic>> — token payload your app passes into IvsChatSession (same logical fields AWS returns for a chat token).

Typical live flow with a backend: createStage (once) → share stage ARN → for each participant mintParticipantTokenIvsRealtimePlatform.join(token: ...) with native grid widget → optional: createChatRoom / mintChatToken / IvsChatSession for messages.

After you implement it: how to use IvsLiveControlPlane in your app #

Implementing the interface is only half the work. You also instantiate your class and call its methods from your widgets / controllers, then feed the return values into the other types from this package.

Object Type Role
control Your implements IvsLiveControlPlane Talks to your backend (or wraps it). Produces tokens and stage/chat metadata.
stage IvsRealtimePlatform Talks to native Android/iOS IVS Real-Time (join / leave / mute / events). Does not use your interface by itself — you call both.
Grid widget AndroidView / UiKitView Renders video tiles; see the Platform view subsection (under App-only below).

1) Live video (Stages) — what goes where

  1. Build final control = MyBackendControlPlane(/* your HTTP client, base URL, auth */); and final stage = IvsRealtimePlatform(); (often State fields).
  2. Discover or create a stage (optional): await control.listStages(region: region) for UI lists, or final created = await control.createStage(region: region, name: name). Your implementation’s map should include something you can treat as stage ARN (same information as AWS CreateStage / ListStages — commonly an arn field on the stage object).
  3. Mint a participant token for the current user:
    final participantToken = await control.mintParticipantToken(region: region, stageArn: stageArn, userId: optionalUserId, durationMinutes: 120, capabilities: const ['PUBLISH', 'SUBSCRIBE']);
    The returned String is the only value that ever goes to native join.
  4. Show the grid in the widget tree (platform view, non-zero size) — same snippet as in the Platform view subsection under App-only below.
  5. Attach to the stage:
    await stage.join(token: participantToken, publish: isHostOrPublisher);
    Mic permission is always requested; camera when publish is true.
  6. While live: use stage.setPublish, stage.setLocalStreamMuted, listen to stage.stageConnectionEvents for disconnect / host-ended flows.
  7. When done: await stage.leave(); and, if you no longer need the AWS stage, await control.deleteStage(region: region, stageArn: stageArn).

Your backend’s JSON shapes are yours; the Dart side only needs to extract String / Map / List values that match the meanings in the table above so you can pass them into join, UI models, and chat below.

2) IVS Chat (optional) — chaining IvsLiveControlPlaneIvsChatSession

  1. Room: final room = await control.createChatRoom(region: region, name: roomDisplayName); — take roomArn (or equivalent) from the map your backend returns (AWS CreateRoom exposes the room ARN).
  2. Session: final chat = IvsChatSession();
  3. Connect: await chat.connect(region: region, resolveChatToken: () async { final m = await control.mintChatToken(region: region, roomArn: roomArn, userId: stableUserId, attributes: {...}); final t = m['token'] as String?; if (t == null || t.isEmpty) throw StateError('no chat token'); return t; });
    IvsChatSession.connect calls resolveChatToken again on reconnect, so each call should hit your backend for a fresh token (short-lived), not reuse one cached string forever.
  4. UI: listen to chat.lines (Stream<IvsChatLine>) for incoming messages; use chat.sendMessage when the socket is open.
  5. Teardown: await chat.dispose(); and optionally await control.deleteChatRoom(region: region, roomArn: roomArn).

3) Summary

  • IvsLiveControlPlane = how your Flutter code gets AWS-shaped data from your servers.
  • IvsRealtimePlatform + platform view = how that data becomes live video on device.
  • IvsChatSession = how chat tokens from the same interface become a WebSocket message stream.

App-only (no backend): where IAM keys and ARNs go #

Preferred built-in type: IvsAwsSigV4ControlPlane with an IvsAwsCredentialResolver — a zero-argument function that returns (accessKeyId, secretAccessKey, sessionToken?).

Put credentials only in one of these places (pick one strategy and stick to it):

Strategy Where you put access key ID, secret key, optional session token Where you put AWS region and stage ARN
A. Build-time defines Inside the resolver, read const String.fromEnvironment('AWS_ACCESS_KEY_ID'), 'AWS_SECRET_ACCESS_KEY', optional 'AWS_SESSION_TOKEN' Same pattern: String.fromEnvironment('AWS_REGION', defaultValue: 'us-east-1'), String.fromEnvironment('IVS_STAGE_ARN')
B. Runtime UI or secure storage Resolver reads TextEditingController.text, flutter_secure_storage, env via Platform.environment, etc. Passed as variables into mintParticipantToken(region: ..., stageArn: ...) from your own state (text fields, remote config, etc.)
C. Literals in source Do not commit keys in Dart string literals to a public repository. Same

Run / build with compile-time defines (strategy A), from your app directory:

flutter run \
  --dart-define=AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY_ID \
  --dart-define=AWS_SECRET_ACCESS_KEY=YOUR_SECRET_ACCESS_KEY \
  --dart-define=AWS_REGION=us-east-1 \
  --dart-define=IVS_STAGE_ARN=arn:aws:ivs:us-east-1:123456789012:stage/yourStageId

Optional: who this participant is on the stage (otherwise AWS / tiles only see an anonymous participant):

  --dart-define=IVS_PARTICIPANT_USER_ID=alice-12345

Optional temporary credentials:

  --dart-define=AWS_SESSION_TOKEN=YOUR_SESSION_TOKEN

Minimal usage after keys are available:

import 'package:aws_ivs_realtime/aws_ivs_realtime.dart';

final ivs = IvsRealtimePlatform();
final control = IvsAwsSigV4ControlPlane(
  resolveCredentials: () => (
    accessKeyId: const String.fromEnvironment('AWS_ACCESS_KEY_ID'),
    secretAccessKey: const String.fromEnvironment('AWS_SECRET_ACCESS_KEY'),
    sessionToken: _opt('AWS_SESSION_TOKEN'),
  ),
);

String? _opt(String k) {
  const v = String.fromEnvironment(k, defaultValue: '');
  return v.isEmpty ? null : v;
}

Future<void> joinWithSigV4() async {
  const region = String.fromEnvironment('AWS_REGION', defaultValue: 'us-east-1');
  const stageArn = String.fromEnvironment('IVS_STAGE_ARN');
  const participantUserId = String.fromEnvironment('IVS_PARTICIPANT_USER_ID', defaultValue: '');

  final token = await control.mintParticipantToken(
    region: region,
    stageArn: stageArn,
    // Sent to AWS CreateParticipantToken as `userId` — use your real signed-in id / handle.
    userId: participantUserId.isEmpty ? null : participantUserId,
  );
  await ivs.join(token: token, publish: true);
}

Where the “name” comes from (app-only is the same idea as backend):

  • Stage / live video: the README snippet above did not show a name before because userId is optional. Pass userId: into mintParticipantToken (from auth, profile, or --dart-define=IVS_PARTICIPANT_USER_ID as a stand-in). That value is what AWS associates with the participant for the Real-Time session; the native grid labels participants using IVS metadata—not a hardcoded “Flutter demo user” from this package.
  • IVS Chat sender labels: set when you call control.mintChatToken(..., userId: ..., attributes: {'displayName': 'Alice Smith'}). Your UI reads IvsChatLine events; other clients see the attributes / user id your app sent. There is no separate “name” field on IvsRealtimePlatform.join—only the opaque participant token—so identity for chat is always via mintChatToken (or your backend’s equivalent).

Important: mintParticipantToken + join do not draw anything on screen by themselves. You must embed the native participant grid with a Flutter platform view or you will hear/encode media but see no tiles / video.

Platform view: show the live grid (AndroidView / UiKitView) #

Use the constant AwsIvsRealtimePlatformView.viewType (ivs_stage_view). Match the plugin’s codec registration with StandardMessageCodec(). Give the view a non-zero size (Expanded, SizedBox.expand, etc.). Backend and app-only flows both use this widget — only the way you obtain the participant token differs.

import 'dart:io';

import 'package:aws_ivs_realtime/aws_ivs_realtime.dart';
import 'package:flutter/cupertino.dart' show UiKitView;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

Widget ivsParticipantGrid() {
  if (!ivsNativeStageSupported) {
    return const Center(child: Text('Stages are only on Android and iOS.'));
  }
  if (Platform.isAndroid) {
    return AndroidView(
      viewType: AwsIvsRealtimePlatformView.viewType,
      layoutDirection: TextDirection.ltr,
      creationParamsCodec: StandardMessageCodec(),
    );
  }
  return UiKitView(
    viewType: AwsIvsRealtimePlatformView.viewType,
    layoutDirection: TextDirection.ltr,
    creationParamsCodec: StandardMessageCodec(),
  );
}

// Typical layout: put the platform view in an Expanded, then call joinWithSigV4()
// (or join with a backend-minted token). If tiles stay blank after join, call
// ivs.refreshStageBindings() once from a post-frame callback — see DOCUMENTATION.md.

Listing stages, showing them in Flutter UI, and joining an existing stage #

The same IvsAwsSigV4ControlPlane (or your IvsLiveControlPlane backend implementation) exposes listStages, createStage, deleteStage, chat helpers, etc. Typical Dart-only flow:

  1. await control.listStages(region: region)List<Map<String, dynamic>> (each map is an AWS stage summary; at minimum expect an arn and often a name).
  2. Render that list with normal Flutter widgets (ListView, ListTile, DataTable, …) — this is where you choose titles, subtitles, pull-to-refresh, empty states, etc.
  3. When the user picks a row, read stage['arn'] as String and call await control.mintParticipantToken(region: region, stageArn: arn, userId: …), then await ivs.join(token: token, publish: …) with the platform view already in the tree.

Optional: await control.createStage(region: region, name: 'my-show-001', tags: {...}) returns the created stage Map (includes arn); mint a token for that ARN to go live as host.

import 'package:aws_ivs_realtime/aws_ivs_realtime.dart';

Future<void> refreshStageCatalog({
  required IvsAwsSigV4ControlPlane control,
  required String region,
  required void Function(List<Map<String, dynamic>> stages) onStages,
}) async {
  final stages = await control.listStages(region: region);
  onStages(stages);
}

Future<void> joinExistingStageFromRow({
  required IvsAwsSigV4ControlPlane control,
  required IvsRealtimePlatform ivs,
  required String region,
  required String stageArn,
  String? participantUserId,
  bool publish = false,
}) async {
  final token = await control.mintParticipantToken(
    region: region,
    stageArn: stageArn,
    userId: participantUserId,
  );
  await ivs.join(token: token, publish: publish);
}

// Example list wiring (simplified — use setState / provider / bloc in a real app):
Widget stagePicker({
  required List<Map<String, dynamic>> stages,
  required void Function(String arn) onPickArn,
}) {
  return ListView.builder(
    itemCount: stages.length,
    itemBuilder: (context, i) {
      final s = stages[i];
      final arn = s['arn'] as String?;
      final title = s['name'] as String? ?? arn ?? 'Stage';
      return ListTile(
        title: Text(title),
        subtitle: arn != null
            ? Text(arn, maxLines: 1, overflow: TextOverflow.ellipsis)
            : null,
        onTap: arn == null ? null : () => onPickArn(arn),
      );
    },
  );
}

If you use tags to mark which stages are “live” (as the repo example/ does with IvsRealtimeStagesApi.tagStatus), filter in Dart with stages.where(...) before building the list — the API returns all stages the credentials can see, not only live ones.


Native stage: embed the grid and join (after you have a participant token) #

This is the same for backend or app-only paths: once you have a participant token string, the native video UI always goes through the platform view above plus IvsRealtimePlatform.join.

  1. Host app: Android minSdk = 28 on your app module; iOS 14+; permissions and permission_handler iOS preprocessor flags — see Requirements and Install.
  2. Widget: AndroidView (Android) or UiKitView (iOS) — same Platform view snippet as in the App-only section above (required for any participant token source).
  3. Join: await ivs.join(token: participantTokenString, publish: hostPublishesA/V);
  4. Events / lifecycle: subscribe to stageConnectionEvents; call leave when done; optionally refreshStageBindings after first frame if tiles misbind — details in DOCUMENTATION.md.

AWS keys vs participant token #

String Pass to join(token:)? Role
Participant token Yes Output of CreateParticipantToken; consumed by native IVS SDK.
Access key ID / secret / session token No Only for signing AWS HTTPS in Dart (IvsAwsSigV4ControlPlane) or on your server.

What you need to know first #

Step Responsibility
1. Stage exists You (console, IaC, createStage via control plane, etc.).
2. Participant token mintParticipantToken on your IvsLiveControlPlane implementation or IvsAwsSigV4ControlPlane / IvsRealtimeTokenClient.
3. Native UI + join AwsIvsRealtimePlatformView.viewType + IvsRealtimePlatform.join.

Where everything lives in the package #

Goal API
Native join / leave / mute / publish IvsRealtimePlatform
Native grid viewType AwsIvsRealtimePlatformView
Backend-shaped control plane (you implement) IvsLiveControlPlane
SigV4 on device (implements same interface) IvsAwsSigV4ControlPlane
Low-level participant token HTTP + SigV4 IvsRealtimeTokenClient
Stage REST helpers (keys passed per call) IvsRealtimeStagesApi
Chat REST helpers IvsChatApi
Chat WebSocket IvsChatSession

Requirements #

Platform Minimum Notes
Android API 28 RECORD_AUDIO, CAMERA when publishing
iOS 14.0 NSMicrophoneUsageDescription, NSCameraUsageDescription

Native SDKs: Android Maven ivs-broadcast stages AAR (1.41.0 in this repo); iOS CocoaPods AmazonIVSBroadcast/Stages (~> 1.36.0 in the podspec).


Install #

From pub.dev:

dependencies:
  aws_ivs_realtime: ^0.1.4

From Git:

dependencies:
  aws_ivs_realtime:
    git:
      url: https://github.com/vipulbansal/aws_ivs_realtime.git

Android — your AndroidManifest.xml (required) #

The plugin’s own android/src/main/AndroidManifest.xml does not declare network or A/V permissions. Your application module must include them so the merged app manifest allows IVS Real-Time and permission_handler prompts.

Inside android/app/src/main/AndroidManifest.xml, as direct children of <manifest> (before <application>), add at least:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
  • INTERNET — AWS HTTPS, IVS signaling, IVS Chat WebSocket.
  • RECORD_AUDIO — join stage (subscribe/publish audio).
  • CAMERA — publish video when join(..., publish: true) / host camera.
  • MODIFY_AUDIO_SETTINGS — used in the reference example for audio routing; safe to keep for parity with example/android/app/src/main/AndroidManifest.xml.

Declaring these is not optional: the Dart side only requests runtime access via permission_handler; the OS still requires the <uses-permission> entries in your manifest.

iOS — your Info.plist + Podfile (required) #

Add (or merge) usage descriptions in ios/Runner/Info.plist — replace the strings with copy appropriate for your app:

<key>NSCameraUsageDescription</key>
<string>Camera is used to publish your video to the IVS Real-Time stage when you go live.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone is used to publish and receive audio on the IVS Real-Time stage.</string>

In ios/Podfile, use at least iOS 14 and, if CocoaPods requires it, use_modular_headers! (see example/ios/Podfile).

permission_handler on iOS: copy the GCC_PREPROCESSOR_DEFINITIONS block from example/ios/Podfile post_install (PERMISSION_MICROPHONE=1, PERMISSION_CAMERA=1) so microphone/camera code is compiled into permission_handler_apple; otherwise dialogs never appear.


Customizing buttons and layout around the live stream (Flutter / Dart) #

The native participant grid (video tiles inside AndroidView / UiKitView) is drawn by the plugin’s embedded Android / iOS UI. You do not need to edit native XML or Swift to:

  • Add lobbies, toolbars, bottom sheets, navigation, theme colors, typography, padding, or any Flutter layout around the platform view (Stack, Scaffold, SafeArea, Row/Column, etc.).
  • Build lists of stages, Join / Leave buttons, host vs viewer toggles, or overlays (mute, end stream) — all in Dart, calling IvsLiveControlPlane / IvsAwsSigV4ControlPlane + IvsRealtimePlatform as in the Listing stages… snippet under App-only earlier in this README.

Treat the platform view like a single embedded surface: you control everything outside and around it with normal Flutter widgets. Changing how each internal video tile looks (pixel-level native skin) is outside typical app integration and is not required for custom product UI.

By default, each native tile is video only (no subscribe/mute/dB strip). Call IvsRealtimePlatform.setShowParticipantStateOverlay with true before join if you want the previous demo-style labels on the tiles.


Example app (run the demo from GitHub) #

The authoritative runnable project lives in the example/ directory of https://github.com/vipulbansal/aws_ivs_realtime (example/ tree). Use it to see lobby → full-screen live → optional IVS Chat, plus a switch between SigV4 on device and a stub IvsLiveControlPlane implementation.

App-only reference (no backend): for a separate Flutter app that consumes the published package and does not use a backend, see aws_ivs_realtime_usage on GitHub — https://github.com/vipulbansal/aws_ivs_realtime_usage. Listed as Sample app (app-only, no backend) in the table at the top of this README.

Run locally (after you clone https://github.com/vipulbansal/aws_ivs_realtime.git):

cd aws_ivs_realtime/example
flutter pub get
flutter run

Use a physical device or emulator that meets Requirements. For SigV4 from defines, pass the same --dart-define=... values documented under App-only in this README.

If you depend on the package from pub.dev only, your own app will not contain this example/ tree — clone the GitHub repository whenever you want to run or copy from the demo.


Documentation #

Channels, SigV4 service scope (ivs vs ivsrealtime), troubleshooting: DOCUMENTATION.md.


Contributing #

Issues and pull requests: https://github.com/vipulbansal/aws_ivs_realtime (same repository linked in Source repository at the top of this README).


Publishing (maintainers) #

dart pub publish from package root. Do not ship IAM credentials in app binaries or public repos.


License #

See LICENSE.

0
likes
150
points
164
downloads

Documentation

API reference

Publisher

verified publishervipulflutter.dev

Weekly Downloads

Flutter plugin for Amazon IVS Real-Time (Stages): native stage video grid, optional SigV4 control-plane helpers, and IVS Chat WebSocket session utilities.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

aws_common, aws_signature_v4, flutter, http, permission_handler

More

Packages that depend on aws_ivs_realtime

Packages that implement aws_ivs_realtime