Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

HotPush with Ionic 2 and CodePush

3,986 views

Published on

HotPush with Ionic 2 and CodePush

  1. 1. Hot Updates using CodePush and Ionic 2 [hot push across the dev lifecycle] 1 / 65
  2. 2. Evan Schultz twitter: @e_p82 github: e-schultz Hello, etc... 2 / 65
  3. 3. Evan Schultz twitter: @e_p82 github: e-schultz Bertrand Karerangabo twitter: @codenarian github: bertrandk Hello, etc... 3 / 65
  4. 4. Agenda Review Prerequisites Resources Ionic 2 CodePush CodePushify Your App Create a Sync Tab Deploying to Staging Selecting Deployments Synching Multiple Versions Detailed Sync & Download Progress Q & A 4 / 65
  5. 5. Prerequisites node git CodePush cli tools Ionic2 CLI tools XCode 5 / 65
  6. 6. Resources: Slide Repo: https://github.com/rangle/codepush-phonegap-days Demo Repo: https://github.com/rangle/pgdays-codepush-demo Gist with Code: http://bit.ly/22hPKC4 6 / 65
  7. 7. Ionic 2 Framework 7 / 65
  8. 8. Ionic 2 Install Ionic 2 npm install -g ionic@beta 8 / 65
  9. 9. Ionic 2 Install Ionic 2 npm install -g ionic@beta Install Cordova npm install -g cordova 9 / 65
  10. 10. Ionic 2 Start a new Ionic Project ionic start pgdays-workshop --v2 --ts cd pgdays-workshop 10 / 65
  11. 11. Ionic 2 Start a new Ionic Project ionic start pgdays-workshop --v2 --ts cd pgdays-workshop Preview in browser ionic serve 11 / 65
  12. 12. Code Push Microsoft CodePush 12 / 65
  13. 13. CodePush Setup Install CLI tools npm install -g code-push-cli 13 / 65
  14. 14. CodePush Setup Install CLI tools npm install -g code-push-cli Create CodePush account code-push register 14 / 65
  15. 15. CodePush Setup Install CLI tools npm install -g code-push-cli Create CodePush account code-push register Register your app code-push app add <appName> 15 / 65
  16. 16. Configuring Cordova for CodePush Install CodePush plugin ionic plugin add cordova-plugin-code-push@latest 16 / 65
  17. 17. Configuring Cordova for CodePush Install CodePush plugin ionic plugin add cordova-plugin-code-push@latest Install Typings npm i typings@0.x -g typings install github:Microsoft/cordova-plugin-code-push/typings/codePush.d.ts --save --ambient 17 / 65
  18. 18. Configuring Cordova for CodePush Add Deployment Key to config.xml config.xml <platform name="ios"> <preference name="CodePushDeploymentKey" value="YOUR-IOS-DEPLOYMENT-KEY" /> </platform> 18 / 65
  19. 19. Configuring Cordova for CodePush Add Deployment Key to config.xml config.xml <platform name="ios"> <preference name="CodePushDeploymentKey" value="YOUR-IOS-DEPLOYMENT-KEY" /> </platform> Forget your app or key? no problem code-push app ls # list your registered apps code-push deployment ls AppName -k 19 / 65
  20. 20. Configuring Cordova for CodePush Let Cordova talk with CodePush config.xml <access origin="*" /> <!-- or --> <access origin="https://codepush.azurewebsites.net" /> <access origin="https://codepush.blob.core.windows.net" /> 20 / 65
  21. 21. Configuring Cordova for CodePush Let Cordova talk with CodePush config.xml <access origin="*" /> <!-- or --> <access origin="https://codepush.azurewebsites.net" /> <access origin="https://codepush.blob.core.windows.net" /> Let CodePush work with CSP www/index.html <meta http-equiv="Content-Security-Policy" content="default-src https://codepush.azurewebsites.net 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *" /> 21 / 65
  22. 22. Settings Tab 22 / 65
  23. 23. Rename Tab app/pages/tabs/tabs.html <ion-tabs> <ion-tab [root]="tab1Root" tabTitle="Settings" tabIcon="cog"></ion-tab> <!--- ... --> </ion-tabs> 23 / 65
  24. 24. Build Settings Tab app/pages/page1/page1.html <ion-navbar *navbar> <ion-title>Settings</ion-title> </ion-navbar> <ion-content padding class="page1"> <ion-row> <ion-col width-50> <button (click)="checkForUpdate()"> Check For Update </button> </ion-col> <ion-col width-50> <button (click)="sync()" [disabled]="!isUpdateAvailable"> Sync </button> </ion-col> </ion-row> </ion-content> 24 / 65
  25. 25. Check For Update 25 / 65
  26. 26. codePush.checkForUpdates app/pages/page1/page1.ts import {Page} from 'ionic-angular'; import {ApplicationRef} from '@angular/core' declare const codePush: CodePushCordovaPlugin; export class Page1 { // ... isUpdateAvailable:boolean = false; constructor(private appRef: ApplicationRef) { } checkForUpdate() { codePush.checkForUpdate((result) => { this.isUpdateAvailable = result !== null; this.appRef.tick(); }); } } 26 / 65
  27. 27. CodePush Sync 27 / 65
  28. 28. codePush.sync app/pages/page1/page1.ts // ... export class Page1 { // ... sync() { codePush.sync(null, { updateDialog: true, installMode: InstallMode.IMMEDIATE }); } 28 / 65
  29. 29. Running the App ionic emulate --target="iPhone-6s" 29 / 65
  30. 30. Deploy with CodePush [code-push release-cordova] 30 / 65
  31. 31. Build & Deploy Build ionic build 31 / 65
  32. 32. Build & Deploy Build ionic build Deploy code-push release-cordova pgdays-demo ios 32 / 65
  33. 33. New Feature: Status Field app/pages/page1/page1.html <!-- ... --> <ion-content padding class="page1"> <ion-row> <ion-col width-20>Status:</ion-col> <ion-col width-80>{{status}}</ion-col> </ion-row> <!-- ... --> </ion-content> 33 / 65
  34. 34. app/pages/page1/page1.ts export class Page1 { status: string = ''; isProcessing: boolean = false; // .. checkForUpdate() { this.isProcessing = true; this.status = 'Checking ... ' codePush.checkForUpdate((result) => { this.isUpdateAvailable = result !== null; this.status = result === null ? 'Up to Date' : 'Update Available' this.isProcessing = false; this.appRef.tick(); }); } // ... } 34 / 65
  35. 35. Sync the Update Build & Release CodePush ionic build code-push release-cordova pgdays-demo ios 35 / 65
  36. 36. Sync the Update Build & Release CodePush ionic build code-push release-cordova pgdays-demo ios Sync the app 36 / 65
  37. 37. Deployments 37 / 65
  38. 38. Select a Version app/pages/page1/page1.html <!-- ... --> <ion-list radio-group [(ngModel)]="deployment"> <ion-list-header> Version </ion-list-header> <ion-item> <ion-label>Staging</ion-label> <ion-radio value="YOUR-IOS-STAGING-KEY"></ion-radio> </ion-item> <ion-item> <ion-label>Production</ion-label> <ion-radio value="YOUR-IOS-PRODUCTION-KEY"></ion-radio> </ion-item> </ion-list> <!-- ... --> 38 / 65
  39. 39. Pass the Deployment Key app/pages/page1/page1.html <!-- ... --> <button (click)="checkForUpdate(deployment)" [disabled]="isInProgress"> Check For Updates </button> <button (click)="sync(deployment)" [disabled]="!isUpdateAvailable"> Sync </button> <!-- ... --> 39 / 65
  40. 40. Update Sync app/pages/page1/page1.ts export class Page1 { // ... sync(key) { codePush.sync(null, { updateDialog: true, installMode: InstallMode.IMMEDIATE, deploymentKey: key }); } } 40 / 65
  41. 41. Update checkForUpdate app/pages/page1/page1.ts export class Page1 { // ... checkForUpdate(key) { this.isInProgress = true; this.status = 'Checking for Update'; codePush.checkForUpdate((result) => { this.isUpdateAvailable = result !== null; this.isInProgress = false; this.status = result === null ? 'Application is up-to date' : 'Update Available' this.appRef.tick(); }, null, // error handler key); // deployment key is an optional 3rd parameter } } 41 / 65
  42. 42. LocalPackage Info 42 / 65
  43. 43. Display Current Package app/pages/page1/page1.html <ion-list radio-group [(ngModel)]="deployment"> <!-- ... --> <ion-list> <ion-list-header> Installed Package </ion-list-header> <ion-item> App Version: {{currentPackage?.appVersion}} </ion-item> <ion-item> Description: {{currentPackage?.description}} </ion-item> <ion-item> Label: {{currentPackage?.label}} </ion-item> </ion-list> 43 / 65
  44. 44. app/pages/page1/page1.ts import {Page, Platform} from 'ionic-angular'; // ... export class Page1 { // ... currentPackage: ILocalPackage; constructor(private platform: Platform, private appRef: ApplicationRef) { } ngOnInit() { this.platform .ready() .then( () => this.getCurrentPackage()); } getCurrentPackage() { codePush.getCurrentPackage((result: ILocalPackage) => { this.currentPackage = result; this.appRef.tick(); }) } } 44 / 65
  45. 45. Deploy and Promote [loading multiple versions as needed] 45 / 65
  46. 46. Deploy ionic build code-push release-cordova pgdays-demo ios -d Staging --description 'Deployment Select' 46 / 65
  47. 47. Deploy ionic build code-push release-cordova pgdays-demo ios -d Staging --description 'Deployment Select' Promote code-push promote pgdays-demo Staging Production --des 'Staging -> Production' 47 / 65
  48. 48. Deploy ionic build code-push release-cordova pgdays-demo ios -d Staging --description 'Deployment Select' Promote code-push promote pgdays-demo Staging Production --des 'Staging -> Production' Run the app ... 48 / 65
  49. 49. A Minor Change 49 / 65
  50. 50. Change the Sync button colour app/pages/page1/page1.html <button (click)="sync(deployment)" [disabled]="!isUpdateAvailable" secondary> <!-- ionic will set this to be green --> Sync </button> <!-- ... --> 50 / 65
  51. 51. Build and Deploy to Staging ionic build code-push release-cordova pgdays-demo ios -d Staging --description 'Color Change' 51 / 65
  52. 52. Build and Deploy to Staging ionic build code-push release-cordova pgdays-demo ios -d Staging --description 'Color Change' Run the app ... Select Production, and Sync Select Staging, and Sync 52 / 65
  53. 53. Promote to Production code-push promote pgdays-demo Staging Production --des 'Color Change to Production' 53 / 65
  54. 54. Detailed Sync 54 / 65
  55. 55. codePush.sync( syncCallback?: SuccessCallback<SyncStatus>, syncOptions?: SyncOptions, downloadProgress?: SuccessCallback<DownloadProgress>): void; declare enum SyncStatus { UP_TO_DATE, UPDATE_INSTALLED, UPDATE_IGNORED, ERROR, IN_PROGRESS, CHECKING_FOR_UPDATE, AWAITING_USER_ACTION, DOWNLOADING_PACKAGE, INSTALLING_UPDATE } 55 / 65
  56. 56. app/pages/page1/page1.ts // ... export class Page1 { syncHandler(status: SyncStatus) { // ... } sync(key) { codePush.sync((status) => this.syncHandler(status), { updateDialog: true, installMode: InstallMode.IMMEDIATE, deploymentKey: key }); } 56 / 65
  57. 57. syncHandler(status: SyncStatus) { switch (status) { case SyncStatus.UP_TO_DATE: this.status = 'Up-to-date'; break; case SyncStatus.UPDATE_INSTALLED: this.status = 'Update Installed'; break; case SyncStatus.UPDATE_IGNORED: this.status = 'Update Ignored'; break; case SyncStatus.ERROR: this.status = 'Error'; break; // ... } 57 / 65
  58. 58. syncHandler(status: SyncStatus) { switch(status) { // ... case SyncStatus.IN_PROGRESS: this.status = 'In Progress'; break; case SyncStatus.CHECKING_FOR_UPDATE: this.status = 'Checking for Update'; break; case SyncStatus.AWAITING_USER_ACTION: this.status = 'Awaiting User Action'; break; case SyncStatus.DOWNLOADING_PACKAGE: this.status = 'Downloading Package'; break; case SyncStatus.INSTALLING_UPDATE: this.status = 'Installing Update'; break; } this.appRef.tick(); } // ... } 58 / 65
  59. 59. Download Progress 59 / 65
  60. 60. codePush.sync( syncCallback?: SuccessCallback<SyncStatus>, syncOptions?: SyncOptions, downloadProgress?: SuccessCallback<DownloadProgress>): void; 60 / 65
  61. 61. codePush.sync( syncCallback?: SuccessCallback<SyncStatus>, syncOptions?: SyncOptions, downloadProgress?: SuccessCallback<DownloadProgress>): void; // Defines the format of the DownloadProgress object, // used to send periodical update notifications on the progress // of the update download. interface DownloadProgress { totalBytes: number; receivedBytes: number; } 61 / 65
  62. 62. // ... export class Page1 { downloadProgress: DownloadProgress // ... updateDownloadProgress(downloadProgress: DownloadProgress) { this.downloadProgress = downloadProgress; this.appRef.tick(); } sync(key) { codePush.sync((status) => this.syncHandler(status), { updateDialog: true, installMode: InstallMode.IMMEDIATE, deploymentKey: key }, (progress) => this.updateDownloadProgress(progress)); } } 62 / 65
  63. 63. <!-- .... after the sync buttons ---> <ion-row> <ion-col width-25>Progress:</ion-col> <ion-col width-75> {{downloadProgress?.receivedBytes}} / {{downloadProgress?.totalBytes}} </ion-col> </ion-row> 63 / 65
  64. 64. Any Questions? 64 / 65
  65. 65. Bertrand Karerangabo twitter: @codenarian github: bertrandk Evan Schultz twitter: @e_p82 github: e-schultz Thanks 65 / 65

×