<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:series="http://organizeseries.com/"
	>

<channel>
	<title>Web技術でアプリ開発2016 &#8211; HTML5Experts.jp</title>
	<atom:link href="/series/web-based-apps-2016/feed/" rel="self" type="application/rss+xml" />
	<link>https://html5experts.jp</link>
	<description>日本に、もっとエキスパートを。</description>
	<lastBuildDate>Sat, 07 Jul 2018 03:14:05 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.7.19</generator>
	<item>
		<title>Electronプログラミング入門 — インストールからミニブラウザ構築まで</title>
		<link>/yosuke_furukawa/20841/</link>
		<pubDate>Thu, 15 Sep 2016 00:00:50 +0000</pubDate>
		<dc:creator><![CDATA[古川陽介]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[Chromium]]></category>
		<category><![CDATA[Electron]]></category>
		<category><![CDATA[Node.js]]></category>

		<guid isPermaLink="false">/?p=20841</guid>
		<description><![CDATA[連載： Web技術でアプリ開発2016 (6)Electronとは、デスクトップクライアントを作るためのフレームワークです。クロスプラットフォームで動作することをサポートしているため、Electronで作ったアプリケーシ...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/web-based-apps-2016/" class="series-391" title="Web技術でアプリ開発2016" data-wpel-link="internal">Web技術でアプリ開発2016</a> (6)</div><div id="attachment_20845" style="width: 650px" class="wp-caption aligncenter"><img src="/wp-content/uploads/2016/09/electron-eyecatch-640x361.png" alt="Electron" width="640" height="361" class="size-large wp-image-20845" srcset="/wp-content/uploads/2016/09/electron-eyecatch.png 640w, /wp-content/uploads/2016/09/electron-eyecatch-300x169.png 300w, /wp-content/uploads/2016/09/electron-eyecatch-207x117.png 207w" sizes="(max-width: 640px) 100vw, 640px" /><p class="wp-caption-text">Electron</p></div>

<p>Electronとは、デスクトップクライアントを作るためのフレームワークです。クロスプラットフォームで動作することをサポートしているため、Electronで作ったアプリケーションはMac、Windows、Linuxの環境でも動作します。Atomと呼ばれる GitHub社製のエディタがあります。 ElectronはAtomを作る際にフレームワークとして作られました。以前はAtomShellと呼ばれていましたが、Electronとして名前を変更し、2016年にはversion 1.0がリリースされるまでに成長しました。</p>

<p>ElectronはJavaScript / HTML / CSSを使ってクライアントアプリケーションを作成します。中のアーキテクチャはChromiumとNode.jsで作られており、Web開発の技術を使ってデスクトップアプリケーションを構築することが可能です。</p>

<p>ElectronはCheng Zhao氏 (以降zcbenz)が開発したフレームワークですが、zcbenz氏は実際Electronの開発前にNW.js(旧 NodeWebkit) と呼ばれるフレームワークのコントリビューターでした。ElectronはNW.jsと非常によく似たフレームワークですが、いくつか技術的に異なるポイントが有ります。決定的な違いは、Chromiumの組み込み方の違いです。ElectronはライブラリとしてChromiumを組み込んでいるのに対して、NW.jsはChromiumをforkしたプロジェクトを使っています。Chromiumは非常に進化が早いプロダクトなので、forkして持つよりもアップデートを考えると効率的です。</p>

<p>とはいえ、NW.jsとElectronの技術的な部分以外は違いはそこまでありません。Atom開発当初にNW.jsが多少不安定だったために新しいプロダクトとして立ち上げたという側面もあるそうです。詳しくは<a href="https://github.com/electron/electron/blob/master/docs/development/atom-shell-vs-node-webkit.md" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">AtomShellとNodeWebkitの違い</a>に詳しく記載されています。</p>

<h2>Electronの特徴</h2>

<p>いくつか特徴があるので紹介します。</p>

<h3>Electronのランタイム</h3>

<p>Electron そのものはただのランタイムライブラリです、Node.jsにおける<code>node</code>コマンドのようなもので、<code>electron</code>コマンドでエントリポイントとなるJavaScriptを実行します。</p>

<p><code>electron</code>コマンドは<a href="http://electron.atom.io/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">公式サイト</a>からダウンロードすることもできますが、Node.jsのパッケージモジュールである、<code>npm</code>コマンドを使ってインストールすることも可能です。</p>

<p></p><pre class="crayon-plain-tag">$ npm install electron -g</pre><p></p>

<p>※ 以前までは <code>npm install electron-prebuilt</code>からインストールする必要がありましたが、最近は<code>npm install electron</code>でinstallできるようになりました。</p>

<p>これで<code>electron</code>コマンドが有効になるので、そのコマンドを使ってデスクトップアプリケーションを起動させます。アプリケーションを実際に書くのは後述します。</p>

<h3>Electron / Browser間でモジュールを共有</h3>

<p>Electronアプリを構築すると、シームレスにブラウザからNode.jsのコードを呼ぶことが可能です。そのため、下記のようなコードを実行することもできます。　</p>

<p></p><pre class="crayon-plain-tag">// script tag から
&lt;script&gt;
// 自分のローカルファイル読みこんだり
const fs = require(‘fs’);
fs.readFile(‘foo/bar/baz’, (err, data) =&gt; {
  console.log(data);
});
&lt;/script&gt;

&lt;script&gt;
// 外部プロセスを呼んだり
const cp = require(‘child_process’);
cp.exec(‘ls -l’, (err, stdout) =&gt; {
  console.log(stdout);
});
&lt;/script&gt;</pre><p></p>

<p>ただし、この方法を使った場合、DOM-based XSSが発生すると、任意のコマンドだったり、ファイルが操作できてしまう結果になるため、プロダクションでElectronを活用する場合は注意が必要です。</p>

<p><a href="http://utf-8.jp/public/2016/0307/electron.pdf" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">参考資料: Electronの倒し方</a></p>

<h2>Hello World</h2>

<p>一旦Electronを起動してみましょう。Electronを動かすだけなら Node.jsはbuilt-inされているので不要ですが、npmがある方が便利なのでNode.jsをインストールしておきましょう。Node.jsは <a href="https://nodejs.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">公式サイト</a>からダウンロードできます。Macであれば、<code>brew</code>でもインストール可能です。</p>

<p>Node.jsがインストールされたらElectronをインストールしてみましょう。下記の通りです。</p>

<p></p><pre class="crayon-plain-tag">$ npm install electron -g</pre><p></p>

<p>適当なフォルダを作成し、<code>package.json</code>、<code>main.js</code>、<code>index.html</code>を作成します。
package.jsonは下記の通りに作成します。</p>

<p></p><pre class="crayon-plain-tag">{
  "name": "electron-intro",
  "version": "0.0.1",
  "main": "main.js"
}</pre><p></p>

<p><code>main.js</code>を記述します。</p>

<p></p><pre class="crayon-plain-tag">const {app, BrowserWindow} = require('electron');

// window objectがGCされないようにするために、globalに定義する
let win;

function createWindow () {
  win = new BrowserWindow({width: 800, height: 600});

  win.loadURL(`file://${__dirname}/index.html`);

  win.on('closed', () =&gt; {
    // windowがクローズされたら null にして削除
    win = null;
  });
}

app.on('ready', createWindow);

app.on('window-all-closed', () =&gt; {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () =&gt; {
  if (win === null) {
    createWindow();
  }
});</pre><p></p>

<p>最後に表示するための<code>index.html</code>を記述します。</p>

<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Hello Electron!&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;Hello Electron!&lt;/h1&gt;
    Node version: &lt;script&gt;document.write(process.versions.node)&lt;/script&gt;,
    Chrome version: &lt;script&gt;document.write(process.versions.chrome)&lt;/script&gt;,
    Electron version: &lt;script&gt;document.write(process.versions.electron)&lt;/script&gt;.
  &lt;/body&gt;
&lt;/html&gt;</pre><p></p>

<p>これだけでHello Worldは一旦完成です。 下記のようなファイル構成になっていることを確認してください。</p>

<pre><code>.
├── index.html
├── main.js
└── package.json
</code></pre>

<p>Electronを起動させてみましょう。</p>

<p></p><pre class="crayon-plain-tag">$ electron .</pre><p></p>

<p>下記のようなウィンドウが出たら完成です。</p>

<div id="attachment_20847" style="width: 650px" class="wp-caption aligncenter"><img src="/wp-content/uploads/2016/09/hello_world-640x477.png" alt="Hello, World実行結果" width="640" height="477" class="size-large wp-image-20847" srcset="/wp-content/uploads/2016/09/hello_world.png 640w, /wp-content/uploads/2016/09/hello_world-300x224.png 300w, /wp-content/uploads/2016/09/hello_world-207x154.png 207w" sizes="(max-width: 640px) 100vw, 640px" /><p class="wp-caption-text">Hello, World実行結果</p></div>

<h2>PhotonKitを使ってミニマムブラウザを作る</h2>

<p>これだけだと味気ないので、PhotonKitを使ってミニマムブラウザを作ってみましょう。ブラウザを作ると言っても、 Chromiumを内包しているElectronであれば、Chromiumの機能を借りてくるだけなのでそこまで難しくはないです。</p>

<p>PhotonKitはCSSフレームワークの1つです。BootstrapやMaterial Design Liteのようなclass setを持っています。Mac のクライアントのようなアプリケーションを作るためのデザインテンプレートになっています。</p>

<div id="attachment_20849" style="width: 650px" class="wp-caption aligncenter"><img src="/wp-content/uploads/2016/09/photon-640x353.png" alt="Photon" width="640" height="353" class="size-large wp-image-20849" srcset="/wp-content/uploads/2016/09/photon.png 640w, /wp-content/uploads/2016/09/photon-300x165.png 300w, /wp-content/uploads/2016/09/photon-207x114.png 207w" sizes="(max-width: 640px) 100vw, 640px" /><p class="wp-caption-text">Photon</p></div>

<p>まずは<code>package.json</code>を作りましょう。</p>

<p></p><pre class="crayon-plain-tag">{
  "name": "electron-mini-browser",
  "version": "0.0.1",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "electron index.js"
  },
  "keywords": [],
  "author": "",
  "license": "MIT",
  "dependencies": {
    "electron": "^1.3.5"
  }
}</pre><p></p>

<p><code>npm start</code>でElectronを起動できるようにしておくことと、<code>dependencies</code>に<code>electron</code>をインストールしておきましょう。下記の方法でpackage.jsonに記述しつつ、インストールさせることが可能です。　</p>

<p></p><pre class="crayon-plain-tag">$ npm install electron --save</pre><p></p>

<p>次に<code>index.js</code>を作成します。</p>

<p></p><pre class="crayon-plain-tag">'use strict';
const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

let mainWindow = null;

app.on('window-all-closed', function() {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('ready', function() {
  mainWindow = new BrowserWindow({
    width: 800, 
    height: 600,
  });
  mainWindow.loadURL(`file://${__dirname}/index.html`);

  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});</pre><p></p>

<p>実際のページ(index.html)を作成します。</p>

<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;link rel="stylesheet" href="./css/photon.css"&gt;
    &lt;script src="./js/main.js"&gt;&lt;/script&gt;
    &lt;title&gt;Hello Electron!&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div class="window"&gt;
    &lt;header class="toolbar toolbar-header"&gt;
    &lt;h1 class="title"&gt;Hello Electron!&lt;/h1&gt;
    &lt;div class="toolbar-actions"&gt;
     &lt;!-- リロードボタン --&gt;
     &lt;button id="reload" class="btn btn-default"&gt;
       &lt;span class="icon icon-arrows-ccw icon-text"&gt;&lt;/span&gt;
       Reload
     &lt;/button&gt; 
     &lt;!-- 戻るボタン --&gt;
     &lt;button id="back" class="btn btn-default"&gt;
       &lt;span class="icon icon-left icon-text"&gt;&lt;/span&gt;
       Back
     &lt;/button&gt; 
     &lt;!-- 進むボタン --&gt;
     &lt;button id="forward" class="btn btn-default"&gt;
       &lt;span class="icon icon-right icon-text"&gt;&lt;/span&gt;
       Forward
     &lt;/button&gt; 
     &lt;!-- URL バー --&gt;
     &lt;input type="text" id="urlbar" class="form-control" placeholder="URL" value="https://github.com/"&gt;
     &lt;!-- お気に入りボタン --&gt;
     &lt;button id="favorite" class="btn btn-default"&gt;
       &lt;span class="icon icon-star icon-text"&gt;&lt;/span&gt;
       Favorite
     &lt;/button&gt; 
    &lt;/div&gt;
    &lt;/header&gt;
      &lt;div class="window-content"&gt;
        &lt;div class="pane-group"&gt;
          &lt;div class="pane-sm sidebar"&gt;
            &lt;!-- お気に入りリスト --&gt;
            &lt;ul id="fav-list" class="list-group"&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
            &lt;!-- Webページ表示領域 --&gt;
          &lt;webview class="pane" id="webview" src="https://www.github.com/" autosize="on" style="height:100%;"&gt;&lt;/webview&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;footer class="toolbar toolbar-footer"&gt;
    &lt;h1 class="title"&gt;Footer&lt;/h1&gt;
    &lt;/footer&gt;
    &lt;/div&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p></p>

<p>ページの中のボタンに動きを与えるため、<code>js/main.js</code>を作成します。</p>

<p></p><pre class="crayon-plain-tag">document.addEventListener('DOMContentLoaded', () =&gt; {
  const webview = document.getElementById('webview');
  const reloadButton = document.getElementById('reload');
  const backButton = document.getElementById('back');
  const forwardButton = document.getElementById('forward');
  const favoriteButton = document.getElementById('favorite');
  const urlbar = document.getElementById('urlbar');
  const favList = document.getElementById('fav-list');

  // webview表示の時にurlbarの値を変える
  webview.addEventListener('load-commit', ({ url, isMainFrame }) =&gt; {
    if (isMainFrame) {
      urlbar.value = url;
    }
  });

  // urlbarでEnterキーを押したら遷移する
  urlbar.addEventListener('keypress', (e) =&gt; {
    if (e.key === 'Enter') {
      webview.setAttribute('src', urlbar.value);
    }
  });

  // 更新ボタンをクリックしたらwebviewをリロードする
  reloadButton.addEventListener('click', () =&gt; {
    webview.reload();
  });

  // 戻るボタンをクリックしたらwebviewを戻る
  backButton.addEventListener('click', () =&gt; {
    webview.goBack();
  });
  
  // 進むボタンをクリックしたらwebviewを進ませる
  forwardButton.addEventListener('click', () =&gt; {
    webview.goForward();
  });
  
  // お気に入りボタンをタップしたらリストにURLを追加する
  favoriteButton.addEventListener('click', () =&gt; {
    const listItem = document.createElement('li');
    const listContent = document.createElement('p');
    listItem.setAttribute('class', "list-group-item");
    listItem.setAttribute('data-url', urlbar.value);
    listContent.textContent = urlbar.value;
    listItem.appendChild(listContent);
    favList.appendChild(listItem);
    listItem.addEventListener('click', () =&gt; {
      const url = listItem.getAttribute('data-url');
      webview.setAttribute('src', url);
    });
  });
});</pre><p></p>

<p>最後にPhotonKitのCSSとFontセットを <a href="http://photonkit.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ダウンロード</a>しておきます。
下記のようなディレクトリ構成になります。</p>

<p></p><pre class="crayon-plain-tag">.
├── css
│   ├── photon.css
│   └── photon.min.css
├── fonts
│   ├── photon-entypo.eot
│   ├── photon-entypo.svg
│   ├── photon-entypo.ttf
│   └── photon-entypo.woff
├── index.html
├── index.js
├── js
│   └── main.js
└── package.json</pre><p></p>

<p>全てを終えたら、<code>npm start</code>コマンドで起動します。下記のようなブラウザが出現できたら完成です。</p>

<div id="attachment_20846" style="width: 650px" class="wp-caption aligncenter"><img src="https://github.com/yosuke-furukawa/electron-intro/raw/master/img/electron-mini-browser.gif" alt="Electron+Photonで作ったミニブラウザ" width="640" height="374" class="size-large wp-image-20846" /><p class="wp-caption-text">Electron+Photonで作ったミニブラウザ</p></div>

<h2>プラットフォーム/ライブラリの特徴</h2>

<table>
<thead>
<tr>
  <th>項目</th>
  <th>説明</th>
</tr>
</thead>
<tbody>
<tr>
  <td>対応プラットフォーム</td>
  <td>Windows, Linux, OS X</td>
</tr>
<tr>
  <td>コードベースは（ほぼ）完全に統一できるか？</td>
  <td>ほぼ統一できる</td>
</tr>
<tr>
  <td>UIを記述する言語</td>
  <td>JavaScript, HTML, CSS</td>
</tr>
<tr>
  <td>UIはネイティブかウェブか</td>
  <td>基本はウェブだが、OSネイティブの機能(タスクバー等)は一部利用できる</td>
</tr>
<tr>
  <td>パフォーマンス</td>
  <td>基本ウェブなのでウェブページと同等、ただし自分でオフラインキャッシュの仕組みを持てるので、改善可能</td>
</tr>
<tr>
  <td>ネイティブな機能を呼び出せるか？</td>
  <td>Node.jsからOSの機能を呼び出せる。</td>
</tr>
</tbody>
</table>

<p>以下に、上の表を補足します。</p>

<h3>対応プラットフォーム</h3>

<p>Electronの公式サポートはWindows, Linux, OS Xの３つのみです。今のところはデスクトップアプリケーションのためのフレームワークなので、モバイル対応は全く考えられていません。</p>

<h3>コードベースは (ほぼ) 完全に統一できるか？</h3>

<p>ほぼ統一できます。ただし、OS X用の機能であったり、Windows専用の機能は用意されていて、プラットフォームによって呼び出し可能なAPIや受信可能なEventが若干異なります。クロスプラットフォームでOSの専用の機能を利用する上で、気になる方は一度<a href="http://electron.atom.io/docs/api/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">API</a>を確認すると良いでしょう。</p>

<h3>UIを記述する言語</h3>

<p>Hello Worldやミニブラウザを作って分かる通り、HTML/JS/CSSで書きます。ネイティブ部分の呼び出しもNode.jsなので、 JavaScriptになります。</p>

<p>JavaScriptのレイヤはNode.js部分とChromium部分でv8(JavaScript Engine)が動くので、ほぼ同一の動きをします、ただし、Node.jsとChromiumでv8のバージョンは若干違う可能性があります。基本的な部分は変わりませんが、ES2016の対応状況を見てもらえれば分かる通り、新しいJavaScriptの機能面で違いはあります。</p>

<div id="attachment_20844" style="width: 650px" class="wp-caption aligncenter"><img src="/wp-content/uploads/2016/09/compat-640x155.png" alt="ES2016の対応状況" width="640" height="155" class="size-large wp-image-20844" srcset="/wp-content/uploads/2016/09/compat.png 640w, /wp-content/uploads/2016/09/compat-300x73.png 300w, /wp-content/uploads/2016/09/compat-207x50.png 207w" sizes="(max-width: 640px) 100vw, 640px" /><p class="wp-caption-text">ES2016の対応状況</p></div>

<h3>UIはネイティブかウェブか</h3>

<p>基本はウェブです。デスクトップアプリケーションとして、タスクトレイに常駐させたい場合やOSネイティブのダイアログボックスを使いたい場合は専用のAPIがあるので、それを利用して機能を作ることも可能です。</p>

<h3>パフォーマンス</h3>

<p>Electronは基本的にウェブなので、ネイティブのデスクトップアプリと比較するとそこまで高速ではありません。</p>

<p>Electronのアプリを起動させると、Chromium用のプロセスが3つ起動し、Node.js用のメインプロセスが1つ起動します。合計4プロセスが常駐することになります。言ってしまえばブラウザそのものを起動しつつ、バックグラウンドにNode.jsを起動しているのと同様です。富豪的な方法で実現していると言えるでしょう。</p>

<p>そのため、描画パフォーマンス等はブラウザの機能がそのまま利用できますが、実行効率が良いモデルとはいえません。パフォーマンスにシビアなアプリケーションを作る場合は Electron ではなく、ネイティブの機能を使って作る方が良いでしょう。</p>

<h3>ネイティブな機能を呼び出せるか？</h3>

<p>ElectronからNode.jsを呼び出せばファイル操作や外部プロセスコールといった基本的な機能は呼び出せます。また、C言語等で書かれたネイティブライブラリもNode.jsアドオンがあれば呼び出すことが可能です。ただし、ネイティブライブラリに関しては、通常のnpmでインストールするだけでは利用できないことがあります。Nodeのバージョンがelectronのbuilt-inで保持しているバージョンと異なる場合にうまく利用できないことが多いです。ネイティブライブラリを利用したい場合は下記のガイドを確認することを推奨します。</p>

<p><a href="https://github.com/electron/electron/blob/master/docs/tutorial/using-native-node-modules.md" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ネイティブライブラリ利用ガイド</a></p>

<h2>まとめ</h2>

<p>Electronの概要とアプリ構築の方法、ウェブ用プラットフォームを構築する上での共通質問項目を記述しました。Electron はこれまでのAngularJSやReact等で構築されたSingle Page Applicationを活用して、デスクトップアプリケーションを構築するのに非常に向いています。</p>

<p>まだv1.0がリリースされて日が浅いこともあり、そこまでノウハウが溜まっているわけではありません。特にセキュリティやパフォーマンスなどの改善は今進んでいますが、ユーザーからのノウハウも溜める必要があると感じています。</p>

<p>もしまだ触っていない方がいらっしゃるのであれば、<a href="http://yosuke-furukawa.hatenablog.com/entry/2015/12/31/223045" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">electronica</a>などのチュートリアルもあるので是非やってみてください。</p>

<p>また今回の<a href="http://nodefest.jp/2016/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Node学園祭</a>では、Electron作者のzcbenzもゲストスピーカーとして登壇する予定です。Electronの今後の話が聞けると思います。</p>

<p>一緒にElectronを盛り上げていきましょう。</p>
]]></content:encoded>
		
		<series:name><![CDATA[Web技術でアプリ開発2016]]></series:name>
	</item>
		<item>
		<title>プログレッシブウェブアプリ詳解 ─ 過去・現在・未来</title>
		<link>/agektmr/20527/</link>
		<pubDate>Wed, 14 Sep 2016 00:00:03 +0000</pubDate>
		<dc:creator><![CDATA[えーじ]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[システム開発]]></category>
		<category><![CDATA[Progressive Web Apps]]></category>
		<category><![CDATA[Service Worker]]></category>

		<guid isPermaLink="false">/?p=20527</guid>
		<description><![CDATA[連載： Web技術でアプリ開発2016 (5)Web技術でアプリ開発2016特集・第5弾は、プログレッシブウェブアプリ (Progressive Web Apps)をご紹介させていただきます。 はじめに プログレッシブウ...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/web-based-apps-2016/" class="series-391" title="Web技術でアプリ開発2016" data-wpel-link="internal">Web技術でアプリ開発2016</a> (5)</div><p>Web技術でアプリ開発2016特集・第5弾は、プログレッシブウェブアプリ (Progressive Web Apps)をご紹介させていただきます。</p>

<p><style>
.youtube {
    height: 0;
    position: relative;
    padding-bottom: 56.25%;
    overflow: hidden;
    margin-bottom: 24px;
}
.youtube > iframe {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
}
</style></p>

<h2>はじめに</h2>

<p>プログレッシブウェブアプリ(Progressive Web Apps)という言葉が初めて登場したのは2015年8月のAlex Russellによる記事<a href="https://medium.com/@slightlylate/progressive-apps-escaping-tabs-without-losing-our-soul-3b93a8561955" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Progressive Web Apps: Escaping Tabs Without Losing Our Soul</a>です。当時オフラインやプッシュ通知など、モバイルウェブを飛躍的に進化させる画期的な機能が次々と追加されていた状況において、このムーブメントを呼称するための言葉が求められていました。Google社内でいくつもの候補が挙げられましたが、Service Workerの発案者としてAlex Russellが推したのが、この「プログレッシブウェブアプリ」でした。</p>

<p>また、当初Googleで始まったプログレッシブウェブアプリの動きではありましたが、先日の<a href="https://www.youtube.com/playlist?list=PLNYkxOF6rcIAWWNR_Q6eLPhsyx6VvYjVb" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Progressive Web App Dev Summit</a>ではMicrosoft、Mozilla、Opera、Samsungの代表者も登壇するなど、各ブラウザベンダーとも足並みが揃いつつあります。これはもはやウェブ全体の動きと言うことができます。</p>

<p>若干古い情報になりますが、以降この (長い) 記事を読む以外に手早く情報を得るための方法として、下記を挙げておきます。</p>

<h3>スマートフォン体験を一歩先へ &#8211; プログレッシブウェブアプリの作り方</h3>

<div class="youtube">

<!-- iframe plugin v.4.3 wordpress.org/plugins/iframe/ -->
<iframe style="width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;" src="https://www.youtube.com/embed/VHN2wJWi0WE?controls=2&amp;modestbranding=1&amp;showinfo=0&amp;utm-source=crdev-wf" class="devsite-embedded-youtube-video" allowfullscreen data-video-id="hmqZxP6iTpo" data-autohide="1" data-modestbranding="1" data-controls="2" data-utm-source="crdev-wf" data-showinfo="0" frameborder="0" width="100%" height="500" scrolling="yes"></iframe>

</div>

<p><a href="https://www.youtube.com/watch?v=VHN2wJWi0WE" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">講演動画</a></p>

<div class="youtube">

<!-- iframe plugin v.4.3 wordpress.org/plugins/iframe/ -->
<iframe src="https://docs.google.com/presentation/d/1VcXsKDaCUpf2SS35WNcrKslkK6PcXxWsnhcKiLfWCXs/embed?start=false&amp;loop=false" width="100%" height="500" scrolling="yes" class="iframe-class" frameborder="0"></iframe>

</div>

<p><a href="https://docs.google.com/presentation/d/1VcXsKDaCUpf2SS35WNcrKslkK6PcXxWsnhcKiLfWCXs/pub?start=false&amp;loop=false&amp;delayms=3000" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">プレゼン資料</a></p>

<h2>プログレッシブウェブアプリとは</h2>

<p>プログレッシブウェブアプリとは、最新の標準ウェブ技術を用いることで、オフラインやプッシュ通知といったこれまでよりも一次元上のユーザー体験をもたらすウェブアプリのことです。必ずしもデスクトップのウェブアプリや、ページ遷移を使ったサーバーサイドでレンダリングされるアプリを除外するものではありません。</p>

<p>理屈で説明するよりも、実際に体験した方が早いかと思います。いくつか具体例を挙げましょう。</p>

<ul>
<li><a href="https://www.flipkart.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Flipkart</a></li>
<li><a href="http://www.washingtonpost.com/pwa/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Washington Post</a></li>
<li><a href="https://m.aliexpress.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">AliExpress</a></li>
<li><a href="http://smp.suumo.jp/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">suumo</a></li>
</ul>

<p>※ 他にも様々なプログレッシブウェブアプリが既に存在していますが、<a href="https://pwa.rocks/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">pwa.rocks</a>というサイトにいくつかまとまっていますので、ぜひご覧頂下さい。</p>

<p>実際に使ってみるとわかりますが、これらのアプリケーションにおいてこれまでにない特徴的な点がいくつかあります。</p>

<ul>
<li>ホーム画面に追加してワンタップで起動</li>
<li>キャッシュを使ってオフライン、もしくは高速に動作</li>
<li>プッシュ通知を送信</li>
<li>自動でログイン</li>
</ul>

<h2>プログレッシブとは何か</h2>

<p>「プログレッシブ」という言葉自体は直訳すると「進歩的な」といった意味がありますが、ピンとこない方は多いと思います。</p>

<p>プログレッシブウェブアプリの「プログレッシブ」のひとつの意味は、ウェブページとして使い始めたサービスが、ホーム画面に追加し、オフラインで動作し、プッシュ通知を送り始めるといった流れの中で、「徐々にアプリへと変化していく」様を指しています。</p>

<p>もう一つ意味があります。</p>

<p>フロントエンドエンジニアであれば、プログレッシブ・エンハンスメントという言葉を聞いたことがあると思います。プログレッシブ・エンハンスメントとは、HTML5 時代に続々と新しい機能が登場する中で、最新の標準技術をまだ盛り込んでいないブラウザでも、情報を届けるといった目的をゴールに、必要最低限の機能をベースとして、可能であれば最新技術を使うことでよりリッチな体験を提供する、という設計コンセプトのことを言いました。(逆に、リッチな体験を提供できるブラウザをベースに、最新の技術が使えないブラウザでも最低限の目的は達成できるように設計する手法をグレースフル・デグラデーションと呼びました)</p>

<p>プログレッシブウェブアプリも同様に捉えることができます。つまり、必要最低限の機能を提供できる状態をベースとし、オフラインやプッシュ通知などをプログレッシブな (進歩的な) 機能として提供する、というものです。</p>

<p>これは言い方を変えれば、対応していないブラウザがあるからといって対応を待つべきではなく、それを前提としてウェブを前に進めていこう、というメッセージでもあるのです。実際、プログレッシブウェブアプリ対応への副作用として、複数の機能に未対応のブラウザでも<a href="https://developers.google.com/web/showcase/2016/aliexpress" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">コンバージョンレートが改善したという事例</a>も出ています。</p>

<h2>アプリとウェブのギャップ</h2>

<p>Web2.0の時代を経てコンピューターの世界はネイティブアプリケーションからウェブアプリケーションの時代へと変化を遂げました。地図アプリケーションを思い出して下さい。その昔CD-ROMからせっせとインストールする必要のあった地図が、URLひとつでブラウザから見られるようになったのです。他にも例を挙げればキリがありません。</p>

<p>ウェブはその後もHTML5やその周辺技術の発展により大きく進化していきました。しかしその恩恵を満足の行く形で受けられたのはデスクトップでの話。モバイル・スマートフォンの時代となり、ユースケースが変化していく中で、スマートフォン上で快適に目的を達成するためには、ウェブブラウザは力不足と言われるようになってしまいました。その象徴的な出来事の一つがFacebookのCEOマーク・ザッカーバーグによるこの発言でした。</p>

<p><a href="http://jp.techcrunch.com/2012/09/14/20120911mark-zuckerberg-our-biggest-mistake-with-mobile-was-betting-too-much-on-html5/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Disrupt：ザッカーバーグ、「HTML5を過大評価したのは、われわれ最大の失敗」と認める | TechCrunch Japan</a></p>

<p>これはひとえに標準化を必要とするウェブという環境の特性ゆえと言わざるを得ません。標準化を進めつつ実装し、浸透を待たなければならなかったウェブと異なり、ネイティブアプリはモバイルに最適化した仕様や機能を次々と取り込み、技術革新を起こしていきました。</p>

<p>しかしウェブには、ネイティブアプリでは実現できない特性も持ち合わせています。それが<strong>SLICE</strong>と呼ばれるものです。</p>

<ul>
<li>Secure (安全)</li>
<li>Linkable (リンク可能)</li>
<li>Indexable (インデックス可能)</li>
<li>Composable (再構成可能)</li>
<li>Ephemeral (一時的な利用)</li>
</ul>

<p>ウェブもネイティブも、お互いの短所を埋める進化を遂げていく中で、ウェブが着実に前進していることの現れが、プログレッシブウェブアプリと言えるでしょう。一度はHTML5化を断念したFacebookがプッシュ通知を採用したのはその最たる例です。</p>

<p><a href="http://jp.techcrunch.com/2015/09/15/20150914facechrome/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Facebook、Googleと協力してモバイルウェブユーザーにプッシュ通知を送信</a></p>

<p>プログレッシブウェブアプリはWeb 2.0、HTML5と続いてきた大きな流れの、次の一歩と捉えて間違いありません。</p>

<h2>プログレッシブウェブアプリを構成する機能</h2>

<p>プログレッシブウェブアプリはそれ自体が機能を表しているわけではなく、様々な先進的機能をまとめたひとつのムーブメントです。具体的にどんな機能があるのか、ひとつひとつ見ていきましょう。</p>

<ul>
<li><a href="#pw-https" data-wpel-link="internal">HTTPS</a></li>
<li><a href="#pw-manifest" data-wpel-link="internal">Web App Manifest</a></li>
<li><a href="#pw-sw" data-wpel-link="internal">Service Worker</a></li>
<li><a href="#pw-cache" data-wpel-link="internal">Cache API</a></li>
<li><a href="#pw-push" data-wpel-link="internal">Web Push / Push Notifications</a></li>
<li><a href="#pw-bg" data-wpel-link="internal">Background Sync</a></li>
<li><a href="#pw-budget" data-wpel-link="internal">Web Budget API</a></li>
<li><a href="#pw-credential" data-wpel-link="internal">Credential Management API</a></li>
<li><a href="#pw-payment" data-wpel-link="internal">Payment Request API</a></li>
</ul>

<h3 id="pw-https">HTTPS</h3>

<p>プログレッシブウェブアプリに対応する上で大前提になるのがサイトの完全なHTTPS対応です。ログイン画面や商品購入画面だけではなく、すべてのページをHTTPS化する必要があります。</p>

<p>一般的に、HTTPSに対応することでウェブサイトは</p>

<ul>
<li>ウェブサイトの一意性を守るアイデンティティ(Identity)</li>
<li>サーバー・ブラウザ間の通信を秘匿するコンフィデンシャリティ(Confidentiality)</li>
<li>送受信されるデータを改ざんさせないインテグリティ(Integrity)</li>
</ul>

<p>の3つを手に入れることができます。</p>

<p>プログレッシブウェブアプリ対応において重要なのが、以下でご紹介する機能のほとんどがHTTPS上でのみ動作 (<a href="https://www.w3.org/TR/secure-contexts/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">セキュアコンテキスト</a>)するという点です。こういった機能はPowerful Features と呼ばれ、以前はHTTP上でも動作したgetUserMediaやgeolocationといったAPIもそこに加えられ、最近HTTPSのみで動作する変更が加えられました。</p>

<p>HTTPSに対応することなしにプログレッシブウェブアプリを実現することは不可能ですので、対応を検討する方はここからスタートして下さい。(ちなみにChromeでは、localhostとfile://もセキュアコンテキストに含まれますので、開発時は少し役に立つかもしれません)</p>

<div class="youtube">

<!-- iframe plugin v.4.3 wordpress.org/plugins/iframe/ -->
<iframe src="https://www.youtube.com/embed/YMfW1bfyGSY" frameborder="0" 0="allowfullscreen" width="100%" height="500" scrolling="yes" class="iframe-class"></iframe>

</div>

<h3 id="pw-manifest">Web App Manifest</h3>

<p>ネイティブアプリとウェブサイトを比較した時に、最も大きく異なるのがアクセスのしやすさです。もちろん、アプリのようにインストールしなくても、リンクを踏むだけでアクセスできるという意味で、ウェブは手に届きやすい存在です。しかしスマートフォンの場合、デスクトップのようにキーボードで手軽に検索ができるわけではありません。ホーム画面からタップひとつで起動できるだけで、ユーザーにとっての身近さは大きく改善します。</p>

<p><img src="/wp-content/uploads/2016/09/Screenshot_20160901-153533-169x300.png" alt="screenshot_20160901-153533" style="width: 169px; height: 300px;" class="aligncenter size-medium wp-image-20903" /></p>

<p>そこで登場するのがWeb App Manifestです。Web App Manifestを使うことで、該当ページに関する様々な情報を定義することができます。</p>

<p><a href="https://developer.mozilla.org/ja/docs/Web/Manifest" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Web App Manifest | MDN</a></p>

<p>最近は<code>lang</code>や<code>scope</code>、<code>screenshots</code>といった項目も新しく追加されていますので、その辺りも注目して下さい。</p>

<p>これらの情報を踏まえ、「ホーム画面に追加」をすると、ウェブアプリはホーム画面に鎮座することができるようになります。しかし、この機能がiOSでも古くからある<code>meta</code>タグを使ったものに近いと思われた方もいるかもしれません。</p>

<p>Chromeの場合、このWeb App Manifestといくつかの条件が加わることで、ブラウザが自動的にホーム画面に追加を促してくれる、という点が大きく異なります。詳しくは下記の記事を参照して下さい。</p>

<p><a href="http://qiita.com/horo/items/ff665e4a6613e7684f8f" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Web App ManifestでWebアプリをインストール可能に &#8211; Qiita</a></p>

<h3 id="pw-sw">Service Worker</h3>

<p>Service Workerはプログレッシブウェブアプリを構成する機能の中でも、コンセプトを成立させた一番の立役者で、中核を成すものです。</p>

<p>従来のウェブにおいて、ページはサーバーから送られたHTMLとそれに付随するリソースで構成される機能がすべてであり、ページが閉じられると同時に忘れ去られる存在でした。Service Workerは、ページとは独立して動作するスクリプトを、ページを閉じた後でもブラウザ上で動かし続けることができる機能です。このService Workerを活用することで、様々な可能性が開かれます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/serviceworker.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/serviceworker-640x99.png" alt="serviceworker" width="640" height="99" class="alignnone size-large wp-image-20543" srcset="/wp-content/uploads/2016/08/serviceworker.png 640w, /wp-content/uploads/2016/08/serviceworker-300x46.png 300w, /wp-content/uploads/2016/08/serviceworker-207x32.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p><strong>オフライン</strong>：Service Workerはページが送信するあらゆるリクエストを横取りすることができます。実質的なローカルプロキシーとなるため、強力なキャッシュを活用すれば、ネットワークに接続していない状態でもレスポンスを返すことができるようになります。詳しくはCache APIの項で説明します。</p>

<p><strong>プッシュ通知</strong>：Service Workerはページが閉じた状態でも、また、ブラウザによっては起動してない状態であっても、イベントを検知することができます。そのため、外部サーバーが送信したプッシュリクエストをイベントとして受け取り、何かしらのアクションを起こすことができるのです。詳しくはWeb Push / Web Notificationsの項で説明します。</p>

<p>それでは、Service Workerの使い方を雰囲気だけ見てみましょう。</p>

<p>Service Workerは独立したJavaScriptとして動作するため、ファイルも分けて記述する必要があります。例えばページ上で動作するスクリプト<code>app.js</code>が、<code>service-worker.js</code>というService Workerを使いたいとします。</p>

<p></p><pre class="crayon-plain-tag">navigator.serviceWorker.register('service-worker.js', {scope: './'});</pre><p></p>

<p>これだけでService Workerが登録されます。簡単ですね。</p>

<p><code>service-worker.js</code>の中身はイベント・ドリブンのスクリプトになります。例えば下記のように記述しておけば、あらゆるリクエストをService Workerが拾い上げて、サーバーにリクエストを転送することなく&#8221;Hello World!&#8221;とレスポンスを返します。</p>

<p></p><pre class="crayon-plain-tag">self.addEventListener('fetch', function(event) {  
  event.respondWith('Hello World!');  
});</pre><p></p>

<p>Service Workerは実際いつ動作を開始するのでしょう？影響範囲はどこまででしょう？こういった細かい話になるとセキュリティへの懸念も出てくるため、若干複雑な内容を理解する必要が出てきます。scopeとライフサイクルについては抑えておきましょう。</p>

<h4>scope</h4>

<p>Service Workerが登録されると、以後半永久的にスクリプトを動かし続けることになります。仮にService Workerがドメインの範囲内すべてに影響をおよぼすことができるとすると、ブログなどのユーザーの権限がパスで区切られたサービスでは、自分の預かり知らないスクリプトが埋め込まれてしまう可能性がでてきます。そこでService Workerでは、scopeという概念を使って影響範囲を制限します。詳しくはこちらの記事が参考になります。</p>

<p><a href="http://qiita.com/nhiroki/items/eb16b802101153352bba" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ServiceWorkerのスコープとページコントロールについて &#8211; Qiita</a></p>

<h4>ライフサイクル</h4>

<p>Service Workerが登録されたあと、スクリプトを手動で更新したい場合もあります。新しいスクリプトはすぐに有効になるのでしょうか？その場合古いスクリプトはどうなってしまうのでしょうか？Service Workerは放っておいたら永久に更新されないのでしょうか？</p>

<p>Service Workerのライフサイクルを正しく理解することはとても重要です。下記の記事をぜひご覧ください。</p>

<ul>
<li><a href="http://www.html5rocks.com/ja/tutorials/service-worker/introduction/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Service Workerの紹介: Service Workerの使い方 &#8211; HTML5 Rocks</a> (一部古い内容が含まれます)  </li>
<li><a href="https://blog.jxck.io/entries/2016-04-24/service-worker-tutorial.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">中級者向け Service Worker Tutorial | blog.jxck.io</a>  </li>
<li><a href="http://blog.nhiroki.jp/2015/07/05/service-worker-registration" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Service WorkerのRegistration</a>  </li>
</ul>

<h4>デバッグ</h4>

<p>Chromeではプログレッシブウェブアプリのデバッグをしやすくするために、最近DevToolsにResourcesパネルの代わりに Applicationパネルが追加されました。Manifestや各種ストレージなどを、ひとつのパネルからまとめて確認することができます。中でもService Worker専用の項目では、現在起動中のスクリプトだけでなく</p>

<ul>
<li>Offline &#8211; オフラインのエミュレーションボタン</li>
<li>Update on reload &#8211; リロードするだけでService Workerを更新</li>
<li>Bypass for network &#8211; ネットワークリクエストの横取りを一時的に停止</li>
</ul>

<p>といったオプションが利用できます。ここからService Workerの単独のDevToolsを開いてデバッグを行ってください。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/devtools.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/devtools-640x238.png" alt="devtools" width="640" height="238" class="alignnone size-large wp-image-20542" srcset="/wp-content/uploads/2016/08/devtools.png 640w, /wp-content/uploads/2016/08/devtools-300x112.png 300w, /wp-content/uploads/2016/08/devtools-207x77.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<h4>少し未来の話</h4>

<p>今後利用可能になるService Worker周辺の重要な機能についても少し触れておきましょう。</p>

<p><strong>Link rel=serviceworker</strong>
Chrome 54からOrigin Trial (特定のドメインに実験的にホワイトリストで機能を提供) ベースでService Workerの登録が linkタグやHTTPヘッダーで行えるようになりました。将来的にこれが利用できるようになれば、JavaScriptを記述することなく、linkタグやHTTPヘッダーのみでService Workerを登録できるようになります。</p>

<p></p><pre class="crayon-plain-tag">&lt;link rel="serviceworker" href="/js/sw.js" scope="/"&gt;</pre><p></p>

<p><a href="https://www.chromestatus.com/feature/5682681044008960" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">https://www.chromestatus.com/feature/5682681044008960</a></p>

<p><strong>Foreign fetch</strong>
また、Web Fontsのような複数ドメインから共有されるリソースをCDN経由で提供するサーバーのリソースも、現在は利用する側のService Workerがハンドリングすることが可能ですが、これをCDN側のService Workerがハンドリングできれば効率が向上します。これを可能にする機能はForeign Fetchと呼ばれ、Chrome 54からOrigin Trialベースで提供が開始されています。</p>

<p><a href="https://www.chromestatus.com/feature/5684130679357440" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">https://www.chromestatus.com/feature/5684130679357440</a></p>

<p>その他、Service Workerのさらに詳しい情報はHTML5 Conference 2016で行われたChromeエンジニアの保呂さんのスライドが参考になります。<br />
<a href="https://goo.gl/YxL2L7" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Service Worker Deep Dive</a></p>

<h3 id="pw-cache">Cache API</h3>

<p>先程説明したように、Service Workerを使ってあらゆるリクエストを横取りすることで、オフラインの機能が実現可能になります。そこで強力なキャッシュ機能を提供するのがCache APIです。</p>

<p>Cache APIは取得されたリソースだけでなく、リクエストやレスポンスの内容も含めて保存されます。下記の例では、キャッシュが残っていればキャッシュされていたレスポンスを、なければサーバーにリクエストを送って、返ってきたレスポンスを返します (キャッシュに保存はしません)。</p>

<p></p><pre class="crayon-plain-tag">self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      return response || fetch(event.request);
    })
  );
});</pre><p></p>

<p>Cache APIを使った実例について、詳しくはこちらの記事が参考になります。</p>

<p><a href="http://qiita.com/horo/items/175c8fd7513138308930" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ServiceWorkerとCache APIを使ってオフラインでも動くWebアプリを作る &#8211; Qiita</a></p>

<p>なお、Cache APIを扱う上で fetch()も避けては通れませんが、ググらビリティの低さから、まとまった資料が見つかりにくいという問題があります。こちらのページがよくまっていたのでリンクしておきます。</p>

<p><a href="http://qiita.com/tomoyukilabs/items/9b464c53450acc0b9574" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">お疲れさまXMLHttpRequest、こんにちはfetch &#8211; Qiita</a></p>

<p>ここまで述べてきたように便利なService Worker + Cache APIですが、多くの人が似たようなコードを書くであろうことは容易に想像ができます。そこで便利なライブラリがいくつかあります。</p>

<h4>sw-toolbox</h4>

<p>リソースをキャッシュする際に必要になるのが、リソースの優先順位の判定です。例えば共通で利用されるJavaScriptファイルは、更新がない限りネットワークにリクエストを送るまでもなく常にキャッシュから読み込むことでスピードを優先したいと思うはずです。逆に例えば、天気アプリであれば、開く度に最新の天気予報を見たいですが、オフラインだった場合はオフラインだと言われるよりは、キャッシュからでもその後の天気予報を見たいと思うはずです。</p>

<p>このように、同じキャッシュを活用するでも、場面によってキャッシュを優先したいのか、ネットワークを優先したいのかが異なってきます。そこで便利なのが<a href="https://github.com/GoogleChrome/sw-toolbox" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">sw-toolbox</a>です。</p>

<p></p><pre class="crayon-plain-tag">toolbox.router.get('/myapp/index.html', toolbox.networkFirst);</pre><p></p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/appshell.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/appshell-640x258.png" alt="appshell" width="640" height="258" class="alignnone size-large wp-image-20539" srcset="/wp-content/uploads/2016/08/appshell.png 640w, /wp-content/uploads/2016/08/appshell-300x121.png 300w, /wp-content/uploads/2016/08/appshell-207x83.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>sw-toolboxではネットワークを優先するnetworkFirst、キャッシュを優先するcacheFirstの他にもfastest、networkOnly、cacheOnlyといった様々なオプションが利用可能です。</p>

<p><a href="https://googlechrome.github.io/sw-toolbox/docs/master/index.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">https://googlechrome.github.io/sw-toolbox/docs/master/index.html</a></p>

<h4>sw-precache</h4>

<p>Service Workerを使ったキャッシュ機能以前にオフラインを実現する機能として登場した<a href="https://developer.mozilla.org/ja/docs/Web/HTML/Using_the_application_cache" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Application Cache</a>は、ページを初めて開いた時点で、予め定義されたリソースをすべてキャッシュするものでした。Service Worker + Cache APIにおいても同様のニーズはあるでしょう。例えばアプリの外枠や必要最低限のCSSやJavaScriptファイルを予めロードしておくことで、コンテンツ部分のみをダイナミックにロードすればよいという<a href="https://github.com/GoogleChrome/application-shell" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Application Shell</a>というアーキテクチャを利用する場合です。</p>

<p>これを実現するのに便利なライブラリが<a href="https://github.com/GoogleChrome/sw-precache" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">sw-precache</a>です。Gulp やGruntといったタスクランナーを使うことで、リストされたリソースを最初のロード時点でキャッシュしてしまうJavaScript のコードを出力してくれます。あとはこれをService Workerとしてロードすればよいだけです。また、リソースの更新もハッシュを使って自動的に管理してくれるので、どのファイルを書き換えたからリストを変更しなければならない、といったようなマニュアル作業が不要になります。</p>

<p></p><pre class="crayon-plain-tag">gulp.task('generate-service-worker', function(callback) {
  var path = require('path');
  var swPrecache = require('sw-precache');
  var rootDir = 'app';

  swPrecache.write(path.join(rootDir, 'service-worker.js'), {
    staticFileGlobs: [rootDir + '/**/*.{js,html,css,png,jpg,gif,svg,eot,ttf,woff}'],
    stripPrefix: rootDir
  }, callback);
});</pre><p></p>

<p>なお、最近追加されたruntimeCachingという機能を使うことで、<a href="https://github.com/GoogleChrome/sw-precache#runtimecaching-arrayobject" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">sw-toolbox の便利な機能を宣言的に記述</a>することもできます。</p>

<h4>sw-appcache-behavior</h4>

<p>もし既にApplication Cacheを使っていて、Service Workerに移行を検討している場合は、<a href="https://github.com/GoogleChrome/sw-helpers" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">sw-helpers</a>ライブラリの一部である<a href="https://github.com/GoogleChrome/sw-helpers/tree/master/projects/sw-appcache-behavior" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">sw-appcache-behavior</a>が便利です。既存の Manifestファイルをそのまま利用してService Workerによるオフラインを実現することができます。</p>

<h4>sw-offline-google-analytics</h4>

<p>オフラインのウェブサイトがうまく作れたとしても、ユーザーがどのアクセスページにアクセスし、どのように利用しているかが分からなければ、本当に役に立っているのかどうかを知ることはできません。これもsw-helpersの一部である<a href="https://developers.google.com/web/updates/2016/07/offline-google-analytics?hl=en" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">sw-offline-google-analytics</a>を使えば、オフライン中のアクセス解析をデータベース上に保存しておいて、オンラインになったタイミングでサーバーに送信してGoogle Analyticsでアクセス解析結果を閲覧することができるようになります。</p>

<h3 id="pw-push">Web Push / Web Notifications</h3>

<p>プッシュ通知は、プログレッシブウェブアプリを語る際、これまでできなかったことの中で、技術者ではなくても効果が理解できるという意味では、最も分かりやすい機能です。実際に既に多くのサービスがこれを利用しています。例えば Facebook です。<a href="http://m.facebook.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">モバイルウェブ版のFacebook</a>にアクセスしてみると、すぐにそのことに気付くでしょう。</p>

<p></p><pre class="crayon-plain-tag">navigator.serviceWorker.ready().then(function(sw) {
  sw.pushManager.subscribe({userVisibleOnly: true})
    .then(function(sub) {
      // パーミッション取得後
      sendSubToServer(sub);  // Send subscription to the server
  });
});</pre><p></p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/push1.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/push1-640x130.png" alt="push1" width="640" height="130" class="alignnone size-large wp-image-20540" srcset="/wp-content/uploads/2016/08/push1.png 640w, /wp-content/uploads/2016/08/push1-300x61.png 300w, /wp-content/uploads/2016/08/push1-207x42.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p></p><pre class="crayon-plain-tag">self.addEventListener('push', function(event) {
  event.waitUntil(
    self.registration.showNotification(title, {
      body: body, icon: icon, tag: tag,
      actions: [{action: 'remindMe', title: 'REMIND ME'}]
    }
  });
});</pre><p></p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/push2.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/push2-640x122.png" alt="push2" width="640" height="122" class="alignnone size-large wp-image-20541" srcset="/wp-content/uploads/2016/08/push2.png 640w, /wp-content/uploads/2016/08/push2-300x57.png 300w, /wp-content/uploads/2016/08/push2-207x39.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>具体的な実装方法は若干複雑ですので、サードパーティーのサービスを使うのも手かもしれません。自分で実装する場合は、こちらのドキュメントがよくまとまっています。</p>

<p><a href="http://qiita.com/tomoyukilabs/items/217915676603fda73b0a" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Web Pushでブラウザにプッシュ通知を送ってみる &#8211; Qiita</a><br />
<a href="http://qiita.com/tomoyukilabs/items/c7268aa29447a1d0a3fb" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firefox (Developer Edition)でW3C Push APIを使ってみる &#8211; Qiita</a></p>

<p>Chromeの場合、以前はGCM (Google Cloud Messaging、もしくはFirebase Cloud Messaging)が必須でしたが、現在は<a href="https://tools.ietf.org/html/draft-ietf-webpush-protocol-08" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">標準の Web Push</a>が利用できます。詳しくは下記をご覧下さい。</p>

<p><a href="http://qiita.com/tomoyukilabs/items/8fffb4280c1914b6aa3d" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ChromeでW3C Push APIを使ってみた &#8211; Qiita</a></p>

<p>Web Pushについては、<a href="https://github.com/web-push-libs/web-push" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">node.js 向けのライブラリ</a>も提供されています。</p>

<h3 id="pw-bg">Background Sync</h3>

<p>妙なタイミングでネットワークがオフラインになってしまったために、リクエストが送れなかったという経験は誰しもあると思います。そんな時にリクエストをキューしておいて、オンラインになったタイミングで送ってくれるとありがたいですよね。それを実現してくれるのが、Background Syncです。</p>

<p><a href="http://qiita.com/horo/items/28bc624b8a26ffa09621" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ServiceWorkerのBackground Syncでオンライン復帰時にデータ送信 &#8211; Qiita</a></p>

<h3 id="pw-budget">Web Budget API</h3>

<p>現状Service Workerはプッシュを受信すると、通知を出さなければなりません。これはブラウザリソースの無駄遣いを防ぐためです。しかし、例えばバックグラウンドで購読しているフィードを更新するといったユースケースは容易に思いつきます。</p>

<p>そこで検討されているのが<a href="https://beverloo.github.io/budget-api/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Web Budget API</a>という機能です。これを使うことで、ページは与えられたバジェットを適切に配分してバックグラウンドでの処理を行うことが可能になりますので、リソースの無駄遣いを防ぎつつ必要な機能を実現できるようになるはずです。</p>

<p><a href="https://www.chromestatus.com/features/5691190548627456" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">https://www.chromestatus.com/features/5691190548627456</a></p>

<h3 id="pw-credential">Credential Management API</h3>

<p>Credential Management APIはユーザーのクレデンシャル (認証情報) を制御するためのAPIです。</p>

<div class="youtube">

<!-- iframe plugin v.4.3 wordpress.org/plugins/iframe/ -->
<iframe src="https://www.youtube.com/embed/O3mBdKYMsMY" frameborder="0" 0="allowfullscreen" width="100%" height="500" scrolling="yes" class="iframe-class"></iframe>

</div>

<p>これを使うことにより</p>

<ul>
<li>id / passwordをブラウザに覚えさせる</li>
<li>ソーシャルログインの選択肢をブラウザに覚えさせる</li>
<li>ログイン時にアカウント選択ダイアログを提供する</li>
<li>ユーザーを自動的にログインさせる</li>
</ul>

<p>といったことが可能になります。</p>

<p>典型的なユースケースとしては、ニュースサイトやコマースサイトといった、必ずしもログインしなくてもよい、しかし提供者側としてはログインしてもらいたいサービスにおいて役立ちます。実際に利用されている例としては<a href="https://m.aliexpress.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">AliExpress</a>の実装が非常によくできていますので、是非一度お試し下さい。</p>

<p>実装は基本的にフロントエンド側だけですので、比較的気軽に導入することができます。</p>

<ul>
<li><a href="https://credential-management-sample.appspot.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">デモアプリ</a> (<a href="https://github.com/GoogleChrome/credential-management-sample" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ソースコード</a>)</li>
<li><a href="https://developers.google.com/web/updates/2016/04/credential-management-api" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">翻訳済みのドキュメント</a></li>
<li><a href="http://g.co/codelabs/cmapi" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">実際に実装を体験できるコードラボ</a></li>
<li><a href="http://w3c.github.io/webappsec-credential-management/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">仕様</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Credential_Management_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">MDN リファレンス</a></li>
</ul>

<h3 id="pw-payment">Payment Request API</h3>

<p>Payment Request APIは支払い時のチェックアウトに必要なフォームを置き換えるUIを提供します。Chromeではバージョン 53から利用できるようになる予定です。</p>

<div class="youtube">

<!-- iframe plugin v.4.3 wordpress.org/plugins/iframe/ -->
<iframe src="https://www.youtube.com/embed/hmqZxP6iTpo" frameborder="0" 0="allowfullscreen" width="100%" height="500" scrolling="yes" class="iframe-class"></iframe>

</div>

<p>Payment Request APIが提供するのは、ユーザーインターフェースです。ブラウザのAutofill機能を活用することで、クレジットカードの情報や住所などを、すばやく簡単に入力できるようになります。</p>

<p>支払い方法は現状クレジットカードのみですが、まもなくAndroid Payも利用可能 (残念ながら当初日本は対象外) になる予定です。将来的には、さらに様々な支払い方法をオープンかつ柔軟に組み込めるようになっていく予定です。</p>

<ul>
<li><a href="https://developers.google.com/web/updates/2016/07/payment-request" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">アナウンス・概要</a></li>
<li><a href="https://developers.google.com/web/fundamentals/primers/payment-request/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">実装ガイド</a></li>
<li><a href="https://developers.google.com/web/fundamentals/primers/payment-request/android-pay" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Android Pay 実装ガイド</a></li>
<li><a href="https://www.w3.org/TR/payment-request/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">仕様</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Payment_Request_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">MDN リファレンス</a></li>
</ul>

<h3>その他の機能</h3>

<p>プログレッシブウェブアプリを語る上で数えるべき機能や考え方は他にもいくつかありますが、キリがありませんのでこの辺にしておきましょう。</p>

<ul>
<li>Web Bluetooth</li>
<li>Web MIDI</li>
<li>Web Animation</li>
</ul>

<p>興味のある方は、この辺りもぜひ抑えておいていただければと思います。</p>

<h2>Lighthouse</h2>

<p>あるウェブアプリを指してそれがプログレッシブウェブアプリかどうかを議論するのはあまり意味のないことですが、それを示す指標を得ることはできます。それが<a href="https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Lighthouse</a>というChrome拡張機能です。ウェブサイトを開いた状態でこの拡張を起動すると、プログレッシブウェブアプリの対応度合いをスコアで示してくれます。</p>

<p><img src="https://lh3.googleusercontent.com/69AN0502kzahk9AmzmLGzRvsVy_6zq2gUnPB8ZH2NIVKMF8DSf9qw44bIh2v9CDVy1FQHFMq1r1US9dey9mjUjA7jg_lLnLcXseLHMVGDDyjGVGetdVCJFu4YlZmQPW18jAcgdg-" alt="" /></p>

<p>Chrome拡張機能としてだけではなく、node moduleとしても利用が可能です。</p>

<p><a href="https://github.com/GoogleChrome/lighthouse" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">https://github.com/GoogleChrome/lighthouse</a></p>

<p>Lighthouseはまだアルファ版の段階のため、評価できない機能が多数ありますが、今後対応していく予定です。</p>

<h2>リソース</h2>

<p>プログレッシブウェブアプリに興味を持たれた方で、最新情報を追いかけたいという方は下記のページをご覧下さい。RSSフィードも配信しています。</p>

<p><a href="https://developers.google.com/web/updates/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">https://developers.google.com/web/updates/</a></p>

<p>資料が英語で読めない？英語が分かる人はぜひ、<a href="http://qiita.com/yoichiro6642/items/3afc2f01706398a5a458" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">翻訳にご協力下さい</a>。</p>

<h2>最後に</h2>

<p>プログレッシブウェブアプリについて長々と書いてきましたが、重要なのは決してこれらの機能すべてに対応することではありません。自分が提供するサービスがユーザーに最大の価値を提供するために必要であれば、ネイティブアプリを提供するべき場合もあるでしょう。オフライン機能だけが必要な場合もあるかもしれません。これらの機能をうまく組み合わせて、ユーザーが本当に求めている価値を提供できるアプリを開発していただければと思います。</p>
]]></content:encoded>
		
		<series:name><![CDATA[Web技術でアプリ開発2016]]></series:name>
	</item>
		<item>
		<title>キミはNativeScriptを知っているか？Angular2でネイティブモバイルアプリが書けるぞ！</title>
		<link>/albatrosary/20691/</link>
		<pubDate>Fri, 09 Sep 2016 02:42:17 +0000</pubDate>
		<dc:creator><![CDATA[佐川 夫美雄]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[Angular2]]></category>
		<category><![CDATA[NativeScript]]></category>

		<guid isPermaLink="false">/?p=20691</guid>
		<description><![CDATA[連載： Web技術でアプリ開発2016 (4)Web技術でアプリ開発2016特集・第4弾は、JavaScript（およびTypeScript）によるクロスプラットフォーム開発が可能ながらネイティブと同様の実行速度を得られ...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/web-based-apps-2016/" class="series-391" title="Web技術でアプリ開発2016" data-wpel-link="internal">Web技術でアプリ開発2016</a> (4)</div><p>Web技術でアプリ開発2016特集・第4弾は、JavaScript（およびTypeScript）によるクロスプラットフォーム開発が可能ながらネイティブと同様の実行速度を得られる、<a href="http://www.telerik.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Telerik</a>社の<a href="https://www.nativescript.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">NativeScript</a>を取り上げたいと思います。</p>

<p>NativeScriptは、Angular2とも組み合わせて使うことができる、現在注目のフレームワークです。本記事では、XMLによるUI定義を行う従来の開発手法だけではなく、Angular2（ただし、RC4という少し古いバージョン）と組み合わせてモバイルアプリを開発する方法まで網羅してご紹介します。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/NativeScript_logo.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/NativeScript_logo.png" alt="NativeScript_logo" width="300" height="300" class="alignnone size-full wp-image-20730" srcset="/wp-content/uploads/2016/09/NativeScript_logo.png 300w, /wp-content/uploads/2016/09/NativeScript_logo-150x150.png 150w, /wp-content/uploads/2016/09/NativeScript_logo-207x207.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<h1>NativeScriptの概要</h1>

<p><a href="https://www.nativescript.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">NativeScript 2.0</a>は、JavaScriptとCSSを使用し、ネイティブのiOSとAndroidのアプリを構築するためのフレームワークです。ネイティブで実行されるパフォーマンスとUXを提供し、その結果、ネイティブプラットフォームのレンダリングエンジンを使ってUIを構築します。WebViewsでのUIレンダリングはしていません。</p>

<p>NativeScriptには<a href="https://www.npmjs.com/package/tns-core-modules" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">tns-core-modules</a>というコアモジュールがあり、上記に述べたJavaScriptからネイティブへの変換を行っています。NativeScriptのgithubリポジトリを見ると「0.9.0」のリリースが「5 Mar 2015」なので、約1年とちょっとの歳月が経過していることになります。現時点での最新バージョンは「2.2.1」です。</p>

<p>NativeScriptでAngular2を利用する場合には、まず、Angular2のテンプレート（@Component.template）に、NativeScriptで提供しているディレクティブを記述します。そして、上記で説明したtns-core-modulesと<a href="https://www.npmjs.com/package/nativescript-angular" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">nativescript-angular</a>を利用してNativeScriptがビルドを行い、iOSやAndroidのネイティブコードを生成します。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/4bd44303086f2a767d223e68d2da08ae.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/4bd44303086f2a767d223e68d2da08ae-300x129.png" alt="nativescript-angular" width="300" height="129" class="alignnone size-medium wp-image-20694" srcset="/wp-content/uploads/2016/09/4bd44303086f2a767d223e68d2da08ae-300x129.png 300w, /wp-content/uploads/2016/09/4bd44303086f2a767d223e68d2da08ae.png 640w, /wp-content/uploads/2016/09/4bd44303086f2a767d223e68d2da08ae-207x89.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>「NativeScript with Angular2」の最初の「v0.3.0」がリリースされたのが今年8月初旬で、最新は「v0.3.1」です。</p>

<p>この記事では、macOS上での開発を前提に解説をしています。</p>

<h1>インストール</h1>

<p>インストール手順は<a href="http://docs.nativescript.org/start/quick-setup" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">quick-setup</a>にも書かれている通り、あまり複雑なところはありません。しかし、もしAndroid SDKをはじめて利用する場合には少し戸惑うと思います（私もNativeScriptのあまりやさしいとはいえないエラーメッセージにちょっと苦しみました）ので、順を追って説明します。</p>

<ul>
<li>ステップ1: Rubyのインストール</li>
<li>ステップ2: Node.jsのインストール</li>
<li>ステップ3: NativeScript CLIのインストール</li>
<li>ステップ4: iOSとAndroid開発に必要なもののインストール</li>
</ul>

<h2>ステップ1: Rubyのインストール</h2>

<p>NativeScriptをビルドするとき、Rubyを利用します。Rubyのバージョンは2.2以降が必要ですが、macOSにデフォルトでインストールされているRubyは古いため、<code>Homebrew</code>を使って最新バージョンをインストールします。最新のRubyが入っている方は読み飛ばして下さい。</p>

<h3>Homebrewのインストール</h3>

<p><a href="http://brew.sh/index_ja.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Homebrew</a>はRubyを使いインストールし、インストール後環境変数を定義します。</p>

<p></p><pre class="crayon-plain-tag">$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
$ brew update
$ echo 'export PATH=/usr/local/bin:$PATH' &gt;&gt; .bash_profile
$ source .bash_profile</pre><p></p>

<h3>rbenvとruby-buildのインストール</h3>

<p>brewを使って<a href="https://github.com/rbenv/rbenv" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">rbenv</a>と<a href="https://github.com/rbenv/ruby-build" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ruby-build</a>をインストールします。rbenvを使ってRubyのバージョン管理を行います。ruby-buildはrbenvのプラグインで、異なるバージョンのRubyをコンパイルし、インストールするためのものです。</p>

<p></p><pre class="crayon-plain-tag">$ brew install rbenv ruby-build
$ echo 'eval "$(rbenv init -)"' &gt;&gt; ~/.bash_profile
$ source ~/.bash_profile
$ rbenv --version
$ rbenv install -l
$ rbenv install 2.2.3
$ rbrnv version
$ rbenv global 2.2.3
$ ruby -v
ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin15]
$</pre><p></p>

<h2>ステップ2: Node.jsのインストール</h2>

<p><code>Node.js</code>はv4.0.0以降を利用する必要があります。<code>rbenv</code>と同様にバージョン管理システムをインストールします。<code>Node.js</code>のバージョン管理システムには<a href="https://github.com/hokaccha/nodebrew" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">nodebrew</a>, <a href="https://github.com/marcelklehr/nodist" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">nodist</a>, <a href="https://github.com/creationix/nvm" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">nvm</a>, <a href="https://github.com/coreybutler/nvm-windows" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">nvm-windows</a>などいくつかありますが、筆者は<code>nodebrew</code>を好んで利用しています。</p>

<h3>nodebrew のインストール</h3>

<p>curlを使ってインストールを行います。インストールが完了するとパスを追加するようにメッセージが表示されますので、.bash_profile に登録してください。</p>

<p></p><pre class="crayon-plain-tag">$ curl -L git.io/nodebrew | perl - setup
$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' &gt;&gt; .bash_profile
$ source .bash_profile</pre><p></p>

<h3>Node.jsのインストール</h3>

<p>続いて、Node.jsをインストールします。<code>nodebrew ls-remote</code>コマンドを使ってバージョンを確認し、<code>nodebrew install-binary</code>コマンドを使ってNode.jsのインストールを行います。利用するバージョンを動かす場合には<code>nodebrew use</code>コマンドを実行します。</p>

<p>今回、Node.jsのバージョンとしては<code>v5.12.0</code>を利用しました。</p>

<p></p><pre class="crayon-plain-tag">$ nodebrew ls-remote
$ nodebrew install-binary v5.12.0
$ nodebrew use v5.12.0
$ node -v
v5.12.0
$</pre><p></p>

<h2>ステップ3: NativeScript CLIのインストール</h2>

<p>いよいよNativeScriptのインストールです。<code>npm</code>コマンドを使って<code>nativescript</code>をグローバルインストールします。<code>nativescript</code>はスカッフォールディング（コード雛形の自動生成）を提供するモジュールで、<code>tns</code>コマンドによって実行されます。</p>

<p><code>tns</code>コマンドを実行して、インストールが正しく行われているか確認しましょう。参考までに<code>tns</code>コマンドで出力される内容は<code>tns --help</code>と同じ内容です。<code>tns</code>コマンドでは主に</p>

<ul>
<li>テンプレートからプロジェクトの生成</li>
<li>プロジェクトへの生成プラットフォーム(iOS, Android)の追加</li>
<li>JavaScriptからネイティブへのビルド</li>
<li>エミュレータの実行</li>
</ul>

<p>を行います</p>

<p></p><pre class="crayon-plain-tag">$ npm install nativescript -g
$ tns
# NativeScript
┌─────────┬─────────────────────────────────────────────────────────────────────┐
│ Usage   │ Synopsis                                                            │
│ General │ $ tns  [Command Parameters] [--command ]                            │
│ Alias   │ $ nativescript  [Command Parameters] [--command ]                   │
└─────────┴─────────────────────────────────────────────────────────────────────┘

・・・

$</pre><p></p>

<h2>ステップ4: iOSとAndroid開発に必要なもののインストール</h2>

<h3>JDKのインストール</h3>

<p>JDKはバージョンが8以降のものをインストールしてください。インストールが完了したら、<code>.bash_profile</code>に設定を登録してください。</p>

<p></p><pre class="crayon-plain-tag">$ echo 'export JAVA_HOME=$(/usr/libexec/java_home)' &gt;&gt; .bash_profile
$ source .bash_profile</pre><p></p>

<h3>Android開発環境のインストール</h3>

<p>Android SDKをHomebrewからインストールし、変数<code>ANDROID_HOME</code>を定義します.</p>

<p></p><pre class="crayon-plain-tag">$ brew install android-sdk
$ echo 'export ANDROID_HOME=/usr/local/Cellar/android-sdk/24.4' &gt;&gt; .bash_profile
$ echo 'export PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools' &gt;&gt; .bash_profile
$ source .bash_profile</pre><p></p>

<h4>Androidエミュレータのインストール</h4>

<p>android-sdkのインストールが終わったら、実際に利用するエミュレータを定義します。<code>android-sdk</code>がインストールされているディレクトリへ移動し、<code>andorid avd</code>を実行することで設定を行います。<code>android-sdk</code>以下のディレクトリ構成は次の通りです。</p>

<p></p><pre class="crayon-plain-tag">$ cd /usr/local/Cellar/android-sdk/24.4
$ tree -L 1
.
├── INSTALL_RECEIPT.json
├── README
├── add-ons -&gt; ../../../var/lib/android-sdk/add-ons
├── bin
├── build-tools
├── etc
├── extras -&gt; ../../../var/lib/android-sdk/extras
├── platform-tools
├── platforms -&gt; ../../../var/lib/android-sdk/platforms
├── samples -&gt; ../../../var/lib/android-sdk/samples
├── sources -&gt; ../../../var/lib/android-sdk/sources
├── system-images -&gt; ../../../var/lib/android-sdk/system-images
├── temp -&gt; ../../../var/lib/android-sdk/temp
└── tools</pre><p></p>

<p>Androidエミュレータを高速化するためのハードウェア支援環境「Intel Hardware Accelerated Execution Manager (Intel® HAXM) 」を事前にインストールします。次のスクリプトを実行してください。</p>

<p></p><pre class="crayon-plain-tag">$ cd /usr/local/Cellar/android-sdk/24.4/extras/intel/Hardware_Accelerated_Execution_Manager
$ sudo ./silent_install.sh</pre><p></p>

<p>完了したら、<code>android avd</code>を起動し、事前にエミュレータ定義を登録します。</p>

<p></p><pre class="crayon-plain-tag">$ cd /usr/local/Cellar/android-sdk/24.4/tools
$ ./android avd</pre><p></p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/08745f58e1623aad624c9c147ce67bdf.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/08745f58e1623aad624c9c147ce67bdf-300x226.png" alt="android avd" width="300" height="226" class="alignnone size-medium wp-image-20697" srcset="/wp-content/uploads/2016/09/08745f58e1623aad624c9c147ce67bdf-300x226.png 300w, /wp-content/uploads/2016/09/08745f58e1623aad624c9c147ce67bdf.png 640w, /wp-content/uploads/2016/09/08745f58e1623aad624c9c147ce67bdf-207x156.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>この設定を忘れると<a href="https://github.com/NativeScript/android-runtime/issues/533" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">「Cannot read property &#8216;targetNum&#8217; of undefined」というエラーが出ます</a>。</p>

<p>参考までに、今回利用しているエミュレータは次のように定義しています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/92e741b3229f54ad2ccec77a5d994344.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/92e741b3229f54ad2ccec77a5d994344-300x250.png" alt="スクリーンショット 2016-09-06 14.11.30" width="300" height="250" class="alignnone size-medium wp-image-20698" srcset="/wp-content/uploads/2016/09/92e741b3229f54ad2ccec77a5d994344-300x250.png 300w, /wp-content/uploads/2016/09/92e741b3229f54ad2ccec77a5d994344.png 640w, /wp-content/uploads/2016/09/92e741b3229f54ad2ccec77a5d994344-207x173.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>よくあるトラブルとしては、Dockerを起動しているようなら終了させておくのが無難です。Dockerが利用しているポートとエミュレータが利用するポートがぶつかり、実行できないことがあります。</p>

<h3>iOS開発環境のインストール</h3>

<p>macOSを利用されていれば、iOSのエミュレータを利用するのは容易だと思います。</p>

<h4>Command Line Tools for Xcode</h4>

<p></p><pre class="crayon-plain-tag">$ sudo gem install xcodeproj
$ sudo gem install cocoapods
$ brew install xcproj</pre><p></p>

<p>だいぶ長くなりましたが、これで開発環境の設定は完了です。尚、tnsコマンドには<code>tns doctor</code>というコマンドがあります。環境設定などうまくできているかのチェックができますので、一通り終わった後に実行し、漏れがないかを確認します。</p>

<p></p><pre class="crayon-plain-tag">$ tns doctor
Verifying CocoaPods. This may take more than a minute, please be patient.
  ◡ Installing iOS runtime.tns-ios@2.2.1 ../../../../../../var/folders/ts/n268b_qx2j7g3ykzkqlj3jt00000gn/T/nativescript-check-cocoapods11686-1391-akcqo6/node_modules/tns-ios
  ◝ Verifying CocoaPods. This may take some time, please be patient..
Your components are up-to-date.

No issues were detected.
$</pre><p></p>

<h1>NativeScriptで作るHello World</h1>

<p>ここではNativeScriptを使ってHello World的なアプリケーションを作成します。手順は</p>

<ol>
<li>プロジェクトの作成</li>
<li>プラットフォームのインストール</li>
<li>エミュレータの実行</li>
</ol>

<p>です。NativeScriptでのアプリケーション作成には<code>tns</code>コマンドを使います。</p>

<p>今、プロジェクトを<code>MyFirstNativeScriptApp</code>としますので、iOSとAndroidアプリケションの両方を作成する場合にはiOSとAndroidのプラットフォーム用ライブラリをインストールしエミュレートを起動します。</p>

<p></p><pre class="crayon-plain-tag">$ cd ~
$ tns create MyFirstNativeScriptApp
$ cd MyFirstNativeScriptApp
$ tns platform add android
$ tns platform add ios
$ tns run android --emulator
$ tns run ios --emulator</pre><p></p>

<p>Androidエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/MyFirstNativeScriptApp-Android.gif" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/MyFirstNativeScriptApp-Android.gif" alt="MyFirstNativeScriptApp-Android" width="200" height="300" class="alignnone size-medium wp-image-20720" /></a></p>

<p>iOSエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/MyFirstNativeScriptApp-iOS.gif" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/MyFirstNativeScriptApp-iOS.gif" alt="MyFirstNativeScriptApp-iOS" width="200" height="300" class="alignnone size-medium wp-image-20721" /></a></p>

<p><code>tns create MyFirstNativeScriptApp</code>で作成されたファイルを確認します。</p>

<p></p><pre class="crayon-plain-tag">$ tree -L 2
.
├── app
│   ├── App_Resources
│   ├── app.css
│   ├── app.js
│   ├── main-page.js
│   ├── main-page.xml
│   ├── main-view-model.js
│   ├── package.json
│   └── references.d.ts
├── node_modules
│   ├── babel-traverse
│   ├── babel-types
│   ├── babylon
│   ├── lazy
│   ├── tns-core-modules
│   └── tns-core-modules-widgets
├── package.json
└── platforms
    ├── android
    └── ios</pre><p></p>

<p>このアプリケーションで特に重要なファイルがありますので、簡単に説明します。</p>

<ul>
<li>app.js</li>
<li>main-page.xml</li>
<li>main-page.js</li>
<li>main-view-model.js</li>
</ul>

<p><code>app.js</code>はアプリケーションが一番最初にロードするエントリーポイントで、このファイルからアプリケーション<code>main-page.js</code>の呼び出しを行っています。</p>

<p></p><pre class="crayon-plain-tag">// app.js
var application = require("application");
application.start({ moduleName: "main-page" });</pre><p></p>

<p></p><pre class="crayon-plain-tag">// main-page.js
var createViewModel = require("./main-view-model").createViewModel;

function onNavigatingTo(args) {
  var page = args.object;
  page.bindingContext = createViewModel();
}
exports.onNavigatingTo = onNavigatingTo;</pre><p></p>

<p><code>main-page.xml</code>は画面をXMLで定義し、関連する処理を<code>main-view-model.js</code>に定義してます。</p>

<p></p><pre class="crayon-plain-tag">&lt;!-- main-page.xml --&gt;
&lt;Page xmlns="http://schemas.nativescript.org/tns.xsd" navigatingTo="onNavigatingTo"&gt;
  &lt;StackLayout&gt;
    &lt;Label text="Tap the button" class="title"/&gt;
    &lt;Button text="TAP" tap="{{ onTap }}" /&gt;
    &lt;Label text="{{ message }}" class="message" textWrap="true"/&gt;
  &lt;/StackLayout&gt;
&lt;/Page&gt;</pre><p></p>

<p></p><pre class="crayon-plain-tag">// main-view-model.js
var Observable = require(&quot;data/observable&quot;).Observable;

function getMessage(counter) {
  if (counter &lt;= 0) {
    return &quot;Hoorraaay! You unlocked the NativeScript clicker achievement!&quot;;
  } else {
    return counter + &quot; taps left&quot;;
  }
}

function createViewModel() {
  var viewModel = new Observable();
  viewModel.counter = 42;
  viewModel.message = getMessage(viewModel.counter);

  viewModel.onTap = function() {
    this.counter--;
    this.set(&quot;message&quot;, getMessage(this.counter));
  }

  return viewModel;
}

exports.createViewModel = createViewModel;</pre><p></p>

<h2>テンプレートを使って簡単なアプリケーションを作成する</h2>

<p>NativeScriptには、テンプレートを使ってプロジェクトを生成する機能があります。</p>

<p></p><pre class="crayon-plain-tag">$ tns create [Project Name] --template [Template Name]</pre><p></p>

<p>繰り返しになりますが、テンプレートを作成した後「プラットフォームのインストール」「エミュレータの実行」を行うとエミュレートで実行確認ができます。</p>

<p>このテンプレートはnpmに登録されています。が、まだあまり多くのテンプレートは定義されていないようです。その中から開発時に利用できそうなものを幾つかピックアップしました。具体的なコードは各テンプレートを使ってコードを生成し確認していただけると幸いです。</p>

<h3>タブを使ったアプリケーション</h3>

<p></p><pre class="crayon-plain-tag">$ tns create MyNextGreatApp --template tns-template-tab-navigation</pre><p></p>

<p>タブ切り替えのテンプレート部分は<code>TabView</code>タグを使い、各タブで表示する内容は<code>TabViewItem</code>で定義しています。</p>

<p></p><pre class="crayon-plain-tag">&lt;!-- main-page.xml --&gt;
&lt;Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded"&gt;
  &lt;TabView&gt;
    &lt;TabView.items&gt;
      &lt;TabViewItem title="First"&gt;
        &lt;TabViewItem.view&gt;
          &lt;StackLayout class="tab-content"&gt;
            &lt;Label text="First View" class="title"/&gt;
            &lt;Label text="This is the content of the first tab." textWrap="true"/&gt;
          &lt;/StackLayout&gt;
        &lt;/TabViewItem.view&gt;
      &lt;/TabViewItem&gt;
      &lt;TabViewItem title="Second"&gt;
        &lt;TabViewItem.view&gt;
          &lt;StackLayout class="tab-content"&gt;
            &lt;Label text="Second View" class="title"/&gt;
            &lt;Label text="This is the content of the second tab." textWrap="true"/&gt;
          &lt;/StackLayout&gt;
        &lt;/TabViewItem.view&gt;
      &lt;/TabViewItem&gt;
    &lt;/TabView.items&gt;
  &lt;/TabView&gt;
&lt;/Page&gt;</pre><p></p>

<p>Androidエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/MyNextGreatApp-Android.gif" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/MyNextGreatApp-Android.gif" alt="MyNextGreatApp-Android" width="200" height="300" class="alignnone size-medium wp-image-20722" /></a></p>

<p>iOSエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/MyNextGreatApp-iOS.gif" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/MyNextGreatApp-iOS.gif" alt="MyNextGreatApp-iOS" width="200" height="300" class="alignnone size-medium wp-image-20723" /></a></p>

<h3>一覧と詳細を表示するアプリケーション</h3>

<p></p><pre class="crayon-plain-tag">$ tns create MyMasterDetailApp --template tns-template-master-detail</pre><p></p>

<p>一覧と明細は<code>GridLayout</code>を使って表示する場所を定義し、一覧部分を表示するテンプレートは<code>ListView</code>を使っています。</p>

<p></p><pre class="crayon-plain-tag">&lt;!-- main-page.xml --&gt;
&lt;Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="pageLoaded"&gt;
  &lt;GridLayout rows="auto, *"&gt;
    &lt;Label text="Items Page" class="title" /&gt;

    &lt;ListView items="{{ items }}" itemTap="listViewItemTap" row="1"&gt;
      &lt;ListView.itemTemplate&gt;
        &lt;Label text="{{ title }}" class="listItem" /&gt;
      &lt;/ListView.itemTemplate&gt;
    &lt;/ListView&gt;
  &lt;/GridLayout&gt;
&lt;/Page&gt;</pre><p></p>

<p>明細部分は<code>details-page.xml</code>でレイアウトを定義していて、具体的な内容の表示には<code>details-view.xml</code>を使っています。</p>

<p></p><pre class="crayon-plain-tag">&lt;!-- details-page.xml --&gt;
&lt;Page xmlns="http://schemas.nativescript.org/tns.xsd"
      xmlns:app="."
      navigatedTo="pageNavigatedTo"&gt;
  &lt;app:details-view /&gt;
&lt;/Page&gt;</pre><p></p>

<p></p><pre class="crayon-plain-tag">&lt;!-- details-view.xml --&gt;
&lt;StackLayout  xmlns="http://schemas.nativescript.org/tns.xsd"&gt;
  &lt;Label text="{{ title }}" class="detail-title"/&gt;
  &lt;Label text="{{ info }}" class="info" textWrap="true"/&gt;
&lt;/StackLayout&gt;</pre><p></p>

<p>Androidエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/MyMasterDetailApp-Android.gif" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/MyMasterDetailApp-Android.gif" alt="MyMasterDetailApp-Android" width="200" height="300" class="alignnone size-medium wp-image-20716" /></a></p>

<p>iOSエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/MyMasterDetailApp-iOS.gif" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/MyMasterDetailApp-iOS.gif" alt="MyMasterDetailApp-iOS" width="200" height="300" class="alignnone size-medium wp-image-20717" /></a></p>

<h3>サイドメニュー付きアプリケーション</h3>

<p></p><pre class="crayon-plain-tag">$ tns create MyDrawerApp --template nativescript-template-drawer</pre><p></p>

<p>サイドメニュー付きアプリケーションを作成する場合には、サイドメニュー<code>drawer-content.xml</code>を定義し、メニューをクリックしたときの画面をそれぞれ定義しています。</p>

<p></p><pre class="crayon-plain-tag">&lt;!-- drawer-content.xml --&gt;
&lt;grid-layout class="drawer-content"&gt;
  &lt;stack-layout&gt;
    &lt;label text="Home" tap="navigate" class="{{ selectedPage == 'home' ? 'selected' : '' }}" /&gt;
    &lt;label text="About" tap="navigate" class="{{ selectedPage == 'about' ? 'selected' : '' }}" /&gt;
    &lt;label text="Settings" tap="navigate" class="{{ selectedPage == 'settings' ? 'selected' : '' }}" /&gt;
  &lt;/stack-layout&gt;
&lt;/grid-layout&gt;</pre><p></p>

<p>Androidエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/MyDrawerApp-Android.gif" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/MyDrawerApp-Android.gif" alt="MyDrawerApp-Android" width="200" height="300" class="alignnone size-medium wp-image-20724" /></a></p>

<p>iOSエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/MyDrawerApp-iOS.gif" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/MyDrawerApp-iOS.gif" alt="MyDrawerApp-iOS" width="200" height="300" class="alignnone size-medium wp-image-20725" /></a></p>

<h1>NativeScriptとAngular2を組み合わせる</h1>

<p>ここからが本記事の一番のポイント、「Angular2を使ったNativeScriptアプリケーション」に入ります。準備が長くて申し訳ありません！</p>

<p><a href="https://www.npmjs.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">npm</a>にはいくつかのAngular2を利用したNativeScriptのテンプレートがありますが、今回は<a href="http://docs.nativescript.org/angular/tutorial/ng-chapter-1#11-install-nativescript-and-configure-your-environment" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">NativeScriptのチュートリアル</a>を参考に、githubリポジトリーからテンプレートをcloneしたものを利用します。</p>

<h2>NativeScript with Angular2で作るHello World</h2>

<p>まずはリポジトリ<code>https://github.com/NativeScript/sample-Groceries</code>をcloneします。clone後、<code>angular-start</code>をcheckoutすると、NativeScript with Angular2で開発するための最も基本的な構成を得ることができます。</p>

<p></p><pre class="crayon-plain-tag">$ git clone https://github.com/NativeScript/sample-Groceries.git
$ cd sample-Groceries
$ git checkout angular-start
$ tree -L 2
├── app
│   ├── App_Resources
│   ├── app.component.ts
│   ├── app.css
│   ├── app.routes.ts
│   ├── main.ts
│   ├── package.json
│   ├── pages
│   ├── platform.android.css
│   ├── platform.ios.css
│   ├── shared
│   └── utils
├── package.json
├── platforms
│   └── ios
├── references.d.ts
└── tsconfig.json
$ tns platform add ios
$ tns platform add android
$ tns run ios --emulator
$ tns run android --emulator</pre><p></p>

<p>Androidエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/bd526adedcc1d8bc115334228f13f924.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/bd526adedcc1d8bc115334228f13f924-186x300.png" alt="HelloWorld-Android" width="186" height="300" class="alignnone size-medium wp-image-20732" srcset="/wp-content/uploads/2016/09/bd526adedcc1d8bc115334228f13f924-186x300.png 186w, /wp-content/uploads/2016/09/bd526adedcc1d8bc115334228f13f924.png 397w, /wp-content/uploads/2016/09/bd526adedcc1d8bc115334228f13f924-128x207.png 128w" sizes="(max-width: 186px) 100vw, 186px" /></a></p>

<p>iOSエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/9c8a45b0a1b5bb63648952bde5c36faa.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/9c8a45b0a1b5bb63648952bde5c36faa-200x300.png" alt="Helloworld-iOS" width="200" height="300" class="alignnone size-medium wp-image-20733" srcset="/wp-content/uploads/2016/09/9c8a45b0a1b5bb63648952bde5c36faa-200x300.png 200w, /wp-content/uploads/2016/09/9c8a45b0a1b5bb63648952bde5c36faa.png 427w, /wp-content/uploads/2016/09/9c8a45b0a1b5bb63648952bde5c36faa-138x207.png 138w" sizes="(max-width: 200px) 100vw, 200px" /></a></p>

<p>NativeScriptではBootstrapに特別なメソッド<code>nativeScriptBootstrap</code>を利用します。具体的にエントリーポイント<code>main.ts</code>は次のように記述されます。</p>

<p></p><pre class="crayon-plain-tag">// main.ts
import {nativeScriptBootstrap} from "nativescript-angular/application";
import {AppComponent} from "./app.component";

nativeScriptBootstrap(AppComponent);</pre><p></p>

<p>Angular2では、NativeScriptのXMLを<code>@Component.template</code>にディレクティブとして定義します。ただ<code>@Component.template</code>ではXMLをそのまま利用できないので、少し書き換える必要があります。具体的には&lt;foo /&gt;を&lt;foo&gt;&lt;/foo&gt;に書き換えるといった作業です。</p>

<p>具体的にこのサンプルの場合、XML定義では</p>

<p></p><pre class="crayon-plain-tag">&lt;Label text='hello world' /&gt;</pre><p></p>

<p>ですが、Angular2ではコンポーネントとして定義します。</p>

<p></p><pre class="crayon-plain-tag">// app.component.ts
import {Component} from "@angular/core";

@Component({
  selector: "my-app",
  template: "&lt;Label text='hello world'&gt;&lt;/Label&gt;"
})
export class AppComponent {}</pre><p></p>

<p><code>Label</code>はHTMLタグではなくNativeScriptで定義されたディレクティブです。NativeScriptでは幾つかのUIコンポーネントを定義していますので一覧にまとめます。</p>

<h2>UIコンポーネントのマッピング</h2>

<p>NativeScriptのUIコンポーネントは、iOSやAndroidのウィジェットにマッピングさせています。ビルドするとNativeScript with Angular2で定義したコンポーネントがマッピングされたiOSやAndroidのウィジェット変換されます。具体的な利用方法に関しては、<a href="http://docs.nativescript.org/angular/ui/components" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Native Script UI Components</a>を見ていただきたいと思います。</p>

<table>
<thead>
<tr>
  <th>NativeScript with Angular2</th>
  <th>Android</th>
  <th>iOS</th>
</tr>
</thead>
<tbody>
<tr>
  <td>Button</td>
  <td>android.widget.Button</td>
  <td>UIButton</td>
</tr>
<tr>
  <td>Label</td>
  <td>android.widget.TextView</td>
  <td>UILabel</td>
</tr>
<tr>
  <td>TextField</td>
  <td>android.widget.EditText</td>
  <td>UITextField</td>
</tr>
<tr>
  <td>TextView</td>
  <td>android.widget.EditText</td>
  <td>UITextView</td>
</tr>
<tr>
  <td>SearchBar</td>
  <td>android.widget.SearchView</td>
  <td>UISearchBar</td>
</tr>
<tr>
  <td>Switch</td>
  <td>android.widget.Switch</td>
  <td>UISwitch</td>
</tr>
<tr>
  <td>Slider</td>
  <td>android.widget.SeekBar</td>
  <td>UISlider</td>
</tr>
<tr>
  <td>Progress</td>
  <td>android.widget.ProgressBar</td>
  <td>UIProgressView</td>
</tr>
<tr>
  <td>ActivityIndicator</td>
  <td>android.widget.ProgressBar</td>
  <td>UIActivityIndicatorView</td>
</tr>
<tr>
  <td>Image</td>
  <td>android.widget.ImageView</td>
  <td>UIImageView</td>
</tr>
<tr>
  <td>ListView</td>
  <td>android.widget.ListView</td>
  <td>UITableView</td>
</tr>
<tr>
  <td>HtmlView</td>
  <td>android.widget.TextView</td>
  <td>UILabel</td>
</tr>
<tr>
  <td>WebView</td>
  <td>android.webkit.WebView</td>
  <td>UIWebView</td>
</tr>
<tr>
  <td>TabView</td>
  <td>android.support.v4.view.ViewPager</td>
  <td>UITabBarController</td>
</tr>
<tr>
  <td>SegmentedBar</td>
  <td>android.widget.TabHost</td>
  <td>UISegmentedControl</td>
</tr>
<tr>
  <td>DatePicker</td>
  <td>android.widget.DatePicker</td>
  <td>UIDatePicker</td>
</tr>
<tr>
  <td>TimePicker</td>
  <td>android.widget.TimePicker</td>
  <td>UIDatePicker</td>
</tr>
<tr>
  <td>ListPicker</td>
  <td>android.widget.NumberPicker</td>
  <td>UIPickerView</td>
</tr>
</tbody>
</table>

<h2>NativeScript + Angular2でHello World</h2>

<p>はじめに作成した「NativeScriptで作るHello World」のAngular2版のテンプレートがあります。アプリケーションの動きはまったく同じですがAngular2で書かれています。</p>

<p></p><pre class="crayon-plain-tag">$ tns create MyNgNativeScriptApp --template tns-template-hello-world-ng 
$ cd MyNgNativeScriptApp
$ tns platform add android
$ tns platform add ios
$ tns run android --emulator
$ tns run ios --emulator</pre><p></p>

<p>テンプレート部分を見比べると、XMLで書かれていたテンプレートコードがAngular2スタイルで記載されていることが理解でき、結果見通しのよいコードになっています。</p>

<p></p><pre class="crayon-plain-tag">&lt;!-- app.component.html --&gt;
&lt;StackLayout&gt;
  &lt;Label text="Tap the button" class="title"&gt;&lt;/Label&gt;
  &lt;Button text="TAP" (tap)="onTap()"&gt;&lt;/Button&gt;
  &lt;Label [text]="message" class="message" textWrap="true"&gt;&lt;/Label&gt;
&lt;/StackLayout&gt;</pre><p></p>

<p></p><pre class="crayon-plain-tag">// app.component.ts
import {Component} from "@angular/core";

@Component({
  selector: "my-app",
  templateUrl: "app.component.html",
})
export class AppComponent {
  public counter: number = 16;

  public get message(): string {
    if (this.counter &gt; 0) {
      return this.counter + " taps left";
    } else {
      return "Hoorraaay! \nYou are ready to start building!";
    }
  }
    
  public onTap() {
    this.counter--;
  }
}</pre><p></p>

<h2>Todosアプリケーション</h2>

<p>NativeScriptのサイトには、より多く機能が実装されたチュートリアル<a href="http://docs.nativescript.org/angular/tutorial/ng-chapter-0" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Building Apps with NativeScript and Angular 2</a>を提供しています。完成したアプリケーションは先ほどと同じリポジトリ<code>https://github.com/NativeScript/sample-Groceries</code>にありますので、是非見て下さい。</p>

<p></p><pre class="crayon-plain-tag">$ git clone https://github.com/NativeScript/sample-Groceries.git NgTodosNative
$ cd NgTodosNative
$ tns platform add ios
$ tns platform add android
$ tns run ios --emulator
$ tns run android --emulator</pre><p></p>

<p>Androidエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/sample-Groceries-Android.gif" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/sample-Groceries-Android.gif" alt="sample-Groceries-Android" width="200" height="300" class="alignnone size-medium wp-image-20727" /></a></p>

<p>iOSエミュレータでの実行結果</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/09/sample-Groceries-iOS.gif" data-wpel-link="internal"><img src="/wp-content/uploads/2016/09/sample-Groceries-iOS.gif" alt="sample-Groceries-iOS" width="200" height="300" class="alignnone size-medium wp-image-20728" /></a></p>

<p>サンプルコードを読むと、NativeScriptで利用するnativeScriptBootstrapの使い方やNativeScript用のルーティング設定が記載されていたりとAngular2の特徴を活かした実装になっています。</p>

<p>今回は、環境設定からはじまり、NativeScriptを使ったもの、NativeScript wit Angular2へと進め、Hello World的なアプリケーションを動かすところまでをテンプレートを使いながら簡単に説明させていただきました。</p>

<h1>最後に</h1>

<p>NativeScriptの事例がないかと探してみましたが<a href="https://www.nativescript.org/showcases" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">NativeScript Showcases</a>にいくつかありました。このアプリケーションがAngular2をベースにしたものかはわかりませんが、NativeScriptを使ったものです。</p>

<p>NativeScriptのXMLで定義したUIコンポーネントが、コンパイル時にiOS、Androidのウィジェットにそれぞれマッピングされネイティブアプリにコンパイルされます（ちょっと古いですがXSLTを思い出しました）。Angular2の@Component.templateを利用することでNativeScriptがUIコンポーネントの定義を解釈し、ネイティブコードの生成を行っています。</p>

<p>ただし、NativeScript with Angular2用に作成したコンポーネントとNativeScriptを使わない通常のAngular2のコンポーネントとの相互再利用性は低いです。ですが、慣れたAngular2の構造を利用しTypeScript(もしくはJavaScript)で書けるというのは非常に興味が湧くところです。</p>

<p><strong>編集部よりお詫び</strong><br />
<small><strong>
2016/9/9 18:30 編集部が付けた以前のタイトルは、一部の方を不快にさせる可能性があるとの判断のもと、記事タイトルを変更いたしました。
執筆者の佐川さん、及び以前のタイトルを不快に感じた多くの方々に、深くお詫び申し上げます。
</strong></small></p>
]]></content:encoded>
		
		<series:name><![CDATA[Web技術でアプリ開発2016]]></series:name>
	</item>
		<item>
		<title>PCからIoTまで! Web技術を使ったユニバーサルWindowsプラットフォーム (UWP) アプリの開発</title>
		<link>/osamum_ms/20545/</link>
		<pubDate>Thu, 08 Sep 2016 01:00:45 +0000</pubDate>
		<dc:creator><![CDATA[物江 修]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<category><![CDATA[Windows 10]]></category>
		<category><![CDATA[Windows Store]]></category>
		<category><![CDATA[uwp]]></category>
		<category><![CDATA[ハイブリッド]]></category>

		<guid isPermaLink="false">/?p=20545</guid>
		<description><![CDATA[連載： Web技術でアプリ開発2016 (3)「Web技術でアプリ開発2016」ということで、この記事ではPCからIoT機器まで、Windows 10プラットフォームであればデバイスを問わず動作する ユニバーサルWind...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/web-based-apps-2016/" class="series-391" title="Web技術でアプリ開発2016" data-wpel-link="internal">Web技術でアプリ開発2016</a> (3)</div><p>「Web技術でアプリ開発2016」ということで、この記事ではPCからIoT機器まで、Windows 10プラットフォームであればデバイスを問わず動作する ユニバーサルWindowsプラットフォーム (以下、UWPと記述) 上で動作するアプリについて紹介します。</p>

<p>このアプリはもちろんHTML、CSS + JavaScriptといったWeb開発者が慣れ親しんだ技術で開発することができます。また、インターネットでホストされているWebページをラップしてアプリ化することができます。</p>

<p>UWPをターゲットとしたアプリ開発では、新規開発はもちろん、既存のWeb資産を利用してアプリを開発し、さまざまな Windows 10デバイスに横断的に機能を提供することができます。</p>

<p>この記事では、UWPがどのようものであるか、UWP上で動作するアプリの開発方法と公開方法について紹介します。</p>

<h1>ユニバーサルWindowsプラットフォーム (UWP)アプリ とは</h1>

<p>Windows 10では、<a title="最新のWindows PC、ノートPC、タブレットのご紹介 | Microsoft Windows 10" href="https://www.microsoft.com/ja-jp/windows/view-all" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>PC</strong></a>、<a title="Windows 10 Mobileにアップグレードする方法 - マイクロソフト" href="https://www.microsoft.com/ja-jp/windows/windows-10-mobile-upgrade" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>モバイル</strong></a>、<a title="Xbox | Official Site" href="http://www.xbox.com/ja-JP/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>XBOX</strong></a>、<a title="Microsoft Surface Hub | コラボレーション デバイス" href="https://www.microsoft.com/microsoft-surface-hub/ja-jp" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>Surface Hub</strong></a>、<a title="Microsoft HoloLens | Official Site" href="https://www.microsoft.com/microsoft-surface-hub/ja-jp" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>HoloLens</strong></a>、<a title="Raspberry Pi 3とArduinoでのWindows 10 IoTアプリの開発 - Windows IoT" href="https://developer.microsoft.com/ja-jp/windows/iot" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>IoT</strong></a> 機器といったデバイスファミリーで共通のカーネルを採用しており、これによりアプリケーションのプラットフォームが統合されました。</p>

<div style="width: 400px;margin: 0px auto">
  <a href="https://html5experts.jp/wp-content/uploads/2016/08/image7.png" data-wpel-link="internal"><img title="image" style="border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px" border="0" alt="image" src="/wp-content/uploads/2016/08/image_thumb7.png"
      width="450" height="174"></a>
</div>

<p><br /></p>

<p>このWindows 10デバイスファミリーで統合されたプラットフォームをユニバーサルWindowsプラットフォーム (Universal Windows Platform : UWP)と呼びます。</p>

<div style="width: 500px;margin: 0px auto">
  <br>
  <a href="https://html5experts.jp/wp-content/uploads/2016/08/image8.png" data-wpel-link="internal"><img title="image" style="border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;border-top-width: 0px;margin-right: auto" border="0" alt="image" src="/wp-content/uploads/2016/08/image_thumb8.png"
      width="500" height="273">
    <br>
  </a>
  <br>
</div>

<p>UWP用のアプリは、OSのバージョンではなくデバイスファミリーを対象としますが、UWPのコアAPIはすべてのWindowsデバイス ファミリーに共通であり、アプリにコアAPIのみを使う場合は、そのアプリはいずれのWindows 10デバイスでも動作します。</p>

<p>つまり、固有のデバイスに縛られることなく、目的のデバイスファミリーをターゲットして再コンパイルすることでPCから IOT基板まで、さまざまな機器に配置し、動作させることができるのです。</p>

<p>Webの開発者からみればハードルが高そうなIoT機器用のアプリもHTML、CSS + JavaScriptで開発することができます。</p>

<p>たとえば、以下の記事では、Raspberry Piとディスプレイをマジックミラーの裏に配置し、洗面台の鏡の中に情報を表示するアプリを紹介していますが、この上表を表示するアプリはHTML、CSS + JavaScriptを使用したUWPアプリです。</p>

<ul>
  <li><a href="https://blogs.windows.com/msedgedev/2016/05/31/magic-mirror-hosted-web-app/#ZA4Bz3egXpR7RBJS.99" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>Building an IoT Magic Mirror with Hosted Web Apps and Windows 10</strong></a> </li>
</ul>

<p>また逆に、拡張機能SDKにより特殊なデバイス用のアプリも開発することもできます。</p>

<h1>UWPアプリのメリット</h1>

<p>UWPアプリのメリットは、前述したようにデバイスファミリーを横断したアプリの開発が容易であるということもありますが、それ以外でも、複数の言語で開発することができることや、UWPが公開する豊富なAPIを直接使用できるということがあるでしょう。</p>

<p>UWPアプリのロジック部分はC#、Visual Basic、C、C++、JavaScriptといった開発言語で記述することができ、UI部分は XAML (C#、VB、C、C++)、DirectX (C、C++)と、HTML/CSS (JavaScript)で記述することができます。</p>

<div style="width: 600px;margin: 0px auto">
  <a href="https://html5experts.jp/wp-content/uploads/2016/09/image1.png" data-wpel-link="internal"><img title="image" style="border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px" border="0" alt="image" src="/wp-content/uploads/2016/09/image_thumb1.png"
      width="600" height="338"></a>
</div>

<p><br /></p>

<p>UWPのリソースにアクセスするためのWindowsランタイム(WinRT) APIには、各言語ともWindows名前空間を空間を介して接続することができます。</p>

<p>WinRT APIは Windows 10の予定表や連絡先、タイルといったOSが持つソフト的なリソースからBluetoothやWi-Fi、USBといったハード的リソースへのアクセスなど、幅広く機能を提供します。そしてこれらのAPIはUWPでサポートされている言語であれば、言語を問わず利用することができます。</p>

<p>Windowsランタイムがアプリ向けに公開しているAPIのついての詳細は以下のドキュメントをご参照ください。</p>

<ul>
  <li><a title="WindowsランタイムアプリのWindows APIリファレンス - Windows app development" href="https://msdn.microsoft.com/ja-jp/library/windows/apps/br211377.aspx" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>Windows ランタイム アプリのWindows APIリファレンス</strong></a> </li>
</ul>

<h1>開発環境</h1>

<p>UWPアプリの開発はWindows 10と<a title="Visual Studio - Microsoft Developer Tools" href="https://www.visualstudio.com/ja-jp/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Visual Studio 2015</a>もしくは、<a title="Apache Cordova" href="https://cordova.apache.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Apache Cordova</a>を使用して行うことができます。</p>

<h2>Visual Studio 2015とApache Cordovaの使い分け</h2>

<p>Visual Studio 2015では、それ単体によるUWPアプリの開発はもちろん、<a title="Visual Studio Tools for Apache Cordova" href="https://www.visualstudio.com/ja-jp/features/cordova-vs.aspx" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>Visual Studio Tools for Apache Cordova</strong></a> を使用してiOS、Android、UWPアプリの開発が行えます。</p>

<p>つまり、Visual Studio 2015ではそれ単体とApache Cordovaのどちらかを使用してUWPアプリを開発することができますが、これは単に機能が重複しているということではなく、以下のように状況や目的に合わせて使い分けるためにあります。</p>

<div style="width: 600px;margin: 0px auto">
  <table cellspacing="0" cellpadding="2" width="600" border="1">
    <tbody>
      <tr>
        <td style="text-align: center;background-color: lightskyblue" valign="middle" width="200">開発環境</td>
        <td style="text-align: center;background-color: lightskyblue" valign="middle">用途</td>
      </tr>
      <tr>
        <td valign="middle" width="200">Visual Studio 単体</td>
        <td valign="middle">特殊デバイス向けの開発など、UWP固有の機能を使用した実装を行う場合</td>
      </tr>
      <tr>
        <td valign="middle" width="200">Apache Cordova</td>
        <td valign="middle">共通のソースで、UWP以外のiOSやAndroidにもアプリを提供する場合</td>
      </tr>
    </tbody>
  </table>
</div>

<p>なお、Visual Studio 2015は有償製品ですが、非営利目的やオープンソースソフトウェアの開発であれば、無償の<strong> </strong><a title="Visual Studio Community - Visual Studio" href="https://www.microsoft.com/ja-jp/dev/products/community.aspx" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>Visual Studio Community</strong></a><strong>　</strong>を使用することができます。</p>

<p>Visual Studio Communityは、機能的にはVisual Studio Professionalと同等であり、クロスプラットフォーム開発をサポートしています。</p>

<h1>開発できるアプリの形式</h1>

<p>HTML、CSS + JavaScriptで開発できるUWPアプリの形式は、大まかにUI部分をクライアントサイドにインストールするパッケージ型と、ネットワークにホストされているコンテンツをラップしたホスト型の2つのタイプに大別されます。</p>

<div style="width: 500px;margin: 0px auto">
  <table cellspacing="0" cellpadding="2" width="500" border="1">
    <tbody>
      <tr>
        <td style="text-align: center;background-color: lightskyblue" valign="middle" width="150">アプリの型式</td>
        <td style="text-align: center;background-color: lightskyblue" valign="middle">状態</td>
      </tr>
      <tr>
        <td valign="middle" width="150">パッケージ型</td>
        <td valign="middle">UI部分をクライアントサイドにインストールするもの
          <br>一部 WebViewコントロールで覆ったものもプロジェクトテンプレート上はこれにあたる</td>
      </tr>
      <tr>
        <td valign="middle" width="150">ホスト型</td>
        <td valign="middle">ネットワークにホストされている
          <br>Webコンテンツをラップしたもの</td>
      </tr>
    </tbody>
  </table>
</div>

<p>一部をWebViewコントロールで覆ったものもVisual Studioのプロジェクトテンプレート上はパッケージ型に含まれます。</p>

<div style="width: 500px;margin: 0px auto">
  <a href="https://html5experts.jp/wp-content/uploads/2016/08/image9.png" data-wpel-link="internal"><img title="image" style="border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px" border="0" alt="image" src="/wp-content/uploads/2016/08/image_thumb9.png"
      width="500" height="331"></a>
</div>

<p>パッケージ型、ホスト型アプリにはそれぞれ特徴とメリットがあります。</p>

<p>パッケージ型アプリは、動作に必要なリソースをクライアントサイドにインストールできるので、アプリの作りによっては、動作にサーバーサイドのリソースを必要としない完全にオフラインのアプリを作ることも可能です。</p>

<p>ホスト型のアプリの場合は、ネットワーク上に公開されているコンテンツを表示しているので、画面や機能を変更する際でも再インストールの必要はなく、常に最新の情報を提供することができます。また、Webサイト向けのコンテンツの開発と作業が一元化できます。
  <br>ホスト型のアプリはその性質上オンラインでの使用が大前提となりますが <a href="https://developers.google.com/web/progressive-web-apps/" target="_brank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>Progressive Web Apps</strong> </a>の実装が可能になればこういった制限も大幅に緩和され、パッケージ型よりもホスト型が選択されるケースが増えることでしょう。</p>

<div style="width: 300px;margin: 0px auto">
  <a href="https://html5experts.jp/wp-content/uploads/2016/08/image10.png" data-wpel-link="internal"><img title="image" style="border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px" border="0" alt="image" src="/wp-content/uploads/2016/08/image_thumb10.png"
      width="400" height="302"></a>
</div>

<p><br />&nbsp;</p>

<p>パッケージ型のアプリはもちろん、ホスト型のアプリも、適切なセキュリティ設定を行うことにより、Windowsランタイム API にアクセスできます。</p>

<p>たとえば、以下の記事では、Webサイトに公開されているページに記述されているJavaScirptからNFCデバイスにアクセスする方法について紹介しています。</p>

<ul>
  <li><a title="UWPのHosted WebアプリからのNFCデバイスへのアクセス" href="https://blogs.msdn.microsoft.com/osamum/2016/06/02/uwp-%e3%81%ae-hosted-web-%e3%82%a2%e3%83%97%e3%83%aa%e3%81%8b%e3%82%89%e3%81%ae-nfc-デバイス%e3%81%b8%e3%81%ae%e3%82%a2%e3%82%af%e3%82%bb%e3%82%b9/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>UWPのHosted WebアプリからのNFCデバイスへのアクセス</strong></a></li>
</ul>

<h1>開発方法</h1>

<p>Visual Studio 2015に用意されたプロジェクトテンプレートを使用してプロジェクトを作成し、コーディングしていきます。</p>

<p>HTML、CSS + JavaScriptで開発するUWPアプリに用意されているプロジェクトテンプレートの種類は以下のとおりです。(2016年9月現在)</p>

<div style="width: 600px;margin: 0px auto">
  <table cellspacing="0" cellpadding="2" width="600" border="1">
    <tbody>
      <tr>
        <td style="text-align: center;background-color: lightskyblue" valign="middle" width="230">プロジェクトテンプレートの種類</td>
        <td style="text-align: center;background-color: lightskyblue" valign="middle">説明</td>
      </tr>
      <tr>
        <td valign="middle" width="230">空白のアプリ</td>
        <td valign="middle">事前定義されたコントロールやレイアウトのないユニバーサルWindowsアプリのためのプロジェクト。コンテンツセキュリティポリシー(CSP)を適用します。すべてのユニバーサルWindows APIに直接アクセスします。</td>
      </tr>
      <tr>
        <td valign="middle" width="230">WinJSアプリ</td>
        <td valign="middle">WinJS を使用しているユニバーサルWindowsアプリのプロジェクトです。すべてのユニバーサルWindows APIに直接アクセスできます。</td>
      </tr>
      <tr>
        <td valign="middle" width="230">ホストされるWebアプリ</td>
        <td valign="middle">リモートの開始ページを含むユニバーサルWindowsアプリのプロジェクトです。すべてのユニバーサル Windows APIにアクセスするには、URLをアプリケーション コンテンツURI規則に追加する必要があります。</td>
      </tr>
      <tr>
        <td valign="middle" width="230">空のアプリ-Webコンテキスト</td>
        <td valign="middle">ローカルコンテンツをWebからのものとして処理します。既定のアプリケーションコンテンツポリシー(CSP)はありません。ユニバーサルWindows APIにアクセスするには、URIがアプリケーション コンテンツURI規則で宣言されている必要があります。</td>
      </tr>
    </tbody>
  </table>
</div>

<p>開発を開始するための具体的な手順について、以下のチュートリアルを参照してください。</p>

<ul>
  <li><a title="Hello, worldアプリを作成する (JS)" href="https://msdn.microsoft.com/windows/uwp/get-started/create-a-hello-world-app-js-universal" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>JavaScript とHTMLのチュートリアル</strong></a>
    <li><a title="Hello, worldアプリを作成する (XAML)" href="https://msdn.microsoft.com/windows/uwp/get-started/create-a-hello-world-app-xaml-universal" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>C#とXAMLのチュートリアル</strong></a>
      <li><a title="C++ を使った&quot;hello world&quot;アプリの作成(Windows 10)" href="https://msdn.microsoft.com//windows/uwp/get-started/create-a-basic-windows-10-app-in-cpp" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>C++とXAMLのチュートリアル</strong></a></li>
</ul>

<h1>配布方法</h1>

<p>UWPアプリの公開は、一般的にはWindowsストアを介して行われます。</p>

<div style="width: 200px;margin: 0px auto">
  <a href="https://html5experts.jp/wp-content/uploads/2016/09/image2.png" data-wpel-link="internal"><img title="image" style="border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;padding-top: 0px;padding-left: 0px;padding-right: 0px;border-top-width: 0px" border="0" alt="image" src="/wp-content/uploads/2016/09/image_thumb2.png"
      width="200"></a>
</div>

<p><br /></p>

<p>Windowsストアにアプリを公開するには、Windowsデベロッパーセンターのダッシュボードから、<a title="UWPアプリのパッケージ化" href="https://msdn.microsoft.com/ja-jp/windows/uwp/packaging/packaging-uwp-apps" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">appx形式にパッケージングした</a>アプリを提出します。Windowsストア側で安全性を含め様々な審査が実施され、合格すると公開されます。</p>

<p>UWPアプリをWindowsストアに公開するまでの、開発者アカウントの作成からパッケージの提出、支払いの受け取り (販売した場合) までの具体的な方法については以下のドキュメントを参照してください。</p>

<ul>
  <li><a title="Windowsアプリの公開 | MSDN" href="https://msdn.microsoft.com/ja-jp/windows/uwp/publish/index" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>Windowsアプリの公開</strong></a></li>
</ul>

<p>会社組織のみの利用を想定した場合など、Windowsストアで公開を希望しない場合にはサイドローディングという方法を使用して、管理化にあるデバイスにUWPアプリを直接インストールすることができます。</p>

<p>サイドローディングの具体的な方法については以下のドキュメントを参照してください。</p>

<ul>
  <li><a title="DISMを使ったアプリのサイドローディング" href="https://msdn.microsoft.com/ja-jp/library/windows/hardware/dn938326(v=vs.85).aspx#UnderstandingConcepts" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>DISM を使ったアプリのサイドローディング</strong></a></li>
</ul>

<h1>収益モデル</h1>

<p>Windowsストアでは提出したアプリを販売することができます。また、アプリ内の課金も可能です。開発者Windowsストアが用意するさまざまな仕組を利用して収益を上げることができます。</p>

<p>現在Windowsストアで収益を上げるには、以下の3つの方法があります。</p>

<ol>
  <li><strong>アプリそのものの販売</strong>
    <li><strong>アプリ内課金(In-App purchase : IAP)</strong>
      <li><strong>アプリ内広告</strong></li>
</ol>

<p>これら収益に関する詳しい内容は、以下のドキュメントを参照してください。</p>

<ul>
  <li><a title="アプリの価格と使用可能状況の設定" href="https://msdn.microsoft.com/ja-jp/windows/uwp/publish/set-app-pricing-and-availability" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>アプリの価格と使用可能状況の設定</strong></a>
    <li><a title="IAPの申請" href="https://msdn.microsoft.com/ja-jp/windows/uwp/publish/iap-submissions" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>IAPの申請</strong></a>
      <li><a title="広告による収益獲得" href="https://msdn.microsoft.com/ja-jp/windows/uwp/publish/monetize-with-ads" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>広告による収益獲得</strong></a></li>
</ul>

<h1>まとめ</h1>

<p>この記事ではWindows 10から採用されたユニバーサルWindowsプラットフォーム用のアプリ(UWPアプリ) について紹介しました。</p>

<p>UWPアプリは Window 10デバイスファミリーに対し横断的にアプリを開発できます。そのためPC、スマートフォンはもちろん、Web開発者からは技術的に遠いIoTデバイス向けのアプリも使い慣れた HTML,CSS + JavaScriptで開発することができます。</p>

<p>Continuumにも対応しているため、対応スマートフォンをテレビやディスプレイに接続した際にユーザーにデスクトップエクスペリエンスを提供することもできます。</p>

<div style="width: 500px;margin: 0px auto">
  <a href="https://html5experts.jp/wp-content/uploads/2016/09/image3.png" data-wpel-link="internal"><img title="image" style="border-left-width: 0px;border-right-width: 0px;border-bottom-width: 0px;float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;border-top-width: 0px;margin-right: auto" border="0" alt="image" src="/wp-content/uploads/2016/09/image_thumb3.png"
      width="500" height="250"></a>
</div>

<p>Webブラウザー上で動作するアプリはもちろん、他のハイブリット アプリ用フレームワーク向けのコンテンツでも、HTML、CSS + JavaScriptを使用して作られているのであれば、特別なことをしていない限りはUWPアプリへの移植はそれほど難しくはありません。</p>

<p>新規での開発はもちろん、既存のアプリの新たな市場獲得のための移植先としても検討してもいいかもしれません。</p>

<p>UWP開発についてのより詳しい情報は以下をぜひご覧ください。</p>

<ul>
  <li><a title="ユニバーサルWindowsプラットフォーム (UWP) 向けアプリの開発" href="https://msdn.microsoft.com/ja-jp/library/dn975273.aspx" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>ユニバーサル Windowsプラットフォーム(UWP)向けアプリの開発</strong></a></li>
  <li><a title="ユニバーサルWindowsアプリの開発 - Windowsアプリの開発" href="https://developer.microsoft.com/ja-jp/windows/develop" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>ユニバーサル Windowsアプリの開発 &#8211; Windowsアプリの開発</strong></a></li>
  <li><a title="ユニバーサルWindowsプラットフォーム アプリ(UWP)のデザイン - Windowsアプリ開発" href="https://developer.microsoft.com/ja-jp/windows/design" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><strong>ユニバーサルWindows プラットフォームアプリ(UWP)のデザイン &#8211; Windowsアプリ開発</strong></a></li>
</ul>
]]></content:encoded>
		
		<series:name><![CDATA[Web技術でアプリ開発2016]]></series:name>
	</item>
		<item>
		<title>Cordovaは今やMicrosoftが主導！？最新状況と基本を素早く再チェック！</title>
		<link>/masahiro/20562/</link>
		<pubDate>Wed, 07 Sep 2016 00:31:55 +0000</pubDate>
		<dc:creator><![CDATA[田中 正裕]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[Cordova]]></category>

		<guid isPermaLink="false">/?p=20562</guid>
		<description><![CDATA[連載： Web技術でアプリ開発2016 (2)Web技術でアプリ開発2016特集・第二弾は、Cordovaの最新状況と基本をご紹介。その歴史からプラットフォーム／ライブラリの特徴、ネイティブな機能を呼び出す方法などを解説...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/web-based-apps-2016/" class="series-391" title="Web技術でアプリ開発2016" data-wpel-link="internal">Web技術でアプリ開発2016</a> (2)</div><p>Web技術でアプリ開発2016特集・第二弾は、Cordovaの最新状況と基本をご紹介。その歴史からプラットフォーム／ライブラリの特徴、ネイティブな機能を呼び出す方法などを解説していきます。</p>

<h1>概要</h1>

<p><a href="https://cordova.apache.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Cordova</a>は<a href="http://phonegap.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">PhoneGap</a>と呼ばれていた時代を含めると、8年以上の歴史があります。PhoneGapが産声を上げたのは2008年、Nitobi社がハッカソンでPhoneGapを発表しました。オープンソースで提供されていたPhoneGapは注目され、2011年にはNitobiはAdobe社に買収されます。その結果、オープンソースで提供されているフレームワーク（PhoneGap本体）はCordovaと名前がつけられ、Apache Foundationの仲間入りします。</p>

<p>その結果、Adobeだけでなく、GoogleやMicrosoft、IBM、インテルといった会社がCordovaを支えています。現在、コミュニティをリードしているのはMicrosoftで、Cordovaのコア機能の実装だけでなく、開発者向けの製品へのCordova対応を進めています。</p>

<p>PhoneGapは、Adobe Creative Cloudのいちプロダクトとして、Cordovaをベースとした有償の<a href="https://build.phonegap.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ビルドツールを提供している</a>ほか、エンタープライズ製品も発表されています。</p>

<h1>Hello, World</h1>

<p>Cordovaはクロスプラットフォームではありますが、ビルドできるアプリはビルド環境に依存します。</p>

<ul>
<li>macOS: iOS, Android</li>
<li>Windows: Windows, Android</li>
<li>Linux: Android</li>
</ul>

<p>ローカル環境に依存してしまうため、クラウド環境を使って複数のOSに対応させるソリューションが各社から提供されています。詳しくは<a href="https://build.phonegap.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">PhoneGap Build</a>や<a href="https://ja.monaca.io/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Monaca</a>を参照してください。</p>

<p>Cordovaアプリの開発には様々なオプションがあります。エディタとしては、MicrosoftのVisual StudioやVS Code、JetBrainsのWebStormなど、Web開発と親和性の高いツールを選ぶと良いでしょう。</p>

<p>Cordovaがオフィシャルに提供しているツールとしてCordova CLIがあります。これを使うと、コマンドラインツールでPC上でのシミュレートからビルドまで行うことができます。Cordova CLIはNode.jsを入れた後、下記のようにインストールします。なお、Cordova CLIはNode.jsバージョン4以上に対応しています。</p>

<p></p><pre class="crayon-plain-tag">$ npm install -g cordova</pre><p></p>

<p>インストールしたらcordovaコマンドが使えるようになります。早速アプリを作成するために、cordova createコマンドを実行します。</p>

<p></p><pre class="crayon-plain-tag">$ cordova create helloworld
$ cd helloworld
$ cordova -v
6.3.1</pre><p></p>

<p>これでプロジェクトが作成されました。次にプラットフォームを追加します。cordova platformコマンドを使用し、引数にはプラットフォーム名（android、ios、windows等）を指定します。</p>

<p></p><pre class="crayon-plain-tag">$ cordova platform add android (ios, windows)</pre><p></p>

<p>ブラウザーでプレビューするには、cordova serveコマンドを使います。</p>

<p></p><pre class="crayon-plain-tag">$ cordova serve</pre><p></p>

<p>ブラウザーを開き、<a href="http://localhost:8000/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">http://localhost:8000/</a>にアクセスします。下記の画面が表示されたら成功です。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/cordova-serve.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/cordova-serve-186x300.png" alt="cordova-serve" width="186" height="300" class="aligncenter size-medium wp-image-20572" srcset="/wp-content/uploads/2016/08/cordova-serve-186x300.png 186w, /wp-content/uploads/2016/08/cordova-serve-129x207.png 129w, /wp-content/uploads/2016/08/cordova-serve.png 385w" sizes="(max-width: 186px) 100vw, 186px" /></a></p>

<p>実際のアプリを表示するには、プラットフォーム名をクリックします。なお、ブラウザではネイティブAPIとの連携ができないため、ブラウザー上で変なエラーメッセージ等が表示される可能性があります。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/cordova-deviceready.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/cordova-deviceready-186x300.png" alt="cordova-deviceready" width="186" height="300" class="aligncenter size-medium wp-image-20573" srcset="/wp-content/uploads/2016/08/cordova-deviceready-186x300.png 186w, /wp-content/uploads/2016/08/cordova-deviceready-129x207.png 129w, /wp-content/uploads/2016/08/cordova-deviceready.png 385w" sizes="(max-width: 186px) 100vw, 186px" /></a></p>

<p>最後にビルドを行ってみましょう。USBで接続した端末に実行するにはemulateを、パッケージを作るにはbuildコマンドを使用します。</p>

<p></p><pre class="crayon-plain-tag">$ # エミュレータを起動します
$ cordova emulate android (ios, windows)
$ # ビルドを実行します
$ cordova build android (ios, windows)</pre><p></p>

<h1>プラットフォーム／ライブラリの特徴</h1>

<table>
<thead>
<tr>
  <th>項目</th>
  <th>説明</th>
</tr>
</thead>
<tbody>
<tr>
  <td>対応プラットフォーム</td>
  <td>iOS, Android, Windows, Firefox OS, Ubuntu&#8230;</td>
</tr>
<tr>
  <td>コードベースは（ほぼ）完全に統一できるか？</td>
  <td>統一できる</td>
</tr>
<tr>
  <td>UIを記述する言語</td>
  <td>HTML、CSS、JavaScript</td>
</tr>
<tr>
  <td>UIはネイティブか、Webか</td>
  <td>WebView上で実行される</td>
</tr>
<tr>
  <td>パフォーマンス</td>
  <td>WebViewのためネイティブより遅い</td>
</tr>
<tr>
  <td>ネイティブな機能を呼び出せるか？</td>
  <td>Cordovaプラグインを通じて呼び出せる</td>
</tr>
</tbody>
</table>

<p>以下に上の表を補足します。</p>

<h2>サポートするプラットフォーム</h2>

<ul>
<li>iOS</li>
<li>Android</li>
<li>Windows (Windows Phone, Windows 10)</li>
</ul>

<p>以前から数多くのモバイルOSに対応しており、上記以外にもBlackberryやTizen、Firefox OSなどもラインアップに加わっています。アンオフィシャルなものでは、<a href="https://github.com/stevengill/cordova-electron" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Electron対応</a>もあります。</p>

<h2>コードベースは完全に統一できるのか？</h2>

<p>作り方次第ではありますが、基本的には完全に統一できます。ただし、プラットフォームごとにブラウザーエンジンが異なるため、その癖を理解しておく必要があります。</p>

<p>iOSはWebKit、AndroidはWebKitから派生したBlinkが使われるため、近い挙動となります。一方Windowsアプリでは、セキュリティの理由でInnerHTMLやインラインJavaScriptが禁止されているなど、細かい挙動に違いがあります。</p>

<p>また、CSSのプロパティやJavaScriptのサポート度合いもブラウザ依存です。その辺りに気をつけて確認をしながら開発を行うことが求められます。</p>

<p>一方、ネイティブ側は各OSごとの実装依存となります。プラットフォームごとの注意点について、CordovaのAPIドキュメントに記述されています。</p>

<h2>UIを記述する言語</h2>

<p>WebView上にUIを表現します。そのためWebサイトやWebアプリと同様、HTML、CSS、JavaScriptの組み合わせで記述していきます。</p>

<p>ただしモバイルUIにゼロから対応していくのは大変です。そのため、<a href="http://ja.onsen.io/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Onsen UI</a>や<a href="http://ionicframework.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Ionic</a>といったオープンソースのUIライブラリーが多用されます。</p>

<h2>パフォーマンス</h2>

<p>WebView上で動作させることから、ネイティブと比べてボトルネックが発生しやすいです。ただし端末スペック向上やブラウザの最適化などのおかげで、昔と比べるとはるかにスムーズに動作します。</p>

<p>一方で、パフォーマンスチューニングの要であるブラウザ上での高速化テクニックに乏しいという事情もあります。Service WorkerやWebAseemblyといった技術に期待したいところです。</p>

<h2>UIはネイティブか、Webか</h2>

<p>WebView上で開発しますので、ブラウザの持つHTML、CSS、JavaScriptを使用します。</p>

<p>ネイティブUIを実装する取り組みも行われており、Microsoftからは<a href="http://microsoft.github.io/ace/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Project Ace</a>というプロジェクトが立ち上がりました。これを使うと、パフォーマンス向上だけでなく、WebView上にネイティブウィジェットを配置したり、WebViewをネイティブUIの中に組み込むといった事が可能になります。</p>

<h2>ネイティブな機能を呼び出す方法</h2>

<p>Webレイヤーからネイティブレイヤーに、非同期的にネイティブAPIを呼び出す仕組みを備えています。SwiftやJavaで記述する必要がありますが、JavaScript APIで実現できないOSやデバイスの機能を呼び出すことができます。</p>

<p>また、Cordovaプラグイン仕組みが提供されており、npmには様々なプラグインが<a href="https://www.npmjs.com/browse/keyword/ecosystem:cordova" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">公開されています</a>。プラグインを組み込むにはcordova pluginコマンドを実行します。</p>

<p></p><pre class="crayon-plain-tag">$ cordova plugin add cordova-plugin-camera</pre><p></p>

<p>上記の例では、カメラを制御するプラグインを組み込んでいます。これで、下記のようにしてカメラ画像の撮影が可能になります。</p>

<p></p><pre class="crayon-plain-tag">navigator.camera.getPicture(onSuccess, onFail, {
  quality: 50,
  destinationType: Camera.DestinationType.FILE_URI
});
function onSuccess(imageURI) {
  var image = document.getElementById('myImage');
  image.src = imageURI;
}
function onFail(message) {
  alert(message);
}</pre><p></p>

<h1>まとめ</h1>

<p>かつてPhoneGapと呼ばれていた頃と異なり、WebやモバイルOSの進化の流れを受け、だいぶ様変わりしました。一方で、一昔前はアーリーステージにつきものの仕様変更や互換性問題がありましたが、現在では比較的落ち着き、良くも悪くも枯れてきたように思います。</p>

<p>Cordovaの強みは、Web技術をそのまま生かすことでのエンジニア層の厚さと、幅広く使われていることによるエコシステムの大きさではないでしょうか。一度使ったことがある方も、そうでない方も、最新のCordovaを試してみてはいかがでしょうか。</p>
]]></content:encoded>
		
		<series:name><![CDATA[Web技術でアプリ開発2016]]></series:name>
	</item>
		<item>
		<title>React Native入門 ─ Hello,Worldからネイティブ連携まで</title>
		<link>/shohey1226/20480/</link>
		<pubDate>Tue, 06 Sep 2016 00:16:23 +0000</pubDate>
		<dc:creator><![CDATA[Kameda Shohei]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[React Native]]></category>

		<guid isPermaLink="false">/?p=20480</guid>
		<description><![CDATA[連載： Web技術でアプリ開発2016 (1)モバイルアプリ開発におけるWeb技術の可能性を探る特集・第一弾でご紹介するのはReact Native。その生い立ち、チュートリアルから、コードベースやUIを記述する言語、パ...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/web-based-apps-2016/" class="series-391" title="Web技術でアプリ開発2016" data-wpel-link="internal">Web技術でアプリ開発2016</a> (1)</div><p>モバイルアプリ開発におけるWeb技術の可能性を探る特集・第一弾でご紹介するのはReact Native。その生い立ち、チュートリアルから、コードベースやUIを記述する言語、パフォーマンスまで解説します。</p>

<h2>概要</h2>

<p>React Nativeは2013年にFacebook社内のハッカソンで生まれたプロジェクトです。2014年にiOSアプリのFacebook Ads ManagerをReact Nativeを用いて開発し、2015年3月にオープンソースとして公開されました。そして、半年後の2015年9月にAndroidをサポートし、今年のF8では、MicrosoftがReact Nativeで<a href="https://github.com/ReactWindows/react-native-windows" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Windowsプラットフォーム（PC, Mobile, Xbox）の開発</a>ができます、という発表がありました。また、<a href="https://github.com/ptmt/react-native-macos" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">macOSアプリの開発</a>、<a href="https://github.com/CanonicalLtd/react-native" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Ubuntuアプリの開発</a>など他のプラットフォームの開発もできるようにするプロジェクトも走っているようです。</p>

<p>React Nativeのコンセプトは、&#8221;Write Once, Run Anywhere”(一つのコードでどこでも動く）ではなく、&#8221;Learn Once, Run Anywhere&#8221;(一度学べば、どこでも動かせる）です。一度React Nativeを理解すれば、どのプラットフォーム上でも同様のコーディングを行って、プラットフォームネイティブなアプリケーションを開発することが出来ます。Githubのスター数は35,000を超え、リリースの頻度も多く、グローバルな視点でみると、非常に熱い技術であると言えます。</p>

<p>（編集部注: 「Write Once, Run Anywhere」は、あらゆるプラットフォームで同一のコードが動作するという、Javaが喧伝していたコンセプトです）</p>

<h2>Hello, World</h2>

<p>以下は、macOS上で開発することを前提としたチュートリアルです。</p>

<p>React Native開発に必要なものは、 Node.js, React Nativeのコマンドラインツール、<a href="https://facebook.github.io/watchman/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Watchman</a>（Facebookによって開発されているファイル監視ツール）になります。Homebrewで下記のようにインストールします。</p>

<p><code>
$ brew install node
$ brew install watchman
$ npm install -g react-native-cli
$ npm -v
3.6.0
$ node -v
v5.0.0
</code></p>

<h3>iOS</h3>

<p>iOSの場合はXcodeが必要です。XcodeはMac App Storeからインストールしましょう。　準備が整ったところで、プロジェクトを作って走らせてみます。</p>

<p><code>
$ react-native init AppByWebTech2016
$ cd AppByWebTech2016
$ react-native run-ios
</code></p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/Simulator-Screen-Shot-2016.08.27-9.57.40.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/Simulator-Screen-Shot-2016.08.27-9.57.40-169x300.png" alt="Simulator Screen Shot 2016.08.27 9.57.40" width="169" height="300" class="alignnone size-medium wp-image-20490" srcset="/wp-content/uploads/2016/08/Simulator-Screen-Shot-2016.08.27-9.57.40-169x300.png 169w, /wp-content/uploads/2016/08/Simulator-Screen-Shot-2016.08.27-9.57.40.png 360w, /wp-content/uploads/2016/08/Simulator-Screen-Shot-2016.08.27-9.57.40-116x207.png 116w" sizes="(max-width: 169px) 100vw, 169px" /></a></p>

<h3>Android</h3>

<p>Androidの場合は、Android Studioが必要なのでインストールしておきます。アプリの起動には、実機をUSBで繋げておくか、Emulatorが必要なので適宜用意します。今回は、<a href="https://www.genymotion.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Genymotion</a>(個人利用は無料）を起動しておいて, 下記のコマンドを走らせます。</p>

<p><code>
$ react-native run-android
</code></p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/a468941aa8d025ee9409bc979399be8d.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/a468941aa8d025ee9409bc979399be8d-182x300.png" alt="スクリーンショット 2016-08-27 10.32.12" width="182" height="300" class="alignnone size-medium wp-image-20492" srcset="/wp-content/uploads/2016/08/a468941aa8d025ee9409bc979399be8d-182x300.png 182w, /wp-content/uploads/2016/08/a468941aa8d025ee9409bc979399be8d.png 389w, /wp-content/uploads/2016/08/a468941aa8d025ee9409bc979399be8d-126x207.png 126w" sizes="(max-width: 182px) 100vw, 182px" /></a></p>

<h3>NativeBaseを使う</h3>

<p>これだけだと味気ないので、<a href="http://nativebase.io/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">NativeBase</a>を用いてUIを作ってみたいと思います。NativeBaseはWebでいうBootstrapのようなものです。ボタン等のUIを自分でデザインする必要がなく見栄えの良いインターフェイスを簡単に作ることができます。</p>

<p>では、NativeBaseをインストールしてみましょう。(※react-nativeのバージョンは0.32)</p>

<p><code>
$ cd AppByWebTech2016
$ npm install native-base --save
$ react-native link react-native-vector-icons
</code></p>

<p>index.ios.jsを下記のように変更すると、</p>

<p></p><pre class="crayon-plain-tag">import React, { Component } from 'react';
import { Container, Content, Button, Header, Title, List, ListItem, Badge } from 'native-base';
import { Col, Row, Grid } from 'react-native-easy-grid';
import { AppRegistry, Text, View } from 'react-native';

class AppByWebTech2016 extends Component {
  render() {
    return (
      &lt;Container&gt;
        &lt;Header&gt;
          &lt;Title&gt;Hello World&lt;/Title&gt;
        &lt;/Header&gt;
        &lt;Content&gt;
          &lt;List&gt;
            &lt;ListItem &gt;
              &lt;Badge&gt;1&lt;/Badge&gt;
            &lt;/ListItem&gt;
            &lt;ListItem&gt;
              &lt;Badge primary&gt;2&lt;/Badge&gt;
            &lt;/ListItem&gt;
            &lt;ListItem&gt;
              &lt;Text&gt;List 3&lt;/Text&gt;
            &lt;/ListItem&gt;
          &lt;/List&gt;
          &lt;Grid&gt;
            &lt;Row&gt;
              &lt;Col&gt;
                &lt;Button style={{margin:10}}&gt; Click Me! &lt;/Button&gt;
              &lt;/Col&gt;
              &lt;Col style={{backgroundColor: '#204d74'}}&gt;
                &lt;Text style={{fontSize: 20, color: 'white', margin: 10}}&gt;React Native!&lt;/Text&gt;
              &lt;/Col&gt;
            &lt;/Row&gt;
            &lt;Row style={{backgroundColor: '#00c497'}}&gt;
              &lt;Text style={{fontSize: 24, color: '#333', margin: 10}}&gt;Learn once, Write anywhere&lt;/Text&gt;
            &lt;/Row&gt;
          &lt;/Grid&gt;
        &lt;/Content&gt;
      &lt;/Container&gt;
    );
  }
}

AppRegistry.registerComponent('AppByWebTech2016', () =&gt; AppByWebTech2016);</pre><p></p>

<p>スタイルのことを気にせずボタンを作ることができ、グリッドなども簡単に使用できます。プロトタイピングなどにはもってこいのモジュールとなっています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/59dd481d8a7df9a47c7015bc6728d49b.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/59dd481d8a7df9a47c7015bc6728d49b-300x279.png" alt="スクリーンショット 2016-08-27 14.09.20" width="300" height="279" class="alignnone size-medium wp-image-20493" srcset="/wp-content/uploads/2016/08/59dd481d8a7df9a47c7015bc6728d49b-300x279.png 300w, /wp-content/uploads/2016/08/59dd481d8a7df9a47c7015bc6728d49b-207x193.png 207w, /wp-content/uploads/2016/08/59dd481d8a7df9a47c7015bc6728d49b.png 373w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<h2>プラットフォーム／ライブラリの特徴</h2>

<table>
<thead>
<tr>
  <th align="left">項目</th>
  <th align="right">説明</th>
</tr>
</thead>
<tbody>
<tr>
  <td align="left">対応プラットフォーム</td>
  <td align="right">iOS, Android, Windows(PC, Mobile, Xbox), macOS※, Ubuntu※</td>
</tr>
<tr>
  <td align="left">コードベースは（ほぼ）完全に統一できるか？</td>
  <td align="right">統一できない（実際は7,8割は共有できる）</td>
</tr>
<tr>
  <td align="left">UIを記述する言語</td>
  <td align="right">JavaScript, React, スタイルシート</td>
</tr>
<tr>
  <td align="left">UIはネイティブか、Webか</td>
  <td align="right">WebViewではない。ネイティブもしくはJSとのハイブリットで実現</td>
</tr>
<tr>
  <td align="left">パフォーマンス</td>
  <td align="right">ネイティブ同等</td>
</tr>
<tr>
  <td align="left">ネイティブな機能を呼び出せるか？</td>
  <td align="right">APIを通じて自由に呼び出せる</td>
</tr>
</tbody>
</table>

<p>※コミュニティがサポート</p>

<p>以下に、上の表を補足します。</p>

<h3>対応プラットフォーム</h3>

<p>私が確認したのはiOSとAndroidですが、前述した通り、下記のプラットフォームでReact Nativeの方法でNativeアプリを動かすことができるようです。</p>

<ul>
<li>iOS</li>
<li>Android</li>
<li>Windows(PC, Mobile, Xbox)</li>
<li>MacOS</li>
<li>Ubuntu</li>
<li>Browser※1</li>
</ul>

<p>※１<a href="https://github.com/necolas/react-native-web" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">React Native for Web</a>というChrome, Firefox, Safari &gt;= 7, IE 10, Edge.のBrowser上でReact Nativeコードを動かすというプロジェクトさえ存在します。</p>

<h3>コードベースは（ほぼ）完全に統一できるか？</h3>

<p>残念ながら完全には統一できません。現実には各プラットフォームの作法（例えば、iOSはtabbarは下部、Androidは上部）
が存在し、完全に同じにすべきかというのは別の議論が必要な気がします。ただ<a href="https://www.quora.com/How-much-will-you-be-able-to-share-code-between-Android-and-iOS-with-React-Native" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">85%は同じコードを再利用できた</a>といった話もないわけではありません。ビジネスロジック部分は統一させ、UIは個別のコードで実現するというのが、コードの再利用＋ネイティブの作法の両面を考慮に入れたReact Nativeの流儀だと言ってよいでしょう。</p>

<h3>UIを記述する言語</h3>

<p>コードはJavaScript(ES6), コンポーネントはReact, デザインはスタイルシートを用いて記述していきます。
スタイルシートはCamel記法となるのでCSSのbackground-colorがbackgroundColorという属性になり、非常に馴染みの深いものになります。
React Nativeは、レイアウトを行うためにFlexboxを用います。最近のWebブラウザでは広くサポートされているので、ご存じの方も多いことでしょう。</p>

<p>ES6やReactは確かに学習コストがあります。しかし、Web業界で生きているひとは少なくとも触っておくべき技術でしょう。React Nativeでのアプリ開発の経験が逆にWebに生かすというようなことも起きるかもしれません。</p>

<h3>パフォーマンス</h3>

<p>ネイティブのコンポーネントを利用する限り、ネイティブと同等のパフォーマンスになると言ってよいでしょう。パフォーマンスの最適化を開発者に意識させないようにすることがReact Nativeが実現しようとしていることです。</p>

<p>しかし、<a href="http://facebook.github.io/react-native/releases/0.32/docs/performance.htm" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">公式のドキュメント</a>によると、現実には何点か難しい箇所があると述べられています。</p>

<p>React Nativeは下図のようにスレッドが走っています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/8E2942F7-B660-46DC-85BA-58DA362472DB.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/8E2942F7-B660-46DC-85BA-58DA362472DB-300x167.png" alt="8E2942F7-B660-46DC-85BA-58DA362472DB" width="300" height="167" class="alignnone size-medium wp-image-20497" srcset="/wp-content/uploads/2016/08/8E2942F7-B660-46DC-85BA-58DA362472DB-300x167.png 300w, /wp-content/uploads/2016/08/8E2942F7-B660-46DC-85BA-58DA362472DB-207x115.png 207w, /wp-content/uploads/2016/08/8E2942F7-B660-46DC-85BA-58DA362472DB.png 622w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p><a href="https://www.youtube.com/watch?v=0MlT74erp60" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">React.js Conf 2016 &#8211; Tadeu Zagallo &#8211; Optimising React Native: Tools and Tips</a>より転載</p>

<p>端的に言うと、JavaScriptのビジネスロジックが動くJSスレッド上で時間のかかる処理を行うと、UI出力時に遅延が起きてしまうケースがあります。
もしパフォーマンスに影響が出たときは、このJSスレッドを意識してコードを見直してみる必要があります。</p>

<p>今年のReact Confの発表でも言及されていましたが、Facebookは社内にReact Nativeのパフォーマンスチームを作ってパフォーマンスを継続的に改善しています。彼らがリソースを割いて注力している部分でもあるので、これからも改善されていく部分だと思います。</p>

<h3>UIはネイティブか、Webか</h3>

<p>WebViewを使わないという観点でWebではありません。ネイティブのライブラリを呼び出すAPIが多いですが、JSとのコードのハイブリッドといったイメージでしょうか。UIの動作は非常にネイティブライクです。</p>

<h3>ネイティブな機能を呼び出す方法</h3>

<p>React Nativeとネイティブ間を受け渡すようなAPIが用意されています。
これを使うことで容易にネイティブからの値を受け取ったり、受け渡したりすることができます。
この程よい抽象化があることで、現行のiOSアプリにも組み込むことが可能となります。
実際、Facebookのアプリでも一部はReact Nativeで書かれてると言っています。</p>

<p>今回は非常に簡単な例ですが、React Native側で２つの数字を渡しネイティブ側で和を求めて返すメソッドを用いて説明します。(今回はiOS）</p>

<p>まずは、Xcodeで<code>ios/AppByWebTech2016.xcodeproj</code>をOpenし、新規作成からCocoaClassを選び、適当なSubクラスを選びます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/ED821C61-EBBF-4046-B1F7-C2C177606302.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/ED821C61-EBBF-4046-B1F7-C2C177606302-300x151.png" alt="ED821C61-EBBF-4046-B1F7-C2C177606302" width="300" height="151" class="alignnone size-medium wp-image-20501" srcset="/wp-content/uploads/2016/08/ED821C61-EBBF-4046-B1F7-C2C177606302-300x151.png 300w, /wp-content/uploads/2016/08/ED821C61-EBBF-4046-B1F7-C2C177606302-207x104.png 207w, /wp-content/uploads/2016/08/ED821C61-EBBF-4046-B1F7-C2C177606302.png 560w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p><a href="https://html5experts.jp/wp-content/uploads/2016/08/EF401AE0-3C72-41CE-BA43-95D68531F7B6.png" data-wpel-link="internal"><img src="/wp-content/uploads/2016/08/EF401AE0-3C72-41CE-BA43-95D68531F7B6-300x210.png" alt="EF401AE0-3C72-41CE-BA43-95D68531F7B6" width="300" height="210" class="alignnone size-medium wp-image-20502" srcset="/wp-content/uploads/2016/08/EF401AE0-3C72-41CE-BA43-95D68531F7B6-300x210.png 300w, /wp-content/uploads/2016/08/EF401AE0-3C72-41CE-BA43-95D68531F7B6.png 640w, /wp-content/uploads/2016/08/EF401AE0-3C72-41CE-BA43-95D68531F7B6-207x145.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>すると、AppNativeSum.hとAppNativeSum.mができると思います。
このファイルを下記のように書き換えます。RCT_*(ReaCTの略らしい）の接頭辞がついたAPIをReact Nativeが提供しています。Callbackを用いて返す方法もありますが、今回はPromiseを使います。</p>

<p></p><pre class="crayon-plain-tag">#import "RCTBridgeModule.h"

@interface AppNativeSum : NSObject &amp;lt;RCTBridgeModule

@end</pre><p></p>

<p></p><pre class="crayon-plain-tag">#import "AppNativeSum.h"

@implementation AppNativeSum

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(sumNumber:(int)val1 val2:(int)val2 resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
  NSInteger val3 = val1 + val2;
  NSString *val3Str = [NSString stringWithFormat:@"%ld", (long)val3];
  resolve(val3Str);
}

@end</pre><p></p>

<p>このメソッドの戻り値は、JavaScriptのPromiseです。通常のPromiseと同様に、async/awaitを使って非同期処理の結果を処理することも可能です。</p>

<p></p><pre class="crayon-plain-tag">import { NativeModules } from 'react-native';
var AppNativeSum = NativeModules.AppNativeSum;

class AppByWebTech2016 extends Component {

  constructor(props){
    super(props);
    this.state = {
      sum: 0
    }
  }

  async componentDidMount(){
    let sum = await AppNativeSum.sumNumber(1,2);
    this.setState({sum: sum});
  }
...</pre><p></p>

<p>ネイティブコードに精通していれば、公式ドキュメントにあるAPIに渡すだけで容易にReact Nativeとネイティブのやりとりができます。</p>

<h2>まとめ</h2>

<p>マレーシアの友人が、彼の国では企業がReact Nativeエンジニアの採用をしていると言っていました(中国でも似たような状況にあるとか)。
日本でもちらほらReact Nativeを採用する会社がでてきているようです。一年半以上経過し、リリース速度が多少遅くなっているといってもどんどん新しいバージョンが出てきて、かつよりよいUIモジュールもでてきています。今こそ、React Nativeを始めてみてはいかがでしょうか。</p>
]]></content:encoded>
		
		<series:name><![CDATA[Web技術でアプリ開発2016]]></series:name>
	</item>
	</channel>
</rss>
