Skip to Content
Dial v1 live 🎉
SdkFlutter SDK

Flutter SDK

Cross-platform SDK for Flutter applications on iOS, Android, Web, and Desktop.

Status

🔄 Coming Q4 2025 - Currently in development

Join the waitlist  to be notified when available.

Planned Features

Core Features

  • âś… Wallet-to-wallet calls (audio/video)
  • âś… Push notifications
  • âś… Messaging
  • âś… Voicemail
  • âś… Call history
  • âś… Cross-platform support

Platform Support

  • âś… iOS
  • âś… Android
  • âś… Web
  • âś… macOS
  • âś… Windows
  • âś… Linux

Requirements

  • Flutter 3.16+
  • Dart 3.2+

Planned Installation

Add to pubspec.yaml:

dependencies: dial_sdk: ^1.0.0

Then run:

flutter pub get

Planned API

Setup

import 'package:dial_sdk/dial_sdk.dart'; final dial = DialClient( apiKey: 'your-api-key', walletAddress: '0x...', );

Authentication

// Sign message with wallet final signature = await wallet.signMessage('Authenticate with Dial'); await dial.authenticate( walletAddress: '0x...', signature: signature, );

Making Calls

final call = await dial.calls.start( to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', type: CallType.video, );

Flutter Widget Integration

import 'package:flutter/material.dart'; import 'package:dial_sdk/dial_sdk.dart'; class CallScreen extends StatefulWidget { @override _CallScreenState createState() => _CallScreenState(); } class _CallScreenState extends State<CallScreen> { final dial = DialClient.instance; DialCall? currentCall; @override void initState() { super.initState(); // Listen for incoming calls dial.onIncomingCall.listen((call) { setState(() { currentCall = call; }); }); } Future<void> makeCall() async { final call = await dial.calls.start( to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', type: CallType.video, ); setState(() { currentCall = call; }); } @override Widget build(BuildContext context) { if (currentCall == null) { return Scaffold( body: Center( child: ElevatedButton( onPressed: makeCall, child: Text('Make Call'), ), ), ); } return Scaffold( body: CallWidget(call: currentCall!), ); } } class CallWidget extends StatelessWidget { final DialCall call; const CallWidget({required this.call}); @override Widget build(BuildContext context) { return Column( children: [ Expanded( child: VideoView( stream: call.remoteStream, ), ), CallControls(call: call), ], ); } }

Provider Pattern

import 'package:provider/provider.dart'; import 'package:dial_sdk/dial_sdk.dart'; class DialProvider extends ChangeNotifier { final DialClient _dial = DialClient.instance; DialCall? _currentCall; DialCall? get currentCall => _currentCall; DialProvider() { _dial.onIncomingCall.listen((call) { _currentCall = call; notifyListeners(); }); } Future<void> startCall(String to, CallType type) async { _currentCall = await _dial.calls.start(to: to, type: type); notifyListeners(); } Future<void> endCall() async { await _currentCall?.end(); _currentCall = null; notifyListeners(); } } // Usage void main() { runApp( ChangeNotifierProvider( create: (_) => DialProvider(), child: MyApp(), ), ); } class CallButton extends StatelessWidget { @override Widget build(BuildContext context) { return Consumer<DialProvider>( builder: (context, dialProvider, child) { return ElevatedButton( onPressed: () => dialProvider.startCall( '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', CallType.video, ), child: Text('Call'), ); }, ); } }

Riverpod Integration

import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:dial_sdk/dial_sdk.dart'; final dialProvider = Provider((ref) => DialClient.instance); final currentCallProvider = StreamProvider<DialCall?>((ref) { final dial = ref.watch(dialProvider); return dial.onIncomingCall; }); class CallScreen extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final currentCall = ref.watch(currentCallProvider); return currentCall.when( data: (call) { if (call == null) { return Center(child: Text('No active call')); } return CallWidget(call: call); }, loading: () => CircularProgressIndicator(), error: (err, stack) => Text('Error: $err'), ); } }

Messaging

// Send message await dial.messages.send( to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', content: 'Hello!', type: MessageType.text, ); // Listen for messages dial.onMessageReceived.listen((message) { print('New message from ${message.from}: ${message.content}'); }); // Get message history final messages = await dial.messages.getHistory( with: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', limit: 50, );

Push Notifications

iOS

import 'package:dial_sdk/dial_sdk.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; Future<void> setupPushNotifications() async { final messaging = FirebaseMessaging.instance; // Request permission await messaging.requestPermission(); // Get token final token = await messaging.getToken(); // Register with Dial await DialClient.instance.registerPushToken(token); }

Android

import 'package:dial_sdk/dial_sdk.dart'; import 'package:firebase_messaging/firebase_messaging.dart'; Future<void> setupPushNotifications() async { final messaging = FirebaseMessaging.instance; // Get token final token = await messaging.getToken(); // Register with Dial await DialClient.instance.registerPushToken(token); // Handle background messages FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); } Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async { await DialNotificationHandler.handle(message); }

Streams & Reactive Programming

Full support for Dart Streams:

// Call stream dial.onIncomingCall.listen((call) { print('Incoming call from ${call.from}'); }); // Message stream dial.onMessageReceived.listen((message) { print('New message: ${message.content}'); }); // Call status changes dial.onCallStatusChanged.listen((status) { print('Call status: $status'); });

Platform-Specific Features

iOS CallKit

import 'package:dial_sdk/dial_sdk.dart'; // Automatically integrated on iOS await dial.enableCallKit( appName: 'MyApp', ringtoneSound: 'ringtone.mp3', );

Android ConnectionService

import 'package:dial_sdk/dial_sdk.dart'; // Automatically integrated on Android await dial.enableConnectionService( serviceName: 'MyApp Calls', );

Web Support

// Works seamlessly on web // Uses WebRTC for calls // No special configuration needed

Video Rendering

import 'package:dial_sdk/dial_sdk.dart'; class VideoView extends StatelessWidget { final MediaStream stream; const VideoView({required this.stream}); @override Widget build(BuildContext context) { return RTCVideoView( stream: stream, mirror: false, objectFit: RTCVideoViewObjectFit.cover, ); } }

Complete Example App

import 'package:flutter/material.dart'; import 'package:dial_sdk/dial_sdk.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // Initialize Dial SDK await DialClient.initialize( apiKey: 'your-api-key', ); runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Dial Example', theme: ThemeData( primarySwatch: Colors.blue, ), home: HomeScreen(), ); } } class HomeScreen extends StatefulWidget { @override _HomeScreenState createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { final dial = DialClient.instance; DialCall? currentCall; bool isMuted = false; bool isVideoEnabled = true; @override void initState() { super.initState(); dial.onIncomingCall.listen((call) { setState(() { currentCall = call; }); _showIncomingCallDialog(call); }); dial.onCallEnded.listen((_) { setState(() { currentCall = null; }); }); } Future<void> _showIncomingCallDialog(DialCall call) async { return showDialog( context: context, barrierDismissible: false, builder: (context) => AlertDialog( title: Text('Incoming Call'), content: Text('Call from ${call.from}'), actions: [ TextButton( onPressed: () { call.decline(); Navigator.pop(context); }, child: Text('Decline'), ), TextButton( onPressed: () { call.answer(); Navigator.pop(context); }, child: Text('Answer'), ), ], ), ); } Future<void> makeCall() async { final call = await dial.calls.start( to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', type: CallType.video, ); setState(() { currentCall = call; }); } @override Widget build(BuildContext context) { if (currentCall == null) { return Scaffold( appBar: AppBar(title: Text('Dial Example')), body: Center( child: ElevatedButton( onPressed: makeCall, child: Text('Make Video Call'), ), ), ); } return Scaffold( body: Stack( children: [ // Remote video (full screen) Positioned.fill( child: VideoView(stream: currentCall!.remoteStream), ), // Local video (pip) Positioned( top: 50, right: 20, width: 120, height: 160, child: VideoView(stream: currentCall!.localStream), ), // Controls Positioned( bottom: 50, left: 0, right: 0, child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ FloatingActionButton( onPressed: () { setState(() { isMuted = !isMuted; }); currentCall!.setMuted(isMuted); }, child: Icon( isMuted ? Icons.mic_off : Icons.mic, ), ), FloatingActionButton( onPressed: () { currentCall!.end(); }, backgroundColor: Colors.red, child: Icon(Icons.call_end), ), FloatingActionButton( onPressed: () { setState(() { isVideoEnabled = !isVideoEnabled; }); currentCall!.setVideoEnabled(isVideoEnabled); }, child: Icon( isVideoEnabled ? Icons.videocam : Icons.videocam_off, ), ), ], ), ), ], ), ); } }

Testing

import 'package:flutter_test/flutter_test.dart'; import 'package:dial_sdk/dial_sdk.dart'; import 'package:mockito/mockito.dart'; void main() { group('Dial SDK Tests', () { late DialClient dial; setUp(() { dial = DialClient( apiKey: 'test-key', walletAddress: '0x...', ); }); test('should start a call', () async { final call = await dial.calls.start( to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb', type: CallType.audio, ); expect(call, isNotNull); expect(call.to, equals('0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb')); }); }); }

Performance

  • Native platform channels for optimal performance
  • Hardware acceleration on all platforms
  • Battery-optimized
  • Memory-efficient video rendering
  • Background execution support

Roadmap

Q4 2025 - Alpha Release

  • Core calling features
  • Messaging
  • Push notifications
  • iOS & Android support

Q1 2026 - Beta Release

  • Video conferencing
  • Web support
  • Desktop support (macOS, Windows, Linux)
  • Screen sharing

Q2 2026 - Stable Release

  • Full feature parity
  • Production-ready
  • Complete documentation
  • Example apps

Example Projects

Complete example projects will be available:

Get Notified

Want early access?

Next Steps

Last updated on