The type of app you can make will depend on the build library you select. If you are using the Node.js build, your app can run as a WebSocket server or as a TCP client. If you are using the vanilla JavaScript build (a minified JS file not tied to any specific build system or server structure), your app can run as a WebSocket client. This guide will cover topics that apply to both Node.js and vanilla JS library builds.
In order to correctly connect to an SDL enabled head unit, developers need to create an AppConfig
configuration object to pass into an instance of the SdlManager
class and then start it. This configuration object requires a LifecycleConfig
object which contains the majority of the settings you need to set in order for the app to function. You will want to use the following methods to get started: setAppId
, setAppName
, setLanguageDesired
, setAppTypes
, and setTransportConfig
. These configuration objects support method chaining, which allow you to create the following example configuration object:
const lifecycleConfig = new SDL.manager.LifecycleConfig() .setAppId('hello-js') .setAppName('Hello JS') .setLanguageDesired(SDL.rpc.enums.Language.EN_US) .setAppTypes([ SDL.rpc.enums.AppHMIType.DEFAULT, ]);
For WebEngine apps, most of this configuration will happen in the manifest.js
file and does not need to be duplicated here.
You have the ability to determine a minimum SDL protocol and minimum SDL RPC version that your app supports. You can also check the connected vehicle type and disconnect if the vehicle module is not supported. We recommend not setting these values until your app is ready for production. The OEMs you support will help you configure correct values during the application review process.
If a head unit is blocked by protocol version, your app icon will never appear on the head unit's screen. If you configure your app to block by RPC version, it will appear and then quickly disappear. So while blocking with minimumProtocolVersion
is preferable, minimumRpcVersion
allows you more granular control over which RPCs will be present.
lifecycleConfig.setMinimumProtocolVersion(new SDL.util.Version(3, 0, 0)); lifecycleConfig.setMinimumRpcVersion(new SDL.util.Version(4, 0, 0));
If you are blocking by vehicle type and you are connected over RPC v7.1+, your app icon will never appear on the head unit's screen. If you are connected over RPC v7.0 or below, it will appear and then quickly disappear. To implement this type of blocking, you need to set up the SDLManager. You will then implement the optional onSystemInfoReceived
method and return true
if you want to continue the connection and false
if you wish to disconnect.
The transport configuration will depend on the environment you're using. For example, you can make a TCP connection with Node.js, but not with vanilla JS. See below for example transport configurations.
lifecycleConfig.setTransportConfig(new SDL.transport.TcpClientConfig(HOST, PORT));
For a WebSocket server connection, the developer is expected to set up the server component, and pass in incoming client connections to the WebSocketServerConfig
. The ws
node module provides the necessary object to the config.
const WS = require('ws'); const PORT = 3000; // create a WebSocket Server const appWebSocketServer = new WS.Server({ port: PORT, }); console.log(`WebSocket Server listening on port ${PORT}`); appWebSocketServer.on('connection', (connection) => { // app setup goes here lifecycleConfig.setTransportConfig( new SDL.transport.WebSocketServerConfig( connection, CONNECTION_LOST_TIMEOUT // connection timeout in milliseconds (default is 60 seconds) ) ); });
lifecycleConfig.setTransportConfig(new SDL.transport.WebSocketClientConfig(HOST, PORT));
There are several additional basic configuration options to set up your app, like the app name and icon.
An app icon can be set in the LifecycleConfig
to automatically upload and set the icon image. Note that although the implementation of retrieving files are different between the JS browser and Node.js environments, the developer can use the same API in both cases, and the SDL library will cover the implementation details for the developer depending on which build they are using.
const filePath = './app_icon.png'; const file = new SDL.manager.file.filetypes.SdlFile() .setName('AppIcon') .setFilePath(filePath) .setType(SDL.rpc.enums.FileType.GRAPHIC_PNG) .setPersistent(true); lifecycleConfig.setAppIcon(file);
In this case, the code snippet expects there to be an app_icon.png
file present in the same directory for the app icon.
You can listen for specific events using the LifecycleConfig
's setRpcNotificationListeners
. The following example shows how to listen for HMI Status notifications. Additional listeners can be added for specific RPCs by using their corresponding FunctionID
in place of the OnHMIStatus
in the following example.
lifecycleConfig.setRpcNotificationListeners({ [SDL.rpc.enums.FunctionID.OnHMIStatus]: (onHmiStatus) => { // HMI Level updates const hmiLevel = onHmiStatus.getHmiLevel(); console.log("Current HMI Level: ", hmiLevel); } });
It is recommended to use this method over the SdlManager.addRpcListener
method for the OnHMIStatus
RPC, or any RPC Notifications that your app cannot afford to miss during the initial connection.
After creating the LifecycleConfig
, it can be set into the AppConfig
and then passed into the SdlManager
. The following snippet will set up the SdlManager
and start it up. A listener is attached to the manager listener to let you know when there is a connection and the managers are ready.
const appConfig = new SDL.manager.AppConfig() .setLifecycleConfig(lifecycleConfig); const managerListener = new SDL.manager.SdlManagerListener() .setOnStart((sdlManager) => { // managers are ready }) .setOnError((sdlManager, info) => { console.error('Error from SdlManagerListener: ', info); }) .setOnSystemInfoReceived((systemInfo) => { console.log(`Connected to system ${systemInfo}`); return true; }) .setManagerShouldUpdateLifecycleToLanguage((language, hmiLanguage) => { return new SDL.manager.lifecycle.LifecycleConfigurationUpdate(); }); const sdlManager = new SDL.manager.SdlManager(appConfig, managerListener) .start();
For WebEngine apps, there are slight modifications for integrating the library, such as importing the manifest file and passing it into the LifecycleConfig.loadManifest
method. Additionally, since the data for the connection information is part of the URL query, the WebSocketClientConfig
class requires no arguments, and the library will read the URL query values instead. The resulting index.html
may look something like this as a result:
<html> <head> <script src='./SDL.min.js'></script> </head> <body> <script type='module'> import sdl_manifest from './manifest.js'; const lifecycleConfig = new SDL.manager.LifecycleConfig() .loadManifest(sdl_manifest) .setLanguageDesired(SDL.rpc.enums.Language.EN_US); lifecycleConfig.setTransportConfig(new SDL.transport.WebSocketClientConfig()); lifecycleConfig.setRpcNotificationListeners({ [SDL.rpc.enums.FunctionID.OnHMIStatus]: (onHmiStatus) => { // HMI Level updates const hmiLevel = onHmiStatus.getHmiLevel(); console.log("Current HMI Level: ", hmiLevel); } }); const appConfig = new SDL.manager.AppConfig() .setLifecycleConfig(lifecycleConfig); const managerListener = new SDL.manager.SdlManagerListener() .setOnStart((sdlManager) => { // managers are ready }) .setOnError((sdlManager, info) => { console.error('Error from SdlManagerListener: ', info); }) .setOnSystemInfoReceived((systemInfo) => { console.log(`Connected to system ${systemInfo}`); return true; }) .setManagerShouldUpdateLifecycleToLanguage((language, hmiLanguage) => { return new SDL.manager.lifecycle.LifecycleConfigurationUpdate(); }); const sdlManager = new SDL.manager.SdlManager(appConfig, managerListener) .start(); </script> </body> </html>
You should now be able to connect to a head unit or emulator. For more guidance on connecting, see Connecting to an Infotainment System. To start building your app, learn about designing your interface. Please also review the best practices for building an SDL app.
View on GitHub.com