Cross-platform apps with Ionic React & Capacitor

Cross-platform apps with Ionic React & Capacitor

JSforWP Conf 2020

75486cbfd37125f121cf4a6c5614601c?s=128

Hidetaka Okamoto

July 11, 2020
Tweet

Transcript

  1. Cross-platform apps with Ionic React & Capacitor J S f

    o rW P C o n f 2 0 2 0
  2. Native

  3. Agenda • About Capacitor / Ionic • Why should we

    use Capacitor • How can we use Capacitor • Create a Native PWA using Capacitor and Ionic • Integrating Capacitor with a Jamstack application
  4. Example: Ionic React with Capacitor https://github.com/getshifter/example-ionic- react-capacitor Example: Gatsby WordPress

    with Capacitor https://github.com/getshifter/example-gatsby- capacitor-wordpress
  5. Hide (Hidetaka Okamoto) • Digitalcube Co. Ltd. • Nishinomiya /

    Kobe • WordPress Core contributor 4.7 / 5.0 / 5.3
  6. h t t p s : / / w w

    w. g e t s h i f t e r. i o /
  7. Agenda • About Capacitor / Ionic • Why should we

    use Capacitor • How can we use Capacitor • Create a Native PWA using Capacitor and Ionic • Integrating Capacitor with a Jamstack application
  8. None
  9. Capacitor: Application runtime for Native PWA • Similar to Apache

    Cordova or Adobe PhoneGap • Easy to convert your application to Native App • iOS / Android / Electron / and PWA • Access the native API from JavaScript
  10. None
  11. Ionic React: Mobile UI toolkit for React • Simply and

    framework friendly toolkit • Angular / React / Vue • Single codebase, running web and native application • Useful and various UI components
  12. Ionic & Capacitor Great for cross-platform apps • Ionic provides

    cross-platform friendly UI components • Capacitor helps us to access the device native API. • Capacitor build application for the native and web. • Single codebase, running everywhere :)
  13. Agenda • About Capacitor / Ionic • Why should we

    use Capacitor • How can we use Capacitor • Create a Native PWA using Capacitor and Ionic • Integrating Capacitor with a Jamstack application
  14. Native W H AT ? !

  15. PWA is good, but NOT a perfect solution • PWA

    provides an installable, app-like experience via the web • PWA can make a multi-device support web application • Many API can use from JavaScript (Web push / Camera / etc..) • But, still not able to access several native APIs. • If we want to access these APIs, we need to create a Native App
  16. None
  17. Declined Web Apis in Safari (June 28, 2020) • Web

    Bluetooth • Web MIDI API • Magnetometer API • Web NFC API - • Device Memory API • Network Information API - • Battery Status API • • Serial API • Web USB Geolocation Sensor (background geolocation) • User Idle Detection • Proximity Sensor Web Bluetooth Scanning • Ambient Light Sensor - • WebHID https://www.zdnet.com/article/apple-declined-to-implement-16-web-apis-in-safari-due-to-privacy-concerns/
  18. PWA or Native Native PWA • Capacitor provides wrapper API

    for PWA and native • Single Capacitor API, calling optimized API • And Ionic provides a device optimized UI component • Build PWA and Native App by JavaScript
  19. Capacitor has check Available method import { Capacitor } from

    '@capacitor/core'; if (Capacitor.isPluginAvailable('Camera')) { // make the call: Camera.getPhoto() } else { // Have the user upload a file instead }
  20. Accessibility Background task Browser Clipboard Filesystem Toast Geolocation Network Push

    Notification Splash Screen Share Device etc… Core APIs of Capacitor
  21. Capacitor has Plugins

  22. Examples of Community Plugins

  23. Access Phone Contacts npm install -S @capacitor-community/contacts

  24. Authenticate Face ID & Touch ID npm install -S \

    capacitor-biometric-auth
  25. NativeAudio.preloadSimple({ assetPath: "audio/chime.mp3", assetId: "chime_audio", }); NativeAudio.preloadComplex({ assetPath: "audio/inception.mp3", assetId:

    "inception_audio", volume: 1.0, audioChannelNum: 1, }); NativeAudio.play({ assetId: "chime_audio", }); Audio Control npm install -S
 @capacitor-community/native- audio
  26. And more… Single Sign On (FB / Apple etc…) Google

    Admob Apple Game Center Google play QRCode scanner Text to Speech Camera preview etc…
  27. Explore your favorite plugins ! • Plugin registry: Search by

    "@capacitor-community" https://www.npmjs.com/search?q=%40capacitor-community • Common plugin: Search by ”capacitor plugin” https://www.npmjs.com/search?q=capacitor%20plugin
  28. Agenda • About Capacitor / Ionic • Why should we

    use Capacitor • How can we use Capacitor • Create a Native PWA using Capacitor and Ionic • Integrating Capacitor with a Jamstack application
  29. $ cd /PATH/TO/YOUR/APP # Install packages $ npm i -S

    @capacitor/core # Initialize $ npx cap init - ? App name YOUR_APPLICATION_NAME - ? App Package ID com.example.app - ? Which npm client would you like to use? › npm yarn Your Capacitor project is ready to go! Simplest setup for existing app
  30. { "appId": "com.example.app", "appName": "YOUR_APPLICATION_NAME", "bundledWebRuntime": false, "npmClient": "npm", "webDir":

    "www", "cordova": {} } ↓ Should replace webDir to your app build destination. { "appId": "com.example.app", "appName": "YOUR_APPLICATION_NAME", "bundledWebRuntime": false, "npmClient": "npm", "webDir": "public", "cordova": {} } Update capacitor.config.json
  31. % npx cap add ios ℹ Installing iOS dependencies –

    Skipping: already installed ✔ Adding native xcode project in: /Users/development/ionic-react/ios in 17.76ms ✔ add in 19.83ms ✔ Copying web assets from public to ios/App/public in 4.21ms ✔ Copying native bridge in 2.36ms ✔ Copying capacitor.config.json in 1.12ms ✔ copy in 23.29ms ✔ Updating iOS plugins in 4.67ms Found 0 Capacitor plugins for ios: ✔ Updating iOS native dependencies with "pod install" (may take several minutes) in 7.46s ✔ update ios in 7.48s Now you can run npx cap open ios to launch Xcode % npx cap add android % npx cap add electron % npx cap add web Add Supported Platform
  32. $ npx cap open electron

  33. $ npx cap open ios

  34. # Build your SPA $ npm run build # Sync

    Capacitor % npx cap sync ✔ Copying web assets from public to android/app/src/main/assets/public in 9.31ms ✔ Copying native bridge in 1.01ms ✔ Copying capacitor.config.json in 766.90μp ✔ copy in 23.18ms ✔ Updating Android plugins in 3.58ms Found 0 Capacitor plugins for android: ✔ update android in 19.35ms ✔ Copying web assets from public to ios/App/public in 4.78ms ✔ Copying native bridge in 912.98μp ✔ Copying capacitor.config.json in 671.34μp ✔ copy in 14.16ms ✔ Updating iOS plugins in 2.32ms Found 0 Capacitor plugins for ios: ✔ Updating iOS native dependencies with "pod install" (may take several minutes) in 6.33s ✔ update ios in 6.34s ✔ copy in 237.76μp ✔ update web in 5.83μp Sync finished in 6.415s Update & Sync
  35. S i m p l e s t u s

    a g e = J u s t c o m p i l e • Capacitor converts your SPA to a Native App • We can publish Native apps just using build artifacts by Capacitor • iOS app: /ios • Android app: /android • Electron app: /electron
  36. Agenda • About Capacitor / Ionic • Why should we

    use Capacitor • How can we use Capacitor • Create a Native PWA using Capacitor and Ionic • Integrating Capacitor with a Jamstack application
  37. Capacitor provides a Native API wrapper

  38. import { Plugins } from ‘@capacitor/core'; const shareTweet = async

    () => { const { Share } = Plugins; const share = await Share.share({ title: 'Share Capacitor', text: 'I deployed a native mobile app', url: 'https://capacitorjs.com', }); } Social Share Example
  39. Show Native share UI

  40. import { Plugins, NetworkStatus } from '@capacitor/core'; import { useState,

    useEffect, useCallback } from ‘react'; const { Network, Toast } = Plugins; export const useNetworkHook = () => { const [status, updateStatus] = useState<NetworkStatus>() const checkNetworkStatus = () => { Network.getStatus() .then(data => updateStatus(data)) } useEffect(() => { checkNetworkStatus() const handler = Network.addListener('networkStatusChange', (status) => { checkNetworkStatus() }); return () => handler.remove(); }, []) const connected = status ? status.connected: undefined useEffect(() => { if (connected === undefined || connected) return Toast.show({ text: "Network is offline" }) }, [connected]) return status } Example of Network status Check hook
  41. import { Plugins, NetworkStatus } from '@capacitor/core'; import { useState,

    useEffect, useCallback } from ‘react'; const { Network, Toast } = Plugins; export const useNetworkHook = () => { const [status, updateStatus] = useState<NetworkStatus>() const checkNetworkStatus = () => { Network.getStatus() .then(data => updateStatus(data)) } useEffect(() => { checkNetworkStatus() const handler = Network.addListener('networkStatusChange', (status) => { checkNetworkStatus() }); return () => handler.remove(); }, []) const connected = status ? status.connected: undefined useEffect(() => { if (connected === undefined || connected) return Toast.show({ text: "Network is offline" }) }, [connected]) return status } Access Native network API from Capacitor
  42. import { Plugins, NetworkStatus } from '@capacitor/core'; import { useState,

    useEffect, useCallback } from ‘react'; const { Network, Toast } = Plugins; export const useNetworkHook = () => { const [status, updateStatus] = useState<NetworkStatus>() const checkNetworkStatus = () => { Network.getStatus() .then(data => updateStatus(data)) } useEffect(() => { checkNetworkStatus() const handler = Network.addListener('networkStatusChange', (status) => { checkNetworkStatus() }); return () => handler.remove(); }, []) const connected = status ? status.connected: undefined useEffect(() => { if (connected === undefined || connected) return Toast.show({ text: "Network is offline" }) }, [connected]) return status } Add event listener to check network status
  43. import { Plugins, NetworkStatus } from '@capacitor/core'; import { useState,

    useEffect, useCallback } from ‘react'; const { Network, Toast } = Plugins; export const useNetworkHook = () => { const [status, updateStatus] = useState<NetworkStatus>() const checkNetworkStatus = () => { Network.getStatus() .then(data => updateStatus(data)) } useEffect(() => { checkNetworkStatus() const handler = Network.addListener('networkStatusChange', (status) => { checkNetworkStatus() }); return () => handler.remove(); }, []) const connected = status ? status.connected: undefined useEffect(() => { if (connected === undefined || connected) return Toast.show({ text: "Network is offline" }) }, [connected]) return status } Toast network offline messages
  44. Show offline notifications

  45. For PWA

  46. Several APIs can’t use from web

  47. $ npm install -S
 pwa-elements

  48. import React from 'react'; import ReactDOM from 'react-dom'; import {

    defineCustomElements } from '@ionic/pwa-elements/loader'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root')); // Call the element loader after the app has been rendered the first time defineCustomElements(window); Add element loader after render function
  49. Show Camera element in browser

  50. Capacitor Access Native API pwa-element Use it from PWA Native

    (and) PWA
  51. Use Ionic React with Capacitor

  52. Capacitor DOES NOT provide UI components

  53. None
  54. Mutli-framework support import React from 'react'; import { IonButton, IonContent

    } from '@ionic/react'; export const ButtonExample: React.FC = () => ( <IonContent> <IonButton>Default</IonButton> </IonContent> ) <template> <!-- Default —> <ion-content> <ion-button>Default</ion-button> </ion-content> </template> <ion-content> <ion-button>Default</ion-button> </ion-content> React Vue Angular
  55. Platform styled component

  56. Support Darkmode

  57. Ionic can create a new app with Capacitor % npx

    ionic start NativePWAApp my-first-app --type=react --capacitor % tree NativePWAApp -I node_modules -L 2 ᵓ── android ᵓ── capacitor.config.json ᵓ── ionic.config.json ᵓ── ios ᵓ── package.json ᵓ── public │ ᵓ── index.html │ └── manifest.json ᵓ── src │ ᵓ── App.test.tsx │ ᵓ── App.tsx │ ᵓ── index.tsx
  58. Blogged how to use Ionic & Capacitor with WP https://bit.ly/323kv6y

  59. Use case: Japanese web magazine Areaia https://air.areaia.jp/

  60. Ionic (Angular) + Capacitor + WordPress.com • UI: Ionic •

    Content (API): WordPress • Native / PWA: Capacitor
  61. Headless WordPress Hosting • Use WordPress as a Content manager

    & API • Call from JS SPA to WP API • Fully managed WordPress
  62. Agenda • About Capacitor / Ionic • Why should we

    use Capacitor • How can we use Capacitor • Create a Native PWA using Capacitor and Ionic • Integrating Capacitor with a Jamstack application
  63. Error: ReferenceError: window is not defined.

  64. Some tool need to use the Window property import React

    from 'react'; import ReactDOM from 'react-dom'; import { defineCustomElements } from '@ionic/pwa-elements/loader'; import App from './App'; ReactDOM.render(<App />, document.getElementById('root')); // Call the element loader after the app has been rendered the first time defineCustomElements(window);
  65. But, Node has no Window obj

  66. Solution: use lazy load to ignore SSR const useLoadPWAElements =

    () => { const windowGlobal = typeof window !== 'undefined' && window useEffect(() => { if (typeof window !== 'undefined') { import('@ionic/pwa-elements/loader') .then((module) => { module.defineCustomElements(windowGlobal) }) } }, [windowGlobal]) }
  67. Lazy load Capacitor component const loadCapComponents = async () =>

    { // Load Component async const { DemoClipboard } = await import('./Clipboard') return <DemoClipboard /> } const Component: FC<Props> = (props) => { // state for handle pwa-elements components const [elem, setSelem] = useState<JSX.Element>( <p>Loading….</p> ) // Load pwa-elements components useEffect(() => { if (typeof window !== 'undefined') { loadCapComponents().then(elements => { setSelem(elements) }) } }, []) return ( <Layout>{elem}</Layout> ) }
  68. $ gatsby build $ npx cap sync $ npx cap

    open ios
  69. Create Native PWA with JavaScript • Capacitor unifies the API

    calling between Native and web • Ionic unifies the UI style too • Single codebase (Use JavaScript / TypeScript) multi build • We can provide our own content from many approaches
  70. Thanks you! • Capacitor unifies the API calling between Native

    and web • Ionic unifies the UI style too • Single codebase (Use JavaScript / TypeScript) multi build • We can provide our own content from many approaches Blog post about Ionic & Capacitor https://bit.ly/323kv6y Shifter https://getshifter.io Twitter @motchi0214 GitHub https://github.com/hideokamoto/