app.nit, a framework for portable applications
The framework provides services to manage common needs of modern mobile applications:
- User interface
- Async HTTP requests
- Package metadata
- Compilation and packaging
The features offered by app.nit are common to all platforms, but may not be available on all devices.
The app.nit application life-cycle is compatible with all target platforms. It relies on the following sequence of events, represented here by their callback method name:
on_create: The application is being created. You should build the UI at this time and launch services.
on_resume: The app enters the active state, it is in the foreground and interactive.
on_pause: The app becomes inactive and it leaves the foreground. It may still be visible in the background.
on_stop: The app is completely hidden. It may then be destroyed (without warning) or go back to the active state with
on_restart: The app goes back to the inactive state. You can revert what was done by
Life-cycle events related to saving and restoring the application state are provided by two special callback methods:
on_save_state: The app may be destroyed soon, save its state for a future
on_restore_state. There is more on how it can be done in the
on_restore_state: The app is launching, restore its state from a previous
These events are synchronized to the native platforms applications
App instance is the first to be notified of these events.
Other UI elements, from the
ui submodule, are notified of the same events using a simple depth first visit.
So all UI elements can react separately to live-cycle events.
app::ui module defines an abstract API to build a portable graphical application.
The API is composed of interactive
Views and an active
Here is a subset of the most useful controls and views:
The classic pushable
Buttonwith text (usually rectangular).
TextInputis a field for the user to enter text.
VerticalLayoutorganize other controls in order.
Each control is notified of input events by callbacks to
All controls have observers that are also notified of the events.
So there is two ways to customize the behavior on a given event:
Create a subclass of the wanted
Control, let's say
Button, and specialize
Add an observer to a
Buttoninstance, and implement
on_eventin the observer.
The example at
examples/ui_example.nit shows off most features of
app::ui in a minimal program.
You can also take a look at the calculator (
../../examples/calculator/src/calculator.nit) which is a concrete usage example.
You can go beyond the portable UI API of app.nit by using the natives services of a platform.
The suggested approach is to use platform specific modules to customize the application on a precise platform. See the calculator example for an adaptation of the UI on Android, the interesting module is in this repository at ../../examples/calculator/src/android_calculator.nit
Persistent State with data_store
app.nit offers the submodule
app::data_store to easily save the application state and user preferences.
The service is accessible by the method
DataStore itself defines 2 methods:
DataStore::=saves and associates any serializable instances to a
nullto clear the value associated to a key.
DataStore::returns the object associated to a
Stringkey. It returns
nullif nothing is associated to the key.
import app::data_store redef class App var user_name: String redef fun on_save_state do app.data_store["first run"] = false app.data_store["user name"] = user_name super # call `on_save_state` on all attached instances of `AppComponent` end redef fun on_restore_state do var first_run = app.data_store["first run"] if first_run != true then print "It's the first run of this application" end var user_name = app.data_store["user name"] if user_name isa String then self.user_name = user_name else self.user_name = "Undefined" super end end
Async HTTP request
app::http_request provides services to execute asynchronous HTTP request.
AsyncHttpRequest hides the complex parallel logic and
lets the user implement methods acting only on the UI thread.
See the documentation of
AsyncHttpRequest for more information and
the full example at
The app.nit framework defines three annotations to customize the application package.
app_nametakes a single argument, the visible name of the application. This name is used for launchers and window title. By default, the name of the target module.
app_namespacespecifies the full namespace (or package name) of the application package. This value usually identify the application uniquely on application stores. It should not change once the application has benn published. By default, the namespace is
app_versionspecifies the version of the application package. This annotation expects at least one argument, usually we use three version numbers: the major, minor and revision. The special function
git_revisionwill use the prefix of the hash of the latest git commit. By default, the version is 0.1.
app_filestells the compiler where to find platform specific resource files associated to a module. By default, only the root of the project is searched for the folders
androidfolder is used as base for the generated Android project, it can be used to specify the resource files, libs and even Java source files. The
iosfolder is searched for icons only.
Each argument of
app_filesis a relative path to a folder containing extra
iosfolders. If there is no arguments, the parent folder of the annotated module is used. In case of name conflicts in the resource files, the files from the project root have the lowest priority, those associated to modules lower in the importation hierarchy have higher priority.
module my_module is app_name "My App" app_namespace "org.example.my_app" app_version(1, 0, git_revision) end
Compiling and Packaging an Application
The Nit compiler detects the target platform from the importations and generates the appropriate application format and package.
Applications using only the portable services of app.nit require some special care at compilation.
Such an application, let's say
calculator.nit, does not depend on a specific platform and use the portable UI.
The target platform must be specified to the compiler for it to produce the correct application package.
There is two main ways to achieve this goal:
The mixin option (
-m module) imports an additional module before compiling. It can be used to load platform specific implementations of the app.nit portable UI.
# GNU/Linux version, using GTK nitc calculator.nit -m linux # Android version nitc calculator.nit -m android # iOS version nitc calculator.nit -m ios
A common alternative for larger projects is to use platform specific modules. Continuing with the calculator example, it is adapted for Android by the module
android_calculator.nit. This module imports both
android, it can then use Android specific code.
module android_calculator import calculator import android # ...