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.

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. 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.

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

Not applicable

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);

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;
}

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 process.

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;                                      
}

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;
}

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.

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.

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);

Last modified: 2014-11-17



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

comments powered by Disqus