Welcome to AXEMAS documentation!¶
Development Framework for MultiPlatform hybrid mobile applications.
AXEMAS handles the whole navigation of the application and transition between views, while it permits to implement the views content in HTML itself.
AXEMAS works using sections
, each Section
represents the content of the view
and is loaded from an HTML file or from an external URL.
Whenever native code requires to be attached to a section, it is possible to attach
a SectionController
to a Section
itself.
Getting Started¶
To Install AXEMAS you need Python 2.7
with the pip
package manager installed
as AXEMAS uses Python to generate project skeletons. To install pip
follow the
Pip Install Guidelines.
Then you can install AXEMAS toolkit using:
$ pip install axemas
To create a new AXEMAS project you can then use the axemas-quickstart
command,
it will automatically create a new AXEMAS project:
$ gearbox axemas-quickstart -n ProjectName -p com.company.example
See Quickstarting a New Application for additional details on the gearbox
command.
Basic Project Introduction¶
By default AXEMAS will create for you a basic application for iOS and Android.
Content of the application will be available inside www
directory and the application
will load www/sections/index/index.html
on startup.
The application can be run by simply opening in Android Studio or XCode the
android
and ios
projects inside the newly created application directory and
then pressing the Run button inside the IDE.
To start customizing the application and providing your own code, you can open the www
directory in your favourite editor and start editing sections.
From the index.html section, you can then use the JavaScript API to push and pop additional sections and implement your whole Application.
Binding to Native Code¶
The previous code shows how to load HTML
based sections and rely on the JavaScript API
to implement your web application. When more advanced features or interaction with the
hardware is needed you might need to get to native code level. AXEMAS has been designed
specifically to make it as easy as possible to work with native code, the main difference
with frameworks like Cordova is explicitly that AXEMAS makes native a first citizen of
your application.
HTML sections loaded by your application are explicitly declared inside the application code
itself and the application window is explicitly create using makeApplicationRootController
from the NavigationSectionsManager
Inside your AppDelegate
for iOS:
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window.rootViewController = [NavigationSectionsManager makeApplicationRootController:@[@{
@"title": @"Home",
@"url": @"www/home.html",
}]];
[self.window makeKeyAndVisible];
return YES;
}
@end
Or in your AXMActivity
subclass onCreate()
method for Android:
public class MainActivity extends AXMActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
JSONObject data = new JSONObject();
try {
data.put("url", "www/home.html");
data.put("title", "Home");
} catch (JSONException e) {
e.printStackTrace();
}
NavigationSectionsManager.makeApplicationRootController(this, data);
}
}
}
The binding between the HTML Sections
and native code is performed using
SectionControllers
, to link a section to a section controller is as easy as
registering the controller class for the specified route:
[NavigationSectionsManager registerController:[MySecionController class] forRoute:@"www/mysection.html"];
NavigationSectionsManager.registerController(this, MySecionController.class, "www/mysection.html");
To get started using SectionControllers
read the iOS API and Android API.
Contents:
iOS API¶
Declaring Sections¶
The main application controller (window.rootViewController
) must be
created using [NavigationSectionsManager makeApplicationRootController]
.
makeApplicationRootController
accepts an array of section data, each data
will be used to create a tab with a section inside.
To create an application with a stack of sections (using a Navigation Controller), and not tabs, just pass data for a single section data:
[NavigationSectionsManager makeApplicationRootController:@[@{
@"url":@"www/index.html",
@"title":@"Home",
}]
];
The created section will contain content of www/index.html
and will be
titled Home
. Further sections can be pushed onto the navigation stack
using axemas.goto(dictionary)
from Javascript.
To create an application with a TabBar just pass data for multiple sections
into the makeApplicationRootController
array, each section must have an
url
pointing to the section path and can have a title
and icon
which
will be used as title and icon for the TabBar tabs.
An application with sidebar can also be created by passing a section data as
sidebar to the makeApplicationRootController
:
[NavigationSectionsManager
makeApplicationRootController:@[@{
@"url":@"www/index.html",
@"title":@"Home",
@"toggleSidebarIcon":@"reveal-icon"}]
withSidebar:@{@"url":@"www/sidebar.html"}
];
The sidebar will be created with content from the section data passed in
withSidebar
parameter, sections that have a toggleSidebarIcon
value in section data will provide a button to open and close the sidebar
with the given icon. If the value is omitted, even when the sidebar is
enabled, there will be no button to show it.
Section Controllers¶
Section controllers permit to attach native code to each section,
doing so is as simple as subclassing section controllers and
providing sectionWillLoad
and sectionDidLoad
methods.
Inside those methods it is possible to register additional native functions on the javascript bridge.
Inside viewWillLoad
method of SectionController
subclass
it is possible to register handlers which will be available
in Javascript using axemas.call
:
@implementation HomeSectionController
- (void)sectionWillLoad {
[self.section.bridge registerHandler:@"openMap" handler:^(id data, WVJBResponseCallback responseCallback) {
UINavigationController *navController = [NavigationSectionsManager activeNavigationController];
[navController pushViewController:[[MapViewController alloc] init] animated:YES];
if (responseCallback) {
responseCallback(nil);
}
}];
}
@end
Registering the SectionController
for a section can be done
using the NavigationSectionsManager
:
[NavigationSectionsManager registerController:[HomeSectionController class] forRoute:@"www/index.html"];
Calling JS from native code is also possible using the section bridge,
after you registered your handlers in JavaScript with axemas.register
:
axemas.register("handler_name", function(data, callback) {
callback({data: data});
});
Calling handler_name
from native code from a SectionController
is possibile using the javascript bridge callHandler
:
[self.section.bridge callHandler:@"handler_name"
data:@{@"key": @"value"}
responseCallback:^(id responseData) {
NSLog(@"Callback with responseData: %@", responseData);
}];
SectionController
available callbacks:
- sectionDidLoad triggered when the webpage finished loading
- sectionWillLoad just before the webpage will start to load
- sectionViewWillAppear when the section is going to be displayed to the user.
- sectionViewWillDisappear when the section is going to disappear to the user.
- sectionOnViewCreate:(UIView)view* when the section view is first created.
- (BOOL)isInsideWebView:(CGPoint)point withEvent:(UIEvent)event* whenever a touch event for the webview happens, can be used to return block events to be trapped by webview.
- navigationbarRightButtonAction Triggered whenever the right button in the navigationBar is pressed.
Android API¶
Declaring Sections¶
The application MainActivity must extend AXMActivity
which creates the application main structure.
In the onCreate
of your MainActivity initialize the root section by
calling NavigationSectionsManager.makeApplicationRootController()
The makeApplicationRootController()
accepts a JSONObject containing the section data:
JSONObject data = new JSONObject();
try {
data.put("url", "www/index.html");
data.put("title", "Home");
} catch (JSONException e) {
e.printStackTrace();
}
NavigationSectionsManager
.makeApplicationRootController(this, data);
The created section will contain content of www/index.html
and will be
titled Home
. Further sections can be pushed onto the navigation stack
using axemas.goto(dictionary)
from Javascript.
An application with sidebar can also be created by passing a section data as
sidebar to the makeApplicationRootController
:
JSONObject data = new JSONObject();
try {
data.put("url", "www/index.html");
data.put("toggleSidebarIcon", "reveal-icon");
data.put("title", "Home");
} catch (JSONException e) {
e.printStackTrace();
}
NavigationSectionsManager
.makeApplicationRootController(this, data, "www/sidebar.html");
The sidebar will be created with content from the section data passed as
sidebarURL`` parameter, sections that have a ``toggleSidebarIcon
value in section data will provide a button to open and close the sidebar
with the given icon. If the value is omitted, even when the sidebar is
enabled, there will be no button to show it.
Section Controllers¶
Section controllers permit to attach native code to each section,
doing so is as simple as subclassing section controllers and
providing sectionWillLoad
and sectionDidLoad
methods.
Inside those methods it is possible to register additional native functions on the javascript bridge.
Inside sectionWillLoad
method of SectionController
subclass
it is possible to register handlers which will be available
in Javascript using axemas.call
:
this.getSection().getJSBridge().registerHandler("openMap", new JavascriptBridge.Handler() {
@Override
public void call(Object data, JavascriptBridge.Callback callback) {
String uri = "https://maps.google.com/maps";
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
section.startActivity(i);
}
});
Registering the SectionController
for a section can be done
using the NavigationSectionsManager
:
NavigationSectionsManager
.registerController(this,HomeSectionController.class, "www/index.html");
Calling JS from native code is also possible using the section bridge,
after you registered your handlers in JavaScript with axemas.register
:
axemas.register("handler_name", function(data, callback) {
callback({data: data});
});
Calling handler_name
from native code from a SectionController
is possibile using the javascript bridge callHandler
:
this.getSection().getJSBridge().callJS("send-passenger-count", data, new JavascriptBridge.AndroidCallback() {
@Override
public void call(JSONObject data) {
Log.d("axemas", "Callback with responseData: "+ data.toString());
}
});
SectionController
available callbacks:
- sectionDidLoad triggered when the webpage finished loading
- sectionWillLoad just before the webpage will start to load
- sectionOnViewCreate(ViewGroup view) when the fragment is first created
- boolean isInsideWebView(MotionEvent ev) whenever a touch event for the webview happens, can be used to return block events to be trapped by webview.
- sectionFragmentWillPause triggered by fragment’s onPause
- sectionFragmentWillResume triggered by fragment’s onResume
- sectionFragmentOnActivityResult triggered by fragment’s onActivityResult
- sectionFragmentOnSaveInstanceState triggered by fragment onSaveInstanceState
- sectionFragmentOnCreateView triggered by fragment View Creation during inflation
- actionbarRightButtonAction triggered whenever the right button is pressed in the actionbar
JavaScript API¶
The JavaScript module axemas.js
permits interaction with the native code of the application:
- goto
- gotoFromSidebar
- call
- alert
- dialog
- showProgressHUD
- hideProgressHUD
- getPlatform
- platformDetails
- storeData
- fetchData
- removeData
- log
goto¶
Pushes new section
on the navigation stack. It is the equivalent of the iOS [NavigationSectionsManager goto]
and Android’s NavigationSectionsManager.goTo()
.
All three functions accept a dictionary as payload which defines the extra actions the goto
call must execute:
axemas.goto(
{"url":"www/home.html",
"title":"HOME",
"toggleSidebarIcon":"slide_icon",
"stackMaintainedElements": 0,
"stackPopElements": 0}
);
The payload structure is shared between JavaScript, Objective C and Java, and accepts the following parameters:
url
contains the local or remote address from which the WebView must load the contenttitle
(optional) is the tile show in the application’s ViewController / Action Bar.toggleSidebarIcon
(optional) is the sidebar’s icon to be displayed and if missing a button to open the sidebar will not be createdactionbarRightIcon
(optional) icon to display as a button on the right of the actionbar inside the target section, pressing the button triggers thenavigationbarRightButtonAction
event on section controllers.stackMaintainedElements
(optional) instructs the navigation stack to pop all views and maintain the last Xsections
indicated on the bottom of the stack; it is ill advised to use in conjunction withstackPopElements
stackPopElements
(optional) instructs the navigation stack to pop the first Xsections
; it is ill advised to use in conjunction withstackMaintainedElements
animation
(optional) only supported on iOS platform, can be used to change the default push/pop animation in one of"fade"
or"slidein"
values
gotoFromSidebar¶
Same as goto
but closes the sidebar and must be used only inside the sidebar section
. Refer to goto
:
axemas.gotoFromSidebar(
{"url":"www/home.html",
"title":"HOME",
"toggleSidebarIcon":"slide_icon",
"stackMaintainedElements": 0,
"stackPopElements": 0}
);
call¶
The call
enables JavaScript to execute a native registered handler inside a SectionController
:
axemas.call('openNativeController');
axemas.call('execute-and-return', '{"payload": "something"}', function(result) {
alert(JSON.strgify(result));
});
alert¶
Creates a native dismissible alert dialog with a title and a message:
axemas.alert('Alert title', "Alert message");
dialog¶
Generates a native dialog with a title, a message and a maximum of three buttons. When pressing a button a callback returns the button’s value as integer, range [0-3]:
axemas.dialog('Dialog title', 'Dialog display message', ['Cancel', 'Ok'],function(data) {
axemas.alert('Pressed button', data.button);
});
showProgressHUD¶
Locks interface interaction by displaying a spinner on the screen. The same spinner is always displayed when lading the contents of a page inside a section
:
axemas.showProgressHUD();
getPlatform¶
Uses the navigator.userAgent
object to determine if the current platform. Returns Android
, iOS
or unsupported
:
if (axemas.getPlatform() == 'your_platform') {
//do something
}
platformDetails¶
Getting information about device: model
, systemName
and systemVersion
.
For example:
axemas.platformDetails(function(device_info) {
console.log(device_info);
});
// Example of the device_infor
//iOS Device
{model: "iPhone", systemVersion: "9.3", systemName: "iPhone OS"}
//Android Device
{model: "Nexus 5", systemName: "Android", systemVersion: "6.0.1"}
storeData¶
Uses the Native/WebView’s localSotrage
for key/value storing. Data stored will be available next time the application is launched:
axemas.storeData("key","only_string_values");
removeData¶
Permanently removes the previously saved data from the locationStorage:
axemas.removeData("key")
log¶
Utility for use native and javascript log system:
axemas.log("Hello World");
or:
axemas.log({'tag': 'CustomTAG', 'message': "Hello World"});
tag
is the tag for Android, default is AXEMAS_LOGmessage
is the message of the log as String
Utilities¶
Crash Logging¶
Android¶
Splunk MINT is used to log crash reports. To enable it, it’s necessary to be registered on their service (https://mint.splunk.com/) Next to the app creation on their portal initiate this code inside the Activity wich extends AXMActivity with:
this.startCrashReporter();
The next step is to add this config string inside strings.xml file inside res/values folder inside your Android project. This String resource contains the api-key got by Splunk MINT Portal for your application.
<string name=’splunk_api_key’></string>
In the end you have to configure gradle to work with the new Mint dependency required. Add this code to your build.gradle project file:
repositories {
maven {
url "https://mint.splunk.com/gradle/"
}
}
dependencies {
compile 'com.splunk.mint:mint:4.2'
}
Once these 3 steps are done you have a fully implemented crash reporter on your Axemas Application.
AXEMAS CookBook¶
Updating Sidebar Whenever it appears¶
By default content of a section is only loaded once, the first time the section itself appears. The Sidebar specifically is only loaded when the application starts, and is never reloaded again.
In case you need to display content that might change during the application lifetime, you will need to somehow receive a notification each time the sidebar appears so that you can actually force its update.
IOS¶
On iOS you can easily achieve this, by calling a custom handler from your sidebar AXMSectionController
each time the sectionViewWillAppear
is performed:
[NavigationSectionsManager registerController:[SidebarSectionController class] forRoute:@"www/sidebar.html"];
@implementation SidebarSectionController
- (void)sectionViewWillAppear {
[self.section.bridge callHandler:@"on-sidebar-appears"];
}
@end
This will correctly call the on-sidebar-appears
handler on Javascript both when the sidebar is
displayed the first time and each time its opened/closed by the user.
Android¶
On Android you can achieve a similar result by relying on the sectionFragmentWillResume
method:
NavigationSectionsManager.registerController(this, SidebarSectionController.class, "www/sidebar.html");
public class SidebarSectionController extends AXMSectionController {
@Override
public void sectionFragmentWillResume() {
super.sectionFragmentWillResume();
section.getJSBridge().callJS("on-sidebar-appears", new JSONObject(), null);
}
}
While this is enough to update the sidebar each time the user switched the application in/out of background,
it won’t update it when the sidebar is opened/closed through the sidebar button. So to achieve the same
behaviour we had on iOS it is required to also @Override
the onSidebarOpened
method inside the MainActivity
and forcefully trigger a sectionFragmentWillResume
each time the sidebar is opened/closed:
public class MainActivity extends AXMActivity {
@Override
public void onSidebarOpened() {
SectionFragment sidebarFragment = (SectionFragment)getFragmentManager().findFragmentByTag("sidebar_fragment");
((SidebarSectionController)sidebarFragment.getRegisteredSectionController()).sectionFragmentWillResume();
}
}
Quickstarting a New Application¶
AXEMAS provides a Gearbox
extension that will generate a new Axemas
project.
Gearbox is a skeleton generation tool for Python
Installaton¶
Create a new virtual environment and install axemas
with pip
.
This will include all needed dependencies like gearbox
:
$ virtualenv --no-site-packages axemas_builder
$ . axemas_builder/bin/activate
(axemas_builder)$ pip install axemas
Usage¶
Run the following command to generate a project called new_project
inside the directory where you want to
create the new project:
(axemas_builder)$ gearbox axemas-quickstart -n ProjectName -p com.company.example
Project structure¶
The resulting project structure will be as follows:
/ root of the project
----/android Axemas Android native Java code
----/axemas-js Axemas library JavaScript code imported by www
----/ios Axemas iOS native Objective-C code
----/www common share html/css/js/resource files
Maintain AXEMAS¶
AXEMAS framework¶
Repositories Structure¶
The project is divided into 5 repositories:
website
examples
framework
releases
doc
Inside framework repo (https://github.com/AXEMAS/framework) you will find the AXEMAS
base library, composed by:
- Android library project
- iOS library project
- HTML library project
When you are done modifing the library please remember to update the debug projects and the release repository with the following commands.
Debug Projects Update¶
To update the Android
and the iOS
demo projects use the following command
(examples folder must be in the same parent folder or will be cloned inside ../examples):
./update_debug
Il will delete all the old files in the iOS and Android projects and copy the new library files; native binaries and HTML. If you want to release demo apps remember to make necessary fixes, tag version and push everything.
Release Repository Update¶
Same as for the Debug Project Update, this will update the repository that the
gearbox axemas-quickstart
command needs to clone in order to quickstart a new project
(releases folder must be in the same parent folder or will be cloned inside ../releases,
be careful if you have pending changes):
./update_release
If you want to release new version remember to commit, tag version and push everything.
Android AXEMAS library¶
This library project is used to build the axemas.aar used inside the Android application.
How to use¶
After modifiying the library please inside this project’s root folder:
./gradlew clean assemble
You will find the app-release.aar
inside the app/build/outputs/aar/
folder. Copy this file
inside the axemas-android
project in the libs
folder.
iOS AXEMAS library¶
This project is used to build the axemas iOS library. Please use the following instructions to make a new release.
Setup¶
Install the command line tools, following the instructions at this link:
https://developer.apple.com/library/ios/technotes/tn2339/_index.html
New Release¶
- Use the following command in the ::
- cp ios ./build_libaxemas
In the release directory you will find all the neccessary files to import the project in Xcode.