Native Apps with Tabris.js
Tim Bond
Developer Week Austin - November 6th, 2019
Truly Native
Web Views
100%
JS ➡️ Bridge ➡️ Native Code
J2V8
JavaScriptCore
A Word on ES6
- Android: Based on V8
- Notable exception: async/await
- iOS: Most features work except on iOS <= 9
- See docs for full list
- Best choice: TypeScript, Babel or your favorite transpiler
Build it your way
- ES5 or ES6
- TypeScript
- JSX
- MVC/MVP/MVVM/MC
- Any directory structure you like
- Use Node modules
W3C APIs
- console
- Timer
- XMLHttpRequest
- Fetch
- WebSockets
- Worker
- Canvas
- Persistent Storage (localStorage)
- Random Source (Crypto)
And More, Not W3 Based
- fs (filesystem)
- InactivityTimer
- printer
- Basic device info
- Model, OS version, screen size, more
Node packages
>1.1 million packages
>4,500 packages
Develop, Test, Repeat
- Write code in your favorite editor
- If transpiling, wait for it to finish
- Device automatically reloads with new code
Let's Get Started
Let's Get Started
Let's Get Started
Tabris.js
playground.tabris.com
import { contentView, Button, TextView } from 'tabris';
let button = new Button({
centerX: 0, top: 100,
text: 'Show Message',
}).appendTo(contentView);
let textView = new TextView({
centerX: 0, top: [button, 50],
font: '24px',
}).appendTo(contentView);
button.on({select: () => textView.text = 'Tabris.js rocks!'});
import { contentView, TextView, Button,
Constraint } from 'tabris';
contentView.append(
<$>
<Button center onSelect={showText}>Tap here</Button>
<TextView centerX padding={16}
bottom={Constraint.prev} font='24px'/>
</$>
);
function showText() {
$(TextView).only().text = 'Tabris.js rocks!';
}
Install Prerequisites
- NPM
- That's it!
No SDKs, no special editors
npm install -g tabris-cli
tabris init
npm start
.
├── cordova
│ └── config.xml
├── package.json
├── package-lock.json
├── README.md
├── src
│ ├── App.tsx
│ └── index.ts
├── tsconfig.json
└── tslint.json
{
"main": "dist",
"private": true,
"scripts": {
"test": "npm run build && npm run lint",
"lint": "tslint --project . -t verbose",
"build": "tsc -p .",
"watch": "tsc -p . -w --preserveWatchOutput --inlineSourceMap",
"start": "tabris serve -a -w"
},
"dependencies": {
"tabris": "~3.2.1"
},
"devDependencies": {
"tslint": "^5.20.1",
"typescript": "~3.3.4000"
}
}
cordova/config.xml
<?xml version='1.0' encoding='utf-8'?>
<widget id="com.example.myfirstapp" version="0.1.0">
<name>My First App</name>
<description>
Example Tabris.js App
</description>
<author email="john@example.org">
John Smith
</author>
<preference name="EnableDeveloperConsole" value="$IS_DEBUG" />
</widget>
npm start
Public WiFi? Might need a tunnel
ngrok http 8080
Simple app - Taco Shaker
NavigationView, Page
}
NavigationView
Drawer/back button
{
Page
tabris.contentView
Actions
Page Title
import { ActivityIndicator, NavigationView, Page,
ScrollView, TextView, contentView } from 'tabris';
import { TacoResponse, getRandomTaco } from './connectors/taco';
let navigationView = new NavigationView({
left: 0, top: 0, right: 0, bottom: 0
}).appendTo(contentView);
let page = new Page({
title: 'Taco Shaker'
}).appendTo(navigationView);
let scrollView = new ScrollView({
left: 0, right: 0, top: 0, bottom: 0
}).appendTo(page);
new TextView({
top: 0, left: 16, right: 16,
id: 'title',
font: 'bold 28px'
}).appendTo(scrollView);
new TextView({
top: ['prev()', 16], left: 16, right: 16,
text: 'Base Layer',
font: 'italic 26px thin sans-serif'
}).appendTo(scrollView);
4 more of these for the other recipe "components"
export function getRandomTaco(): Promise<TacoResponse> {
return new Promise((resolve, reject) => {
fetchWithBackoff(URL).then((response: any) => {
if (!response.ok) {
throw new Error('Error fetching taco');
}
return response.json();
}).then((json) => {
resolve(new TacoResponse(json));
}).catch(reject);
});
}
function loadTaco() {
let activityIndicator = new ActivityIndicator({
centerX: 0, centerY: 0
}).appendTo(contentView);
getRandomTaco().then((taco: TacoResponse) => {
scrollView.find(TextView).only('#title').text = taco.title;
scrollView.find(TextView).only('#recipe').text = taco.recipe;
// ...
}).catch((error) => {
console.error(error);
}).then(() => {
activityIndicator.dispose();
});
}
loadTaco();
cordova/config.xml
<widget>
<!-- ... -->
<plugin name="cordova-plugin-shake" version="0.6.0" />
<!-- ... -->
</widget>
Build your app when:
- Add a Cordova plugin
- Update a Cordova plugin
- Release to app stores (with debug off)
Updating JavaScript? Just reload
Two Ways To Build
- Free online build service
- Local build
- Must install platform SDKs and Cordova
- Android: Linux, Windows, OSX
- iOS: OSX
- Docker image available for Android builds
- Must install platform SDKs and Cordova
Deploy Built App
- Android
-
adb install
- Sideload by opening APK
-
- iOS
- Sideload through Xcode
- OTA distribution (HTML + XML)
- Test Flight et al.
src/app.ts
// ...
shake.startWatch(loadTaco, 40, console.error);
Debugger?
Yes!
In its current issue 11/2018, the German CHIP computer magazine tested several online banking apps in the context of the article “Our money in safe hands”. Our 1822direkt Banking App developed with the Tabris framework came out best. We are very proud of this great result, which we reached in close co-operation with 1822direkt!
Where to Get Help
- Join the tabrisjs Slack channel
- Stack Overflow with
tabrisjs
tag - Open an issue on GitHub for bugs
Questions
Native Mobile Apps with Tabris.js
By Tim Bond
Native Mobile Apps with Tabris.js
Developer Week Austin - November 6th, 2019
- 1,109