I recently had to add voice and video calling between two people inside a Flutter app we were building. Instead of creating the whole system from scratch like handling audio, video, servers, and network stuff, we wanted something that already does most of the tough work for us.
We checked out a few tools and ended up going with MirrorFly. It covered what we needed: smooth calling, easy integration, and good support.
In this write-up, I’ll walk you through how the setup went, what we needed to get started, and a few things I ran into during the process.
Overview
The MirrorFly Flutter SDK supports:
- One-to-one voice and video calling
- Cross-platform (Android and iOS)
- Call management using Flutter APIs
- Built-in listeners for call events
This guide assumes you're working with an existing Flutter app.
System Requirements
Android:
- Android 5.0+ (API 21+)
- Java 7+
- Gradle 4.1.0+
compileSdk
and targetSdk
should be 34 or higher
iOS:
- iOS 12.1+
- Xcode project must support certain background capabilities (covered below)
Step-by-Step Setup
1. Get a License Key
Create a MirrorFly account and retrieve your license key from the dashboard. You’ll need this to initialize the SDK.
2. Android Integration
Update your root build.gradle
:
allprojects {
repositories {
...
...
jcenter()
maven {
url "https://repo.mirrorfly.com/release"
}
}
}
In app/build.gradle
, confirm:
android {
compileSdk 34
defaultConfig {
minSdkVersion 21
targetSdkVersion 34
}
}
3. iOS Integration
At the bottom of your iOS project’s Podfile, add:
post_install do |installer|
installer.aggregate_targets.each do |target|
...
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.1'
config.build_settings['ENABLE_BITCODE'] = 'NO'
...
end
end
Then:
- Disable Bitcode in Build Settings
- Add capabilities to the target:
- App Groups
- Background Modes → enable:
- Audio, AirPlay, Picture in Picture
- Voice over IP
- Background fetch
- Remote notifications
4. Flutter Setup
Add this to your pubspec.yaml
:
dependencies:
mirrorfly_plugin: ^1.4.0
Then run:
flutter pub get
Import the package:
import 'package:mirrorfly_plugin/mirrorfly.dart';
5. Initialize the SDK
Call this in main()
before runApp()
:
void main() {
WidgetsFlutterBinding.ensureInitialized();
Mirrorfly.initializeSDK(
licenseKey: LICENSE_KEY,
iOSContainerID: IOS_APP_GROUP_ID,
flyCallback: (FlyResponse response) {
runApp(MyApp());
}
);
}
licenseKey
: from your MirrorFly account
iOSContainerID
: App Group ID for shared storage
6. Logging In
Mirrorfly.login(
userIdentifier: "user123",
fcmToken: "your_fcm_token",
isForceRegister: true,
flyCallback: (FlyResponse response) {
if (response.isSuccess) {
}
}
);
Notes:
isForceRegister
ensures old sessions are cleared if user limit is reached.
- Only use
login()
once per session unless logging out first.
Calling Features
Making a Call
Mirrorfly.makeVoiceCall(
toUserJid: "user123@xmpp.chatsystem.dev.contus.us",
flyCallBack: (FlyResponse response) {
if (response.isSuccess) {
}
}
);
toUserJid
format: userID@domain
Receiving a Call
MirrorFly handles incoming calls and displays system call UI. Listen to call status:
Mirrorfly.onCallStatusUpdated.listen((event) {
var callInfo = jsonDecode(event);
print("Call status: ${callInfo['callStatus']}");
});
You'll receive:
callMode
(OneToOne / groupCall)
userJid
callType
(Audio / Video)
callStatus
(Ringing, Connected, Ended, etc.)
Permissions to Watch
Android:
RECORD_AUDIO
CAMERA
POST_NOTIFICATIONS
(Android 13+)
BLUETOOTH_CONNECT
(Android 12+)
READ_PHONE_STATE
(Android 12+)
iOS:
- Microphone and Camera permissions must be handled through your
Info.plist
Final Thoughts
The SDK does what it promises, but the setup needs close attention especially around permissions and platform-specific tweaks. Once that’s sorted, getting basic calling up and running is pretty smooth. The Flutter plugin gives you access to the essentials without needing a lot of extra code.
If you're planning to build things like group calls or a fully custom UI, you’ll probably need to spend more time digging into the SDK or tapping into the APIs directly.
I’ve taken notes while working through this so if you want a breakdown of the call flow or how to customize the UI, just let me know. Happy to share.