Integrating Android Intents in Flutter

Read about what Android intents are and how to integrate them in Flutter

Blog Cover Image
Moksh Mahajan

Moksh Mahajan

Calender

October 28, 2022

Android Intents

Intents are the means by which Android components communicate with one another. They’re message-passing mechanisms in Android that help various Android components talk to one another seamlessly.

Usecases

The three fundamental usecases of intents include:

  1. to trigger another activity
  2. to start a service
  3. to deliver a broadcast receiver

An Activity represents a single screen in a native android app. A Service is a non-UI component that performs operations in the background. A broadcast is a message that any app can receive. The system delivers various broadcasts for system events, such as when the system boots up or the device starts charging.

Types

1. Explicit intent

Here we mention explicitly the name of the android component, we want to trigger using the intent.

Intent secondActIntent= new Intent(MainActivity.this,ActivitySecond.class);
startActivity(secondActIntent);

2. Implicit intent

Here we don’t mention the name of the Android component (activity, service or broadcast receiver) that we intend to trigger explicitly.

Then how does the identification of the components that needs to be triggered happens?

The component that needs to be triggered is resolved through a concept called intent filter and this process is known as intent resolution.

Assume we have a component 1 which can be anything i.e. activity, service or broadcast receiver and we want to trigger component 2. In explicit event, component 1 explicitly mentions the component i.e component 2 that it wants to trigger.

But in the case of implicit intents, component 1 will broadcast a intent, then that intent is allowed to be handled by the android system. Through the intent filter, the android system finally identifies the other component that needs to be trigger.

Intent Resolution

Any component that needs to be triggered through the implicit intent has to declare a certain set of attributes to which it wants to respond. This is done through intent filters.

In the manifest.xml file, for the android component (which want to be triggered through implicit intent), we need to add an intent filter tag and this tag contains further three attributes i.e. action, category, and data.

Action: A string that specifies the generic action to perform (such as view or pick). Example,

ACTION_VIEW (when we have some information that an activity can show to the user, such as an address to view in a map app) ACTION_SEND: (when we have some data that the user can share through another app, such as an email app)

Category: A string containing additional information about the kind of component that should handle the intent. Example, CATEGORY_BROWSABLE: The target activity allows itself to be started by a web browser to display data referenced by a link, such as an image or an e-mail message.

Data: The type of data supplied is generally dictated by the intent's action. For example, if the action is ACTION_EDIT, the data should contain the URI of the document to edit.

This particular component (declared in the manifest file) with the intent filter will only respond if an intent happens in the application with the matching intent filter. When an intent is triggered its action, category and data are compared against declarations present in the intent filter.

A correct match follows these three rules:

  1. The action of the intent should match at least one of the actions present in the intent filter. This is because an intent filter can contain multiple action declarations.
  2. The category of the intent should match all the categories present in the intent filter
  3. The data of intent should match (event partially) with the data of the intent filter

What happens when there are multiple components with matching intent filters? App picker/chooser is shown as shown below intent-chooser

Passing the data

Intents are all about passing the data between de-coupled android components which are activities, services and broadcast receivers.Intent is a messaging passing mechanism as well as the message holder.

We can put any data inside the intent in a key-value pair and then pass it around to communicate that message to other components.

This is done through putExtra() method.

And for the component receiving the intent, we need to use getIntent() method and provide the key in order to receive the passed data.

Launching Intents in Flutter

An interesting this to know is that all these flutter plugins used for opening camera, gallery, file explorers, etc. internally use intents (for android platform) to trigger these activities like the image_picker and file_picker plugins.

Intents are a platform-specific concept and it only exists in an Android Environment. In order to communicate with platform-specific APIs in Flutter we have to make the use of Method Channels.

But luckily there’s a plugin that takes care of all the pain of dealing with Platform Channels for us and allows us to launch android intents from our flutter application. android_intent_plus is a plugin developed and maintained by the Flutter Community. This plugin allows Flutter apps to launch arbitrary intents when the platform is Android. If the plugin is invoked on some other platform, it will crash the app.

We can add the plugin to our project using the following command: flutter pub add android_intent_plus

As discussed previous section, creating an intent implicitly would require us to mention these three properties: action, category, and data. And for passing the data in the intent object (using putExtra() method for native Android code), here we can simply use the arguments field which expects a Map<String, dynamic>.

if (platform.isAndroid) {
 AndroidIntent intent = AndroidIntent(
     action: 'action_view',
     data: 'https://play.google.com/store/apps/details?'
         'id=com.google.android.apps.myapp',
     arguments: {'authAccount': currentUserEmail},
 );
 await intent.launch();
}

We can mention any string in the action parameter including the name of any custom class to be invoked. In case we want to use any standard android action, chances are that the string constant would not be available for that particular action. Flutter community recommends adding support for that in the plugin and using an action constant to refer to it. Some examples of constant action strings which are available in the plugin as of now are: 'action_view' translates to android.os.Intent.ACTION_VIEW 'action_location_source_settings' translates to android.settings.LOCATION_SOURCE_SETTINGS 'action_application_details_settings' translates to android.settings.ACTION_APPLICATION_DETAILS_SETTINGS

For the arguments parameter, the supported dart values with their corresponding android values are listed here: https://docs.flutter.dev/development/platform-integration/platform-channels#codec

For example, in order to launch the gmail app from your Flutter Application you can do something like this:

if (Platform.isAndroid) {
     const AndroidIntent intent = AndroidIntent(
         action: 'action_view',
         package: 'com.google.android.gm',
         data: 'mailto:test@gmail.com?subject=Issue');
     await intent.launch();
   }

So that’s all for triggering intents from your Flutter Application. But can we also trigger a Flutter Application from an externally broadcasted event? The answer to this question is: Yes, it can definitely be done. But that’s a topic for an incoming blog…