Not applicable
Sending invocation
An invocation message contains a target, an action, and data. To learn more about these parameters, see Invocation framework. You can configure your app to invoke target apps by using bound or unbound invocations.
You cannot invoke any UI apps or cards while your app is minimized or running as a headless app. These types of invocations work only if your app is running in the foreground.
If you're using Cascades, the InvokeManager class provides a convenient way to build invocations using C++. For core apps that you write in C, to send an invocation request, you must use the Navigator Invoke API functions.
Bound invocation
Bound invocation occurs when a client app explicitly identifies the target app to handle the invocation. The following image shows how a client app can use bound invocation to invoke a specific target app. In this case, Target app opens the document contained in the client app.

You can specify a target app's name by using the InvokeRequest class. For example, a client app that wants to open a .png file uses bound invocation to invoke a target app for viewing images.
Here's an example that shows how to send an invocation request:
InvokeManager invokeManager; InvokeRequest request; // Set the target app request.setTarget("com.example.image.view"); // Set the action that the target app should execute request.setAction("bb.action.OPEN"); // Set the MIME type of the data request.setMimeType("image/png"); // Specify the location of the data request.setUri(QUrl("file:///path/to/image.png")); InvokeTargetReply *reply = invokeManager.invoke(request);
You can specify a target app's name by using the navigator_invoke_invocation_set_target() function. To use this function, you must specify the target app's ID. For example, a client app that wants to open a .png file uses bound invocation to invoke a target app for viewing images.
Here's an example that shows how to send an invocation request:
/* Allocate a structure for the request */ navigator_invoke_invocation_t *iRequest = NULL; /* Create the request */ navigator_invoke_invocation_create(&iRequest); /* Set the action that the target app should execute */ navigator_invoke_invocation_set_action(iRequest, "bb.action.OPEN"); /* Set the target app */ navigator_invoke_invocation_set_target(iRequest,"com.example.MyTarget"); /* Send the request */ navigator_invoke_invocation_send(iRequest); /* Destroy the request structure when finished */ navigator_invoke_invocation_destroy(iRequest);
It's important to verify whether your invoke request is successful so that your app can respond appropriately.
Not applicable
You can connect to the finished() signal, which is emitted by InvokeTargetReply, and listen for the response:
... InvokeTargetReply reply) { // Remember to take ownership of the reply object reply->setParent(this); // Listen for the invoke response // by connecting to the finished() // signal bool connectResult; Q_UNUSED(connectResult); connectResult = QObject::connect(reply, SIGNAL(finished()), this, SLOT(onInvokeResult())); // This is only available in Debug builds Q_ASSERT(connectResult); // Store the reply somewhere, so you can // access it when onInvokeResult() is called _invokeTargetReply = reply; } // Because we connected this function to the finished() signal on the // reply object, this function will be called when the app // receives an invoke response void MyApp::onInvokeResult() { // Check for errors switch(_invokeTargetReply->error()) { // Invocation could not find the target; // did we use the right target ID? case InvokeReplyError::NoTarget: { cout << "invokeFinished(): Error: no target" << endl; break; } // There was a problem with the invocation request; // did we set all of the values correctly? case InvokeReplyError::BadRequest: { cout << "invokeFinished(): Error: bad request" << endl; break; } // Something went completely // wrong inside the invocation request, // so find an alternate route case InvokeReplyError::Internal: { cout << "invokeFinished(): Error: internal" << endl; break; } // Message received if the invocation request is successful default: cout << "invokeFinished(): Invoke Succeeded" << endl; break; } // Free the resources that were allocated for the reply delete _invokeTargetReply; }
You can decode the ID from a target app's response and retrieve the error from the event:
switch (bps_event_get_code(event)) { case NAVIGATOR_INVOKE_TARGET_RESULT: { const char *id = navigator_event_get_id(event); const char *err = navigator_event_get_err(event); } break; }
To determine if your request was successful, you can assign an identifier to your request and then monitor BlackBerry Platform Services (BPS) events for the response:
/* Set the identifier when setting up the request */ navigator_invoke_invocation_set_id(invoke, "1"); /* In the BPS event handler, event is the bps_event being handled */ if (bps_event_get_domain(event) == navigator_get_domain()) { /* Invoke responses are part of the navigator domain */ if (bps_event_get_code(event) == NAVIGATOR_INVOKE_TARGET_RESULT) { /* Compare the identifiers */ const char* id = navigator_event_get_id(event); if (id && strcmp(id, "1", strlen("1") == 0) { /* Check whether we had an error using navigator_event_get_err */ } } }
Target discovery
You can hard code the target app that you want to send an invocation message to, or you can query the invocation framework to find out what targets are installed on the BlackBerry device. The invocation framework uses a target filter to allow the target apps to declare the types of invocation they support. When a client app queries the invocation framework, the framework uses the target app's filter to describe the kind of target it is and the data it can accept.
The quality of the results depends on how specific the target query request is. A target query request should consist of the URI and MIME type. If the MIME type is omitted, the framework tries to determine the type using the URI.
A client app can include the action to be performed on the data in its target query request. If the action is not specified in the target query request, the query result will contain a list of all the actions that can be performed on the specified data by the available targets.
The invocation framework returns a query result that includes the targets grouped by the action that these targets support. For each target, the query result provides the target ID, the target type (an app or a card), and other information about the target, such as icons and labels, that can be used to display the target in the client app's screen.
To determine what targets are suitable candidates, the invocation framework applies a set of brokering rules. For more information, see Target selection and brokering.
Here's how you can search for targets that support the bb.action.OPEN action on image/png images, which are sent as a file:// URI:
Not applicable
InvokeManager invokeManager; InvokeQueryTargetsRequest request; // Find the targets that support bb.action.OPEN request.setAction("bb.action.OPEN"); // Find the targets that can handle image/png data request.setMimeType("image/png"); // Find the targets that are sent as a file from this path request.setUri(QUrl("file:///path/to/image.png")); InvokeQueryTargetsReply* results = invokeManager.queryTargets(request); if (results) { // Remember to take ownership of the results results->setParent(this); // Listen for the results QObject::connect(results, SIGNAL(finished()), this, SLOT(onQueryResponse())); // Store the reply so you can access the results // when onQueryResponse() is called _queryResults = results; }
/* Allocate a structure for the query */ navigator_invoke_query_t *iQuery = NULL; /* Create the query */ navigator_invoke_query_create(&iQuery); /* Set the query ID */ navigator_invoke_query_set_id(iQuery, "123"); /* Set the action that the target app should support */ navigator_invoke_query_set_action(iQuery, "bb.action.OPEN"); /* Set the MIME type */ navigator_invoke_query_set_type(iQuery, "image/png"); /* Send the query */ navigator_invoke_query_send(iQuery);
Make sure to handle the results of a query appropriately.
Not applicable
Q_SLOT void onQueryResponse() { switch(_queryResults->error()) { case InvokeReplyError::BadRequest: // Resolve the error break; case InvokeReplyError::Internal: // Resolve the error break; default: // If the error is resolved, proceed QList<InvokeAction> targetsByAction = _queryResults->actions(); for (int i = 0; i < targetsByAction.size(); i++) { // See the API documentation for the full set of action attributes QString actionName = targetsByAction[i].name(); QList<InvokeTarget> targets = targetsByAction[i].targets(); for (int j = 0; j < targets.size(); j++) { // See the API documentation for the full set of target attributes QString targetId = targets[j].name(); } } break; } // Free the resources that were allocated for the query delete _queryResults; }
switch (bps_event_get_code(event)) { case NAVIGATOR_INVOKE_QUERY_RESULT: { const char *id = navigator_event_get_id(event); /* Create integer holding the number of actions returned by the query */ int action_count = navigator_invoke_event_get_query_result_action_count(event); int i=0; /* Loop through all actions returned by the query */ for (; i < action_count; i++) { const navigator_invoke_query_result_action_t *action = navigator_invoke_event_get_query_result_action(event, i); /* Retrieve action attributes */ const char *name = navigator_invoke_query_result_action_get_name(action); const char *icon = navigator_invoke_query_result_action_get_icon(action); const char *label = navigator_invoke_query_result_action_get_label(action); /* Create integer holding the number of targets in the action */ int target_count = navigator_invoke_query_result_action_get_target_count(action); int j=0; /* Loop through all targets in the action */ for (; j < target_size; j++) { const navigator_invoke_query_result_target_t *target = navigator_invoke_query_result_action_get_target(action, j); /* Retrieve target attributes */ const char *target_key = navigator_invoke_query_result_target_get_key(target); const char *target_icon = navigator_invoke_query_result_target_get_icon(target); const char *target_splash = navigator_invoke_query_result_target_get_splash(target); const char *target_label = navigator_invoke_query_result_target_get_label(target); navigator_invoke_target_type_t target_type = navigator_invoke_query_result_target_get_type(target); navigator_invoke_perimeter_type_t perimeter = navigator_invoke_query_result_target_get_perimeter(target); } } } }
Unbound invocation
The invocation framework can make invoking a target app easy by removing the need to query. Instead of sending a target query request to determine the available targets, the client app can simply send an invocation request to the framework without specifying a target. This kind of invocation is called unbound invocation. If you send an unbound invocation request, the framework searches for and invokes a suitable target app for you.
The following image shows how a client app lets the invocation framework return the most suitable target app for a particular action. In this case, Target app is the most suitable app to open the document contained in the client app.

To find the best target app, the framework first uses a brokering process. It applies a set of rules to determine which target apps support the client app's invocation request. If there is more than one suitable target available, the framework applies a set of selection rules to choose the most appropriate target. For more information, see Target selection and brokering.
You can also send an invocation request without specifying an action. In this type of request, only the data is sent. The framework determines the type of target and the action to be performed.
If you don't specify an action, the invocation framework tries to find an appropriate target app for the bb.action.VIEW action. If no suitable target app is found for bb.action.VIEW, the invocation framework falls back to determine an appropriate target app that supports bb.action.OPEN. If still no suitable target app is available for bb.action.OPEN, the invoke request is unsuccessful.
Here's how you can create an unbound invocation request. The invocation framework invokes the most suitable target app to handle the image.png file, which is specified by the URI.
Not applicable
InvokeManager invokeManager; InvokeRequest request; // Set the URI request.setUri(QUrl("file:///path/to/image.png")); // Send the invocation request InvokeTargetReply *reply = invokeManager.invoke(request);
/* Allocate a structure for the request */ navigator_invoke_invocation_t *iRequest = NULL; /* Craete the request */ navigator_invoke_invocation_create(&iRequest); /* Set the action that the target app should execute */ navigator_invoke_invocation_set_action(iRequest, "bb.action.OPEN"); /* Set the MIME type */ navigator_invoke_invocation_set_type(iRequest, "image/png"); /* Set the URI */ navigator_invoke_invocation_set_uri(iRequest, "http:///www.mysite.com/myphoto.png"); /* Send the request */ navigator_invoke_invocation_send(iRequest); /* Destroy the request structure when finished */ navigator_invoke_invocation_destroy(iRequest);
Here's how you can decode the ID from a target's response and retrieve the error from the event:
switch (bps_event_get_code(event)) { case NAVIGATOR_INVOKE_TARGET_RESULT: { const char *id = navigator_event_get_id(event); const char *err = navigator_event_get_err(event); } break; }
Last modified: 2015-05-07