RAKUS Developers Blog

株式会社ラクスのエンジニアブログ

インストール不要!スマホで自作アプリを動かす方法【疑似Webアプリ】

こんにちは。エンジニアのmickey-STRANGEです。
今回はめんどくさがりによるめんどくさがりのためのスマホアプリ開発についてお話したいと思います。
とはいえ、このブログの内容ではスマホアプリは作りません。
タイトル詐欺ぎりぎりですが、嘘はついていませんので、そういう認識でお楽しみいただけますと幸いです。

構成

先に書きました通り筆者は非常にめんどくさがりです。開発環境・実行環境の整備といったところに手間をかけたくありません。
今回使うのはGitHubのみです。
GitHubのみで疑似Webアプリを実現します。
ではGitHubのみで疑似Webアプリをどう作るか考えていきましょう。
Webアプリというと大雑把に考えて3つ、大事な要素があります。

  1. サーバそのもの(apachetomcatなど)
  2. プログラム実行環境(phpJavaなど)
  3. 記憶領域(postgres、Oracleなど)

これらに対応させて考えていきます。
まずサーバにはGitHub Pagesを使用します。 GitHub PagesはGitHubのサービスであり、静的ページをホスティングしてくれるもので、簡単なWebサイトを公開することが出来ます。

そして公開した静的Webサイト(HTML)にjavascriptを書いておきます。つまり実行環境はブラウザです。

最後に記憶領域ですが、アクセスした各端末に必要な情報を記憶させます。
javascriptによる永続の記憶領域として、Web StorageIndexedDBというものがあります。

これらを使用してスマホでも実行可能なプログラムを作成することが可能です。では各要素について見ていきましょう。

GitHub Pages

まずサーバの役割を担うGitHub Pagesです。
上記の通り静的ページのホスティングサービスですが、すごく簡単に言うと「GitHubにHTMLファイルをpushすればWebサイトとして公開してくれる」という認識でいいと思います。

ここからGitHub Pagesの使いかたをご説明いたします。といっても大層なものではなく、2ステップで完了です。

1.まずHTMLファイルをpushします

ここは詳しい説明は省きます。方法は問いませんので自分のリポジトリにHTMLファイルをpushしてください。
めんどくさがりの意見としてましてはGitHub Desktopを今回初めて使いましたが、何も考えなくていい感じがとてもよかったです。GitHub Desktop | Simple collaboration from your desktop

例としてHello,World!的なHTMLを作成しました。

2.pushしたリポジトリを公開する設定をします

リポジトリ画面の上部にある「Settings」リンクをクリックし…

f:id:mickey-STRANGE:20180129194437p:plain

GitHub Pagesカテゴリ内のSource設定を「master branch」に変更して隣の「Save」をクリック。

f:id:mickey-STRANGE:20180129194440p:plain

以上です!
これでGitHub Pagesの設定が完了しました。pushしたファイルにアクセスしてみましょう。

f:id:mickey-STRANGE:20180129202306p:plain

表示されているリンクをクリックすると…

https://mickeystrange.github.io/tools/

Hello,GitHubPages!が表示されればOKです。

発行されるURLはhttps://[ユーザ名].github.io/[リポジトリ名]/ファイル名なので、https://mickeystrange.github.io/tools/index.htmlにアクセスしても同じものが表示されます。
(おそらくファイル名を省略した場合にindex.htmlを自動的に表示してくれているのではないかと。)

HTMLを公開する設定が出来ましたので、あとはjavascriptを作っていくだけです。

これでGitHub Pagesの説明は終わりです。実行環境のブラウザは言わずもがなということで記憶領域の1つ目、Web Storageの説明に移ります。

Web Storage

Web Storageはブラウザの記憶領域にKey-Value Storeで値を保持できる仕組みです。
Web Storage API - Web API インターフェイス | MDN

使いかたはとても簡単で、準備も不要です。

これでもう値の格納と取り出しが出来ています。それぞれ1行だけです。
もう見たままですが一応ご説明いたしますと、
3行目の

localStorage.setItem('key', value);

の部分で'key'というキーで変数valueの値を格納しています。
また、 5行目の

var item = localStorage.getItem('key');

の部分で'key'というキーで格納されている値を変数itemに取り出しています。

localStorageというのはWeb Storageの種類の1つで、記憶領域が保持される期間が永続のものです。
もう1つの種類としてsessionStorageというものがありますが、こちらはブラウザを閉じるまでの間のみ有効なものになります。

このWeb Storageを使用して、ページへのアクセス数をカウントする簡単なプログラムを作成いたしました。

LocalStorage 静的リソースだけでアプリケーションを作るための記憶領域テスト

ページの再表示やブラウザの再起動などをして遊んでいただきますと、記憶領域をたしかに持っていることが確認出来ると思います。
開発者ツールなどで見ることが出来ますが、特別隠すようなものでもありませんのでコードは以下の通りです。
tools/storage_test.html at master · mickeySTRANGE/tools · GitHub

簡単な値の保持だけであればWeb Storageが十分な機能を持っていることをご説明いたしましたが、続いてもっと強力な記憶領域といたしましてIndexedDBの説明に移ります。

IndexedDB

IndexedDBはブラウザの記憶領域にオブジェクトを保持する仕組みです。
Web Storageと比べて最大容量が多い、KVSではなくJSONを保存できる、検索に強い、などの特徴がある、NoSQLデータベースです。

これからIndexedDBの使用方法についての説明をいたしますが、Web Storageの後で見るととても複雑です。
インストールや外部ライブラリは不要(ブラウザの機能なので当たり前)ですが、手順が多いです。

1.DBに接続する

IndexedDBは基本的にリクエストと、そのリクエストの結果によって実行される部分を書いていきます。
今回の例ですと、3行目の

var openRequest = indexedDB.open("sampleDatabase", version);

がDB接続のリクエストで、4-10行目の

// 接続に成功すれば各処理を実行
openRequest.onsuccess = function(event) { 
  db = event.target.result; 
  db.onerror = function(event) { 
    alert("Database error: " + event.target.errorCode); 
  };
}; 

が接続成功時に実行する処理、といった具合です。サンプルは関数の外の変数にDBのインスタンスを保存しています。
11-15行目の

// DB定義を更新
openRequest.onupgradeneeded = function(event) {
  db = event.target.result;
  db.createObjectStore('sampleObject', {keyPath: 'key'});
};

は、保存するオブジェクトの定義を行っています。
アクセスする時のオブジェクトストアの名前を第一引数に、オブジェクトの定義を第二引数に持っています。
サンプルは'sampleObject'という名前のオブジェクトストアで'key'をキーに定義しています。

このonupgradeneededというものは、DBのバージョンが上がった時に実行されるものです。
3行目のopen()の第二引数にversionがありますが、これはIndexedDBのバージョンではなく、自分が作るDBのバージョンです。
バージョン1としてこのサンプルの通りオブジェクトストアを定義し、変更が必要になった時にバージョン2として接続し、onupgradeneededの中で新しくオブジェクトストアを追加したり、オブジェクトストア定義変更を行ったりすることが出来ます。

2.オブジェクトストアにアクセスする

DBに接続出来れば次はデータへのアクセスです。データの格納と取得を見てみましょう。

setValueではDB接続のサンプルで作ったsampleObjectに1つのオブジェクトを追加しています。
keyは'sample'value'hoge'という値を持っています。keyは必須かつ重複不可の制約がありますが、他の要素は何を持っていても構いません、

getValueではsampleObjectから'sample'というkeyPath(サンプルでは'key')を持つ値を検索しています。

IndexedDBの記憶領域は全て永続なので、この構文のみでもアプリを作成することが可能です。
これらの構文を使用し、またページへのアクセス数をカウントする簡単なプログラムを作成いたしました。

Indexed Database 静的リソースだけでアプリケーションを作るための記憶領域テスト

tools/indexed_database_test.html at master · mickeySTRANGE/tools · GitHub

ページのリロード等をしていただきますとカウントが正常に出来ていることが分かります。

3.IndexedDBの注意点

簡単なサンプルをお見せいたしましたが、indexed_database_test.htmlのコードを見ていただきますと、Web Storageの時とは大きく構成が違うことが分かっていただけるかと思います。

そうです、「取得する関数」と「格納する関数」で分けて処理をきれいに書くことが出来なかったのです。

理由がありまして、リクエストを書き、その成功時失敗時に実行する処理を書くと説明いたしました。
実はこれが曲者で、リクエストが完了したかどうかをイベント外から見ることが出来ないのです。

「取得する→1増やす→格納する」という流れを切り分けることが出来ず、
取得するリクエストのonsuccessイベントで「1増やして格納する」という処理の流れになります。
更に言うと取得するリクエストさえ接続するリクエストのonsuccessイベント内で実行しています。

IndexedDBはWeb Storageよりも強力なデータベースが使用できる代わりに、処理の流れを作るところで非常にややこしくなってしまう、というデメリットがあると言えます。

まとめ

自分の書いたコードを簡単にスマホで動かす方法をご紹介いたしました。いかがでしたでしょうか。

一番手軽なのはやはりWeb Storageを使用する方法です。 多分これが一番早いと思います。

これにJQueryやBootstrapなどの部品を組み合わせることで十分なスマホアプリのようなものが作れると思います。
今回の記事とは別に業務を効率化するJSなども趣味で作っていたりしたため、ここ最近でJS面で成長したことを感じています。
自分で使えるツールをもっとpushしてJSライフを楽しんでいきたいです。

Copyright © RAKUS Co., Ltd. All rights reserved.