The Intent API class allows your app to communicate with other apps on the device. With this API, you’ll be able to communicate between two RhoMobile applications as well as between RhoMobile and a native application.
To us this class, you should first read up on the Intent API in our API docs so that the concepts mentioned here are more familiar.
Before we start sending or receiving intents, we first need to answer the question, “What are intents?”. Intents are a mechanism setup and used by the Android operating system that allow application components to request functionality from other Android components. Intents allow you to interact with components from the same application as well as with components contributed by other applications.
On other platforms, like iOS, there are concepts like URL Schemes. Although URL Schemes have been supported by RhoMobile, this approach practically only allows launching of other applications and services and has some limitations. Intents, however, allow for a more robust cross-application communication that allows passing of data objects as well as two-way communication.
When we talk about “sending” or “receiving” an intent, we are referring to the action of sending an object to the OS that can be interpreted by the OS and turned into a native device command. For instance, if we send an intent with the “uri” of “geo:37.422, -122.084”, the Android OS knows to launch it’s default maps app (since we did not specify an appName), and pinpoint Google’s Mountain View headquarters. This is useful since we don’t want to have to write our own mapping program that may not be as good as Google’s provided mapping app.
Another example, may be where you want something returned by the secondary application like when you want to take a picture or choose one from the gallery. This allows the application developer some freedom in not having to write code to handle this task. It is possible that the device has multiple applications with different abilities to take pictures and in that case the user would be presented with a choice to pick one.
When it comes to having multiple RhoMobile applications running on a device, you may want to write a core service apps that listens for intents from secondary apps. This approach may be more efficient in managing your applications instead of replicating this code in all of the applications.
You can also read up on intents on Google’s Android docs regarding intents.
As you may have gleaned from our Intent API docs, there are only three methods available:
This is basically because you are either sending an intent or receiving one. Since Intents involve multiple applications, you need to first decide what role your RhoMobile application is going to participate as. Does your application need to send an Intent to another RhoMobile application? Does it need to send an Intent to a common Android native application? Does it expect any information back from the Intent or are you trying to just launch an application or service? Maybe you want your application to enable listening in order to respond to Intents from other applications. Understanding the required configuration between the two sides is crucial in getting the expected behavior you are looking for.
Applications register for receiving events typically by a combination of multiple parameters:
EXTRAS
)If you don’t know the right combination of parameters, then your Intent will never be received. Let’s use a simple example, the one listed above regarding sending a GeoLocation coordinate to the maps app. For Android, I would check the Android docs to see that an action
and data-uri
are the only components that are required.
When the Android docs reference a constant, we will need to use the actual string that it refers. For example, when the Android docs show “ACTION_VIEW”, we need to instead use
"android.intent.action.VIEW"
, which can be retrieved by clicking on the constant name in the Android docs.
Now that we know the different pieces we’ll need, let’s put the intent together. These are the parameters that we need to send to open the maps app and plot the location of Google’s Mountain View HQ.
Now that we have these, we simply need to put them into a hash and use the Rho Intent API method Intent.send()
to send the intent. This api takes two parameters. The first one is an object that represents the intent options that the intent receiver application is expecting. The second optional parameter is a callbackhandler for Intent call. In our example, we have chosen to not handle a callback.
def send_geo intent_params = { :action => "android.intent.action.VIEW", :intentType => Rho::Intent::START_ACTIVITY, :uri => "geo:37.422, -122.084" } Rho::Intent.send intent_params end
function sendGeo(){ var intentParams = {action : "android.intent.action.VIEW", intentType : Rho.Intent.START_ACTIVITY, uri : "geo:37.422, -122.084"}; Rho.Intent.send(intentParams); }
This intent will send the string “geo:37.422, -122.084” to the Android OS and request that it start the activity that handles geolocation coordinates. If there are multiple different apps on the device that provide geolocation services, an app chooser will pop up asking the user to choose which app they want to open the coordinates in.
The response that will be sent from the intent will be the same as the data that was sent from the intent that is sent. For instance, if you send intent Parameters that contain an extra called dataFromSender defined as such { data => { dataFromSender => "Example Data" } }
, you would access this data using the following syntax:
def callback Alert.popup @params['data']['dataFromSender'] end
function callback(){ alert(params['data']['dataFromSender']); }
Ok, we can send intents, great! But what if what you want to do is send an intent to another one of your apps, or receive an intent from another app? We can also use the Rho Intent API for this but it requires a bit more work than the sending did.
There are a few things we need to do to receive an intent:
When an app is installed on an Android device, it’s Android manifest gets registered with the OS so that the OS knows whether or not the app is going to accept incoming intents. We need to make sure that our app’s Android manifest is formatted correctly to let our app receive intents. The AndroidManifest.erb is held in the root directory of your app’s project.
This was handled differently prior to version 4.1 - Any application project that was created prior to 4.1, should manually add a file called `AndroidManifext.erb` in the root of the project as well as add an entry to your `build.yml` file `android: manifest_template: 'AndroidManifest.erb'`. If you create a new project using RhoStudio's application wizard, you will see this performed automatically. |
This is what our intent-filter will look like to receive a simple, plain text, intent from another app:
<app_root/AndroidManifest.erb>
:::xml
Let’s explain a few of the items here:
receiver android:name
This should always say com.rho.intent.IntentReceiver
. For Android, we are basically setting up a Broadcast Receiver that will receive any intents that are sent as a broadcast
.
intent-filter
action android:name
- This is the intent action that our app will expect from intents the it receives.category android:name
- This is the category of intents that our app will expect. A value of default will accept all categoriesdata android:mimeType
- This is the data type that our app will be expecting to handle in intents that it receives.
For Android, this is common syntax for an [intent-filter element].(http://developer.android.com/guide/topics/manifest/intent-filter-element.html). Also, We could have easily used any custom string that we wanted for our
action
and category
fields. By using standard Android strings, our application will be presented as a choice when another app uses the same signature for sending an intent.
Now, before we can start sending intents to this app, we need to add some code that will allow us to tell the app to start listening for intents. We do this with the Rho Intent API method Intent.startListening()
.
def start_listening Rho::Intent.startListening "/app/Intent/listening_for_intent_callback" end
You can see here that we have specified a callback handler but we have not yet defined the callback handler, we'll do that next.
Rho.Intent.startListening(function(params){ // Your callback code here console.log(params.responseCode); });
You can see here that we have specified a callback handler and defined the callback handler in an anonymous function. All that's left is to fill in the code to handle the callback, we'll do that next.
We can now receive intents but, without a callback handler, receiving an intent is meaningless.
def listening_for_intent_callback Rho::Notification.showPopup({ :message => @params['data']['dataFromSender'], :title => "Alert!", :buttons => ["ok"] }) puts @params.responseCode end
Rho.Intent.startListening(function(params){ alert(params['data']['dataFromSender']); console.log(params.responseCode); });
All we are doing with the received data is showing a pop-up with the data that is passed in through the uri
parameter.
With these pieces complete, we should be able to compile an intent to send to this app and display the data that we send.
From whatever other app you want to send an intent to this app, you must construct an intent to send to it. When creating the intent to send to the intent receiver, you must make sure the sent intent’s parameters match the parameters that the intent receiver is looking for. In our case, we need to make sure we use a SEND action, some data with the text/plain mimeType, and use the DEFAULT category. We will also use a BROADCAST intentType.
def send_intent intent_params = { :action => "android.intent.action.SEND", :intentType => Rho::Intent::BROADCAST, :data => { "android.intent.extra.TEXT" => "Text to send to receiving app." }, :mimeType => "text/plain", :categories => "android.intent.category.DEFAULT" } Rho::Intent.send intent_params end
function sendIntent(){ var intentParams = {action : "android.intent.action.SEND", intentType : Rho.Intent.BROADCAST, data : { "android.intent.extra.TEXT" : "Text to send to receiving app." }, mimeType : "text/plain", categories : "android.intent.category.DEFAULT"} Rho.Intent.send(intentParams); }
public void sendIntent() { Intent intentRho = new Intent("android.intent.action.SEND"); intentRho.addCategory("android.intent.category.DEFAULT"); intentRho.setType("text/plain"); intentRho.putExtra("android.intent.extra.TEXT": "Text to send to receiving app."); sendBroadcast(intentRho); }