SlideShare a Scribd company logo
Building a cross-platform Hybrid
Ionic App with TypeScript
Lessons learned in building a real-world hybrid application using the
Ionic framework and TypeScript
Oleksandr Zinchenko [Macaw], Serge van den Oever [Macaw]
Versions used
This document is produced when using the following versions:
• Cordova version 4.1.2 (cordova --version)
• Ionic version 1.2.8 (ionic --version)
• Ionic framework version 1.0.0-beta.11 (ionic lib)
Contents
1. Introduction
2. Minimal Ionic project structure
3. Create a project
4. Project modifications: initial
structure
5. Project modifications: npm
packages
6. Project modifications: shellinit
7. Project modifications: hooks
8. Project modifications: TypeScript
interfaces
9. Project modifications: TypeScript
compiler
10.Working with Typescript
11.app.ts template
12.Controller template
13.Service template
14.Directive template
15.Restore existing project from
source control
16.Running app
17.Debugging
18.Development tools
19.Accessing the file system
20.Development strategy
21.Best coding practices
22.Debug/release code compilation
23.Preparing for the store: Android
24.Preparing for the store: iOS
25.Update the app without store
approval
26.Optimization tips
27.Ionic/Angular issues (1)
28.Ionic/Angular issues (2)
29.References
Introduction
TypeScript.
TypeScript is a strict superset of JavaScript, and adds optional static
typing and class-based object-oriented programming to the language.
It is designed for development of large applications and transcompiles to
JavaScript.
Additional features include:
1) Type annotations and compile-time type checking
2) Interfaces
3) Classes
4) Modules
5) Abbreviated "arrow" syntax for anonymous functions
Cordova.
Apache Cordova is a set of device APIs that allow to access native device
function from JavaScript. Combined with a UI framework this allows to
create cross-platform app using just HTML, CSS and JavaScript.
Cordova command-line interface (cli) includes:
1) create template Cordova project
2) build app for target platform using the same source code
3) run app in an emulator or device
Angular.
AngularJS lets you write client-side single-page web applications using
JavaScript. Its goal is to simplify both development and testing of an app
by providing a framework for client-side model-view-controller (MVC)
architecture.
Most important concepts in AngularJS:
1) Services
2) Controllers
3) Directives
Ionic.
Ionic is an open source front-end SDK (CSS framework and a Javascript
UI library) for developing hybrid mobile apps with HTML5. Ionic Javascript
UI library is built on top of angular and cordova. The Ionic framework
introduces its own command-line interface (cli) on top of the Cordova cli.
Ionic cli extends Cordova cli with:
1) livereload - reload app immediately after code changes
2) packaging for store deployment – certificates
3) build in the cloud - build for iOS on Windows
4) Gulp build system and the Bower package manager
The purpose of the current presentation is to show the complete developing
cycle of a cross-platform hybrid app using Cordova, Angular, Ionic
and TypeScript.
Minimal Ionic project structure
The following folders and files would be created in new project:
hooks - used to “hook in” actions during the different stages of the Ionic (or actually Cordova) build process
node_modules - project specific node.js modules
plugins - Cordova plugins are located here
scss - the sass files are managed here, builds to css (we move this folder into www to enable css debugging based
on generated map files in the sass compilation)
www - the actual folder where the source code for our app lives. The www folder contains all files that are packaged
into the native host application. All other folders and files are there to support the build process of the native
application, or contains sources compiled into the www folder (like the scss folder, which we move into www).
Ionic uses two package management systems:
• npm - for node packages, useful for installing packages to extends the build process
• packages required are managed through package.json
• packages are installed in the folder node_modules
• Bower - managing client-side libraries
• .bowerrc contains the Bower configuration: { "directory": “www/lib" }
all client-side library packages are installed in www/lib
• packages required are managed through bower.json
gulpfile.js is the “makefile” for the Gulp build system
config.xml is the Cordova configuration file that is used in building the hybrid app
Create a project
1. Use either Windows, OSX or Linux (We only tested on Windows and OSX)
2. Make sure that node.js is installed (see http://nodejs.org/)
3. install the node package cordova and ionic globally using the node.js package manager:
>npm install cordova -g (or update if already installed)
>npm install ionic -g (or update if already installed)
4. Create ionic project:
>ionic start myapp blank --appname "My App" –id com.mycompany.myapp --sass
5. where:
myapp is the folder created in the current folder for your project
blank is the template used for the project
--appname specifies the name of the app
--id specifies the package name (internal name)
--sass specifies to use SASS for CSS precompiling
6. Add target platform (do: > ionic platform list for available platforms on your OS):
>ionic platform add <PLATFORM>
Project modifications: initial structure
1. Move the folder scss into the folder www. All sources that are compiled should we in the www
folder, so source maps can point to the original source files while debugging.
2. Change gulpfile.js so the sass folder points to the www/scss folder:
var paths = {sass: ['./www/scss/**/*.scss']};
3. Change gulpfile.js so the 'sass' task also points to the www/scss folder:
gulp.src('./www/scss/ionic.app.scss')
4. Add the folders used by the package managers www/lib, node_modules, plugins, platforms
to the .gitignore file (Gist).
All external packages, plugins and platforms should not be managed in source control.
5. When working on Windows and using Visual Studio, it is important to mark the node_modules
folder as hidden to avoid issues in Visual Studio which can’t handle deep folder structures
correctly.
6. When working in Visual Studio it is recommended that each project member create his own
solution file to be able to use different path to the project. *.suo files should be excluded from
source control.
Project modifications: npm packages
We also install the Cordova and Ionic packages locally inside the project folder so we can
ensure specific versions of Ionic and Cordova for the project.
> npm install cordova --save-dev
> npm install ionic --save-dev
Use the --save-dev option to register the packages as dependency, so they can be
pulled in later using npm install. The information about packages would be written into
package.json file (initially this file created by ionic start command).
Initially the above commands install the latest versions of Cordova and Ionic. When done
with development lock-down the used versions using the command:
> npm shrinkwrap
Project modifications: shellinit
1) The project specific node packages and their commands are installed in the folder
node_modules/.bin. Add this folder to the PATH (at the beginning) to ensure the usage of the
project specific versions of the packages.
On OSX/Linux add in the file ~/.bash-profile: export PATH=./node_modules/.bin:$PATH
On Windows add file shellinit.bat (Gist) with the following lines:
@rem Add the node_modules.bin folder (found with 'npm bin') to the
path
@cd %~dp0
@for /f %%i in ('npm bin') do set PATH=%%i;%PATH%
On Windows execute the script shellinit.bat before executing command-line commands.
2) In addition you can add the following lines to be sure that all dependent packages will be always installed
by their respective package manager and are up to date:
@rem make sure everything is installed
call npm install
call bower install
call tsd update
call tsd rebundle
call cordova restore plugins --experimental
Project modifications: hooks
When working with a Cordova hybrid app, you might need a way to extend your build process. Cordova Hooks
serves that purpose and can execute scripts before or after certain points of the build process. The obvious
example of hook usage is copying app icons and splash screens to the appropriate platform folder during build
(see more info here).
An example of hook script for copying resources that executes after Cordova’s ‘prepare’ command is
hooksafter_prepare030_resource_files.js (Gist):
#!/usr/bin/env node
var fs = require('fs');
var path = require('path');
var rootdir = process.argv[2];
filestocopy.forEach(function(obj) {
Object.keys(obj).forEach(function(key) {
var val = obj[key];
var srcfile = path.join(rootdir, key);
var destfile = path.join(rootdir, val);
console.log("copying "+srcfile+" to "+destfile);
var destdir = path.dirname(destfile);
if (fs.existsSync(srcfile) && fs.existsSync(destdir)) {
fs.createReadStream(srcfile)
.pipe(fs.createWriteStream(destfile));
}
});
});
var filestocopy = [{
"config/ios/splashscreens/Default-568h@2x~iphone.png":
"platforms/ios/MyApp/Resources/splash/Default-568h@2x~iphone.png"
}, {
"config/ios/splashscreens/Default-Landscape@2x~ipad.png":
"platforms/ios/MyApp/Resources/splash/Default-Landscape@2x~ipad.png"
}, {
"config/ios/splashscreens/Default-Landscape~ipad.png":
"platforms/ios/MyApp/Resources/splash/Default-Landscape~ipad.png"
}, {
"config/ios/splashscreens/Default-Portrait@2x~ipad.png":
"platforms/ios/MyApp/Resources/splash/Default-Portrait@2x~ipad.png"
}, {
"config/ios/splashscreens/Default-Portrait~ipad.png":
"platforms/ios/MyApp/Resources/splash/Default-Portrait~ipad.png"
}, {
"config/ios/splashscreens/Default@2x~iphone.png":
"platforms/ios/MyApp/Resources/splash/Default@2x~iphone.png"
}, {
"config/ios/splashscreens/Default~iphone.png":
"platforms/ios/MyApp/Resources/splash/Default~iphone.png"
}];
Project modifications: TypeScript interfaces
A large set of type definitions for common JavaScript libraries is managed by the DefinitlyTyped interfaces
library. In order to be able to install definitely typed interfaces (definitions) you can use the TypeScript
Definition Manager (tsd):
1. Install tsd locally (0.6.0-beta.4 or greater):
>npm install tsd@next --save-dev
At the time of writing tsd@next was a beta version. Later you should be able to install it using:
>npm install tsd -–save-dev
2. Install all needed type definitions. For example all cordova plugins definitions:
>cd www
>tsd install cordova/* --save –overwrite
--save –overwrite flags will save a list of installed definitions in tsd.json.
3. Add the tsd.json file to source control. Exclude the typings folder (wwwtypings) from source control.
It is possible to update or restore all definitions files configured in tsd.json by:
> tsd reinstall
> tsd rebundle - create the tsd.d.ts file included by _reference.ts
Project modifications: TypeScript compiler
1. In order to be able to compile TypeScript into JavaScript we need to install the gulp-tsc npm module:
> npm install gulp-tsc —save-dev
2. In the default Ionic gulpfile.js add the following bold lines to support TypeScript compilation (Gist):
var typescript = require('gulp-tsc');
var paths = {
sass: ['./www/scss/**/*.scss'],
typescript: ['./www/scripts/**/*.ts']
};
gulp.task('default', ['sass', 'compile']);
function compileTypeScript(done) {
gulp.src(paths.typescript)
.pipe(typescript({ sourcemap: true, out: 'tslib.js', sourceRoot: '../scripts' }))
.pipe(gulp.dest('./www/js/'))
.on('end', done);
}
gulp.task('compile', compileTypeScript);
gulp.task('watch', function() {
compileTypeScript();
gulp.watch(paths.sass, ['sass']);
gulp.watch(paths.typescript, ['compile']);
});
3. The above additions compile all TypeScript files in the www/scripts folder to a single file www/js/tslib.js. Include this resulting JavaScript file in
index.html:
<script src="js/tslib.js"></script>
Working with Typescript
1. Each TypeScript file should begin with the line:
/// <reference path='../_reference.ts'/>
Using this reference all TypeScript files ‘know’ about each other, and editors like Visual Studio
can provide intellisense.
2. Create a _reference.ts file in the www/scripts. This file should contain references to all
theTypeScript files in the project: typings, services, controllers, directives, interfaces and of
course the main entrypoint of the app, app.ts:
/// <reference path='../typings/tsd.d.ts' />
/// <reference path="controllers/MyController.ts" />
/// <reference path="services/MyService.ts" />
/// <reference path="directives/MyDirective.ts" />
/// <reference path="interfaces/MyInterface.ts" />
/// <reference path="app.ts" />
Note that the file ../typings/tsd.d.ts is generated and maintained by the tsd tool.
app.ts template
app.ts is the entry point of the app (Gist).
1. Add reference to _reference.ts:
/// <reference path="_reference.ts"/>
2. We declare an interface for the global rootScope object
$rootScope:
interface IAppRootScopeService extends
ng.IRootScopeService {
online: boolean;
lastScrollTimestamp: number;
isScrolling: () => boolean;
onScroll: () => void;
}
3. Directives are registered using angular.module() calls:
var myApp: ng.IModule = angular.module("angularApp", [
"ngSanitize",
"ionic",
"directive.bindonce",
]);
4. Services should be registered using myApp.service() calls:
myApp.service("serviceName",
myNameSpace.MyServiceClassName);
5. Controllers should be registered in the UI-routing structure (Learn
more here: https://github.com/angular-ui/ui-router).
myApp.config(($stateProvider, $urlRouterProvider) => {
$stateProvider.state("view", {
url: "/view",
templateUrl: "views/view.html",
controller: "ViewController"
});
});
6. Actual code entry point of the app is myApp.run():
myApp.run(
function (
$rootScope: ft.IAppRootScopeService
) {
// myApp entry point
}
);
Controller template
1) Add reference in _reference.ts
2) Bind in app.ts to angular UI-router state:
.state(‘home', {
templateUrl: "views/home.html",
controller: “MyController”
});
/// <reference path='../_reference.ts'/>
interface IMyControllerScope extends ng.IScope {
vm: IMyController; // now our view model (vm) in the scope is typed
}
interface IMyController {
myString: string;
myFunction: (arg) => boolean;
}
class MyController implements IMyController {
myString: string = ‘initial value’;
// $inject annotation. It provides $injector with information about dependencies to be injected into constructor
// it is better to have it close to the constructor, because the parameters must match in count and type.
// See http://docs.angularjs.org/guide/di
public static $inject = [
"$scope",
"$rootScope“
];
constructor(
private $scope: IMyControllerScope,
private $rootScope: IAppRootScopeService
) {
var currentClass: MyController = this;
$scope.vm = this;
$scope.$on("$destroy", () => {
// Clean up detached Dom elements
// Clean up attached listeners
});
currentClass.myString = 'assigning variables here';
}
myFunction(arg): boolean {
// arg processing here
return true;
}
}
Gist of the template
Service template
/// <reference path='../_reference.ts'/>
module myNameSpace {
"use strict";
export class MyServiceClassName {
public static $inject = [
"$log"
];
public pubVar: string;
private privVar: string;
constructor(
private $log: ng.ILogService
) {
privVar = ‘5’;
}
someFunction(element): number {
return parseInt(privVar, 10);
}
}
}
Register a service:
1) Add reference in _reference.ts
2) Register in app.ts:
var myApp: ng.IModule = angular.module("angularApp",
[
"ngSanitize",
"ionic",
"directive.bindonce",
]);
myApp.service(“serviceName", myNameSpace.MyServiceClassName);
Gist of the template
Note that we’re creating a service inside myNameSpace name space. This kind of structure is useful for big proje
cts. As an example you can redefine some interface inside a certain namespace and it will not affect the code out
side this name space.
Directive template
/// <reference path='../../typings/angularjs/angular.d.ts' />
interface IMyDirectiveScope extends ng.IScope {
bookmarker: string;
}
angular.module('directive.bindonce', [])
.directive('bindOnce', function () {
return {
restrict: 'A',
scope: true,
link: ($scope: IMyDirectiveScope): void => {
setTimeout(() => {
$scope.$destroy();
}, 0);
}
}
});
Register a directive:
1) Add reference in _reference.ts
2) Register in app.ts file:
var myApp: ng.IModule = angular.module("angularApp",
[
"ngSanitize",
"ionic",
"directive.bindonce",
]);
Nota bene: Always use functions for your directive definitions. See: http://discventionstech.wordpress.com/2014/01/19/wri
te-angularjs-code-using-typescript/
Gist of the bind-once directive
Restore existing project from source control
1. Update/install node.js (http://nodejs.org/)
2. Pull existing project
3. >cd root_directory_of_the_project
4. >shellinit.bat - This script configures settings for command-line development with local node_modules and
automatically runs:
npm install – reads package.json file and installs listed packages and dependencies
bower install – reads bower.json file and installs listed JavaScript libraries
tsd update – reads tsd.json and installs TypeScript interfaces
tsd rebundle – create tsd.d.ts file which is included to the project for references to TypeScript interfaces
cordova restore plugins --experimental – reads the Cordova config.xml and installs listed plugins
5. When working on Windows AND using Visual Studio, it is important to mark the node_modules folder as hidden to
avoid issues in Visual Studio which can’t handle deep folder structures correctly.
6. >ionic platform add <PLATFORM> - Adds target platform and copies installed plugins.
Running app
To run the app on Android device:
1) enable usb debugging on your device (see tutorial)
2) install OEM USB Drivers (see docs)
3) >gulp – to build the project
4) >ionic run android – to run app from device’s file system
>ionic run android ––livereload – to run app in remote server and access it from your device.
Changing any of the source files will result in an immediate compilation and reload of the app. This option is
extremely useful during development and debugging.
To run the app on Genymotion Android emulator:
1) disable hyper-v (see tutorial)
2) install genymotion Android emulator (http://www.genymotion.com)
3) >ionic run android or >ionic run android –livereload (note that for Genymotion you
should use >ionic run instead of ionic emulate)
To run the app on IOS device
//to do
To run the app on IOS emulator
//to do
To run the app in PC browser (without Cordova support):
>ionic serve – same as run --livereload but this time without Cordova and in the desktop browser.
Debugging
1) Android chrome debugging (Android version 4.4+)
The app uses a web browser component running the Cordova api to
communicate with native features of the device or emulator. The app can be
debugged using the Chrome browser. The Chrome browser allows to connect
remotely (url: chrome://inspect/#devices) to the app running on an
android device or emulator using usb debugging. Note that this approach is
not possible if you have an Android version less than 4.4.
2) IOS safari debugging
//to do
Development tools
Windows:
1) Visual Studio as an editor
2) Genymotion android emulator
3) ConEmu - Windows terminal supporting multiple tabs
4) TotalCommander with ADB plugin to get access to the file system of
the device or emulator
OSX:
WebStorm
iFunBox
Accessing the file system
Files on a device could be accessed for read and write using org.apache.cordova.file plugin. As of
v1.2.0, URLs to important file-system directories are provided as constants which make it extremely
convenient, because file system on different platforms vary significantly. As an example the path to
the application directory in the code looks like
var path = cordova.file.applicationDirectory for both Android and iOS, but the actual
value of path variable would be different.
It is important to know that:
1) >ionic serve – doesn’t use Cordova at all and runs in desktop browser only. This command
creates a small webserver which runs the app. To read files you can use $http requests.
2) >ionic run <PLATFORM>
>ionic emulate <PLATFORM> - these runs will actually install the app on the device (or
emulator) and you will have full access to the file system and app files via the cordova.file
plugin.
3) >ionic run <PLATFORM> --livereload
>ionic emulate <PLATFORM> --livereload
these commands create a remote livereload webserver and access it from the browser component in
the app. You do have access to device’s file system with the cordova.file plugin here, but you
can not access the HTML, JavaScript and CSS files embedded in the app.
Development strategy
1) Start with browser based (w/o Cordova) development using Chrome, simulate device
functionality where possible
• Fast development cycle (>ionic serve)
• Full Chrome debugging power
• Possible to release app preview as an url accessible on dropbox or other location
2) To develop interactions with a device we should use livereload approach using a real device or
an emulator (>ionic run <PLATFORM> --livereload)
3) Develop for Android, test on iOS
• From Android 4.4 full remote debugging and profiling through Chrome inspect
• iOS debugging is “suboptimal”
4) Test for the correct css layout on different devices for every platform.
5) Test JavaScript functionallity of the app in different platforms. The behaviour might be different
(As an example: not all Cordova plugins are cross-platform).
Best coding practices
1. Don’t use ‘this’ pointer directly in a code as it is misleading and most likely will produce
scope-related errors(in case of nested functions). Instead you should assign value of ‘this’
pointer to a definitly typed variable:
var currentClass: ClassName = this;
2. Use types for all variables and functions as it helps to find type missmach.
3. Read best coding practices for TypeScript.
4. Read angularJS ‘style guide’ which contain the best coding practices for angular.
Debug/release code compilation
In order to place the app into the web store it is recommended to:
1.minify HTML, CSS and JavaScript code
2.uglify JavaScript code
3.remove all comments from HTML, CSS and JavaScript
Install ready to use gulp modules that could perform these tasks:
1.>npm install gulp-ng-annotate -–save-dev
used to remove angularJS injections and comments and minifies
JavaScript
2.>npm install gulp-uglify –save-dev
3.>npm install gulp-sync –save-dev
helper module that is used to make sync calls of the tasks in Gulp
4.>npm install gulp-minify-html –save-dev
5.>npm install gulp-rename –save-dev
used to change file name
It is convinient to add these tasks to project gulpfile.js (see full gulpfile.js
at Gist):
var ngAnnotate = require('gulp-ng-annotate');
var uglify = require("gulp-uglify");
var gulpsync = require('gulp-sync')(gulp);
var minifyHTML = require('gulp-minify-html');
var rename = require("gulp-rename");
gulp.task('compile', compileTypeScript);
gulp.task('default', ['debug']);
gulp.task('release', gulpsync.sync(['minifyHtml', 'sass',
'compile', 'minifyJs']));
gulp.task('debug', ['sass', 'compile']);
gulp.task('minifyJs', function (done) {
gulp.src('./www/js/tslib.js')
.pipe(ngAnnotate({remove: true, add: true, single_quotes:
true}))
.pipe(uglify())
.pipe(gulp.dest('./www/js'))
.on('end', done);
});
gulp.task('minifyHtml', function (done) {
gulp.src('./www/index.html')
.pipe(minifyHTML({ empty: true }))
.pipe(rename(function (path) { path.basename += "-min"; }))
.pipe(gulp.dest('./www'));
gulp.src('./www/views/*')
.pipe(minifyHTML({ empty: true }))
.pipe(gulp.dest('./www/views/min'))
.on('end', done);
});
Now it’s much easier to compile debug/release versions of your code:
>gulp debug
>gulp release
Preparing for the store: Android
Before publishing it is necessary to:
1. increase android-versionCode in project/config.xml
file
2. Build:
>cordova build –release
3. sign the App with jarsigner (a part of Java SE
Development Kit)
4. allign the App with zipalign (a part of Android SDK)
It is convinient to write nodejs script ‘build.js’ that will
handle all mentioned tasks:
function shellExec(cmd, callback){
console.log(cmd + ' executing...');
exec(cmd, function(err, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (err !== null) {
console.error('fatal Error: ' + err);
process.exit(1);
} else {
typeof callback === 'function' && callback();
}
});
}
shellExec('cordova build --release android', function ()
{
shellExec('jarsigner -verbose -sigalg SHA1withRSA -
digestalg SHA1 –keystore <PATH_TO_KEYSTORE>
<PATH_TO_release-unsigned.apk> -storepass <PASSWORD>
elsevierMyApp', function() {
shellExec('zipalign -v 4 <PATH_TO_release-
unsigned.apk> <OUTPUT_APK_PATH>');
});
});
usage: >gulp build
Preparing for the store: iOS
//to do
Update the app without store approval
Why it’s important to avoid web store approval?
1) First of all it’s important because people which were not directly involved with developing could update a
content.
2) Second reason is that verifying a new release could take enormous amount of time for some platforms (up
to 10 days for iOS).
The idea is to build a hybrid app that will be a wrapper (bootstrapper app) for an actual App (embedded app).
Bootstrapper app should be configured (name, icons, splash) as it is embedded app and during the run it
should redirect to the actual embedded app. Luckily it is easy to do using javaScript window.location
command.
Bootstrapper app contains:
1) bootstrapper files
2) platform specific cordova.zip file with archived Cordova and plugins
3) embedded app archived into www.zip file
4) content.zip archive containing additional app content
During each start bootstrapper compares version file version.json in the app folder with version file on a
remote server. If updates found bootstrapper detects it and installs new version of the embedded app or
installs new content.
Source code for the bootstrapper you could find at Git, flow diagram you can fins in the blogpost . (Note that
this version still uses old cordova.file plugin conventions for device file system)
Optimization tips
1. Only release versions of the app should be published
2. Exclude console output in release version of the app
3. AngularJS ng-repeat might significantly slow down a hybrid app. Critical case is when each ng-
repeat item contain other angular bindin(s)
4. Minimize amount of angular bindings in HTML code
5. Allways manually unregister Jquery listeners at onDestroy event as angular don’t do it
automatically
6. Allways manually clean all detached DOM elements at onDestroy event as angular don’t do it
automatically
7. Use bind-once bindings if you don’t expect binded value to be changed (see directive template)
8. Starting from angularJS v1.3.5 It is possible to turn off angular debug data (see docs)
Ionic/Angular issues (1)
• Ionic scroll (overflow-scroll=“false”) gives problem with
$ionicScrollDelegate.scrollTo() function. We solve it by using native scrolling
(overflow-scroll=“true”)
• Tap during scroll issue. Touching of a list item during scroll process results in firing touch event of
another item. This bug could be solved by using scroll detection $ionicScrollDelegate.on-
scroll or by creating a directive in case of overflow-scroll=“false”:
angular.module('directive.scrolldetector', [])
.directive('scrollDetector', function ($window) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
function handler(e) {
scope.$evalAsync(function () {
scope.$eval((<any>attrs).scrollDetector);
});
}
scope.$on('$destroy', () => {
element[0].removeEventListener("scroll", handler);
});
element[0].addEventListener("scroll", handler);
}
}
});
Next create function that we can call to check if scrolling is active:
$rootScope.onScroll = () => {
$rootScope.lastScrollTimestamp = (new Date()).getTime();
}
$rootScope.isScrolling = () => {
//to be sure that at least 300 ms we have no scrolling
if ($rootScope.lastScrollTimestamp + 300 > (new Date()).getTime()) {
return true;
} else {
return false;
}}
usage:
in html: <ion-content overflow-scroll="true" scroll-detector="onScroll()">
in script: onTap = (e) => {
if (typeof $rootScope.isScrolling == 'function' && !$rootScope.isScrolling()) {
//tap event here
}}
Ionic/Angular issues (2)
• Angular digest loop and $ionicLoading sync issue. Let’s imagine that you want to use $ionicLoading mesage
right before script start heavy calculation. You will probably write the following:
$ionicLoading.show({ template: ‘wait…’, noBackdrop: true });
//script for heavy calc
which will result in heavy calc first and only then you will see your message. Next you will probably add
timeout wrapper to push your heave calc script call to digest loop right after $ionicLoading.show call:
$ionicLoading.show({ template: ‘wait…’, noBackdrop: true });
$timeout(()={
//script for heavy calc
});
which results with the same problem. We don’t know the clean way to solve the issue and as a workaround
we use this:
$ionicLoading.show({ template: ‘wait…’, noBackdrop: true });
$timeout(()={
//script for heavy calc
}, 300);
References
1. http://nodejs.org/
2. https://angularjs.org/
3. https://github.com/angular-ui/ui-
router
4. http://ionicframework.com/
5. http://www.typescriptlang.org/
6. http://cordova.apache.org/
7. http://plugins.cordova.io/#/
8. http://www.genymotion.com/
9. https://conemu.codeplex.com/
10. http://www.totalcmd.net/plugring/an
droid_adb.html
The end.

More Related Content

What's hot (20)

PDF
Creating an hybrid app in minutes with Ionic Framework
Julien Renaux
 
PPT
Ionic Framework
Thinh VoXuan
 
PDF
Ionic 2 intro
Wojciech Langiewicz
 
PDF
Cross Platform Mobile Apps with the Ionic Framework
Troy Miles
 
PDF
Hybrid app development with ionic
Wan Muzaffar Wan Hashim
 
PDF
Creating mobile apps - an introduction to Ionic (Engage 2016)
Mark Leusink
 
PDF
Ionic CLI Adventures
Juarez Filho
 
PDF
Workshop Ionic Framework - CC FE & UX
JWORKS powered by Ordina
 
PPTX
Introduction to Ionic framework
Shyjal Raazi
 
PPTX
Workshop on Hybrid App Development with Ionic Framework
Aayush Shrestha
 
PDF
Ionic Framework
Cristián Cortéz
 
PDF
Ionic Crash Course! Hack-a-ton SF
Lukas Ruebbelke
 
PDF
Ionic Framework
Dylan Swartz
 
PPTX
Hybrid Mobile Development with Apache Cordova and Java EE 7 (JavaOne 2014)
Ryan Cuprak
 
PDF
Ionic2
Jiayun Zhou
 
PDF
Cordova: APIs and instruments
Ivano Malavolta
 
PDF
Cordova + Ionic + MobileFirst
Raymond Camden
 
PPTX
React Native for ReactJS Devs
Barak Cohen
 
PPTX
Cross-Platform Development
Syed Owais Ali Chishti
 
Creating an hybrid app in minutes with Ionic Framework
Julien Renaux
 
Ionic Framework
Thinh VoXuan
 
Ionic 2 intro
Wojciech Langiewicz
 
Cross Platform Mobile Apps with the Ionic Framework
Troy Miles
 
Hybrid app development with ionic
Wan Muzaffar Wan Hashim
 
Creating mobile apps - an introduction to Ionic (Engage 2016)
Mark Leusink
 
Ionic CLI Adventures
Juarez Filho
 
Workshop Ionic Framework - CC FE & UX
JWORKS powered by Ordina
 
Introduction to Ionic framework
Shyjal Raazi
 
Workshop on Hybrid App Development with Ionic Framework
Aayush Shrestha
 
Ionic Framework
Cristián Cortéz
 
Ionic Crash Course! Hack-a-ton SF
Lukas Ruebbelke
 
Ionic Framework
Dylan Swartz
 
Hybrid Mobile Development with Apache Cordova and Java EE 7 (JavaOne 2014)
Ryan Cuprak
 
Ionic2
Jiayun Zhou
 
Cordova: APIs and instruments
Ivano Malavolta
 
Cordova + Ionic + MobileFirst
Raymond Camden
 
React Native for ReactJS Devs
Barak Cohen
 
Cross-Platform Development
Syed Owais Ali Chishti
 

Viewers also liked (19)

PDF
Building Mobile Applications with Ionic
Morris Singer
 
PDF
Building Mobile Apps with Cordova , AngularJS and Ionic
Kadhem Soltani
 
PDF
Ionic 2: The Power of TypeScript
Jacob Orshalick
 
PDF
Hybrid Apps with Angular & Ionic Framework
Cihad Horuzoğlu
 
PPTX
Building Flexible SharePoint Solutions with AngularJS
bgerman
 
PPT
Zend PHP 5.3 Demo Certification Test
Carlos Buenosvinos
 
PDF
Practical management of development & QA environments for SharePoint 2013
SharePointRadi
 
PPTX
Exploring the SharePoint 2013 Community Site Template
Susan Hanley
 
PDF
Ionic 2: Mobile apps with the Web
Mike Hartington
 
PDF
Intro to ionic 2
Jamal Sinclair O'Garro
 
PDF
Synergy Hub - help us create one of the coolest working spaces in Europe!
Mihai Dragomirescu
 
PPS
Sql Nexus
Amit Banerjee
 
PPTX
Hybrid mobile and Ionic
Liju Pillai
 
PPTX
Collab365 Global Summit Slides
Rick Van Rousselt
 
PPTX
European SharePoint Conference - TH3
Rick Van Rousselt
 
PPTX
Session Slides from DEVintersection Europe
Rick Van Rousselt
 
PPTX
Next Gen Portal in Office 365: April 2015. SUGUK
pearce.alex
 
PDF
Mobile HTML5 websites and Hybrid Apps with AngularJS
Carlo Bonamico
 
PPTX
Microsoft PowerApps Introduction by Usama Wahab Khan MVP
Usama Wahab Khan Cloud, Data and AI
 
Building Mobile Applications with Ionic
Morris Singer
 
Building Mobile Apps with Cordova , AngularJS and Ionic
Kadhem Soltani
 
Ionic 2: The Power of TypeScript
Jacob Orshalick
 
Hybrid Apps with Angular & Ionic Framework
Cihad Horuzoğlu
 
Building Flexible SharePoint Solutions with AngularJS
bgerman
 
Zend PHP 5.3 Demo Certification Test
Carlos Buenosvinos
 
Practical management of development & QA environments for SharePoint 2013
SharePointRadi
 
Exploring the SharePoint 2013 Community Site Template
Susan Hanley
 
Ionic 2: Mobile apps with the Web
Mike Hartington
 
Intro to ionic 2
Jamal Sinclair O'Garro
 
Synergy Hub - help us create one of the coolest working spaces in Europe!
Mihai Dragomirescu
 
Sql Nexus
Amit Banerjee
 
Hybrid mobile and Ionic
Liju Pillai
 
Collab365 Global Summit Slides
Rick Van Rousselt
 
European SharePoint Conference - TH3
Rick Van Rousselt
 
Session Slides from DEVintersection Europe
Rick Van Rousselt
 
Next Gen Portal in Office 365: April 2015. SUGUK
pearce.alex
 
Mobile HTML5 websites and Hybrid Apps with AngularJS
Carlo Bonamico
 
Microsoft PowerApps Introduction by Usama Wahab Khan MVP
Usama Wahab Khan Cloud, Data and AI
 
Ad

Similar to Building an Ionic hybrid mobile app with TypeScript (20)

PPTX
Pemrograman mobile menggunakan ionic framework
Puguh Rismadi
 
PDF
Developing ionic apps for android and ios
gautham_m79
 
PDF
Ionic2 First Lesson of Four
Ahmed Mahmoud Kesha
 
PDF
[2015/2016] Apache Cordova
Ivano Malavolta
 
PDF
Cordova 101
Rob Dudley
 
PDF
Apache Cordova 4.x
Ivano Malavolta
 
PPTX
Ionic framework
Software Infrastructure
 
PPTX
Introduction To Ionic3
Knoldus Inc.
 
PPTX
Hybrid Mobile Development with Apache Cordova,AngularJs and ionic
Ermias Bayu
 
PDF
Apache Cordova
Ivano Malavolta
 
PDF
Building Cross-Platform Mobile Apps
Troy Miles
 
PPTX
Hybrid Mobile Applications
Ruwan Ranganath
 
PPTX
Cross-Platform Development using Angulr JS in Visual Studio
Mizanur Sarker
 
PDF
Cross Platform Mobile Apps with the Ionic Framework
Troy Miles
 
PDF
Hybrid Apps with Ionic Framework
Bramus Van Damme
 
PPTX
[not edited] Demo on mobile app development using ionic framework
Sayed Ahmed
 
PDF
Top Cordova Challenges and How to Tackle Them
Ionic Framework
 
Pemrograman mobile menggunakan ionic framework
Puguh Rismadi
 
Developing ionic apps for android and ios
gautham_m79
 
Ionic2 First Lesson of Four
Ahmed Mahmoud Kesha
 
[2015/2016] Apache Cordova
Ivano Malavolta
 
Cordova 101
Rob Dudley
 
Apache Cordova 4.x
Ivano Malavolta
 
Ionic framework
Software Infrastructure
 
Introduction To Ionic3
Knoldus Inc.
 
Hybrid Mobile Development with Apache Cordova,AngularJs and ionic
Ermias Bayu
 
Apache Cordova
Ivano Malavolta
 
Building Cross-Platform Mobile Apps
Troy Miles
 
Hybrid Mobile Applications
Ruwan Ranganath
 
Cross-Platform Development using Angulr JS in Visual Studio
Mizanur Sarker
 
Cross Platform Mobile Apps with the Ionic Framework
Troy Miles
 
Hybrid Apps with Ionic Framework
Bramus Van Damme
 
[not edited] Demo on mobile app development using ionic framework
Sayed Ahmed
 
Top Cordova Challenges and How to Tackle Them
Ionic Framework
 
Ad

Recently uploaded (20)

PPTX
Java Native Memory Leaks: The Hidden Villain Behind JVM Performance Issues
Tier1 app
 
PDF
Odoo CRM vs Zoho CRM: Honest Comparison 2025
Odiware Technologies Private Limited
 
PDF
Understanding the Need for Systemic Change in Open Source Through Intersectio...
Imma Valls Bernaus
 
PDF
Beyond Binaries: Understanding Diversity and Allyship in a Global Workplace -...
Imma Valls Bernaus
 
PDF
Capcut Pro Crack For PC Latest Version {Fully Unlocked} 2025
hashhshs786
 
PPTX
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
PDF
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
PDF
Automate Cybersecurity Tasks with Python
VICTOR MAESTRE RAMIREZ
 
PPTX
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
PDF
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
PPTX
Revolutionizing Code Modernization with AI
KrzysztofKkol1
 
PPTX
Comprehensive Guide: Shoviv Exchange to Office 365 Migration Tool 2025
Shoviv Software
 
DOCX
Import Data Form Excel to Tally Services
Tally xperts
 
PPTX
Fundamentals_of_Microservices_Architecture.pptx
MuhammadUzair504018
 
PDF
Alarm in Android-Scheduling Timed Tasks Using AlarmManager in Android.pdf
Nabin Dhakal
 
PPTX
MiniTool Power Data Recovery Full Crack Latest 2025
muhammadgurbazkhan
 
PPTX
3uTools Full Crack Free Version Download [Latest] 2025
muhammadgurbazkhan
 
PDF
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
PDF
Streamline Contractor Lifecycle- TECH EHS Solution
TECH EHS Solution
 
PDF
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 
Java Native Memory Leaks: The Hidden Villain Behind JVM Performance Issues
Tier1 app
 
Odoo CRM vs Zoho CRM: Honest Comparison 2025
Odiware Technologies Private Limited
 
Understanding the Need for Systemic Change in Open Source Through Intersectio...
Imma Valls Bernaus
 
Beyond Binaries: Understanding Diversity and Allyship in a Global Workplace -...
Imma Valls Bernaus
 
Capcut Pro Crack For PC Latest Version {Fully Unlocked} 2025
hashhshs786
 
Equipment Management Software BIS Safety UK.pptx
BIS Safety Software
 
GetOnCRM Speeds Up Agentforce 3 Deployment for Enterprise AI Wins.pdf
GetOnCRM Solutions
 
Automate Cybersecurity Tasks with Python
VICTOR MAESTRE RAMIREZ
 
A Complete Guide to Salesforce SMS Integrations Build Scalable Messaging With...
360 SMS APP
 
Unlock Efficiency with Insurance Policy Administration Systems
Insurance Tech Services
 
Revolutionizing Code Modernization with AI
KrzysztofKkol1
 
Comprehensive Guide: Shoviv Exchange to Office 365 Migration Tool 2025
Shoviv Software
 
Import Data Form Excel to Tally Services
Tally xperts
 
Fundamentals_of_Microservices_Architecture.pptx
MuhammadUzair504018
 
Alarm in Android-Scheduling Timed Tasks Using AlarmManager in Android.pdf
Nabin Dhakal
 
MiniTool Power Data Recovery Full Crack Latest 2025
muhammadgurbazkhan
 
3uTools Full Crack Free Version Download [Latest] 2025
muhammadgurbazkhan
 
Mobile CMMS Solutions Empowering the Frontline Workforce
CryotosCMMSSoftware
 
Streamline Contractor Lifecycle- TECH EHS Solution
TECH EHS Solution
 
iTop VPN With Crack Lifetime Activation Key-CODE
utfefguu
 

Building an Ionic hybrid mobile app with TypeScript

  • 1. Building a cross-platform Hybrid Ionic App with TypeScript Lessons learned in building a real-world hybrid application using the Ionic framework and TypeScript Oleksandr Zinchenko [Macaw], Serge van den Oever [Macaw]
  • 2. Versions used This document is produced when using the following versions: • Cordova version 4.1.2 (cordova --version) • Ionic version 1.2.8 (ionic --version) • Ionic framework version 1.0.0-beta.11 (ionic lib)
  • 3. Contents 1. Introduction 2. Minimal Ionic project structure 3. Create a project 4. Project modifications: initial structure 5. Project modifications: npm packages 6. Project modifications: shellinit 7. Project modifications: hooks 8. Project modifications: TypeScript interfaces 9. Project modifications: TypeScript compiler 10.Working with Typescript 11.app.ts template 12.Controller template 13.Service template 14.Directive template 15.Restore existing project from source control 16.Running app 17.Debugging 18.Development tools 19.Accessing the file system 20.Development strategy 21.Best coding practices 22.Debug/release code compilation 23.Preparing for the store: Android 24.Preparing for the store: iOS 25.Update the app without store approval 26.Optimization tips 27.Ionic/Angular issues (1) 28.Ionic/Angular issues (2) 29.References
  • 4. Introduction TypeScript. TypeScript is a strict superset of JavaScript, and adds optional static typing and class-based object-oriented programming to the language. It is designed for development of large applications and transcompiles to JavaScript. Additional features include: 1) Type annotations and compile-time type checking 2) Interfaces 3) Classes 4) Modules 5) Abbreviated "arrow" syntax for anonymous functions Cordova. Apache Cordova is a set of device APIs that allow to access native device function from JavaScript. Combined with a UI framework this allows to create cross-platform app using just HTML, CSS and JavaScript. Cordova command-line interface (cli) includes: 1) create template Cordova project 2) build app for target platform using the same source code 3) run app in an emulator or device Angular. AngularJS lets you write client-side single-page web applications using JavaScript. Its goal is to simplify both development and testing of an app by providing a framework for client-side model-view-controller (MVC) architecture. Most important concepts in AngularJS: 1) Services 2) Controllers 3) Directives Ionic. Ionic is an open source front-end SDK (CSS framework and a Javascript UI library) for developing hybrid mobile apps with HTML5. Ionic Javascript UI library is built on top of angular and cordova. The Ionic framework introduces its own command-line interface (cli) on top of the Cordova cli. Ionic cli extends Cordova cli with: 1) livereload - reload app immediately after code changes 2) packaging for store deployment – certificates 3) build in the cloud - build for iOS on Windows 4) Gulp build system and the Bower package manager The purpose of the current presentation is to show the complete developing cycle of a cross-platform hybrid app using Cordova, Angular, Ionic and TypeScript.
  • 5. Minimal Ionic project structure The following folders and files would be created in new project: hooks - used to “hook in” actions during the different stages of the Ionic (or actually Cordova) build process node_modules - project specific node.js modules plugins - Cordova plugins are located here scss - the sass files are managed here, builds to css (we move this folder into www to enable css debugging based on generated map files in the sass compilation) www - the actual folder where the source code for our app lives. The www folder contains all files that are packaged into the native host application. All other folders and files are there to support the build process of the native application, or contains sources compiled into the www folder (like the scss folder, which we move into www). Ionic uses two package management systems: • npm - for node packages, useful for installing packages to extends the build process • packages required are managed through package.json • packages are installed in the folder node_modules • Bower - managing client-side libraries • .bowerrc contains the Bower configuration: { "directory": “www/lib" } all client-side library packages are installed in www/lib • packages required are managed through bower.json gulpfile.js is the “makefile” for the Gulp build system config.xml is the Cordova configuration file that is used in building the hybrid app
  • 6. Create a project 1. Use either Windows, OSX or Linux (We only tested on Windows and OSX) 2. Make sure that node.js is installed (see http://nodejs.org/) 3. install the node package cordova and ionic globally using the node.js package manager: >npm install cordova -g (or update if already installed) >npm install ionic -g (or update if already installed) 4. Create ionic project: >ionic start myapp blank --appname "My App" –id com.mycompany.myapp --sass 5. where: myapp is the folder created in the current folder for your project blank is the template used for the project --appname specifies the name of the app --id specifies the package name (internal name) --sass specifies to use SASS for CSS precompiling 6. Add target platform (do: > ionic platform list for available platforms on your OS): >ionic platform add <PLATFORM>
  • 7. Project modifications: initial structure 1. Move the folder scss into the folder www. All sources that are compiled should we in the www folder, so source maps can point to the original source files while debugging. 2. Change gulpfile.js so the sass folder points to the www/scss folder: var paths = {sass: ['./www/scss/**/*.scss']}; 3. Change gulpfile.js so the 'sass' task also points to the www/scss folder: gulp.src('./www/scss/ionic.app.scss') 4. Add the folders used by the package managers www/lib, node_modules, plugins, platforms to the .gitignore file (Gist). All external packages, plugins and platforms should not be managed in source control. 5. When working on Windows and using Visual Studio, it is important to mark the node_modules folder as hidden to avoid issues in Visual Studio which can’t handle deep folder structures correctly. 6. When working in Visual Studio it is recommended that each project member create his own solution file to be able to use different path to the project. *.suo files should be excluded from source control.
  • 8. Project modifications: npm packages We also install the Cordova and Ionic packages locally inside the project folder so we can ensure specific versions of Ionic and Cordova for the project. > npm install cordova --save-dev > npm install ionic --save-dev Use the --save-dev option to register the packages as dependency, so they can be pulled in later using npm install. The information about packages would be written into package.json file (initially this file created by ionic start command). Initially the above commands install the latest versions of Cordova and Ionic. When done with development lock-down the used versions using the command: > npm shrinkwrap
  • 9. Project modifications: shellinit 1) The project specific node packages and their commands are installed in the folder node_modules/.bin. Add this folder to the PATH (at the beginning) to ensure the usage of the project specific versions of the packages. On OSX/Linux add in the file ~/.bash-profile: export PATH=./node_modules/.bin:$PATH On Windows add file shellinit.bat (Gist) with the following lines: @rem Add the node_modules.bin folder (found with 'npm bin') to the path @cd %~dp0 @for /f %%i in ('npm bin') do set PATH=%%i;%PATH% On Windows execute the script shellinit.bat before executing command-line commands. 2) In addition you can add the following lines to be sure that all dependent packages will be always installed by their respective package manager and are up to date: @rem make sure everything is installed call npm install call bower install call tsd update call tsd rebundle call cordova restore plugins --experimental
  • 10. Project modifications: hooks When working with a Cordova hybrid app, you might need a way to extend your build process. Cordova Hooks serves that purpose and can execute scripts before or after certain points of the build process. The obvious example of hook usage is copying app icons and splash screens to the appropriate platform folder during build (see more info here). An example of hook script for copying resources that executes after Cordova’s ‘prepare’ command is hooksafter_prepare030_resource_files.js (Gist): #!/usr/bin/env node var fs = require('fs'); var path = require('path'); var rootdir = process.argv[2]; filestocopy.forEach(function(obj) { Object.keys(obj).forEach(function(key) { var val = obj[key]; var srcfile = path.join(rootdir, key); var destfile = path.join(rootdir, val); console.log("copying "+srcfile+" to "+destfile); var destdir = path.dirname(destfile); if (fs.existsSync(srcfile) && fs.existsSync(destdir)) { fs.createReadStream(srcfile) .pipe(fs.createWriteStream(destfile)); } }); }); var filestocopy = [{ "config/ios/splashscreens/Default-568h@2x~iphone.png": "platforms/ios/MyApp/Resources/splash/Default-568h@2x~iphone.png" }, { "config/ios/splashscreens/Default-Landscape@2x~ipad.png": "platforms/ios/MyApp/Resources/splash/Default-Landscape@2x~ipad.png" }, { "config/ios/splashscreens/Default-Landscape~ipad.png": "platforms/ios/MyApp/Resources/splash/Default-Landscape~ipad.png" }, { "config/ios/splashscreens/Default-Portrait@2x~ipad.png": "platforms/ios/MyApp/Resources/splash/Default-Portrait@2x~ipad.png" }, { "config/ios/splashscreens/Default-Portrait~ipad.png": "platforms/ios/MyApp/Resources/splash/Default-Portrait~ipad.png" }, { "config/ios/splashscreens/Default@2x~iphone.png": "platforms/ios/MyApp/Resources/splash/Default@2x~iphone.png" }, { "config/ios/splashscreens/Default~iphone.png": "platforms/ios/MyApp/Resources/splash/Default~iphone.png" }];
  • 11. Project modifications: TypeScript interfaces A large set of type definitions for common JavaScript libraries is managed by the DefinitlyTyped interfaces library. In order to be able to install definitely typed interfaces (definitions) you can use the TypeScript Definition Manager (tsd): 1. Install tsd locally (0.6.0-beta.4 or greater): >npm install tsd@next --save-dev At the time of writing tsd@next was a beta version. Later you should be able to install it using: >npm install tsd -–save-dev 2. Install all needed type definitions. For example all cordova plugins definitions: >cd www >tsd install cordova/* --save –overwrite --save –overwrite flags will save a list of installed definitions in tsd.json. 3. Add the tsd.json file to source control. Exclude the typings folder (wwwtypings) from source control. It is possible to update or restore all definitions files configured in tsd.json by: > tsd reinstall > tsd rebundle - create the tsd.d.ts file included by _reference.ts
  • 12. Project modifications: TypeScript compiler 1. In order to be able to compile TypeScript into JavaScript we need to install the gulp-tsc npm module: > npm install gulp-tsc —save-dev 2. In the default Ionic gulpfile.js add the following bold lines to support TypeScript compilation (Gist): var typescript = require('gulp-tsc'); var paths = { sass: ['./www/scss/**/*.scss'], typescript: ['./www/scripts/**/*.ts'] }; gulp.task('default', ['sass', 'compile']); function compileTypeScript(done) { gulp.src(paths.typescript) .pipe(typescript({ sourcemap: true, out: 'tslib.js', sourceRoot: '../scripts' })) .pipe(gulp.dest('./www/js/')) .on('end', done); } gulp.task('compile', compileTypeScript); gulp.task('watch', function() { compileTypeScript(); gulp.watch(paths.sass, ['sass']); gulp.watch(paths.typescript, ['compile']); }); 3. The above additions compile all TypeScript files in the www/scripts folder to a single file www/js/tslib.js. Include this resulting JavaScript file in index.html: <script src="js/tslib.js"></script>
  • 13. Working with Typescript 1. Each TypeScript file should begin with the line: /// <reference path='../_reference.ts'/> Using this reference all TypeScript files ‘know’ about each other, and editors like Visual Studio can provide intellisense. 2. Create a _reference.ts file in the www/scripts. This file should contain references to all theTypeScript files in the project: typings, services, controllers, directives, interfaces and of course the main entrypoint of the app, app.ts: /// <reference path='../typings/tsd.d.ts' /> /// <reference path="controllers/MyController.ts" /> /// <reference path="services/MyService.ts" /> /// <reference path="directives/MyDirective.ts" /> /// <reference path="interfaces/MyInterface.ts" /> /// <reference path="app.ts" /> Note that the file ../typings/tsd.d.ts is generated and maintained by the tsd tool.
  • 14. app.ts template app.ts is the entry point of the app (Gist). 1. Add reference to _reference.ts: /// <reference path="_reference.ts"/> 2. We declare an interface for the global rootScope object $rootScope: interface IAppRootScopeService extends ng.IRootScopeService { online: boolean; lastScrollTimestamp: number; isScrolling: () => boolean; onScroll: () => void; } 3. Directives are registered using angular.module() calls: var myApp: ng.IModule = angular.module("angularApp", [ "ngSanitize", "ionic", "directive.bindonce", ]); 4. Services should be registered using myApp.service() calls: myApp.service("serviceName", myNameSpace.MyServiceClassName); 5. Controllers should be registered in the UI-routing structure (Learn more here: https://github.com/angular-ui/ui-router). myApp.config(($stateProvider, $urlRouterProvider) => { $stateProvider.state("view", { url: "/view", templateUrl: "views/view.html", controller: "ViewController" }); }); 6. Actual code entry point of the app is myApp.run(): myApp.run( function ( $rootScope: ft.IAppRootScopeService ) { // myApp entry point } );
  • 15. Controller template 1) Add reference in _reference.ts 2) Bind in app.ts to angular UI-router state: .state(‘home', { templateUrl: "views/home.html", controller: “MyController” }); /// <reference path='../_reference.ts'/> interface IMyControllerScope extends ng.IScope { vm: IMyController; // now our view model (vm) in the scope is typed } interface IMyController { myString: string; myFunction: (arg) => boolean; } class MyController implements IMyController { myString: string = ‘initial value’; // $inject annotation. It provides $injector with information about dependencies to be injected into constructor // it is better to have it close to the constructor, because the parameters must match in count and type. // See http://docs.angularjs.org/guide/di public static $inject = [ "$scope", "$rootScope“ ]; constructor( private $scope: IMyControllerScope, private $rootScope: IAppRootScopeService ) { var currentClass: MyController = this; $scope.vm = this; $scope.$on("$destroy", () => { // Clean up detached Dom elements // Clean up attached listeners }); currentClass.myString = 'assigning variables here'; } myFunction(arg): boolean { // arg processing here return true; } } Gist of the template
  • 16. Service template /// <reference path='../_reference.ts'/> module myNameSpace { "use strict"; export class MyServiceClassName { public static $inject = [ "$log" ]; public pubVar: string; private privVar: string; constructor( private $log: ng.ILogService ) { privVar = ‘5’; } someFunction(element): number { return parseInt(privVar, 10); } } } Register a service: 1) Add reference in _reference.ts 2) Register in app.ts: var myApp: ng.IModule = angular.module("angularApp", [ "ngSanitize", "ionic", "directive.bindonce", ]); myApp.service(“serviceName", myNameSpace.MyServiceClassName); Gist of the template Note that we’re creating a service inside myNameSpace name space. This kind of structure is useful for big proje cts. As an example you can redefine some interface inside a certain namespace and it will not affect the code out side this name space.
  • 17. Directive template /// <reference path='../../typings/angularjs/angular.d.ts' /> interface IMyDirectiveScope extends ng.IScope { bookmarker: string; } angular.module('directive.bindonce', []) .directive('bindOnce', function () { return { restrict: 'A', scope: true, link: ($scope: IMyDirectiveScope): void => { setTimeout(() => { $scope.$destroy(); }, 0); } } }); Register a directive: 1) Add reference in _reference.ts 2) Register in app.ts file: var myApp: ng.IModule = angular.module("angularApp", [ "ngSanitize", "ionic", "directive.bindonce", ]); Nota bene: Always use functions for your directive definitions. See: http://discventionstech.wordpress.com/2014/01/19/wri te-angularjs-code-using-typescript/ Gist of the bind-once directive
  • 18. Restore existing project from source control 1. Update/install node.js (http://nodejs.org/) 2. Pull existing project 3. >cd root_directory_of_the_project 4. >shellinit.bat - This script configures settings for command-line development with local node_modules and automatically runs: npm install – reads package.json file and installs listed packages and dependencies bower install – reads bower.json file and installs listed JavaScript libraries tsd update – reads tsd.json and installs TypeScript interfaces tsd rebundle – create tsd.d.ts file which is included to the project for references to TypeScript interfaces cordova restore plugins --experimental – reads the Cordova config.xml and installs listed plugins 5. When working on Windows AND using Visual Studio, it is important to mark the node_modules folder as hidden to avoid issues in Visual Studio which can’t handle deep folder structures correctly. 6. >ionic platform add <PLATFORM> - Adds target platform and copies installed plugins.
  • 19. Running app To run the app on Android device: 1) enable usb debugging on your device (see tutorial) 2) install OEM USB Drivers (see docs) 3) >gulp – to build the project 4) >ionic run android – to run app from device’s file system >ionic run android ––livereload – to run app in remote server and access it from your device. Changing any of the source files will result in an immediate compilation and reload of the app. This option is extremely useful during development and debugging. To run the app on Genymotion Android emulator: 1) disable hyper-v (see tutorial) 2) install genymotion Android emulator (http://www.genymotion.com) 3) >ionic run android or >ionic run android –livereload (note that for Genymotion you should use >ionic run instead of ionic emulate) To run the app on IOS device //to do To run the app on IOS emulator //to do To run the app in PC browser (without Cordova support): >ionic serve – same as run --livereload but this time without Cordova and in the desktop browser.
  • 20. Debugging 1) Android chrome debugging (Android version 4.4+) The app uses a web browser component running the Cordova api to communicate with native features of the device or emulator. The app can be debugged using the Chrome browser. The Chrome browser allows to connect remotely (url: chrome://inspect/#devices) to the app running on an android device or emulator using usb debugging. Note that this approach is not possible if you have an Android version less than 4.4. 2) IOS safari debugging //to do
  • 21. Development tools Windows: 1) Visual Studio as an editor 2) Genymotion android emulator 3) ConEmu - Windows terminal supporting multiple tabs 4) TotalCommander with ADB plugin to get access to the file system of the device or emulator OSX: WebStorm iFunBox
  • 22. Accessing the file system Files on a device could be accessed for read and write using org.apache.cordova.file plugin. As of v1.2.0, URLs to important file-system directories are provided as constants which make it extremely convenient, because file system on different platforms vary significantly. As an example the path to the application directory in the code looks like var path = cordova.file.applicationDirectory for both Android and iOS, but the actual value of path variable would be different. It is important to know that: 1) >ionic serve – doesn’t use Cordova at all and runs in desktop browser only. This command creates a small webserver which runs the app. To read files you can use $http requests. 2) >ionic run <PLATFORM> >ionic emulate <PLATFORM> - these runs will actually install the app on the device (or emulator) and you will have full access to the file system and app files via the cordova.file plugin. 3) >ionic run <PLATFORM> --livereload >ionic emulate <PLATFORM> --livereload these commands create a remote livereload webserver and access it from the browser component in the app. You do have access to device’s file system with the cordova.file plugin here, but you can not access the HTML, JavaScript and CSS files embedded in the app.
  • 23. Development strategy 1) Start with browser based (w/o Cordova) development using Chrome, simulate device functionality where possible • Fast development cycle (>ionic serve) • Full Chrome debugging power • Possible to release app preview as an url accessible on dropbox or other location 2) To develop interactions with a device we should use livereload approach using a real device or an emulator (>ionic run <PLATFORM> --livereload) 3) Develop for Android, test on iOS • From Android 4.4 full remote debugging and profiling through Chrome inspect • iOS debugging is “suboptimal” 4) Test for the correct css layout on different devices for every platform. 5) Test JavaScript functionallity of the app in different platforms. The behaviour might be different (As an example: not all Cordova plugins are cross-platform).
  • 24. Best coding practices 1. Don’t use ‘this’ pointer directly in a code as it is misleading and most likely will produce scope-related errors(in case of nested functions). Instead you should assign value of ‘this’ pointer to a definitly typed variable: var currentClass: ClassName = this; 2. Use types for all variables and functions as it helps to find type missmach. 3. Read best coding practices for TypeScript. 4. Read angularJS ‘style guide’ which contain the best coding practices for angular.
  • 25. Debug/release code compilation In order to place the app into the web store it is recommended to: 1.minify HTML, CSS and JavaScript code 2.uglify JavaScript code 3.remove all comments from HTML, CSS and JavaScript Install ready to use gulp modules that could perform these tasks: 1.>npm install gulp-ng-annotate -–save-dev used to remove angularJS injections and comments and minifies JavaScript 2.>npm install gulp-uglify –save-dev 3.>npm install gulp-sync –save-dev helper module that is used to make sync calls of the tasks in Gulp 4.>npm install gulp-minify-html –save-dev 5.>npm install gulp-rename –save-dev used to change file name It is convinient to add these tasks to project gulpfile.js (see full gulpfile.js at Gist): var ngAnnotate = require('gulp-ng-annotate'); var uglify = require("gulp-uglify"); var gulpsync = require('gulp-sync')(gulp); var minifyHTML = require('gulp-minify-html'); var rename = require("gulp-rename"); gulp.task('compile', compileTypeScript); gulp.task('default', ['debug']); gulp.task('release', gulpsync.sync(['minifyHtml', 'sass', 'compile', 'minifyJs'])); gulp.task('debug', ['sass', 'compile']); gulp.task('minifyJs', function (done) { gulp.src('./www/js/tslib.js') .pipe(ngAnnotate({remove: true, add: true, single_quotes: true})) .pipe(uglify()) .pipe(gulp.dest('./www/js')) .on('end', done); }); gulp.task('minifyHtml', function (done) { gulp.src('./www/index.html') .pipe(minifyHTML({ empty: true })) .pipe(rename(function (path) { path.basename += "-min"; })) .pipe(gulp.dest('./www')); gulp.src('./www/views/*') .pipe(minifyHTML({ empty: true })) .pipe(gulp.dest('./www/views/min')) .on('end', done); }); Now it’s much easier to compile debug/release versions of your code: >gulp debug >gulp release
  • 26. Preparing for the store: Android Before publishing it is necessary to: 1. increase android-versionCode in project/config.xml file 2. Build: >cordova build –release 3. sign the App with jarsigner (a part of Java SE Development Kit) 4. allign the App with zipalign (a part of Android SDK) It is convinient to write nodejs script ‘build.js’ that will handle all mentioned tasks: function shellExec(cmd, callback){ console.log(cmd + ' executing...'); exec(cmd, function(err, stdout, stderr) { console.log('stdout: ' + stdout); console.log('stderr: ' + stderr); if (err !== null) { console.error('fatal Error: ' + err); process.exit(1); } else { typeof callback === 'function' && callback(); } }); } shellExec('cordova build --release android', function () { shellExec('jarsigner -verbose -sigalg SHA1withRSA - digestalg SHA1 –keystore <PATH_TO_KEYSTORE> <PATH_TO_release-unsigned.apk> -storepass <PASSWORD> elsevierMyApp', function() { shellExec('zipalign -v 4 <PATH_TO_release- unsigned.apk> <OUTPUT_APK_PATH>'); }); }); usage: >gulp build
  • 27. Preparing for the store: iOS //to do
  • 28. Update the app without store approval Why it’s important to avoid web store approval? 1) First of all it’s important because people which were not directly involved with developing could update a content. 2) Second reason is that verifying a new release could take enormous amount of time for some platforms (up to 10 days for iOS). The idea is to build a hybrid app that will be a wrapper (bootstrapper app) for an actual App (embedded app). Bootstrapper app should be configured (name, icons, splash) as it is embedded app and during the run it should redirect to the actual embedded app. Luckily it is easy to do using javaScript window.location command. Bootstrapper app contains: 1) bootstrapper files 2) platform specific cordova.zip file with archived Cordova and plugins 3) embedded app archived into www.zip file 4) content.zip archive containing additional app content During each start bootstrapper compares version file version.json in the app folder with version file on a remote server. If updates found bootstrapper detects it and installs new version of the embedded app or installs new content. Source code for the bootstrapper you could find at Git, flow diagram you can fins in the blogpost . (Note that this version still uses old cordova.file plugin conventions for device file system)
  • 29. Optimization tips 1. Only release versions of the app should be published 2. Exclude console output in release version of the app 3. AngularJS ng-repeat might significantly slow down a hybrid app. Critical case is when each ng- repeat item contain other angular bindin(s) 4. Minimize amount of angular bindings in HTML code 5. Allways manually unregister Jquery listeners at onDestroy event as angular don’t do it automatically 6. Allways manually clean all detached DOM elements at onDestroy event as angular don’t do it automatically 7. Use bind-once bindings if you don’t expect binded value to be changed (see directive template) 8. Starting from angularJS v1.3.5 It is possible to turn off angular debug data (see docs)
  • 30. Ionic/Angular issues (1) • Ionic scroll (overflow-scroll=“false”) gives problem with $ionicScrollDelegate.scrollTo() function. We solve it by using native scrolling (overflow-scroll=“true”) • Tap during scroll issue. Touching of a list item during scroll process results in firing touch event of another item. This bug could be solved by using scroll detection $ionicScrollDelegate.on- scroll or by creating a directive in case of overflow-scroll=“false”: angular.module('directive.scrolldetector', []) .directive('scrollDetector', function ($window) { return { restrict: 'A', link: function (scope, element, attrs) { function handler(e) { scope.$evalAsync(function () { scope.$eval((<any>attrs).scrollDetector); }); } scope.$on('$destroy', () => { element[0].removeEventListener("scroll", handler); }); element[0].addEventListener("scroll", handler); } } }); Next create function that we can call to check if scrolling is active: $rootScope.onScroll = () => { $rootScope.lastScrollTimestamp = (new Date()).getTime(); } $rootScope.isScrolling = () => { //to be sure that at least 300 ms we have no scrolling if ($rootScope.lastScrollTimestamp + 300 > (new Date()).getTime()) { return true; } else { return false; }} usage: in html: <ion-content overflow-scroll="true" scroll-detector="onScroll()"> in script: onTap = (e) => { if (typeof $rootScope.isScrolling == 'function' && !$rootScope.isScrolling()) { //tap event here }}
  • 31. Ionic/Angular issues (2) • Angular digest loop and $ionicLoading sync issue. Let’s imagine that you want to use $ionicLoading mesage right before script start heavy calculation. You will probably write the following: $ionicLoading.show({ template: ‘wait…’, noBackdrop: true }); //script for heavy calc which will result in heavy calc first and only then you will see your message. Next you will probably add timeout wrapper to push your heave calc script call to digest loop right after $ionicLoading.show call: $ionicLoading.show({ template: ‘wait…’, noBackdrop: true }); $timeout(()={ //script for heavy calc }); which results with the same problem. We don’t know the clean way to solve the issue and as a workaround we use this: $ionicLoading.show({ template: ‘wait…’, noBackdrop: true }); $timeout(()={ //script for heavy calc }, 300);
  • 32. References 1. http://nodejs.org/ 2. https://angularjs.org/ 3. https://github.com/angular-ui/ui- router 4. http://ionicframework.com/ 5. http://www.typescriptlang.org/ 6. http://cordova.apache.org/ 7. http://plugins.cordova.io/#/ 8. http://www.genymotion.com/ 9. https://conemu.codeplex.com/ 10. http://www.totalcmd.net/plugring/an droid_adb.html