top

How to Create a NaCl App

Tutorial on creating a sample Native Client application.

Introduction

Native Client (or simply NaCl) is a technology first developed by Google and then adopted by Samsung Smart TV. It can run native C/C++ code inside of a web browser as a web plugin. It’s designed to enhance JavaScript, which is a slow, interpreted language, with fast, portable native code. This is useful in cases where simple raw computing power is required or native system capabilities are needed, e.g. 3D Games, applications using host hardware, etc.

This page provides a basic entry point for creating applications for TizenTV, often called widgets, with NaCl plugin embedded. For basics understanding of how NaCl works under the hood it highly recommended to first read NaCl Getting Started.

Prerequisites

In order to develop a Native Client application you have to prepare your workspace. You also need an intermediate knowledge of JavaScript, HTML and C/C++.

Development Environment

In order to develop Samsung Smart TV NaCl applications you will need the Tizen SDK with NaCl development plugin, which includes the IDE and all the necessary tools for a NaCl application creation and deployment on Google Chrome™ and Smart TV Emulator. More information about the setup process of the IDE and the SDK can be found in the IDE category page.

In case you only need to run your application on Google Chrome and does not care about TizenTV NaCl features you can use Google NaCl toolchain and a code editor of your choice, this is discussed in greater detail on Google NaCl SDK download page

Note

Keep in mind that in order to develop for TizenTV usage of Tizen SDK is mandatory.

Runtime Environment

In order to run a compiled Native Client application you will need one of the following:

  • Google Chrome™ web browser of version equal to or greater than toolchain version and a simple webserver of your choice. Alternatively you can use NaCl development plugin for TizenTV SDK to run your applications inside of the Chrome browser. Get Chrome.
  • TizenTV emulator that is included in TizenTV SDK.
  • Developer sample of TizenTV.
Note

Running application inside of the Google Chrome web browser requires the Native Client flag to be enabled (this is done by the IDE by default). Keep in mind that, although Samsung toolchains produce binaries compatible with the Google Chrome runtime, Chrome won’t allow you to run widgets that require Samsung specific interfaces.

Widget Structure

Each widget has to have a minimum set of files that define it. These consist of:

  • index.html - a file that describes a webpage that a NaCl application will be running on, as well as specifies the manifest location and the basic Javascript functions to handle widget communication (those scripts can be moved to separate files if desired). The web page can also contain other html files, CSS styles and JS script files.
  • application_arch.nexe - binaries compiled by a NaCl toolchain, one for every system architecture.
  • application.nmf - a manifest file that describes location of each binary.
  • config.xml - a configuration file for a TizenTV widget. This file is not used by the Google Chrome runtime, thus can be omitted when testing the application on the Chrome web browser. It’s generated automatically by the NaCl IDE.

Another difference between Chrome and TizenTV widgets is that TizenTV NaCl applications are delivered to the device in a application.wgt signed package. These packages have to be installed directly on a desired device. Chrome widgets are just aforementioned files placed in specified directory under the webserver host directory.

Coding Your First NaCl Application

In this section a process of creating a basic “Hello World” NaCl widget will be covered. This simple plugin will reply to the JavaScript side with “Hello World” message upon receiving any message from the JavaScript. Most of the process (index.html, app.nmf and config.xml creation) is the same for C and C++ applications, the only difference regards the native code.

index.html

The index.html file is a standard HTML webpage file, that doesn’t look any different from any other HTML file. The design of the webpage is completely up to a developer, you can include as much PHP/CSS/JS as you want. The only requirement for the webpage is that inside of the `````` tags there must be an embed element placed that looks as follows:


The embed element attributes are:

  • id - your desired id from the HTML object
  • width, height - the size of the Native Client module plugin visible on the webpage
  • src - location of the .nmf file.
  • type - must be set to “application/x-nacl”; this tells the browser that the embedded element is in fact a NaCl module.
    Additionally it’s recommended (in case of this application even necessary) to add event listeners for embedded NaCl module to enable load event handling and message receiving. In order to do so, you need to put the tag inside the tag. Then you can add listeners to this element on required events. More about NaCl module events (including a list of available event types) can be read in Google NativeClient documentation here.

  
    function moduleDidLoad(event) {
        var app = document.getElementById('nacl-app');
        app.postMessage("Hello NaCl");
    }

    function handleMessage(message) { alert(message); } //display message in popup

    var listener = document.getElementById('listener');
    listener.addEventListener('load', moduleDidLoad, true);
    listener.addEventListener('message', handleMessage, true);
  

  

The above HTML code is probably sufficient for loading 95% of NaCl widgets. Additional actions can be performed on specific events or on receiving certain messages from the module but that is totaly up to the developer.

Manifest File

Manifest is a JSON file with .nmf extension. It’s syntax is very easy to understand, as you can see below:

{
  "program": {
    "x86-32": {
      "url": "application_x86_32.nexe"
    },
    "x86-64": {
      "url": "application_x86_64.nexe"
    },
    "arm": {
      "url": "application_arm.nexe"
    }
  }
}

Inside each architecture keys ( “x86-32”, “x86-64”, “arm”) there is a url field coresponding to the .nexe binary file that was created during compilation. This tells the browser where is the location of NaCl executable for current architecture, this should be loaded and executed.

Note

If you wish to not support certain architecture you’re free to remove it from the manifest. Keep in mind though that in order to run a NaCl application:

  • on TizenTV you have to provide a support for an “arm” architecture.
  • on TizenTV Emulator you have to provide a support for an “x86-32” architecture.
  • on Google Chrome you have to provide a support for the architecture of the host system.

config.xml

The config.xml file is a Tizen specific file that is created for every widget. During the normal development the config.xml file is generated by the TizenTV SDK. If you wish to learn about the structure of this file please refer to: W3C standard. The sample code for the config.xml file is provided below:


 

    
    
    
     
     
     Your App Name Goes Here

NaCl Application Coding preabule

Before delving into writing the NaCl application code there are some things that need clearing up, thus it’s important to explain some basic terms used in this context:

  • a NaCl plugin - the NaCl part of the NaCl application.
  • Interface - a set of functionalities that are used by the plugin. There are two main types of interfaces:
  1. With the names starting with PPP - these are the interfaces which implementation is provided by the plugin itself. They are usually a set of callbacks that are called by the browser.
  2. With the names starting with PPB - these are provided by the browser and and allow the plugin to use different functionalities.
  • Module - the main entry point for every NaCl widget. It is responsible for the creation of interfaces.
  • Instance - a special type of PPP interface which needs to be implemented by every plugin. It’s created by the module and logically represents an instance of the NaCl application in the widget.
Note

Although NaCl supports both C and C++ we highly recommend to use C++. The C++ code is much nicer, shorter, easier to read and highly maintainable. Use C only if you really need to and you possess good knowledge of the language.

NaCl Application Code in C

Every C NaCl application has to implement three basic functions:

  • PPP_InitializeModule() - application entry point, called when the module is loaded.
  • PPP_ShutdownModule() - called right before the module is destroyed.
  • PPP_GetInterface() - getter for the PPP interfaces implemented by the plugin to the browser. Every implemented PPP interface (in particular instance interface) needs to be returned by this function.

Every PPP_Instance interface structure contains pointers to following functions that handle all important instance events:

  • DidCreate() - called by the browser on the instance creation.
  • DidDestroy() - called by the browser when the instance is destroyed.
  • DidChangeView() - called by the browser on the instance viewport change (e.g. resize).
  • DidChangeFocus() - called by the browser when the instance gains/loses focus.
  • HandleDocumentLoad() - not used in TizenTV NaCl widgets, should return false.

Aditionally you would most likely want to use PPP_Messaging interface for receiving messages from the web page. To do so you need to implement a function:

  • HandleMessage() - called by the browser when a message from the web page is received.

In the same fashion a developer can choose to use different interfaces for example to handle input events, display 3D graphics, etc. For further information regarding available interfaces please refer to Pepper API.

Below code snippet presents basic C implementation for a module that upon receiving any message from the browser replies with the “Hello World” message:

#include 
#include 

#include "ppapi/c/pp_errors.h"
#include "ppapi/c/ppp.h"
#include "ppapi/c/ppp_instance.h"
#include "ppapi/c/ppp_messaging.h"
#include "ppapi/c/pp_bool.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/c/ppb_messaging.h"
#include "ppapi/c/pp_var.h"

/* Global pointers to selected browser interfaces. */
const PPB_Messaging* g_messaging_interface;
const PPB_Var* g_var_interface;

static PP_Bool Instance_DidCreate(PP_Instance instance, uint32_t argc,
                                  const char* argn[], const char* argv[]) {return PP_TRUE;}

static void Instance_DidDestroy(PP_Instance instance) {}

static void Instance_DidChangeView(PP_Instance pp_instance, PP_Resource view) {}

static void Instance_DidChangeFocus(PP_Instance pp_instance, PP_Bool has_focus) {}

static PP_Bool Instance_HandleDocumentLoad(PP_Instance pp_instance,
                                           PP_Resource pp_url_loader) {return PP_FALSE;}

PP_EXPORT int32_t PPP_InitializeModule(PP_Module module_id,
                                       PPB_GetInterface get_browser_interface) {
  // Initializing pointers to used browser interfaces.
  g_messaging_interface = (const PPB_Messaging*) get_browser_interface(
                                                      PPB_MESSAGING_INTERFACE);
  g_var_interface = (const PPB_Var*) get_browser_interface(PPB_VAR_INTERFACE);
  return PP_OK;
}

PP_EXPORT void PPP_ShutdownModule() {}

void Messaging_HandleMessage(PP_Instance instance, struct PP_Var message) {
  char str_buff[] = "Hello World!\n";
 
  // Create PP_Var containing the message body.
  struct PP_Var var_response = g_var_interface->VarFromUtf8(str_buff, strlen(str_buff));

  // Post message to the Javascript layer.
  g_messaging_interface->PostMessage(instance, var_response);
}

PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {

  if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
    static PPP_Instance instance_interface = {
        &Instance_DidCreate,
        &Instance_DidDestroy,
        &Instance_DidChangeView,
        &Instance_DidChangeFocus,
        &Instance_HandleDocumentLoad
    };
    return &instance_interface;
  }
  if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
    static PPP_Messaging messaging_interface = {
        &Messaging_HandleMessage
    };
    return &messaging_interface;
  }
  return NULL;
}

For further information regarding implementation of C based NaCl applications refer to Hello World in C article.

NaCl Application Code in C++

Every C++ NaCl application has to implement two basic classes and one entry function:

  • a pp::Module deriving class that represents a NaCl module.
  • a pp::Instance deriving class that represents a NaCl application instance.
  • a CreateModule() function responsible for the module creation.

Let’s name our classes HelloWorldModule and HelloWorldInstance respectively.

The first thing that needs to be done is the implementation of HelloWorldModule. It needs to derive from pp::Module and override only one method - CreateInstance(). This method should construct new HelloWorldInstance class and return a pointer to it. To define the entry point for module creation the CreateModule() function is implemented inside the namespace pp brackets. It returns a pointer to the newly created module object.

This part of the application is identical (with exception to the module class name) in every C++ NaCl plugin.

#include "ppapi/cpp/module.h"

class HelloWorldModule : public pp::Module {
 public:
  virtual pp::Instance* CreateInstance(PP_Instance instance) {
    return new HelloWorldInstance(instance);
  }
};

namespace pp {

Module* CreateModule() {
  return new HelloWorldModule();
}

}  // namespace pp

The next step is the implementation of the HelloWorldInstance class. It must derive from pp::Instance and define an explicit constructor from PP_Instance which must call base the class constructor with the same argument. Additionally pp::Instance provides many virtual methods which can be overriden by HelloWorldInstance like:

  • Init() - called with arguments provided in Javascript immediately after the instance object is constructed.
  • DidChangeView() - called on the instance viewport change (e.g. resize).
  • DidChangeFocus() - called when the instance gains/loses focus.
  • HandleInputEvent() - called when an input event from the web page is received.
  • HandleMessage() - called when a message from the web page is received.

In our demo we only need to override HandleMessage() method. The mechanism of sending back a message is provided by a PostMessage() method. The code looks as follows:

#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/var.h"

class HelloWorldInstance : public pp::Instance {
 public:
  explicit HelloWorldInstance(PP_Instance instance)
      : pp::Instance(instance) {}

  void HandleMessage(const pp::Var& message) override {
    if (message.is_string()) {
      PostMessage("Hello World\n");
    }
  }
};

For further information regarding the implementation of C++ based NaCl applications refer to: Hello World in C++.

Compilation and Execution

The whole process of compilation and execution of nacl widgets is automated by the NaCl TizenTV SDK. If you really want to do it yourself read the section below. Keep in mind that this method will work only for Google Chrome web browser.

Manual Compilation

Below a sample makefile file is attached that will compile above applications (when compiling C code please remove ppapi_cpp from $(LIBS)) and also generate proper manifest. You would also need to set environmental variable NACL_SDK_ROOT to the desired pepper folder from the toolchain and then call make command.

makefile download

Execution

Execution via NaCl IDE is handled automatically both for Google Chrome and TizenTV emulator.

In order to manually execute NaCl application on Google Chrome you need to place all widget files (*.nexe, *.nmf, *.html, *.js) under folder managed by webserver of your choice and then enter the address of your webserver to the Google Chrome web browser. Soon you should see your application running.

Note

It’s suggested to enable the developer tools in Chrome and disable cache in order to be sure that no errors are thrown and that the newest build is executed.