Expand Minimize Picture-in-picture Power Device Status Voice Recognition Skip Back Skip Forward Minus Plus Play Search
Internet Explorer alert
This browser is not recommended for use with smartdevicelink.com, and may not function properly. Upgrade to a different browser to guarantee support of all features.
close alert
To Top Created with Sketch. To Top
To Bottom Created with Sketch. To Bottom
JavaScript Suite Guides
Using App Services

Using App Services (RPC v5.1+)

App services is a powerful feature enabling both a new kind of vehicle-to-app communication and app-to-app communication via SDL.

App services are used to publish navigation, weather and media data (such as temperature, navigation waypoints, or the current playlist name). This data can then be used by both the vehicle head unit and, if the publisher of the app service desires, other SDL apps. Creating an app service is covered in another guide.

Vehicle head units may use these services in various ways. One app service for each type will be the "active" service to the module. For media, for example, this will be the media app that the user is currently using or listening to. For navigation, it would be a navigation app that the user is using to navigate. For weather, it may be the last used weather app, or a user-selected default. The system may then use that service's data to perform various actions (such as navigating to an address with the active service or to display the temperature as provided from the active weather service).

An SDL app can also subscribe to a published app service. Once subscribed, the app will be sent the new data when the app service publisher updates its data. This guide will cover subscribing to a service. Subscribed apps can also send certain RPCs and generic URI-based actions (see the section Sending an Action to a Service Provider, below) to your service.

Currently, there is no high-level API support for using an app service, so you will have to use raw RPCs for all app service related APIs.

Getting and Subscribing to Services

Once your app has connected to the head unit, you will first want to be notified of all available services and updates to the metadata of all services on the head unit. Second, you will narrow down your app to subscribe to an individual app service and subscribe to its data. Third, you may want to interact with that service through RPCs, or fourth, through service actions.

1. Getting and Subscribing to Available Services

To get information on all services published on the system, as well as on changes to published services, you will use the SystemCapabilityManager.

// Grab the capability once
const servicesCapabilities = await sdlManager.getSystemCapabilityManager().updateCapability(SDL.rpc.enums.SystemCapabilityType.APP_SERVICES);

...

// Subscribe to updates
sdlManager.getSystemCapabilityManager().addOnSystemCapabilityListener(SDL.rpc.enums.SystemCapabilityType.APP_SERVICES, (servicesCapabilities) => {

});

Checking the App Service Capability

Once you've retrieved the initial list of app service capabilities or an updated list of app service capabilities, you may want to inspect the data to find what you are looking for. Below is example code with comments explaining what each part of the app service capability is used for.

// This array contains all currently available app services on the system
const appServices = servicesCapabilities.getAppServices();

if (appServices !== null) {
    appServices.forEach(anAppServiceCapability => {
        // This will tell you why a service is in the list of updates
        const updateReason = anAppServiceCapability.getUpdateReason();
        // The app service record will give you access to a service's generated id, which can be used to address the service directly (see below), it's manifest, used to see what data it supports, whether or not the service is published (it always will be here), and whether or not the service is the active service for its service type (only one service can be active for each type)
        const serviceRecord = anAppServiceCapability.getUpdatedAppServiceRecord();
    });
}

2. Getting and Subscribing to a Service Type's Data

Once you have information about all of the services available, you may want to view or subscribe to a service type's data. To do so, you will use the GetAppServiceData RPC.

Note that you will currently only be able to get data for the active service of the service type. You can attempt to make another service the active service by using the PerformAppServiceInteraction RPC, discussed below in Sending an Action to a Service Provider.

// sdl_javascript_suite v1.1+
// Get service data once
const getAppServiceData = new SDL.rpc.messages.GetAppServiceData()
    .setServiceType(SDL.rpc.enums.AppServiceType.MEDIA);

// Subscribe to future updates if you want them
getAppServiceData.setSubscribe(true);

const response = await sdlManager.sendRpcResolve(getAppServiceData);
if (response !== null && response.getSuccess()) {
    const mediaServiceData = response.getServiceData().getMediaServiceData();
}
...

// Unsubscribe from updates
const unsubscribeServiceData = new SDL.rpc.messages.GetAppServiceData(SDL.rpc.enums.AppServiceType.MEDIA);
unsubscribeServiceData.setSubscribe(false);

sdlManager.sendRpcResolve(unsubscribeServiceData);
// thrown exceptions should be caught by a parent function via .catch()


// Pre sdl_javascript_suite v1.1
// Get service data once
const getAppServiceData = new SDL.rpc.messages.GetAppServiceData()
    .setServiceType(SDL.rpc.enums.AppServiceType.MEDIA);

// Subscribe to future updates if you want them
getAppServiceData.setSubscribe(true);

const response = await sdlManager.sendRpc(getAppServiceData).catch(error => error);
if (response !== null && response.getSuccess()) {
    const mediaServiceData = response.getServiceData().getMediaServiceData();
}
...

// Unsubscribe from updates
const unsubscribeServiceData = new SDL.rpc.messages.GetAppServiceData(SDL.rpc.enums.AppServiceType.MEDIA);
unsubscribeServiceData.setSubscribe(false);

sdlManager.sendRpc(unsubscribeServiceData);

Interacting with a Service Provider

Once you have a service's data, you may want to interact with a service provider by sending RPCs or actions.

3. Sending RPCs to a Service Provider

Only certain RPCs are available to be passed to the service provider based on their service type. See the Creating an App Service guide Supporting Service RPCs and Actions section for a chart detailing which RPCs work with which service types. The RPC can only be sent to the active service of a specific service type, not to any inactive service.

Sending an RPC works exactly the same as if you were sending the RPC to the head unit system. The head unit will simply route your RPC to the appropriate app automatically.

Note

Your app may need special permissions to use the RPCs that route to app service providers.

const buttonPress = new SDL.rpc.messages.ButtonPress()
    .setButtonPressMode(SDL.rpc.enums.ButtonPressMode.SHORT)
    .setButtonName(SDL.rpc.enums.ButtonName.OK)
    .setModuleType(SDL.rpc.enums.ModuleType.AUDIO);

// sdl_javascript_suite v1.1+
const response = await sdlManager.sendRpcResolve(buttonPress);
// thrown exceptions should be caught by a parent function via .catch()

// Pre sdl_javascript_suite v1.1
const response = await sdlManager.sendRpc(buttonPress).catch(error => error);

4. Sending an Action to a Service Provider

Actions are generic URI-based strings sent to any app service (active or not). You can also use actions to request to the system that they make the service the active service for that service type. Service actions are schema-less, i.e. there is no way to define the appropriate URIs through SDL. The service provider must document their list of available actions elsewhere (such as their website).

const performAppServiceInteraction = new SDL.rpc.messages.PerformAppServiceInteraction()
    .setServiceUri("sdlexample://x-callback-url/showText?x-source=MyApp&text=My%20Custom%20String")
    .setServiceID(previousServiceId)
    .setOriginApp(appId);

// sdl_javascript_suite v1.1+
const response = await sdlManager.sendRpcResolve(performAppServiceInteraction);
// thrown exceptions should be caught by a parent function via .catch()

// Pre sdl_javascript_suite v1.1
const response = await sdlManager.sendRpc(performAppServiceInteraction).catch(error => error);

5. Getting a File from a Service Provider

In some cases, a service may upload an image that can then be retrieved from the module. First, you will need to get the image name from the AppServiceData (see point 2 above). Then you will use the image name to retrieve the image data.

// sdl_javascript_suite v1.1+
const weatherServiceData = appServiceData.getWeatherServiceData();

if (weatherServiceData === null || weatherServiceData.getCurrentForecast() === null || weatherServiceData.getCurrentForecast().getWeatherIcon() === null) {
    // The image doesn't exist, exit early
    return;
}
const currentForecastImageName = weatherServiceData.getCurrentForecast().getWeatherIcon().getValueParam();

const getFile = new SDL.rpc.messages.GetFile()
    .setFileName(currentForecastImageName)
    .setAppServiceId(serviceId);

const getFileResponse = await sdlManager.sendRpcResolve(getFile);
const fileData = getFileResponse.getBulkData();
const sdlArtwork = new SDL.manager.file.filetypes.SdlArtwork(fileName, FileType.GRAPHIC_PNG, fileData, false);
// Use the sdlArtwork 
// thrown exceptions should be caught by a parent function via .catch()


// Pre sdl_javascript_suite v1.1
const weatherServiceData = appServiceData.getWeatherServiceData();

if (weatherServiceData === null || weatherServiceData.getCurrentForecast() === null || weatherServiceData.getCurrentForecast().getWeatherIcon() === null) {
    // The image doesn't exist, exit early
    return;
}
const currentForecastImageName = weatherServiceData.getCurrentForecast().getWeatherIcon().getValueParam();

const getFile = new SDL.rpc.messages.GetFile()
    .setFileName(currentForecastImageName)
    .setAppServiceId(serviceId);

const getFileResponse = await sdlManager.sendRpc(getFile).catch(error => error);
const fileData = getFileResponse.getBulkData();
const sdlArtwork = new SDL.manager.file.filetypes.SdlArtwork(fileName, FileType.GRAPHIC_PNG, fileData, false);
// Use the sdlArtwork 
View on GitHub.com
Previous Section Next Section