PWAとは、railsにPWA導入、vuejsにPWA導入


PWAとは

  • Progressive Web Apps
  • モバイル端末でウェブサイトを表示するときに、まるでネイティブアプリのような動作を可能にする仕組み

PWAとネイティブアプリとウェブサイトの違い

ウェブサイト

  • ブラウザーでURLアクセス出来る
  • HTML/CSS/WEB Frameworkで開発する
  • どの端末でもブラウザーがあれば、アクセス出来る
  • OSの深い機能触れません

 アプリ

  • OSにサポートしているSDKを使って、アプリを開発する
  • OSによって、アプリが違う(Android, IOS, Mac Os, Windows)
  • アプリ使えるため、アプリをダウンロードして、インストールして、開けます。 (OSのデフォルトアプリがあります、そのアプリはインストール不要です)
  • OSの深い機能触れます
    • オフラインモード
    • I/Oアクセス
    • Push Notification
    • セキュリティー

PWA

  • ウェブサイトとアプリの真ん中
  • HTML/CSS/WEB Frameworkで開発する(ウェブサイト)
  • ブラウザーでURLアクセス出来る (ウェブサイト)
  • アプリをインストールして、開けます。(アプリ)
  • どの端末でもブラウザーがあれば、アクセス出来る(ウェブサイト)
  • OSの深い機能は少しさわれます
    • オフラインモード
    • Push Notification


PWAとネイティブアプリとウェブサイト


PWAのインストール

qiitaページはPWA入っています。


ChromeでPWA導入確認出来ます


ウェブサイトにPWA導入準備

  • manifest.json : アプリアイコン、アプリ名など設定するファイル
  • service_worker.js : JSキャッシュ、Push Notificationなど設定ファイル

PWA導入例

RAILS

manifest.json ファイル作成

  • routers.rb に追加
...
resources :manifest, only: [:index]
...
  • manifest_controller.rb ファイル作成
class ManifestController < ApplicationController
    protect_from_forgery except: :index
    def index
    end
end
  • app/views/manifest/index.json.erb ファイル作成
{
  "name": "PWAテスト",
  "short_name": "PWAテスト",
  "start_url": "/",
  "icons": [
    {
      "src": "icon/android-chrome-192x192.png,
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ],
  "theme_color": "#000000",
  "background_color": "#FFFFFF",
  "display": "standalone",
  "orientation": "portrait"
}

  • app/views/layouts/application.html.erb に追加

    <%# PWA %>
    <link rel="manifest" href="/manifest.json&nocache=<%= (0...50).map { ('a'..'z').to_a[rand(26)] }.join %>" />
    <link rel="apple-touch-icon" href="icon/android-chrome-192x192.png">
    <meta name="theme-color" content="rgb(125, 212, 32)"/>
    <meta name="apple-mobile-web-app-capable" content="yes">


serviceworker.js ファイル作成

  • routers.rb に追加
...
resources :serviceworker, only: [:index]
...
  • serviceworker_controller.rb ファイル作成
class ServiceworkerController < ApplicationController
    protect_from_forgery except: :index
    def index
    end
end

  • app/views/serviceworker/index.js.erb ファイル追加
var CACHE_VERSION = 'v1';
var CACHE_NAME = CACHE_VERSION + ':sw-cache-';

function onInstall(event) {
  console.log('[Serviceworker]', "Installing!", event);
  event.waitUntil(
    caches.open(CACHE_NAME).then(function prefill(cache) {
      return cache.addAll([

        // make sure serviceworker.js is not required by application.js
        // if you want to reference application.js from here

        '/offline.html',

      ]);
    })
  );
}

function onActivate(event) {
  console.log('[Serviceworker]', "Activating!", event);
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.filter(function(cacheName) {
          // Return true if you want to remove this cache,
          // but remember that caches are shared across
          // the whole origin
          return cacheName.indexOf(CACHE_VERSION) !== 0;
        }).map(function(cacheName) {
          return caches.delete(cacheName);
        })
      );
    })
  );
}

// Borrowed from https://github.com/TalAter/UpUp
function onFetch(event) {
  event.respondWith(
    // try to return untouched request from network first
    fetch(event.request).catch(function() {
      // if it fails, try to return request from the cache
      return caches.match(event.request).then(function(response) {
        if (response) {
          return response;
        }
        // if not found in cache, return default offline content for navigate requests
        if (event.request.mode === 'navigate' ||
          (event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html'))) {
          console.log('[Serviceworker]', "Fetching offline content", event);
          return caches.match('/offline.html');
        }
      })
    })
  );
}

self.addEventListener('install', onInstall);
self.addEventListener('activate', onActivate);
self.addEventListener('fetch', onFetch);

  • app/views/layouts/application.html.erb に追加

    <script>
      if (navigator.serviceWorker) {
        navigator.serviceWorker.register('/serviceworker.js', { scope: './' })
          .then(function(reg) {
            console.log('[Companion]', 'Service worker registered!');
          });
      }
    </script>


VUEJSに追加

PWAの問題

  • Storeにアップロード出来ません
  • OSの深い機能に関して、IOSとAndroidは違います。

https://medium.com/@firt/progressive-web-apps-on-ios-are-here-d00430dee3a7#:~:text=With%20iOS%2011.3%2C%20Apple%20has,Web%20Apps%20%E2%80%9D%20(PWAs).&text=This%20App%20is%20a%20PWA,app%20from%20the%20App%20Store.


以上です。