Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Conquering Mobile with JavaScript: PWAs and Nat...

Conquering Mobile with JavaScript: PWAs and NativeScript

Are you looking for a comprehensive mobile development strategy that can help you deliver “the right” mobile app for every project? Look no further. This workshop deck explores a complete workflow for building mobile apps with JavaScript (and TypeScript) that can be applied to any mobile project. From achieving maximum reach with Progressive Web Apps, to delivering maximum richness with native apps powered by JavaScript (via NativeScript), the techniques in this workshop give you the tools you need to make sure your mobile app projects don’t fail. Whether you’re looking to get up-to-speed on PWAs or discover how web skills can be used to create native mobile apps, this decks provides insights that can be immediately applied to your next mobile project.

Todd Anglin

March 29, 2018
Tweet

More Decks by Todd Anglin

Other Decks in Programming

Transcript

  1. 1. We've built apps, we need a better way 2.

    We're tired of maintaining web AND apps
  2. What we thought. Web Presence Mobile Web Presence iOS app

    Android app Voice skills Chat bots My problem Some else's problem
  3. Reality. Web Presence Mobile Web Presence *Required *Required iOS app

    Android app Preferred for high transaction apps Voice skills Coming soon Chat bots Your problem
  4. Top 3 Problems with "App Strategy v1" 1. Built native

    apps for iOS, Android – too expensive 2. Built hybrid apps – too slow, too janky 3. Built web apps – too limited
  5. Reality. Web Presence Mobile Web Presence *Required *Required iOS app

    Android app Preferred for high transaction apps Voice skills Coming soon Chat bots
  6. No compromises PWA iOS app Android app Maximum reach, discoverability

    "Light" experience Unlimited power, capability "Premium" experience
  7. We'll be using JavaScript § It's everywhere § It's the

    web § With TypeScript, it's familiar and easy
  8. What are PWAs (really)? Why do we need them? And,

    what ever happened to Responsive Web Apps?
  9. Evolution of the web Web 1.0 Responsive Web Design Progressive

    Web Apps Foundation Design for all Screens Design for offline
  10. Pillars of PWA 1. Reliable 2. Fast 3. Engaging 1.

    Progressive 2. Responsive 3. Connectivity independent 4. App-like 5. Safe 6. Discoverable 7. Re-engageable 8. Installable 9. Linkable
  11. "Progressive Web Apps use modern web capabilities to deliver an

    app- like user experience." "Progressive Web Apps work everywhere but are supercharged in modern browsers. ."
  12. Application Shell My App My App Settings Account Something else

    My App 80º Orlando 20º Boston Shell Content Cached on first visit Loaded from network
  13. Approaches to PWA 1. App Shell + SSR for Entry

    Pages 2. App Shell + CSR for Content 3. Full SSR SSR == Server Side Rendering
  14. Service Worker § It's just a separate JavaScript file §

    Special type of web worker focused on controlling network requests § Runs separate from main thread § Can run in the background (when no tab open) § No direct DOM access § Communicates with main thread via postMessages § One service worker "per scope" § Updated (at least) every 24 hours
  15. Service Worker fetch cache API for retrieving content from the

    network API for storing/retrieving cached app content/data
  16. Service Worker Lifecycle First Install 1. register 2. install 3.

    activate 4. idle Updates 1. install 2. waiting 3. activate 4. idle navigator.serviceWorker.register('./service-worker.js')
  17. Cache strategies § Cache Only § Network Only § Cache

    First, Fallback on Network § Cache First, Then Network § Cache and Network Race § Network First, Fallback on Cache § Generic Fallback
  18. Cache Only For "static" resources that change with "versions" of

    your site Page Cache Service Worker 1 2 3
  19. Network Only For resources that cannot (or should not) be

    cached Page Network Service Worker 1 2 3
  20. Cache First, Fallback on Network Primary offline-first pattern: load from

    cache if available, otherwise fetch Page Cache Service Worker Network x 1 2 3 4
  21. Network First, Fallback on Cache Load new content by default,

    or show cache if offline Page Cache Service Worker Network x 1 2 3 4
  22. Cache First, Then Network Display cached resource immediately, then update

    when network responds Page Cache Service Worker Network 1 1 2 2 3
  23. Cache and Network Race For cases where disk access may

    be slower than network response Page Cache Service Worker Network 1 2 2 3 x 3
  24. Generic Fallback For stuff that's not available in the cache

    OR on the network Page Cache Service Worker Network 1 2 3 x 5 x 4
  25. sw-precache § Auto-generates service worker at build time § Can

    handle static and dynamic caching gulp.task('generate-service-worker', function(callback) { var swPrecache = require('sw-precache'); var rootDir = 'app'; swPrecache.write(`${rootDir}/service-worker.js`, { staticFileGlobs: [rootDir + '/**/*.{js,html,css,png,jpg,gif,svg,eot,ttf,woff}'], stripPrefix: rootDir }, callback); });
  26. § Evolution of sw-precache & sw-toolbox § JavaScript library to

    handle service worker boilerplate workbox.routing.registerRoute( new RegExp('^https://fonts.(?:googleapis|gstatic).com/(.*)'), workbox.strategies.cacheFirst(), ); workbox.routing.registerRoute( /\.(?:js|css)$/, workbox.strategies.staleWhileRevalidate(), );
  27. Web App Manifest § Evolution of mobile meta tags §

    Control PWA's home screen icon, splash screen, theme colors, start URL § Helps PWA feel more "app like" (on Android) <link rel="manifest" href="/manifest.json">
  28. Image Source: Addy Osmani, https://addyosmani.com/blog/getting-started-with-progressive-web-apps/ Web App Install banner Requires:

    • Web App Manifest • HTTPS • Registered Service Worker • 2 visits, at least 5 min between visits
  29. Image Source: Addy Osmani, https://addyosmani.com/blog/getting-started-with-progressive-web-apps/ Home screen icon & splash

    screen Define: • App icon • App name • App theme color • Splash screen background color • Orientation limits
  30. • name • short_name • icons • dir • lang

    Control Home Screen • start_url • display • fullscreen, standalone, minimal-ui, browser • orientation • any, natural, landscape, portrait, landscape-preferred, landscape-secondary, portrait- preferred, portrait-secondary • background_color • theme_color Control App Behavior • description • related_ applications • prefer_ related_ applications • scope Extras
  31. Background Sync // Register your service worker: navigator.serviceWorker.register('/sw.js'); // Then

    later, request a one-off sync: navigator.serviceWorker.ready.then(function(swRegistration) { return swRegistration.sync.register('myFirstSync'); }); self.addEventListener('sync', function(event) { if (event.tag == 'myFirstSync') { event.waitUntil(doSomeStuff()); } }); In app js: In service worker:
  32. iOS & Safari § Some PWA features coming soon §

    BUT some potentially problematic differences
  33. Hybrid Promise 100% Web 100% Native Hybrid Reach Code/Skill Reuse

    Richness Premium experience Device APIs Best of both?
  34. "Hybrid" Web UI with limited access to native APIs Native

    App Shell WebView Plugins Plugins Entire app lives here
  35. Native App "JavaScript-driven Native" Native UI driven by JavaScript Native

    UI JavaScript-to-Native bridge JavaScript Engine (Your app code runs here) Native APIs
  36. “JavaScript-driven Native” • Share code • Reuse existing skills/teams •

    Reuse existing libraries • Native UI (no WebView!) • Full access to device APIs • Immediate access to new OS features Fast to market Best experience
  37. What is NativeScript? • Open source framework (ASLv2) • Create

    native mobile apps for iOS, Android (and eventually Windows 10) • Use JavaScript (“web skills”) • Write once, run everywhere • Share 100% code between iOS/Android • Share 80% code with web • Reuse popular plugins from NodeJS/iOS/Android • Integrates deeply with Angular and TypeScript
  38. 2013 2014 2015 2016 2017 Early prototypes “Core” engineering Public

    launch Adoption ramp-up Mass adoption Project Timeline 30k 170k 1m+
  39. Solid community growth • More than 6000 Slack channel members

    • Expanding community KB (forum.nativescript.org) • 1000+ unique answer providers • Over 800 community created npm plugins for {N} Top Plugins (by downloads): 1. Theme Core 2. Vue 3. Firebase 4. Image Picker 5. Google Maps SDK
  40. • Unit tested • Supports iOS & Android VERIFIED •

    Documented • Supports “vanilla” & Angular
  41. NativeScript Module Layer (NML) § Abstractions on native APIs that

    provide unified, cross- platform API § Dozens available out of the box § Easy for developers to add § IMPORTANT: All native APIs still available at JavaScript layer for platform- specific scenarios § NativeScript modules follow Node module’s conventions (CommonJS).
  42. Command Line Interface (CLI) § Use Command Prompt (Win) or

    Terminal (Mac, Linux) § Free, Part of open source project § Requires installation, local environment setup to build for iOS/Android (requires Mac for iOS) § Integrates with Visual Studio Code (via plugin) WHY: More control, Free, Integrate with existing IDEs/code editors WHO: More technical developers used to using CLI, Open source developers
  43. Sidekick § Visual companion to simplify common {N} tasks §

    Build in the cloud (no local install required) § Easiest way to get started WHY: Richer tooling, Easier setup, Platform integrated WHO: Less technical developers, Prefer Platform integrations, Windows developers targeting iOS
  44. Quickly start new apps • Choose from growing list of

    app templates • Pre-integrate with Progress cloud services
  45. Build locally or in the cloud • Build for iOS

    and Android • Use cloud builds to: • Offload local SDK configuration/ maintenance • Build for iOS from Windows • 100 free cloud builds per month • Pay for additional builds • Fast, secure
  46. Plugins for Visual Studio and VSCode • Integrated Sidekick capabilities

    • Deep integration in Visual Studio for native workflow • Build for iOS with cloud builds directly from VS • Plugins for other code editors/IDEs possible in the future • Webstorm • Eclipse
  47. Choice in Architecture JavaScript Write your application using plain JavaScript

    TypeScript Use TypeScript to get Object Oriented features and compile time error checking Angular Use Angular to architect application. Reuse almost all code between web and mobile
  48. Starting a new project (CLI) $ npm install –g nativescript

    $ tns create MyFirstProject --ng $ tns run ios
  49. CSS Convention: app.css <-- Global styles [viewName].css <-- View styles

    [viewName].[platform].css @Component({ ... styleUrls: ["./items.component.css"] })
  50. Supported Properties § color § background-color § background-image § background-repeat

    § background-position § background-size § border-color § border-width § border-radius § font § font-family § font-size § font-style § font-weight § text-align § text-decoration § text-transform § vertical-align § horizontal-align § margin § margin-top § margin-right § margin-bottom § margin-left § width § height § min-width § min-height § padding § padding-top § padding-right § padding-bottom § padding-left § visibility § opacity
  51. Supported Selectors § Element § button { color: red; }

    § Class § .mybutton { color: green; } § ID § #myButton { color: #FFF; } § Hierarchical § button .mybutton { … } § button > .mybutton { … } § Attribute § button[attr] { … } § button[attr='val'] { … } § Pseudo § button:highlighted { … }
  52. Sass & LESS § Use Sass or LESS syntax §

    Auto-compiled $ tns install sass OR $tns install less
  53. Theme Core § Bootstrap for {N} § Pre-defined CSS classes

    to quickly give apps a polished look-and-feel § iOS and Android $ npm install nativescript-theme --save
  54. Theme for text <Label text="Name" class="text- primary text-right"></Label> <Label text="Email"

    class="text- danger"></Label> Change text color: - text-primary, text- muted, text-danger Change text alignment: - text-center, text- left, text-right to Apply text transformation - text-lowercase, text- uppercase, text-capitalize
  55. Theme for buttons General style: - btn, btn-primary, btn-outline, btn-active

    Round buttons: - btn-rounded-sm and btn-rounded-lg Add color (this only work in conjunction with btn-primary): - btn-blue, btn-brown, btn-forest, btn-grey, btn-lemon, btn-lime, btn-ruby and btn-sky
  56. Theme for buttons <Button text="Primary" class="btn btn- primary"></Button> <Button text="Outline"

    class="btn btn- outline"></Button> <Button text="Orange" class="btn btn-primary btn- ornage"></Button> <Button text="Rounded Grey" class="btn btn-primary btn-grey btn-rounded- sm"></Button>
  57. Theme: Other UI components ActionBar styling: <ActionBar title="Title" class="action-bar"></ActionBar> Switch

    styling: <Switch [(ngModel)]="optIn" class="switch"></Switch> Slider styling: <Slider [(ngModel)]="size" class="slider"></Slider>
  58. Theme margin and padding Use m for Margin and p

    for Padding Add direction: -t: top -b: bottom -l: left -r: right -x: horizontal (left and right) -y: vertical (top and bottom) • 0 • 2 • 4 • 5 • 8 • 10 • 12 • 15 • 16 • 20 • 24 • 25 • 28 • 30 Available size classes:
  59. Theme margin and padding <TextBox class="m-20"... <Label class="m-r-20 p-x-2"... Examples:

    Margin all directions 20: m-20 Margin Right 10: m-r-10 Padding Left and Right 2: p-x-2
  60. Custom Fonts 1. Use TTF or OTF fonts 2. Put

    fonts in: app > fonts 3. Use in CSS .icon { font-size: 30; font-family: 'FontAwesome'; }
  61. Icon Font Helper § Angular pipe for handling icon fonts

    <Label class="fa" text="\uf293"></Label> <Label class="fa" [text]="'fa-bluetooth' | fonticon"></Label> npm install nativescript-ngx-fonticon --save
  62. Pipes § Transform bound data import { Pipe, PipeTransform }

    from "@angular/core"; @Pipe({ name: "myPipeName" }) export class MyPipe implements PipeTransform { transform(value: number): any { // Do something return newValue; } }
  63. Pages § XML markup structure § Elements (e.g. <Page>, <Label>)

    are NativeScript modules Angular Gotcha Must use closing tags with Angular
  64. Layouts: FlexBox <div style="display: flex;"> </div> == These are the

    same == <FlexboxLayout> </FlexboxLayout> Supported Flex properties: § Set flex properties via XML, CSS or JS § Uses same syntax as web § Use FlexboxLayout as root element § Same as HTML <div /> with "display: flex;" § Multiple FlexboxLayouts can be nested For containers: • flex-direction • flex-wrap • flex-flow • justify-content • align-items • align-content For children: • order • flex-grow • flex-shrink • flex • align-self • flex-wrap-before
  65. UI Widgets § Button § Label § TextField § TextView

    § SearchBar § Switch § Slider § Progress § ActivityIndicator § Image § ListView § HtmlView § WebView § TabView § SegmentedBar § DatePicker § TimePicker § ListPicker § Dialogs Out-of-the-box Native UI widgets means… • Native behavior • Native perf • Native accessibility • Parity with “native”
  66. NativeScript Pro UI Powerful collection of native iOS & Android

    UI components for advanced business use cases
  67. NativeScript UI (free) • ListView • SideDrawer • Calendar •

    Chart • DataForm • Gauges • AutoComplete
  68. Targeting Views § Target based on: § screens size §

    minWH<X>, minW<X>, minH<X> § platform § ios, android, windows § Orientation § land, port <file-name>[.<qualifier>]*.<extension> styles.android.css styles.ios.css mypage.minWH600.xml mypage.xml Angular Gotcha Angular projects only support platform targeting
  69. TIP § Platform specific capabilities are always available § JavaScript:

    <view>.android or <view>.ios § Markup: <android></android> or <ios></ios> § Attributes: android:<attribute> or ios:<attribute> § Ex: <label android:class="…" ios:class="…" /> Write once by default. Target specific platform capabilities when needed.
  70. “If debugging is the process of removing software bugs, then

    programming must be the process of putting them in.” - Edsger Dijkstra
  71. Debugging Strategies § Debug by alert (no really) § Debug

    by console.log § Debug by Developer Tools § Debug by IDE § Visual Studio § Visual Studio Code
  72. [ value ] or {{ value }} = One way

    binding from class to view
  73. import { Component } from ”@angular/core” @Component({ selector: 'app', template:

    ` <input value=”{{ message }}”> ` }); export class AppComponent { message: 'Root Component' } app.component.ts
  74. import { Component } from ”@angular/core” @Component({ selector: 'app', template:

    ` <label [text]=”message”> <button (tap)=“showMessage($event)”>Show Message</button> ` }); export class AppComponent { message: 'Root Component’; showMessage() { alert(this.message); } } app.component.ts
  75. Handling Events tap label.on(gestures.GestureTypes.tap, function (args) { console.log("Tap"); }); swipe

    label.on(gestures.GestureTypes.swipe, function (args) { console.log("Swipe Direction: " + args.direction); }); Multiple events label.on("tap, doubleTap, longPress", function (args) { console.log("Event: " + args.eventName); }); § Tap § Double Tap § Long Press § Swipe § Pan § Pinch § Rotation § Touch
  76. import { Component } from ”@angular/core” @Component({ selector: 'app', template:

    ` <input [(ngModel)]=”message”> <button (click)=“showMessage()”>Show Message</button> ` }); export class AppComponent { message: 'Root Component’; showMessage() { alert(this.message); } } app.component.ts
  77. Two-way binding import { NativeScriptFormsModule } from 'natives cript-angular/forms'; …

    imports: [ NativeScriptModule, AppRoutingModule, NativeScriptHttpModule, NativeScriptFormsModule ], § You also need to add NativeScriptForms Module to @NgModule imports
  78. import { Injectable } from ”@angular/core” export class MessageService {

    message: string = ”Service Message” } message.service.ts
  79. import { Injectable } from ”@angular/core” @Injectable() export class MessageService

    { message: string = ”Service Message” } message.service.ts
  80. import { Component } from ”@angular/core” @Component({ selector: 'app', template:

    ` <input [(ngModel)]=”message”> <button (click)=“showMessage()”>Show Message</button> ` }); export class AppComponent { message: 'Root Component’; showMessage() { alert(this.message); } } app.component.ts
  81. import { Component } from ”@angular/core” import { MessageService }

    from ”./message.service” @Component({ selector: 'app', template: ` <input [(ngModel)]=”message”> <button (click)=“showMessage()”>Show Message</button> ` }); export class AppComponent { message: 'Root Component’; showMessage() { alert(this.message); } } app.component.ts
  82. @Component({ selector: 'app', providers: [MessageService] template: ` <input [(ngModel)]=”message”> <button

    (click)=“showMessage()”>Show Message</button> ` }); export class AppComponent { message: string; showMessage() { alert(this.message); } constructor(MessageService _messageService) { this.message = _messageService.message; } app.component.ts
  83. Routing configuration const routes: Routes = [ { path: "",

    redirectTo: "/items", pathMatch: "full" }, { path: "items", component: ItemsComponent }, { path: "item/:id", component: ItemDetailComponent }, ]; § Initial routes config in NativeScript with default Angular template
  84. Routing configuration { path: "", redirectTo: "/items", pathMatch: "full" },

    Sets up the default path to redirect to /items path by default When the app starts it will automatically navigate to /items
  85. Routing configuration { path: "items", component: ItemsComponent }, § Sets

    up the items path to navigate to ItemsComponent
  86. Routing configuration { path: "item/:id", component: ItemDetailComponent } Sets up

    the item + id path to navigate to the ItemDetailComponent Additionally it will provide the id as the parameter into the ItemDetailComponent For example: calling navigate to "/item/25" will open the ItemDetailComponent with id = 25
  87. Routing configuration: Parent/Child const routes: Routes = [ { path:

    '', redirectTo: '/articles', pathMatch: 'full' }, { path: 'items', children: [ { path: '', component: ItemsComponent }, { path: ':id', component: ItemDetailComponent }, ]}, { path: 'articles', children: [ { path: '', component: ArticlesComponent }, { path: 'read/:id', component: ArticleComponent }, { path: 'edit/:id', component: EditArticleComponent }, { path: 'search/:tech/:keyword', component: ArticleSearchResultsComponent }, ]}, ];
  88. Routing configuration: Parent/Child const routes: Routes = [ … {

    path: 'articles', children: [ { path: '', component: ArticlesComponent }, { path: "read/:id", component: ArticleComponent }, { path: "edit/:id", component: EditArticleComponent }, { path: "search/:tech/:keyword", component: ArticleSearchResultsComponent } ]} ]; Navigate to "/articles" will trigger this path
  89. Routing configuration: Parent/Child const routes: Routes = [ … {

    path: 'articles', children: [ { path: '', component: ArticlesComponent }, { path: "read/:id", component: ArticleComponent }, { path: "edit/:id", component: EditArticleComponent }, { path: "search/:tech/:keyword", component: ArticleSearchResultsComponent } ]} ]; Navigate to "/articles/read/25" will trigger this path and pass 25 as the id
  90. Routing configuration: Parent/Child const routes: Routes = [ … {

    path: 'articles', children: [ { path: '', component: ArticlesComponent }, { path: "read/:id", component: ArticleComponent }, { path: "edit/:id", component: EditArticleComponent }, { path: "search/:tech/:keyword", component: ArticleSearchResultsComponent } ]} ]; Navigate to "/articles/search/web/angular" will trigger this path and pass web as the tech and angular as the keyword
  91. Navigation from template <Label text="Angular Navigation" [nsRouterLink]="['/articles/read', '5']"> </Label> §

    Add [nsRouterLink] to provide navigation instructions § Will navigate to '/articles/read/5' path
  92. Navigation from template: Relative paths Navigate to parent: [nsRouterLink]="['..']" Navigate

    to sibling: [nsRouterLink]="['../sibling']" Navigate to child: [nsRouterLink]="['./child']" [nsRouterLink]="['child']"
  93. Navigation from template: Clear History <Label text="Back to Articles" [nsRouterLink]="['..']"

    clearHistory="true"> </Label> § Use clearHistory to clear the navigation stack
  94. Navigation with code import { Router } from '@angular/router'; //

    or import { RouterExtensions } from 'nativescript-angular'; Navigation is easy: 1. Import the router you need 2. Inject the router in the constructor 3. Call navigate
  95. Navigation with code constructor(private router: RouterExtensions) { } Navigation is

    easy: 1. Import the router you need 2. Inject the router in the constructor 3. Call navigate
  96. Navigation with code readArticle(id: number) { this.router.navigate(['/articles/read', id]); } Navigation

    is easy: 1. Import the router you need 2. Inject the router in the constructor 3. Call navigate
  97. Navigation with code: Relative Path import { ActivatedRoute } from

    '@angular/router'; 1. Import ActivatedRoute 2. Inject it in the constructor 3. Provide it as a parameter f or `navigate`, as `relativeTo`
  98. Navigation with code: Relative Path constructor( private router: RouterExtensions, private

    route: ActivatedRoute) { } 1. Import ActivatedRoute 2. Inject it in the constructor 3. Provide it as a parameter f or `navigate`, as `relativeTo`
  99. Navigation with code: Relative Path this.router.navigate(['./read', id], { relativeTo: this.route

    }); 1. Import ActivatedRoute 2. Inject it in the constructor 3. Provide it as a parameter for `navigate`, as `relativeTo`
  100. Navigation with code: Relative path Navigate to parent: this.router.navigate(['..'], {relativeTo:

    this.route}); Navigate to sibling: this.router.navigate(['../sibling'], {relativeTo: this.route}); Navigate to child: this.router.navigate(['./child'], {relativeTo: this.route}); this.router.navigate(['child'], {relativeTo: this.route});
  101. Clear History this.router.navigate(['/articles', { clearHistory: true }]); § To clear

    history just provide clearHistory into navigate, as an optional parameter
  102. Navigating back There are two functions available from RouterExtensions: -

    this.router.back() – goes one step back - this.router.backToPreviousPage() – goes to the previous page
  103. ArticlesComponent back vs backToPreviousPage 1. navigate `/articles` 2. navigate `/articles/read/1`

    3. navigate `/articles/read/4` 4. navigate `/articles/edit/7` ReadComponent EditComponent [1] articles [2] read/1 [3] read/4 [4] edit/6
  104. Receiving parameters import { ActivatedRoute } from '@angular/router'; 1. Import

    ActivatedRoute 2. Inject it in the constructor 3. Extract the params from route.snapshot. params
  105. Receiving parameters constructor( private router: RouterExtensions, private route: ActivatedRoute) {

    } 1. Import ActivatedRoute 2. Inject it in the constructor 3. Extract the params from route.snapshot. params
  106. Receiving parameters ngOnInit() { this.tech = this.route.snapshot.params['tech']; this.keyword = this.route.snapshot.params['keyword'];

    this.searchArticles(this.tech, this.keyword); } 1. Import ActivatedRoute 2. Inject it in the constructor 3. Extract the params from route.snapshot. params
  107. Receiving parameters: Navigating to self ngOnInit() { this.route.params.forEach(params => {

    this.tech = params['tech']; this.keyword = params['keyword']; this.searchArticles(this.tech, this.keyword); }); } § Use route.params Observable and then the snapshot
  108. Page Transitions § curl (same as curlUp) (iOS only) §

    curlUp (iOS only) § curlDown (iOS only) § explode (Android only) § fade § flip (same as flipRight) § flipRight § flipLeft § slide (same as slideLeft) § slideLeft § slideRight § slideTop § slideBottom
  109. Use Transition from Code this.router.navigate(['/relative/path'], { transition: { name: 'slideBottom',

    duration: 500, curve: 'linear' } }); § Provide transition attribute into the optional parameters
  110. Animations 1. Leveraging Angular-style animation 2. Use NativeScript's built-in animation

    library 3. Use Animate.css 4. Use CSS keyframe animation techniques 5. Use Lottie (AirBnB's library) or Keyframes (by Facebook) animations 6. Use a community-generated animation plugin
  111. Animations @keyframes zoom { from { transform: scale(0.5, 0.5) }

    40% { transform: scale(1.6, 1.6) } to { transform: scale(1.0,1.0) } } .zoom { animation-name: zoom; animation-duration: 2s; } § CSS keyframe animation example
  112. Animation basics Animate: § opacity § backgroundColor § translateX and

    translateY § scaleX and scaleY § rotate Configure: § target (UI element) § duration (in ms) § delay § iterations § curve
  113. Simple animation var view = page.getViewById("myLabel"); view.animate({ translate: { x:

    0, y: 100}, duration: 1000, curve: enums.AnimationCurve.easeIn }); § Animations can be chained together § Multiple properties and elements can be animated § Return a promise that can be canceled
  114. Code Sharing § One code base, web and mobile §

    Share logic, routes, etc § Build views optimized for each platform
  115. Options § Start with a "seed" project § Convert an

    existing {N} project § Convert an existing Angular web project (coming soon)
  116. Why do this? § Improve developer workflow across web, mobile

    § Share more code/assets between web, mobile § Deliver web, mobile updates simultaneusly
  117. No compromises PWA iOS app Android app Maximum reach, discoverability

    "Light" experience Unlimited power, capability "Premium" experience +
  118. • Largely read-only • Simple user interactions • Mostly dynamic

    content • No need to access device APIs • No need for encrypted device storage • Web distribution • Frequently used • More complex user interactions • Need for access to device APIs • Need for encrypted storage • App store distribution PWA