Webportal

emmbedded apps

Quick Start

    ACCESS DATA #

    The API will allow you to do the following:

    • Car: Get information about the vehicle: VIN code, Fuel type, unit and level, Current speed and unit, Mileage and distance unit, Autonomy, level of battery and fuel, the driving state, the time,
    • Connectivity: Detect the connectivity status
    • Device: Request a popup, get hardware and software version of the system,
    • HMI: Information on the user, UIN, language, country,
    • Media: Information on the media: album name, artist name, current track, state of the media, type of media
    • Navigation: Get the current position info, destination info, maneuver info, journey info, waypoint info, start new journey,
    • Phone: Launch phone call,
    • Privacy: Manage privacy mode of user
    • Radio: Information on the radio: frequency, preset…
    • System: Settings action reserved to administrative use
    • Webportal: All the events associated to user interaction or due to server

    GETTING STARTED #

    You will need to contact PSA Team in order to become a partner and deploy your apps on the Webportal so you should start by doing so. The team will also be able to help you with questions you might have.

    This tutorial will guide you through the creation of your Application. You can also start by downloading the base of your application directly.

    HTML

    The HTML part of your project is conventional, you create your objects and static content.

    <!-- STYLES -->
    <link rel="stylesheet" type="text/css" href="css/main.css">
    <!-- SCRIPTS -->
    <script type="text/javascript" src="../test/shared/libs/jquery/1.10.0/jquery.js"></script>
    <script type="text/javascript" src="js/main.js"></script>
    
    <div id="mainContainer">
        Hello World!
    </div>
    

    Be carefull: your app is a single page application. It mean that you must have only one html file (‘index.html’) in your project.

    CSS

    You can customize your CSS stylesheet, here is simply an example changing the color of the text displayed.

    //Your normal css file
    #mainContainer {
        color: blue;
    }
    

    JS

    Here you have the required JS for your application to function properly. You can add the functions you need to handle other events.

    //On document ready
    document.addEventListener("DOMContentLoaded", function(event) {
    
        // Inform the parent window (applications portal) that the application is
        // loaded and ready
        window.parent.postMessage({
            'type' : 'WebPortal.onApplicationLoaded'
        }, '*');
    });
    

    APP STRUCTURE #

    This is the file structure your application should use.

    Once development is finish, you have to submit your application to PSA for us to check its behavior before actually deploying it. The structure of the file to submit is mostly free with some requirements:

    • The files must be sent in a TAR archive compressed via GZIP
    • The .md5 file is required in order to perform an integrity check
    • An index.html file must be present at the root of the project and is the starting point of the application
    • The logo for the application: icon-100x100.png (15kB max) and icon-136x136.png (21kB max) must be present at the root of the project for the different screen sizes (respectively for SD devices and WHD devices).
    • JavaScript functions must be executed when the DOM is ready
    • It is required to add a version file in the root directory of the app, named info.json and containing the following information:
    {
      "artifactId": "appid",
      "name": "appname (optional)",
      "description": "appdescription (optional)",
      "version": "X.Y.Z",
      "buildDate": "YYYY-MM-DD HH:mm"
    }
    

    In addition to the package submitted, the following information must be provided separately:

    • App name (translated if needed) The partner must provide at least one name for its app, that can be translated into several languages if needed. The master name will be displayed if no translation was given for the language chosen by the user.
    • Country scope The partner must provide the list of countries where the app can be activated for customers, within the list of countries where the WebPortal is available.
    • Brand scope The partner must provide the list of brands for which the app can be activated for customers. Today, Peugeot, Citroën, DS, Opel and Vauxhall are available.
    • Device scope The partner must provide the list of devices and configurations where the app can be activated for customers. Today NACw2.1, NACw3.1 and NACw4 are available.
    • App identifier To be given by PSA, this App Id is mandatory as it enables us to identify the app in MQTT exchanges and in the process of display in the vehicles.
    • MQTT partner account

    DEBUG CONSOLE #

    There is no native debug console within webportal therefore, you cannot access execution errors in your code. However, we advise setting up a debug console inside own your app during your development process.

    This is an example of debug console that you can display inside your app:

    HTML
    <div id="debug-console">
    </div>
    
    JavaScript
    try {
      document.getElementById(kk);
    } 
    catch (error) {
      var debugConsole = document.getElementById('debug-console'); 
      debugConsole.innerHTML = error;
    }
    
    CSS
    #debug-console {
      border: 1px solid red;
    }
    

    Doing so, errors will be displayed inside your app as HTML.

    VIRTUAL KEYBOARD #

    A virtual keyboard is available on the NAC. It is displayed on the full size of the NAC touchscreen.

    virtualKeyboard

    You just have to create an HTML input text, once the user set the focus on this text field the virtual keyboard is displayed.

    <input type="text" />
    <!-- Focus the field and the keyboard is diplayed -->
    

    Note: When the keyboard is being displayed, you cannot receive events.

    Note 2: Before WAVE4: 42.03.06.50 / WAVE 2: 21.08.63.40, pre-filled text was deleted once the user set the focus in the input field. Since these versions, webportal’s virtual keyboard acts like modern webrowsers as it keeps pre-filled text in the input when the user set the focus in it.


    WEBPORTAL EVENTS #

    The WebPortal will forward events to your application in order to be informed about the current state of both the App and the Portal.

    STRUCTURE OF A WEBPORTAL MESSAGE

    {
    	/**
    		* @type {string}
    		*/
    	"type": "WebPortal.onCurrentNotificationReceived",
    
    	/**
    		* Only present when type=WebPortal.onCurrentNotificationReceived
    		* Contains the payload of the MQTT message
    		*/
    	"value": {}
    }
    

    HANDLING THE EVENT MESSAGES

    To deal with these events you will need to implement event listeners and call the functions you need in each case. Below is an example on how to manage them.

    //Global messages listeners
    window.addEventListener("message", function(event){
    
    	var data = event.data;
    	var type = event.data.type;
    
    	switch(type){
    
    	//When the application is killed or reloaded via an update
    	case "WebPortal.onApplicationUnloaded":
    	console.log("The application will be killed, it's time to save your application data");
    	alert("The application will be killed, it's time to save your application data");
    	break;
    
    	//When a notification is pushed to the application
    	case "WebPortal.onCurrentNotificationReceived":
    	if (typeof data.value !== 'undefined'){
    		console.log("Notification received",data.value);
    		if (typeof data.value === 'object'){
    		alert("Notification received: "+JSON.stringify(data.value));
    		} else {
    		alert("Notification received: "+data.value);
    		}
    	}
    	break;
    	}
    });
    

    We will now see how to handle the main events.


    CONNECTIVITY MODE #

    It is important to handle changes in the connectivity mode in order to inform the user of any connectivity issue or even to change the behavior of your application.

    Connectivity.addEventListener("connectivityOn", function(){
    	console.log("success, " + "Connectivity.connectivityOn()");
    });
    Connectivity.addEventListener("connectivityOff", function(){
    	console.log("success, " + "Connectivity.connectivityOff()");
    });
    


    PRIVACY MODE #

    For every app it is also mandatory to handle the privacy mode of the user.

    The user can select one of 3 modes:

    • Public, you can access both the internet and the geolocation of the user
    • Geoloc, you can only access the internet as the geolocation is locked
    • Full, you can access neither the internet nor the geolocation
    if ((typeof Privacy !== "undefined") && (typeof Privacy.addEventListener !== "undefined")) {
    	Privacy.addEventListener("ModePublic", function(){
    		console.log("success, " + "Privacy.ModePublic()");
    	});
    	Privacy.addEventListener("ModeFull", function(){
    		console.log("success, " + "Privacy.ModeFull()");
    	});
    	Privacy.addEventListener("ModeGeoloc", function(){
    		console.log("success, " + "Privacy.ModeGeoloc()");
    	});
    }
    

    Some functionnalities will be unavailable in Geoloc or Full privacy mode.

    WHEN Privacy.Mode()=Full

    The following methods return undefined:

    • Car.GetVINCode()
    • Car.GetSpeed()
    • Navigation.GetCurrentPositionLatitude()
    • Navigation.GetCurrentPositionLongitude()
    • Navigation.CurrentPosition.Altitude
    • Navigation.GetCurrentPosition()
    • Navigation.CurrentPosition.Address
    • Navigation.CurrentPosition.Town
    • Navigation.CurrentPosition.City
    • Navigation.CurrentPosition.Province
    • Navigation.CurrentPosition.Coutry
    • Navigation.GetDestination()
    • Navigation.Destination.Latitude
    • Navigation.Destination.Longitude
    • Navigation.Destination.Address
    • Navigation.Destination.Town
    • Navigation.Destination.City
    • Navigation.Destination.Province
    • Navigation.Destination.Coutry
    • Navigation.GetManeuverInfo()
    • Navigation.ManeuverInfo.Latitude
    • Navigation.ManeuverInfo.Longitude
    • Navigation.ManeuverInfo.nextStreetName
    • Navigation.ManeuverInfo.Town
    • Navigation.ManeuverInfo.City
    • Navigation.ManeuverInfo.Province
    • Navigation.ManeuverInfo.Country
    • Navigation.GetJourneyInfo()
    • Navigation.JourneyInfo.estimatedTimeOfArrivalH
    • Navigation.JourneyInfo.estimatedTimeOfArrivalMin
    • Navigation.GetNextWaypoint.ETAHours()
    • Navigation.GetNextWaypoint.ETAMinutes()

    These methods won’t do anything and return false:

    • Navigation.LaunchGuidance()
    • Navigation.LaunchGuidanceWaypoint()

    WHEN Privacy.Mode()=geoloc

    The following methods return undefined:

    • Navigation.GetCurrentPositionLatitude()
    • Navigation.GetCurrentPositionLongitude()
    • Navigation.CurrentPosition.Altitude
    • Navigation.GetCurrentPosition()
    • Navigation.CurrentPosition.Address
    • Navigation.CurrentPosition.Town
    • Navigation.CurrentPosition.City
    • Navigation.CurrentPosition.Province
    • Navigation.CurrentPosition.Coutry
    • Navigation.GetDestination()
    • Navigation.Destination.Latitude
    • Navigation.Destination.Longitude
    • Navigation.Destination.Address
    • Navigation.Destination.Town
    • Navigation.Destination.City
    • Navigation.Destination.Province
    • Navigation.Destination.Coutry
    • Navigation.GetManeuverInfo()
    • Navigation.ManeuverInfo.Latitude
    • Navigation.ManeuverInfo.Longitude
    • Navigation.ManeuverInfo.nextStreetName
    • Navigation.ManeuverInfo.Town
    • Navigation.ManeuverInfo.City
    • Navigation.ManeuverInfo.Province
    • Navigation.ManeuverInfo.Country
    • Navigation.GetJourneyInfo()
    • Navigation.JourneyInfo.estimatedTimeOfArrivalH
    • Navigation.JourneyInfo.estimatedTimeOfArrivalMin
    • Navigation.GetNextWaypoint.ETAHours()
    • Navigation.GetNextWaypoint.ETAMinutes()

    These methods won’t do anything and return false:

    • Navigation.LaunchGuidance()
    • Navigation.LaunchGuidanceWaypoint()


    DRIVING MODE #

    When indicating the configuration of your app you will have to specify the behavior in the case of the driving mode:

    • The App supports driving mode: The application has to have a specific display mode for driving mode.
      The application will receive the events triggered when the driving mode changes and will have to adapt its display.

    • The App does not support driving mode: The portal will hide the application with an overlay when the user is driving.

    The application receives the events, Car.driverDistractionOn and Car.driverDistractionOff, triggered when the driving mode changes and must adapt its display accordingly.

    //Triggered when the driver distraction mode switches from off to on
    Car.addEventListener('driverDistractionOn',function(){
    	console.log("driver distraction mode switches from off to on");
    });
    
    //Triggered when the driver distraction mode switches from on to off
    Car.addEventListener('driverDistractionOff',function(){
    	console.log("driver distraction mode switches from on to off");
    });
    

    Note: Remember the Driving mode has its specific guidelines to follow.


    APP LIFECYCLE #

    This part will help you better understand the way your application’s lifecycle is managed by the WebPortal

    LAUNCHING APPLICATION

    When the DOM is loaded and the initialization is finished, the application must send a message to the WebPortal. In order to know when the DOM is loaded you have to listen to the DOMContentLoaded event. You can then send the message of type WebPortal.onApplicationLoaded to WebPortal.

    For example, it can be sent like this:

    window.addEventListener("load", function(event) {
        window.parent.postMessage({'type':'WebPortal.onApplicationLoaded'}, '*');
    });
    

    Note: If the message is not received during a 10s timeframe, the application will be closed and an error message will be displayed to the user.

    UNLOADING APPLICATION

    The portal can kill an application in order to launch another one or to update it. When it is unloading an application the portal sends a message WebPortal.onApplicationUnloaded to inform the app it has 100ms to save its state. The app must listen to messages from WebPortal to be able to react.

    //Global messages listeners
    window.addEventListener("message", function(event){
    
    	var data = event.data;
    	var type = event.data.type;
    
    	switch(type){
    
    		//When the application is killed or reloaded via an update
    		case "WebPortal.onApplicationUnloaded":
    		console.log("The application will be killed, it's time to save your application data");
    		break;
    		
    	}
    });
    

    HIDING APPLICATION

    When the user clicks on the Home button the portal sends a message WebPortal.onApplicationHide to inform the app it has 100ms to save its state. The Application is then hidden.

    //Global messages listeners
    window.addEventListener("message", function(event){
    
    	var data = event.data;
    	var type = event.data.type;
    
    	switch(type){
    
    		//When the application is put in background    
    		case "WebPortal.onApplicationHide":  
    		console.log("Application is hidden");
    		break;
    
    	}
    });
    

    SHOWING APPLICATION

    When the application gains focus after the user clicked on it while it was hidden, the portal sends a WebPortal.onApplicationShow to inform the app.

    //Global messages listeners
    window.addEventListener("message", function(event){
    
    	var data = event.data;
    	var type = event.data.type;
    
    	switch(type){
    
    		//When the application is put in foreground
    		case "WebPortal.onApplicationShow":
    		console.log("Application is shown");
    		break;
    
    	}
    });
    

    You can now continue to the Advanced Tutorial.