Skip to main content

flutter_zoom_sdk_advanced 0.5.0 copy "flutter_zoom_sdk_advanced: ^0.5.0" to clipboard
flutter_zoom_sdk_advanced: ^0.5.0 copied to clipboard

A Flutter plugin for Zoom Meeting SDK with support for joining meetings, email login, meeting controls, and real-time meeting events.

example/lib/main.dart

import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/material.dart';
import 'package:flutter_zoom_sdk_advanced/flutter_zoom_sdk_advanced.dart';
import 'package:permission_handler/permission_handler.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Zoom SDK Example',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(colorSchemeSeed: const Color(0xFF2D8CFF), useMaterial3: true, brightness: Brightness.light),
      home: const ZoomExamplePage(
        // JWT token from server
        jwtToken:
            'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzZGtLZXkiOiJpVjl0a2lqUmRLblpLcWtGOFNvMUEiLCJhcHBLZXkiOiJpVjl0a2lqUmRLblpLcWtGOFNvMUEiLCJtbiI6IjYxMjA2MDMxMDUiLCJyb2xlIjowLCJpYXQiOjE3OTI0OTI0MjIsImV4cCI6MTc5MjQ5OTYyMiwidG9rZW5FeHAiOjE3OTI0OTk2MjJ9.fnx2WMaiUR3FFaInxAUak6M98xDUu48O3SroaJoV3QQ',
        zakToken: null,
        // USER_ZAK_TOKEN_FROM_BACKEND (For Zoom org users)
        joinToken: "",
        // USER_JOIN_TOKEN_FROM_BACKEND (For external registered users)
      ),
    );
  }
}

class ZoomExamplePage extends StatefulWidget {
  final String jwtToken;
  final String? zakToken;
  final String? joinToken;

  const ZoomExamplePage({super.key, required this.jwtToken, this.zakToken, this.joinToken});

  @override
  State<ZoomExamplePage> createState() => _ZoomExamplePageState();
}

class _ZoomExamplePageState extends State<ZoomExamplePage> {
  final _zoomPlugin = FlutterZoomSdkAdvanced();
  String _status = 'Initializing...';
  bool _sdkInitialized = false;
  bool _sdkInitFailed = false;
  bool _joining = false;
  StreamSubscription? _eventSubscription;

  final _meetingIdController = TextEditingController(text: "6120603105");
  final _meetingPasswordController = TextEditingController(text: "52eBMv");
  final _displayNameController = TextEditingController(text: 'Abootty');

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

  Future<void> _initSdk() async {
    setState(() {
      _status = 'Initializing...';
      _sdkInitFailed = false;
    });
    final result = await _zoomPlugin.initZoom(ZoomOptions(jwtToken: widget.jwtToken));
    final success = result['status'] == true;
    if (!mounted) return;
    setState(() {
      _sdkInitialized = success;
      _sdkInitFailed = !success;
      _status = success ? 'Ready' : result['message']?.toString() ?? 'Init failed';
    });
    if (success) {
      _eventSubscription = _zoomPlugin.onMeetingStateChanged().listen((event) {
        if (!mounted) return;
        final status = event['status']?.toString() ?? '';
        debugPrint('[ZoomSDK] Dart event: $status');
        if (status.contains('ENDED') || status.contains('IDLE')) {
          setState(() => _joining = false);
        }
      });

      // These are global MobileRTCMeetingSettings toggles, not scoped to a
      // live meeting — set them right after init, before joinMeeting(), so
      // the meeting UI never builds the invite/passcode/share elements in
      // the first place. iOS only; Android uses ZoomMeetingOptions fields
      // (noInvite, hideMeetingId, hidePassword, disableShare) at join time
      // instead.
      if (Platform.isIOS) {
        _zoomPlugin.setInviteVisibility(hideInvite: true, hideInviteUrl: true).then((r) => debugPrint('[ZoomSDK] setInviteVisibility -> $r'));
        _zoomPlugin.setMeetingInfoVisibility(hidePassword: true).then((r) => debugPrint('[ZoomSDK] setMeetingInfoVisibility -> $r'));
        _zoomPlugin.setShareVisibility(true).then((r) => debugPrint('[ZoomSDK] setShareVisibility -> $r'));
        _zoomPlugin.setParticipantsVisibility(true).then((r) => debugPrint('[ZoomSDK] setParticipantsVisibility -> $r'));
      }
    }
  }

  Future<void> _joinMeeting() async {
    final meetingId = _meetingIdController.text.trim();
    final password = _meetingPasswordController.text.trim();
    final name = _displayNameController.text.trim();

    if (meetingId.isEmpty || name.isEmpty) {
      _showSnackBar('Meeting ID and Display Name are required');
      return;
    }

    final cameraStatus = await Permission.camera.request();
    final micStatus = await Permission.microphone.request();
    if (!cameraStatus.isGranted || !micStatus.isGranted) {
      if (!mounted) return;
      _showSnackBar('Camera and microphone permissions are required');
      return;
    }

    setState(() => _joining = true);
    debugPrint('[ZoomSDK] Dart joinMeeting - id: $meetingId, hasZak: ${widget.zakToken != null}, hasJoinToken: ${widget.joinToken != null}');
    if (widget.joinToken != null) {
      debugPrint('[ZoomSDK] joinToken length: ${widget.joinToken!.length}, starts with: ${widget.joinToken!.substring(0, widget.joinToken!.length > 20 ? 20 : widget.joinToken!.length)}...');
    }
    final result = await _zoomPlugin.joinMeeting(
      ZoomMeetingOptions(
        meetingId: meetingId,
        meetingPassword: password,
        displayName: name,
        zakToken: widget.zakToken,
        joinToken: widget.joinToken,
        noInvite: true,
        hideMeetingId: true,
        hidePassword: true,
        disableShare: true,
        hideParticipants: true,
      ),
    );

    debugPrint('[ZoomSDK] Dart join result: $result');
    if (!mounted) return;
    final success = result['status'] == true;
    if (!success) {
      setState(() => _joining = false);
      _showSnackBar(result['message']?.toString() ?? 'Failed to join');
    }
  }

  void _showSnackBar(String message) {
    ScaffoldMessenger.of(context)
      ..clearSnackBars()
      ..showSnackBar(
        SnackBar(
          content: Text(message),
          behavior: SnackBarBehavior.floating,
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
        ),
      );
  }

  @override
  void dispose() {
    _eventSubscription?.cancel();
    _meetingIdController.dispose();
    _meetingPasswordController.dispose();
    _displayNameController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);

    return Scaffold(
      backgroundColor: theme.colorScheme.surface,
      body: SafeArea(
        child: Center(
          child: SingleChildScrollView(
            padding: const EdgeInsets.symmetric(horizontal: 24),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                // Logo / Header
                Container(
                  width: 80,
                  height: 80,
                  decoration: BoxDecoration(color: theme.colorScheme.primaryContainer, borderRadius: BorderRadius.circular(20)),
                  child: Icon(Icons.videocam_rounded, size: 40, color: theme.colorScheme.primary),
                ),
                const SizedBox(height: 16),
                Text('Join Meeting', style: theme.textTheme.headlineMedium?.copyWith(fontWeight: FontWeight.bold)),
                const SizedBox(height: 4),
                Text(
                  _sdkInitialized ? 'Enter your meeting details below' : _status,
                  style: theme.textTheme.bodyMedium?.copyWith(color: _sdkInitFailed ? theme.colorScheme.error : theme.colorScheme.onSurfaceVariant),
                  textAlign: TextAlign.center,
                ),
                if (_sdkInitFailed) ...[const SizedBox(height: 16), OutlinedButton.icon(onPressed: _initSdk, icon: const Icon(Icons.refresh_rounded), label: const Text('Retry'))],
                const SizedBox(height: 32),

                // Form Card
                Card(
                  elevation: 0,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(16),
                    side: BorderSide(color: theme.colorScheme.outlineVariant),
                  ),
                  child: Padding(
                    padding: const EdgeInsets.all(20),
                    child: Column(
                      children: [
                        _buildTextField(controller: _meetingIdController, label: 'Meeting ID', icon: Icons.tag_rounded, keyboardType: TextInputType.number),
                        const SizedBox(height: 12),
                        _buildTextField(controller: _meetingPasswordController, label: 'Password', icon: Icons.lock_outline_rounded, obscureText: true),
                        const SizedBox(height: 12),
                        _buildTextField(controller: _displayNameController, label: 'Display Name', icon: Icons.person_outline_rounded),
                      ],
                    ),
                  ),
                ),
                const SizedBox(height: 20),

                // Join Button
                SizedBox(
                  width: double.infinity,
                  height: 52,
                  child: FilledButton(
                    onPressed: _sdkInitialized && !_joining ? _joinMeeting : null,
                    style: FilledButton.styleFrom(shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14))),
                    child: _joining
                        ? const SizedBox(width: 22, height: 22, child: CircularProgressIndicator(strokeWidth: 2.5, color: Colors.white))
                        : const Text('Join Meeting', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
                  ),
                ),
                const SizedBox(height: 32),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildTextField({required TextEditingController controller, required String label, required IconData icon, TextInputType? keyboardType, bool obscureText = false}) {
    return TextField(
      controller: controller,
      keyboardType: keyboardType,
      obscureText: obscureText,
      decoration: InputDecoration(
        labelText: label,
        prefixIcon: Icon(icon),
        filled: true,
        fillColor: Theme.of(context).colorScheme.surfaceContainerLowest,
        border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none),
        enabledBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(12),
          borderSide: BorderSide(color: Theme.of(context).colorScheme.outlineVariant, width: 0.5),
        ),
        focusedBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(12),
          borderSide: BorderSide(color: Theme.of(context).colorScheme.primary, width: 1.5),
        ),
      ),
    );
  }
}
0
likes
160
points
382
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A Flutter plugin for Zoom Meeting SDK with support for joining meetings, email login, meeting controls, and real-time meeting events.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_zoom_sdk_advanced

Packages that implement flutter_zoom_sdk_advanced