
SDKAppID: Application identifier (required). TRTC uses SDKAppID for billing and details.SDKSecretKey: Application secret key.
atomic_x_core dependency in your pubspec.yaml file and execute flutter pub get.dependencies:atomic_x_core: ^3.6.0
android/app/src/main/AndroidManifest.xml file.<uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.RECORD_AUDIO" />
iOS directory and to the Info.plist file in the ios/Runner directory.post_install do |installer|installer.pods_project.targets.each do |target|flutter_additional_ios_build_settings(target)target.build_configurations.each do |config|config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)','PERMISSION_MICROPHONE=1','PERMISSION_CAMERA=1',]endendend
<key>NSCameraUsageDescription</key><string>TUILiveKit needs to access your camera permission. Video recording with picture only after enabling.</string><key>NSMicrophoneUsageDescription</key><string>TUILiveKit needs to access your mic permission. Recorded video will have sound when enabled.</string>

LoginStore.shared.login in your project to log in. This is the key premise for using all functions of AtomicXCore.LoginStore.shared.login after successful log-in to your App's user account to ensure clear and consistent business logic.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';void main() async {WidgetsFlutterBinding.ensureInitialized();final result = await LoginStore.shared.login(sdkAppID: 1400000001, // replace with your sdkAppIDuserID: "test_001", // replace with your userIDuserSig: "xxxxxxxxxxx", // replace with your userSig);if (result.isSuccess) {debugPrint("login success");} else {debugPrint("login failed code: ${result.errorCode}, message: ${result.errorMessage}");}runApp(const MyApp());}
Parameter | Type | Note |
sdkAppID | int | |
userID | String | The unique ID for the current user. Only letters, numbers, hyphens, and underscores are allowed. To avoid login conflicts across devices, do not use simple IDs like 1, 123, etc. |
userSig | String | Credential for TRTC authentication. Please note: In development environment: You can use the local GenerateTestUserSig.genTestSig function to generate a UserSig or generate a temporary UserSig via the UserSig Generation Tool.In production environment: To prevent SecretKey leakage, always generate UserSig on your server. For details, see Generating UserSig on the Server. |

LiveCoreWidget instance and control the live stream behavior through LiveCoreController.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// YourAnchorPage represents your anchor starts live streaming pageclass YourAnchorPage extends StatefulWidget {final String liveId;const YourAnchorPage({super.key, required this.liveId});@overrideState<YourAnchorPage> createState() => _YourAnchorPageState();}class _YourAnchorPageState extends State<YourAnchorPage> {// 1. Create a LiveCoreController instancelate final LiveCoreController _controller;@overridevoid initState() {super.initState();// 2. Initialize the controller_controller = LiveCoreController.create();// 3. Set up live streaming ID_controller.setLiveID(widget.liveId);}@overrideWidget build(BuildContext context) {return Scaffold(body: Stack(children: [// 4. Load the broadcaster stream page to your viewLiveCoreWidget(controller: _controller),// Your other UI components],),);}}
DeviceStore.shared.openLocalCamera and DeviceStore.shared.openLocalMicrophone to enable the camera and microphone. LiveCoreWidget will automatically preview the camera video stream:import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// YourAnchorPage represents your anchor starts live streaming pageclass YourAnchorPage extends StatefulWidget {final String liveId;const YourAnchorPage({super.key, required this.liveId});@overrideState<YourAnchorPage> createState() => _YourAnchorPageState();}class _YourAnchorPageState extends State<YourAnchorPage> {late final LiveCoreController _controller;@overridevoid initState() {super.initState();_controller = LiveCoreController.create();_controller.setLiveID(widget.liveId);// Turn on the device_openDevices();}void _openDevices() {// 1. Open front cameraDeviceStore.shared.openLocalCamera(true);// 2. Turn on the microphoneDeviceStore.shared.openLocalMicrophone();}@overrideWidget build(BuildContext context) {return Scaffold(body: Stack(children: [LiveCoreWidget(controller: _controller),],),);}}
createLive API to start video live streaming:import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// YourAnchorPage represents your anchor starts live streaming pageclass YourAnchorPage extends StatefulWidget {final String liveId;const YourAnchorPage({super.key, required this.liveId});@overrideState<YourAnchorPage> createState() => _YourAnchorPageState();}class _YourAnchorPageState extends State<YourAnchorPage> {late final LiveCoreController _controller;@overridevoid initState() {super.initState();_controller = LiveCoreController.create();_controller.setLiveID(widget.liveId);_openDevices();}void _openDevices() {DeviceStore.shared.openLocalCamera(true);DeviceStore.shared.openLocalMicrophone();}// Call the go live API to start live streamingFuture<void> _startLive() async {// 1. Prepare the LiveInfo objectfinal liveInfo = LiveInfo(// Set up live streaming room idliveID: widget.liveId,// Set up live streaming room nameliveName: "test live stream",// Configure the layout template, default: 600 dynamic grid layoutseatLayoutTemplateID: 600,// Configure the anchor to always stay on the seatkeepOwnerOnSeat: true,);// 2. Call LiveListStore.shared.createLive to start live streamingfinal result = await LiveListStore.shared.createLive(liveInfo);if (result.isSuccess) {debugPrint("startLive success");} else {debugPrint("startLive error: ${result.errorMessage}");}}@overrideWidget build(BuildContext context) {return Scaffold(body: Stack(children: [LiveCoreWidget(controller: _controller),// Go live buttonPositioned(bottom: 50,left: 0,right: 0,child: Center(child: ElevatedButton(onPressed: _startLive,child: const Text('Start live broadcast'),),),),],),);}}
Parameter Name | Type | Attribute | Description |
liveID | String | Required | Unique identifier for the live streaming room. |
liveName | String | Optional. | Name of the live streaming room. |
notice | String | Optional. | Announcement information of the live streaming room. |
isMessageDisable | bool | Optional. | Whether to mute ( true: yes, false: no). |
isPublicVisible | bool | Optional. | Whether the live room is publicly visible ( true: yes, false: no). |
isSeatEnabled | bool | Optional. | Enable seat feature ( true: enabled, false: disabled). |
keepOwnerOnSeat | bool | Optional. | Whether to keep the room owner on the seat. |
maxSeatCount | int | Optional. | Maximum seat count. |
seatMode | TakeSeatMode | Optional. | Seat mode: TakeSeatMode.free: free seatTakeSeatMode.apply: apply for seat |
seatLayoutTemplateID | int | Required | Seat layout template ID. |
coverURL | String | Optional. | Cover image URL of the live streaming room. |
backgroundURL | String | Optional. | Background image URL of the live streaming room. |
categoryList | List<int> | Optional. | Category tags for the live room. |
activityStatus | int | Optional. | Live stream status. |
isGiftEnabled | bool | Optional. | Whether to enable the gift function ( true: yes, false: no). |
LiveListStore.shared.endLive to stop streaming and close the room. The SDK will handle cleanup automatically.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// YourAnchorPage represents your anchor starts live streaming pageclass YourAnchorPage extends StatefulWidget {final String liveId;const YourAnchorPage({super.key, required this.liveId});@overrideState<YourAnchorPage> createState() => _YourAnchorPageState();}class _YourAnchorPageState extends State<YourAnchorPage> {// ... Other code ...End live streamingFuture<void> _stopLive() async {final result = await LiveListStore.shared.endLive();if (result.isSuccess) {debugPrint("endLive success");} else {debugPrint("endLive error: ${result.errorMessage}");}}// ... Other code ...}

LiveCoreWidget instance and control the live stream behavior through LiveCoreController.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// YourAudiencePage represents your audience viewing webpageclass YourAudiencePage extends StatefulWidget {final String liveId;const YourAudiencePage({super.key, required this.liveId});@overrideState<YourAudiencePage> createState() => _YourAudiencePageState();}class _YourAudiencePageState extends State<YourAudiencePage> {// 1. Create a LiveCoreController instancelate final LiveCoreController _controller;@overridevoid initState() {super.initState();// 2. Initialize the controller_controller = LiveCoreController.create();// 3. Bind live streaming id_controller.setLiveID(widget.liveId);}@overrideWidget build(BuildContext context) {return Scaffold(body: Stack(children: [// 4. Load the audience pull stream page to your viewLiveCoreWidget(controller: _controller),],),);}}
LiveListStore.shared.joinLive to join the live stream. LiveCoreWidget will automatically play the video stream:import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// YourAudiencePage represents your audience viewing webpageclass YourAudiencePage extends StatefulWidget {final String liveId;const YourAudiencePage({super.key, required this.liveId});@overrideState<YourAudiencePage> createState() => _YourAudiencePageState();}class _YourAudiencePageState extends State<YourAudiencePage> {late final LiveCoreController _controller;@overridevoid initState() {super.initState();_controller = LiveCoreController.create();_controller.setLiveID(widget.liveId);// Enter live room_joinLive();}Future<void> _joinLive() async {// Call LiveListStore.shared.joinLive to enter live room// - liveId: same liveId as anchor starts live streamingfinal result = await LiveListStore.shared.joinLive(widget.liveId);if (result.isSuccess) {debugPrint("joinLive success");} else {debugPrint("joinLive error: ${result.errorMessage}");// Failed to enter the room, must exit the page// if (mounted) Navigator.of(context).pop();}}@overrideWidget build(BuildContext context) {return Scaffold(body: Stack(children: [LiveCoreWidget(controller: _controller),],),);}}
LiveListStore.shared.leaveLive to exit. The SDK will stop streaming and leave the room automatically.import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// YourAudiencePage represents your audience viewing webpageclass YourAudiencePage extends StatefulWidget {final String liveId;const YourAudiencePage({super.key, required this.liveId});@overrideState<YourAudiencePage> createState() => _YourAudiencePageState();}class _YourAudiencePageState extends State<YourAudiencePage> {// ... Other code ...End live streamFuture<void> _leaveLive() async {final result = await LiveListStore.shared.leaveLive();if (result.isSuccess) {debugPrint("leaveLive success");} else {debugPrint("leaveLive error: ${result.errorMessage}");}}// ... Other code ...}
LiveListListener to listen for live events:import 'package:flutter/material.dart';import 'package:atomic_x_core/atomicxcore.dart';/// YourAudiencePage represents your audience viewing webpageclass YourAudiencePage extends StatefulWidget {final String liveId;const YourAudiencePage({super.key, required this.liveId});@overrideState<YourAudiencePage> createState() => _YourAudiencePageState();}class _YourAudiencePageState extends State<YourAudiencePage> {late final LiveCoreController _controller;// 1. Define LiveListListener to manage event monitoringlate final LiveListListener _liveListListener;@overridevoid initState() {super.initState();_controller = LiveCoreController.create();_controller.setLiveID(widget.liveId);// 2. Listen to Live Event_setupLiveEventListener();// 3. Enter live room_joinLive();}// 4. Add a method to set up event listeningvoid _setupLiveEventListener() {_liveListListener = LiveListListener(onLiveEnded: (liveID, reason, message) {// Listen to live streaming enddebugPrint("Live ended. liveID: $liveID, reason: ${reason.value}, message: $message");// Handle the logic for exiting a live streaming room herein, such as closing current page// if (mounted) Navigator.of(context).pop();},onKickedOutOfLive: (liveID, reason, message) {// Listen to being kicked out of live streamdebugPrint("Kicked out of live. liveID: $liveID, reason: ${reason.value}, message: $message");// Handle the logic for exiting a live streaming room herein// if (mounted) Navigator.of(context).pop();},);LiveListStore.shared.addLiveListListener(_liveListListener);}Future<void> _joinLive() async {final result = await LiveListStore.shared.joinLive(widget.liveId);if (result.isSuccess) {debugPrint("joinLive success");} else {debugPrint("joinLive error: ${result.errorMessage}");}}Future<void> _leaveLive() async {final result = await LiveListStore.shared.leaveLive();if (result.isSuccess) {debugPrint("leaveLive success");} else {debugPrint("leaveLive error: ${result.errorMessage}");}}@overridevoid dispose() {// 5. Remove event listeningLiveListStore.shared.removeLiveListListener(_liveListListener);super.dispose();}@overrideWidget build(BuildContext context) {return Scaffold(body: Stack(children: [LiveCoreWidget(controller: _controller),],),);}}
Layout | Dynamic Grid Layout | Floating Window Layout | Fixed Grid Layout |
Template ID | 600 | 601 | 800 |
Description | Default layout; grid size adjusts dynamically based on number of co-hosts. | Co-hosts are displayed as floating windows. | Fixed number of co-hosts; each occupies a fixed grid. |
Example | ![]() | ![]() | ![]() |
Feature | Description | Store | Implementation Guide |
Audience Audio/Video Co-hosting | Audience can apply to join the host and interact via real-time video. | ||
Host Cross-room PK | Hosts from different rooms can connect for interaction or PK. | ||
Live Comments Chat | Audience can send and receive real-time text messages in the live room. | ||
Gift System | Audience can send virtual gifts to the host, increasing engagement and fun. |
Store/Component | Feature Description | API Documentation |
LiveCoreWidget | Core view for live video display and interaction: handles video rendering and widget management; supports host streaming, audience co-hosting, host cross-room connections, and more. | |
LiveCoreController | Controller for LiveCoreWidget: set live stream ID, control preview, and other operations. | |
LiveListStore | Live room lifecycle management: create, join, leave, destroy room; query room list; update live info (name, announcement, etc.); listen for live status (kicked out, ended). | |
DeviceStore | Audio/video device control: microphone (toggle/volume), camera (toggle/switch camera/video quality), screen sharing, real-time device status monitoring. | |
CoGuestStore | Audience co-host management: co-host application/invitation/accept/reject, member permissions (microphone/camera), status sync. | |
CoHostStore | Host cross-room connection: supports multiple layouts (dynamic grid, etc.), initiate/accept/reject connection, co-host interaction management. | |
BattleStore | Host PK battles: initiate PK (set duration/opponent), manage PK status (start/end), sync scores, listen for results. | |
GiftStore | Gift interaction: get gift list, send/receive gifts, listen for gift events (including sender and gift details). | |
BarrageStore | Live comments: send text/custom comments, manage comment list, monitor comment status in real time. | |
LikeStore | Like interaction: send likes, listen for like events, sync total like count. | |
LiveAudienceStore | Audience management: get real-time audience list (ID/name/avatar), count audience, listen for audience enter/leave events. | |
AudioEffectStore | Audio effects: voice changer (child/male), reverb (KTV, etc.), ear monitoring, real-time effect switching. | |
BaseBeautyStore | Basic beauty filters: adjust smoothing/whitening/rosy (0-100), reset beauty status, sync effect parameters. |
liveID has been set for the LiveCoreController instance before calling the live streaming or viewing API.DeviceStore.shared.openLocalCamera(true) to open the camera.permission_handler plug-in to request camera and mic permission:import 'package:permission_handler/permission_handler.dart';Future<void> requestPermissions() async {await [Permission.camera,Permission.microphone,].request();}
dispose method, such as removing event listeners:@overridevoid dispose() {LiveListStore.shared.removeLiveListListener(_liveListListener);super.dispose();}
Feedback