HybridOS Specification 01-C
Topic: HybridOS Foundation Class Library
Author: Vincent Wei
Category: App Framework
Date: November 2018
Status: Proposal
Copyright Notice
Copyright (C) 2018, 2019 FMSoft Technologies
All Rights Reserved.
Introduction
HFCL (HybridOS Foundation Class Library) is a C++ class library. As described in HybridOS Architecture, the developer can write an HybridOS app by using HFCL when the device has a low hardware configuration.
HFCL provides APIs to create and manage assets, activities, and services for your HybridOS app. It also provides the API to extend or customize your own HVML view types and also a set of built-in view types.
The key features of HFCL are as follows:
-
It acts as the framework for the C++ edition of your HybridOS app.
-
It manages the local assets (images, fonts, localization text) for your app. Unlike web app, most assets of an HybridOS app may be loaded from local file system, or embedded directly into the program executable. HFCL provides a universal way to manage the local assets.
-
It manages the activities of your app. You can launch an activity and pass an intent to it.
-
It manages the services of your app. You can start a service and register one or more request responders at the specific end points.
-
It implements the built-in view types which conform to HVML specification.
Components of HFCL
The components of HFCL are classified into the following categories:
- Assets management
- Activity management
- Activity and intent
- Animation and transition
- Service management
- WebSocket responder
- HTTP responder
- MQTT service provider
- ...
- HVML view types
- System classes
- hiBus event and task management
- SQLite queries
- JSON data
- Asynchronous task management
Activity and Intent
Customizing View Types
Service
To be continued.
The below words are deprecated...
It is derived from mGNGUX, a C++ library for MiniGUI. mGNGUX had been used as the foundation of two MMI (man-machine interface) solutions for feature phones.
mGNGUX introduced a new MMI framework for feature phone, and borrowed some concepts from other operating system (especially Android). mGNGUX also provided a new set of controls/widgets in C++ classes. These classes construct the view hierarchy of mGNGUX app framework.
The most important feature of mGNGUX is it introduced a new way to define the UI elements, including resource, views, and menus. And we can easily define the maps of views to C++ class member variables. Indeed, the UI definition files are C++ source files, but we wrote them in pre-defined C++ macros.
However, mGNGUX still uses the traditional widget-based programming mechanism, which does not provide a good solution for decoupling relationship among data, interaction, and rendering.
Therefore, as described in HybridOS Architecture, we use HybridOS View Markup Language and hiWebKit to support HVML and render the activities.
HFCL implements the view types for HVML and help the developer to create and
Resource Assets
We treat HVML files, CSS files, JavaScript files, images, and l10n text are all resource assets of a HybridOS apps.
Unlike web browser, for an app running in a device or client, the assets generally stored locally, either on the file system or embedded in the app program image.
HybridOS provides an easy and magic way for developer to define the assets and bind the assets with your C++ code.
Specifically, HFCL uses pre-defined C++ macros to define the resource assets. For our first sample, the main asset file will look like:
begin_app(firstSample)
begin_assets()
image(defAvatar, "file:///assets/image/def-avatar.png")
css(default, "file:///assets/css/default.css"
activity(userList, "file:///assets/hvml/userlist.hvml")
activity(userInfo, "file:///assets/hvml/userInfo.hvml")
l10n(en, "file:///assets/message/en.mo")
l10n(zh_CN, "file:///assets/message/zh_CN.mo")
l10n(zh_TW, "file:///assets/message/zh_TW.mo")
end_assets
end_app(en, userList)
L10N of Text
For the L10N (localization) text, HFCL provides two ways:
- Using .mo files of GNU gettext.
- Using identifiers instead of text as GNU
gettext
does.
The interpreter hfclify
can generate the C++ L10N translation
source files for the app according to the L10N translation file specified
in the assets section of the app.
The identifiers referred as STRID_TITLE
or STRID_COPYING
will be
defined as C++ macros, and the l10n text table can be zipped by
using zlib
.
Assets Management
Not like HVML apps, the link of an asset (e.g., an image file) defined in
a HFCL app is handled as a reference key first. We can integrate the assets
data into the executable image of your app. We call them as in-core resource.
If HFCL could not load a specific asset from the in-core resource, it will
try to load if from the URL specified in the begin_assets
section.
In this way, HFCL will provide a maximal flexibility for the app developers.
For our user list activity, the asset code will look like:
begin_activity(userList, ActivityUserList)
def_name(thePanel)
def_name(theHeader)
def_name(theList)
def_name(theFooter)
begin_view_template(UserItemView, ItemView, my_style_sheet(normalItem))
begin_view(HiddenView, NULL))
set(Name, "id")
end_view
begin_view(ImageView, my_style_sheet(userAvatar)))
set(Name, "avatar")
end_view
begin_view(TextView, my_style_sheet(userName)))
set(Name, "name")
end_view
end_view_template
begin_view(PanelView, my_style_sheet(panel))
map(my(thePanel))
begin_view(TextView, my_style_sheet(panelHeader))
map(my(theHeader))
set(Content, STRID_TITLE)
end_view
begin_view(ListView, my_style_sheet(userList))
map(my(theList))
set(ItemTemplate, my_template(UserItemView))
set(Name, "userItem")
end_view
begin_view(TextView, my_style_sheet(panelFooter))
map(my(theFooter))
set(Content, STRID_COPYING)
end_view
end_view
end_activity
begin_activity(userInfo)
begin_view(PanelView, ...)
...
end_view
end_activity
This file (assume named `firstsample.res.inc") will be pre-compiled by your C++ compiler in a magic way:
-
In a C++ header file, include the resource file in the following way to generate the identifiers and names of the resource:
#include <hfcl/resource/resdefines.head.h> #include "firstsample.res.inc" #include <hfcl/resource/resundefines.h> #include <hfcl/resource/resdefines.name.h> #include "firstsample.res.inc" #include <hfcl/resource/resundefines.h>
-
In a C++ source file, include the resource file in the following way to generate the source code and the initialization code:
#include <hfcl/resource/resdefines.source.h> #include "firstsample.res.inc" #include <hfcl/resource/resundefines.h> #include <hfcl/resource/resdefines.init.h> #include "firstsample.res.inc" #include <hfcl/resource/resundefines.h>
By using the method described above, we do not need a utility tool to interpret the resource file and generate the souce code, the C++ compiler will do this for us.
The another advantage is that we seperate the resource data with the app logical code in a good way.
The last advantage is that the resource file can be generated from the HVML tags. Thus, if you have to use C++ to write your device app because the poor hardware performance, you can easily keep up your C++ code with the JavaScript code.
If you have some expirience with HTML and CSS, you will easily get the the define the style sheet of views with the same manner of CSS. For example, the style sheet of the user name corresponds to the following CSS definition:
.userAvatar {
display: inline-block;
position: relative;
margin: 0px 0px 0px 0px;
padding: 0px 0px 0px 0px;
height: 20px;
width: 20px;
border-radius: 5px 5px 5px 5px;
}
For performance reason, we do not use the direct literal CSS definition in HFCL. We use the macros to define every style element in C++ way instead:
begin_css(userAvatar, ".avatar")
style(Display, PV_INLINE_BLOCK)
style(Position, PV_RELATIVE)
style(Margin, PV_LENGTH_PX, 0)
style(Padding, PV_LENGTH_PX, 0)
style(Height, PV_LENGTH_PX, 20.0f)
style(Width, PV_PERCENTAGE, 100.0f)
style(BorderRadius, PV_LENGTH_PX, 5.0f)
end_css
In the definition of a view which uses a style sheet, we passed the class of the way:
begin_view_ex(hvimage, "avatar", ...))
...
end_view
Translate HTML/HVML and CSS into C++ Code
It will be a trouble if we write the style sheets and views by hand in the way above. So we introduce a interpreting tool which can translate the HVML tags and CSS into the HFCL resource source files.
This tool is called hfclify
, and it will be written in Python.
If you want to change the style sheet of one view on the fly, you can call one of the following APIs of HFCL:
view->addStyleSheet (HFCL_STYLE_SET_NAME (firstSample, activeItem));
view->useStyleSheet (HFCL_STYLE_SET_NAME (firstSample, focusItem));
view->setStyleProperty (HCFL_STYLE_COLOR, Color::WHITE);
Note that the resource source file can not reflect all details in your
HVML tags. You need to write the interaction code in your C++ source
file. For example, in HVML tags, you can define the iteration of
an item from a template view by using the property hbd-iterate-by
,
but in HFCL, we can not do this for you. You need to initialize the
list view in your implementation classes manually.
When you re-generate the resource source file from HVML tags, because the real implemenations are seperated from the resource source files, the translator will not override your own code.
In HFCL, a view template is defined as a derived class of one standard view, as shown in the sample:
begin_view_template(UserItemView, ItemView, my_style_sheet(normalItem))
...
end_view_template
The UserItemView
will be defined by the macro as a new view class
in the resource header file, just a simply subclass of ItemView:
class UserItemView : public ItemView {
public:
UserItemView (View* parent) : ItemView (parent) { }
UserItemView (View* parent, StyleSheet* style_sheet) : ItemView (parent, style_sheet) { }
virtual ~UserItemView () {};
}
The UserItemView
will be defined by the macro as an interface class
in the resource header file. You should define the implemetation class
by yourself (in separated files):
class UserItemViewIf : public ItemView {
public:
UserItemViewIf (View* parent) : ItemView (parent) { }
UserItemViewIf (View* parent, StyleSheet* ss) : ItemView (parent, ss) { }
virtual View* getChildByName (const char* name) = 0;
virtual ~UserItemViewIf () {};
}
class UserItemViewIm : public UserItemViewIf {
public:
UserItemViewIm (View* parent);
UserItemViewIm (View* parent, StyleSheet* ss);
virtual View* getChildByName (const char* name);
...
private:
...
}
...The above words are deprecated.