Sending invocation

An invocation message contains a target, an action, and data. To learn more about these parameters, see Invocation framework.

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() function.

Bound invocation

Bound invocation occurs when a client app explicitly identifies the target app to handle the invocation.

Not applicable

You can specify a target app's name in the target parameter of InvokeRequest class. For example, a client app that wants to open a .png file invokes a target app for viewing images using the bound invocation.

The following image shows how a client app can use a bound invocation to invoke a specific target app. In this case, Target app opens the document contained in the client app.

Diagram showing how a client app can use the bound invocation to invoke a target app of its choice

Here's an example that shows how to send an invocation request:

Not applicable

InvokeManager invokeManager;
InvokeRequest request;
// Who do we want to send the invoke request to?
request.setTarget("com.example.image.view"); 
// What do we want the target application to do with it?
request.setAction("bb.action.OPEN");
// What are we sending?         
request.setMimeType("image/png");
// Where is the data?            
request.setUri(QUrl("file:///path/to/image.png"));  
InvokeTargetReply *reply = invokeManager.invoke(request);

To verify whether your invoke request is successful, you can:

Not applicable

Connect to the finished() signal 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.  
    
    // If any Q_ASSERT statement(s) indicate that the slot failed to connect to 
    // the signal, make sure you know exactly why this has happened. This is not
    // normal, and will cause your app to stop working!!
    bool connectResult;
    
    // Since the variable is not used in the app, this is added to avoid a 
    // compiler warning.
    Q_UNUSED(connectResult);
    
    connectResult =  QObject::connect(reply, SIGNAL(finished()), 
                                      this,  SLOT(onInvokeResult()));

    // This is only available in Debug builds.
     Q_ASSERT(connectResult);
     
    // Store reply somewhere, so you can 
    // access it when onInvokeResult fires.
    _invokeTargetReply = reply;    
}


// Because we connected this method to the finished() SIGNAL on the 
// reply object, this method will be called when the application
// 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 invoke request
        // did we set all the values correctly?
    case InvokeReplyError::BadRequest: {
            cout << "invokeFinished(): Error: bad request" << endl;
            break;
        }
        // Something went completely 
        // wrong inside the invocation request 
        // Find an alternate route :(
    case InvokeReplyError::Internal: {
            cout << "invokeFinished(): Error: internal" << endl;
            break;
        }
        //Message received if the invoke request is successful
    default:
        cout << "invokeFinished(): Invoke Succeeded" << endl;
        break;
    }

    // A little house keeping never hurts...
    delete _invokeTargetReply;
}

Target discovery

You can hard code the target application 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 the client app is looking for and the data it has to offer.

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 left out, 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 process.

The following code sample demonstrates a target query request in which a client app searches 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()));  
// Best to store the reply
// so you can access the results when onQueryResponse fires
_queryResults = results;                                      
}

Here's how you can handle the results:

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..
     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;
   }
  // Clean up the results
  delete _queryResults; 

Unbound invocation

The invocation framework can make invoking a target application 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, the framework searches for and invokes a suitable target app for you.

The following image shows how a client app (App 1) lets the invocation framework return the most suitable target app for a particular action. In this case, App 2 is the most suitable app to open the document contained in the client app.

Diagram showing how a client app lets the invocation framework return the most suitable target app for a particular action.

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.

The following code sample shows how you can create an unbound invocation request. The sample code 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 invoke 
InvokeTargetReply *reply = invokeManager.invoke(request);       

Last modified: 2014-09-30



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus