on
Using intents to leave the app
In an iOS application, we often have to redirect the user outside of the application for a variety of reasons: calling a number, sharing content, writing an email, etc.
UIKit comes with a number of built in ways to perform these actions but there is not an unified method to do it. And sometimes you even want to use third party schemes instead of native ones (using Google Maps instead of Maps for instance).
Let’s see with a few examples how we could hide this logic into more abstract types and simplify the calling site.
Let’s say we want to display the user a mail compose sheet. Thanks to the documentation, the right class to use is MFMailComposeViewController
.
Use this view controller to display a standard email interface inside your app.
The detail here is that MFMailComposeViewController
is a class of the MessageUI
framework. And this detail bothers me because I try to keep the imported frameworks to the minimum. I don’t want to import MessageUI
in my view controller class, and rather hide implementation details.
A solution in this case is to use the MFMailComposeViewController
in a specific object that will not be visible to the external world.
For this, let’s borrow the intent naming of Android developers and create a MailIntent
that will be used by the sender to inform its intent to display a mail interface, but without knowing how.
The caller can use it like so:
The implementation of MailIntent
can import MessageUI
and use MFMailComposeViewController
. All the MessageUI
code is constrained into this class. That also means we can use the intent in different places in the application, the display of the mail interface will always be the same and we won’t have to repeat ourselves.
That also means that if we want to change the way we send an email, it’s simple. For example if we choose to redirect the user to the Mail app instead of opening a compose sheet, we could just rewrite the mail(to:)
function like so:
What’s more, we all know that MFMailComposeViewController
is not working on simulator. That means we can’t be sure our actions that display the compose sheet are well implemented when we test on simulator (either manually or with UI tests). In this case we can create a dummy implementation of MailIntent
that will just display an alert controller with the recipient as the message.
Map
We can apply the same technique for opening map items into Maps application and hide the import of the MapKit
framework.
The implementation will be:
What’s interesting in this case is that we can create another implementation for Google Maps, a third party application.
Phone Call
Even if there is no framework to hide in this case, the naming of the intent makes things very convenient to use.
The implementation will be:
In this case we directly call the provided number, but we could imagine passing a view controller to the native intent, and display an alert before calling.
Conclusion
This simple technique allows two things:
- hide the implementation details of the intent (import of frameworks) and keep things simple in the caller site
- easily reuse the same intent in different places