Home / Writing

How !to make a calling app in Flutter for Android devices

#flutter #android #plugin #hack original on dev.to ↗

Disclaimer- That ! in the title is not a typo, read it as not. This article is not a tutorial about how to make a whatsapp or skype type calling app, rather it is an article about how I fell short of making such an app using flutter.

I have been trying to make a voice calling app using Flutter. You will find many articles and videos about how easy peasy it is to integrate Twilio or Agora into a flutter app, but I could not find one resource which dived deep into making a true calling app in Flutter. What do I mean by true calling app ?

What a true calling app should have

On receiving data notification for call

On receiving data notification for call

Building the app

I am using the agora_rtc_engine plugin for making voice calls. You can find a tutorial on their official docs here. If we implement just what the tutorial says, we will be joining a voice channel as soon as we launch the app, and anyone having the same app can speak into and listen to this voice call.

So the voice call part is taken care of pretty easily. Now for how to get the behaviour of getting an actual phone call(getting a Caller ID screen, an accept/reject screen).

Take #1

I set up a FCM in flutter to receive data messages. You can read about difference between notification messages and data messages in my stackoverflow answer here. I went with data messages because I wanted to be in control of the notification I generate.

My next plan was to use flutter_local_notifications plugin and generate a notification. This plugin also has a full screen intent option, which when set to true can show your app when when phone is locked. But there are certain properties the notification should have.So I would listen to a data message, in both foreground and background/terminated state. Upon receiving one, I will generate a notification with full screen intent as true.

Properties of the notification

The fault in our notifications

Always has been eh

Always has been eh?

Navigating to a particular screen upon tapping the notification is rather easy, as there are callbacks available for times when the app has been opened due to a notification. For this though you need to use a notificaication message, in which the notification will be handled directly by the plugin. If you want to implement it in data messages, you will have to write some platform dependent code as well.

Take #2

I tried handling the incoming calls like a gentleman! Upon further digging I found out that apps like Whatsapp, Skype, Insta, Zoom etc handle incoming calls and outgoing calls using something called callkit in iOS and ConnectionService in Android. Plugins already exist for this in flutter, namely callkeep and flutter_callkeep.

These plugins, when asked to show a call, mimic the exact behavior as a normal telecom call would, using the same notifications, showing the same UI. Each interaction, like accepting a call, rejecting a call, toggling loudspeaker, holding a call etc all have their callbacks. Seems pretty straightforward, right?

Callkeep couldn't keep up

There is a bug in both the packages.

The plugins are still a bit usable in Android Pie, but completely unusable in Android 10.

Why are we here, just to suffer?

Why are we here, just to suffer?

Take #3

A hacky solution (platform side code included).

Our pain problem with notification is that we can't have action buttons + time sensitive + full screen notifications together. We can all compensate for this by generating our own notification using platform channel.

The plan

    /// This code snippet is taken from flutter_local_notification plugin
    private static Intent getLaunchIntent(Context context) {
        String packageName = context.getPackageName();
        PackageManager packageManager = context.getPackageManager();
        return packageManager.getLaunchIntentForPackage(packageName);
    }

Same energy as our solution

Same energy as our solution

Take #4

What I feel is the legit solution!

Previously in the article I mentioned something about ConnectionService. This is the recommended way for any app that either

What both callkeep and flutter_callkeep plugins offered is system managed ConnectionService. What we need is self managed. The main issue here is resources, or lack thereof. The only resource I could find is this guide. There are not any tutorials/blogs about how to implement this. We can learn how to implement this by looking at some existing projects though, a good point is AgoraIO-Usercase/Video-Calling repository.

Getting this functionality all wrapped in a flutter plugin is the best solution we can manage with flutter in my opinion. What I believe personally though is that implementing it in native is the easiest way out. That way we do not have to worry about handling communication between native android and flutter.

Flutter is a cross-platform UI toolkit that is designed to allow code reuse across operating systems such as iOS and Android, while also allowing applications to interface directly with underlying platform services. - Flutter architectural overview

Google considers Flutter as a UI toolkit, and personally so do I. Sometimes we may have to implement some framework level functionalities(like handling telephony in this case) just so that we can show a call accept/reject screen in flutter. This can be pretty straightforward in native android. So the question lies with the developer, is it worth the effort?

'tis complicated

P.S - This article is everything I could find and make sense of while researching about this for 3 days straight. I decided to write this article because there are a lot of people on StackOverflow and Github Issues who do not have an answer to this question. While I have not been able to provide an answer, yet, I hope to make the question clearer.

I am not a pro developer, so if you find any discrepancies, feel free to comment, the whole point of this article to bring whatever little exists about this on the internet at a single place! Also, I'll be working on the plugin myself, I'll be updating the article with a link to the repo in some days.