<?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アプリ &#8211; HTML5Experts.jp</title>
	<atom:link href="/tag/Webアプリ/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>「改めまして、Progressive Web Appsと申します」── Web UXの新たな基準を考える</title>
		<link>/uskay/25391/</link>
		<pubDate>Thu, 19 Apr 2018 03:23:45 +0000</pubDate>
		<dc:creator><![CDATA[宇都宮佑亮]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[PWA]]></category>
		<category><![CDATA[Progressive Web Apps]]></category>
		<category><![CDATA[Service Worker]]></category>
		<category><![CDATA[UX]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=25391</guid>
		<description><![CDATA[Progressive Web Appsというワードが世に出て約2年半が経ちました。2015年10月に開催されたChrome Dev SummitにてFlipkartの事例をもってお披露目となったそのコンセプトは、201...]]></description>
				<content:encoded><![CDATA[<p><strong>Progressive Web Appsというワードが世に出て約2年半が経ちました。</strong>2015年10月に開催されたChrome Dev Summitにて<a href="https://www.youtube.com/watch?v=StdKz32M1RM" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Flipkartの事例</a>をもってお披露目となったそのコンセプトは、2018年現在までに徐々に成功事例を増やしながらWeb界隈の注目を集め、ついに先日（忘れもしない2018年3月30日！）iOS 11.3からiOSデバイスでも一部の機能が利用できるようになるまで成長しました。これは、まるで進学する我が子を見ているかのような、新年度にふさわしい晴れやかなニュースですし、<strong>いい機会なので PWAとは何かを改めて振り返ってみようと思います。</strong></p>

<p><img src="/wp-content/uploads/2018/04/pwa01.jpg" alt="pwa01" /></p>

<h2>Webに足りなかったもの</h2>

<p>私はWebが大好きです。リンクを1つクリックしたら（インストールなど煩わしい手続きなしで）すぐに新しいコンテンツを読めるのは最高の体験だなと常日頃感じています。ただし、<strong>今までのWebアプリのユーザー体験は決して最適なものではないとも思っています。</strong>たとえば以下のような体験をした覚えはありませんか？</p>

<ul>
<li>朝の満員電車でも情報収集に勤しむ現代のビジネスパーソンのあなた。つり革に捕まりながらなんらかの記事コンテンツを見ようとリンクをタップする</li>
<li>途端にHTMLのレスポンス待ちで真っ白な画面。レスポンスが返ってきたと思ったら今度はWebアプリ側のローディングGIFが動き出す。</li>
<li>しばらく待つとテキストが表示され読み始めるものの、時間差で画像が差し込まれレイアウトがずれる（どこを読んでいたんだっけ？）。極めつけは全画面広告が画面を占拠し、嫌になってそっとブラウザを閉じる（代わりにソーシャルアプリやゲームアプリを起動する）。</li>
</ul>

<p>このように世に出回っている多くのWebアプリはパフォーマンスに課題があります。特に、さまざまなスペックなデバイスがあらゆる環境で利用されるモバイルにおいては、Webアプリは単純に耐えられないくらい遅く、実測で3G回線と同等な環境における平均ページロード時間は19秒もかかっているという統計もあります[1]。 <strong>Webアプリはとにかくこのパフォーマンスをどうにかしなければなりません。</strong></p>

<p>一方ですでにネイティブ アプリに慣れ親しんでいるユーザーの期待値を満たすためには、パフォーマンスを改善するだけでは十分ではありません。</p>

<ul>
<li>ホーム画面にアイコンを追加したり</li>
<li>プッシュ通知がタイミングよく送られてきたり</li>
<li>オフラインでも動作する信頼性だったり</li>
</ul>

<p>「ユーザー体験の基準」がどんどん上がっていくなか、Webアプリだけがこのような体験を提供できずに取り残されている状況がずっと続いていました。<strong>時代に合わせて、ユーザーが求める機能性もWebアプリで実現できなければならないのです。</strong></p>

<h2>PWAはベストプラクティス集である</h2>

<p>そこで満を持して登場したのがPWAです。PWAと聞くと何かを特定の技術を指すものと思われるかもしれませんが、実はそのコンセプトは幅広く、どちらかというと前述した <strong>Webアプリ本来の課題を解決し、よりよいユーザー体験を実現するためのベストプラクティス集のようなものです。</strong>Googleが提供している<a href="https://developers.google.com/web/progressive-web-apps/checklist" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Progressive Web App Checklist</a>
なるものがあり詳細な内容はそちらを確認いただければと思いますが、PWAのコンセプトをざっくり申し上げると以下となります。</p>

<ul>
<li><strong>とにかくパフォーマンスいいWebアプリを作りましょう。</strong>SPAでもSPAじゃなくても、どんなフレームワーク使っても使わなくても、なんでもいいので、表示が速くて画面遷移がスムーズなものにしてユーザーに好かれましょう。</li>
<li>また、最新のWeb APIを積極的に使って、機能性も身につけましょう。たとえば、Webアプリをホーム画面に追加できるようにしたり、オフラインでも動作するようにしたり。<strong>そんな今までWebアプリでは実現できなかった機能が実装できるようになったんだから、やらない手はないでしょう？</strong></li>
</ul>

<p>少し上記でも触れていますが、PWAはあくまでベストプラクティス集なので特定のサードパーティーフレームワークやライブラリには依存しません。世の中には ReactやAngularを使ったPWAもありますし、Vanilla JavaScriptなPWAもあります。また、サーバーサイドの構成には一切言及しません。<strong>したがって技術スタックを変えずとも適用可能なベストプラクティスでありますし、一度に全部を適用するのではなく段階的に（= Progressively）最適化することもできます。</strong></p>

<p>以下の項目でPWAの特徴をより具体的に見ていきます。</p>

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

<p>何より重要であり最も難しいテーマとなります。パフォーマンスの基準としては、2015年にChromeチームが発表したユーザー中心に考えるパフォーマンスモデルである<strong>RAIL</strong>[2]を前提に考えていただければ間違いありませんが、各Webアプリの特性や環境に応じてそれぞれのサービスごとに <strong>Performance Budget</strong>（ロード時間やファイルサイズ等の上限を決め、それを「予算」として管理する）を設けることをオススメします。たとえば、2017年のChrome Dev SummitでChromeチームが推奨したPerfromance Budgetは、<strong>TTI（Time to interactive)を5秒以内</strong>、それを実現するために<strong>クリティカルパスのファイルサイズを170KB以内に収める</strong>というものです。[3][4]</p>

<p>何事もまずは現状分析から。Webアプリのパフォーマンス測定やプロファイリングをする<a href="https://developers.google.com/web/tools/lighthouse/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Lighthouse</a>や<a href="https://developers.google.com/web/tools/chrome-devtools/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Chrome DevTools</a>等のツールを使って現状の評価とボトルネックを確認し、対応すべきポイントを決めて最適化を進めます。その後は<a href="https://calibreapp.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Calibre</a>や<a href="https://speedcurve.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">SpeedCurve</a>といったパフォーマンスモニタリングツールを利用して定点観測するといいでしょう。</p>

<p><img src="/wp-content/uploads/2018/04/pwa02.png" alt="pwa02" /></p>

<p>ハイパフォーマンスなPWAを作るためのデザインパターンである<a href="https://developers.google.com/web/fundamentals/performance/prpl-pattern/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">PRPLパターン</a>もまた参考にすべき方式です。PRPLパターンは<strong>Push 、Render、Pre-cache、Lazy-load</strong>の頭文字を取ったもので、主に<a href="https://developers.google.com/web/fundamentals/architecture/app-shell?hl=ja" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">App Shell モデル</a>やSPAを採用したWebアプリのために用意されたパターンですが、それ以外の構成に関してもパフォーマンス向上のヒントとなる点が多くあります。</p>

<ul>
<li><strong>Push/Render:</strong> 初期描画に必須なリソースを<a href="https://tools.ietf.org/html/rfc7540#section-8.2" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HTTP/2 Server Push</a>するか <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Preloading_content" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">link rel=preload</a> を利用することで先行取得します。そしてそのリソースを利用し、特にAbove the fold [5] (スクロールしないで見える範囲)を優先してレンダリングします。</li>
<li><strong>Pre-cache:</strong> 次ページ（またはルート）で使用するであろうリソースを先読みします。これには<a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Service Worker</a>を利用するといいでしょう。</li>
<li><strong>Lazy-load:</strong> 初期描画に必要なもの以外はすべてLazy-loadします。SPAであれば別ルートの取得がこちら該当しますし、スクロールに合わせたフラグメントの取得であれば<a href="https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Intersection Observer API</a>を利用するといいでしょう。</li>
</ul>

<p>上記のとおり、Webアプリでもパフォーマンスをあげるためのツールやデザインパターンなど、使えるナレッジが多くたまってきました。ぜひともこれらを利用してハイパフォーマンスなWebアプリの開発を実現してください。</p>

<h3>ホーム画面に追加</h3>

<p><a href="https://developer.mozilla.org/en-US/docs/Web/Manifest" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Web App Manifest</a>を実装するとWebアプリをホーム画面に追加できるようになります。以下のようなJSON形式のマニフェストファイルを用意し、</p>

<p></p><pre class="crayon-plain-tag">{
   "name": “PWA Demo Application”,    
   "short_name": “PWA demo”,
    "icons": [{
        "src": “/assets/icon.png”, "sizes": “192x192”
     }],
    "start_url": “/index.html”,
    "display": “standalone”,
    "scope": “/”
}</pre><p></p>

<p>link タグでページにひも付けた上で、Service Workerをインストールすると、</p>

<p></p><pre class="crayon-plain-tag">&lt;link rel="manifest" href="/manifest.json"&gt;

&lt;script&gt;
if ('serviceWorker' in navigator)    
   navigator.serviceWorker.register('/sw.js')
&lt;/script&gt;</pre><p></p>

<p>このようにホーム画面へ追加を促すプロンプトが上がってきます。ホームに追加した後はフルスクリーンで起動しますし、Androidの場合は1つの アプリとしてみなされディープリンクまで可能です。</p>

<p><img src="/wp-content/uploads/2018/04/pwa03.gif" alt="pwa03" /></p>

<p>1点補足すると、この「ホーム画面に追加」は強力ですが、よりユーザーに気持ちよく追加してもらえるように、<strong>意味のあるタイミングでプロンプトを表示するとさらにいいでしょう。</strong>これを実現するためにぜひとも<code>onbeforeinstallprompt</code>イベントハンドラーを利用してください。</p>

<p><code>onbeforeinstallprompt</code>イベントハンドラーはプロンプトが表示される直前に呼び出されます。そのタイミングでプロンプト表示が適切でなければ表示をキャンセルし、別の任意のタイミングで表示することができます。たとえば、画面上に独自の「ホームに追加アイコン」を作成し、それの <code>onclick</code>のイベントハンドラ内でプロンプトを表示させることも可能です。</p>

<p></p><pre class="crayon-plain-tag">var deferredPrompt;
window.addEventListener('beforeinstallprompt', (e) =&gt; {
  console.log('beforeinstallprompt Event fired');
  // デフォルトのタイミングでは表示させない
  e.preventDefault();
  // Eventオブジェクトを保存しておく
  deferredPrompt = e;
  return false;
});
// どっか別のタイミングで...
deferredPrompt.prompt();</pre><p></p>

<p>また執筆時点での最新の<a href="https://www.google.com/chrome/browser/canary.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Chrome Canary</a> (67.0.3394.0)ではプロンプト表示形式を以下のように変更して、ホームに追加の体験をより良くすべく機能検証をしています。ポイントはページ下部に表示されるバナーがコンテンツの邪魔にならないサイズに調整され、PWAが追加済であればそのディープリンク用のバナーに差し替えます。また、前述の<code>prompt</code>関数を利用してユーザーのインタラクションに応じてプロンプトを表示する際は、モーダル表示に切り替わります。</p>

<p><img src="/wp-content/uploads/2018/04/pwa04.png" alt="pwa04" /></p>

<h3>オフライン対応</h3>

<p>ハイパフォーマンスの解説でも少し登場した<strong>Service Worker</strong> と <a href="https://developer.mozilla.org/en-US/docs/Web/API/Cache" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Cache API</a>を利用することでWebアプリをオフラインで実行することが可能になります。Service Workerとはオリジン単位（またはパスの粒度）でインストール可能なJavaScriptで書かれたクライントサイドプロキシのことで、ページ内で発生するHTTPリクエスト / レスポンスを監視したり、それを書き換えたり、必要に応じてリソースを先読みすることもできます。これとCache APIというHTTPリクエスト/ レスポンスオブジェクトをKey-Value形式で保存できるAPIを組み合わせることで、<strong>オフライン時でもあらかじめキャッシュしておいたレスポンスを利用すことができるようになるわけです。</strong></p>

<p><img src="/wp-content/uploads/2018/04/pwa05.png" alt="pwa05" /></p>

<p>このService WorkerとCache APIの組み合わせは<a href="https://developers.google.com/web/fundamentals/primers/service-workers/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">「Service Worker の紹介」</a>に記載の方法で使用することができますが、より汎用的な使い方をまとめた<a href="https://developers.google.com/web/tools/workbox/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Workbox</a>というライブラリを利用するのも1つの手です。Workbox を利用すると実装が煩雑になる、特定のファイルのラインタイムキャッシュも以下のようにシンプルに記述することができます。</p>

<p></p><pre class="crayon-plain-tag">workbox.routing.registerRoute(
  new RegExp('.*\.js'),
  workbox.strategies.networkFirst()
);</pre><p></p>

<p>Workboxはその他にも、<a href="https://developers.google.com/web/tools/workbox/modules/workbox-precaching" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ファイル単位でリビジョンを付与したPrecaching</a>、<a href="https://developers.google.com/web/tools/workbox/modules/workbox-cache-expiration" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Expirationの定義</a>や<a href="https://developers.google.com/web/tools/workbox/guides/enable-offline-analytics" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Background Syncを利用したオフライン時の Google Analytics の計測</a>などの機能も提供します。</p>

<p>オフラインの戦略はWebアプリの特性に応じて変わってくるものです。例えばニュースサイトであれば、トップページに出ている注目記事をすべて先読みし、オフラインでも読めるようにすることも考えられますし、ECサイトであればまた別の戦略が適している場合もあるでしょう。電波状況が比較的良好な日本においても、速度制限や電車内などオフライン（または不安定なネットワーク）になりえるユースケースは存在しますし、最低限でも <a href="https://www.google.co.jp/search?q=Offline+Dinosaur&amp;source=lnms&amp;tbm=isch&amp;sa=X&amp;ved=0ahUKEwiHmNqQ05vaAhUDOJQKHUkjBh0Q_AUICigB&amp;biw=1745&amp;bih=1003" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Offline Dinasour</a>はユーザーに見せないようにフォールバックページを用意すべきです。</p>

<h3>その他のWeb API</h3>

<p>以下にPWAを実装する上で注目すべきその他のWeb APIを列挙します。</p>

<ul>
<li><strong>プッシュ通知:</strong> <a href="https://developer.mozilla.org/en-US/docs/Web/API/Push_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Push API</a> / <a href="https://developer.mozilla.org/en-US/docs/Web/API/notification" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Notification API</a></li>
<li><strong>自動ログイン:</strong> <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">Credential Management API</a></li>
<li><strong>支払いフォームの強化:</strong> <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">Payment Request API</a></li>
</ul>

<p>上記のAPIも組み合わせることによって、リエンゲージメント性の向上や商品の購買フローを最適化することができます。</p>

<h2>クロスプラットフォームなイニシアチブ</h2>

<p>上記にあげたPWAで利用するWeb APIは、すべてのブラウザで利用できることを目標に標準化を進めています。個別の対応状況を確認するには<a href="https://caniuse.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Can I Use</a>をご参照いただければと思いますが、冒頭に述べましたとおりiOSでもiOS 11.3からSafariでService Workerが動作するようになりましたし、Microsoft はWindowsストアにPWAを載せはじめました[6]。このように、さまざまな形でPWAのクロスプラットフォーム利用の機運が高まっていると言えます。</p>

<p>また、PWAは<a href="https://en.wikipedia.org/wiki/Progressive_enhancement" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Progressive Enhancement</a>な実装を推奨している点も改めて触れておきます。たとえばService Workerを利用したオフラインキャッシュの実装は、Service Workerが未実装なブラウザでもWebアプリ本来の動作には影響がないように以下のように条件分岐をいれることを推奨しています。</p>

<p></p><pre class="crayon-plain-tag">// ServiceWorkerが利用できる場合にのみ
if ('serviceWorker' in navigator) {
  // ServiceWorkerを登録する
  navigator.serviceWorker.register('/sw.js')
}</pre><p></p>

<p>特定の環境のみでしか動かないWebアプリを作るのではなく、どの環境でもハイパフォーマンスに動作するようにし、最新のWeb APIが利用できる環境では進んでそれをレバレッジするとよいでしょう。</p>

<h2>Webアプリ vs ネイティブ アプリ</h2>

<p>PWAはその機能性や実現したいコンセプトから「PWAはネイティブ アプリを潰そうとしているのか？」「Webアプリがネイティブアプリにかなうはずない！」など当該テーマにおいては辛辣なコメントを見かける場面もあります。ここで1つお伝えしたいことは、多くのユーザーはネイティブアプリなのかWebアプリなのかというプラットフォームの選択には関心がないということです。大事なのは「うまい、やすい、はやい」ユーザー体験の良いサービスを提供することです。PWAの出現によりWebアプリでもそれを実現する準備が整いつつあり、<strong>事業者やソフトウェア エンジニアとしては理想のサービスを提供できるプラットフォームのオプションが増えるという意味で、このWebの進化を前向きに捉えていただければ幸いです。</strong></p>

<p>実際Webアプリにはまだできないこともあります[7]。ただし、Webアプリには他のプラットフォームよりも優れたリーチがあり、<strong>その意味でWeb アプリとネイティブ アプリがむしろ手を取ることは、戦略としても決して矛盾しません。</strong></p>

<p><img src="/wp-content/uploads/2018/04/pwa06.png" alt="pwa06" /></p>

<p>使用したい機能がWebプラットフォームが提供するもので十分であり、技術スタックをWebのみに集約するメリットも感じるのであれば「PWA のみ」という選択肢も今後は出てくるかと思います。しかし、前述した「まだできないこともある」という前提を加味するとネイティブアプリが活躍する場面は引き続きありますし、<strong>PWAは「Webアプリ vs ネイティブアプリ」という二者択一を迫る提案ではない点をご理解ください。</strong></p>

<h2>ユーザー体験の新たな基準</h2>

<p>このようにPWAはWebアプリの「ユーザー体験の新たな基準」を満たすために作られたベストプラクティスでしかありません。重要なのはそれぞれの機能を単純に実装するのではなく、Webアプリの特性に応じて使い分け、ときにはカスタマイズし、ユーザーによりよいサービスを提供することです。今回ご紹介しました各種ツールやデザインパターン、iOSでもService Workerが利用できるようになった点など、舞台は整いつつあります。<strong>ぜひとも最高のWeb体験を実現すべくPWAの考え方を取り入れてみてください。</strong></p>

<ul>
<li>[1] <a href="https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">The need for mobile speed: How mobile latency impacts publisher revenue</a></li>
<li>[2] <a href="https://developers.google.com/web/fundamentals/performance/rail" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">RAILモデルでパフォーマンスを計測する</a></li>
<li>[3] <a href="https://youtu.be/_srJ7eHS3IM" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Fast By Default: Modern Loading Best Practices (Chrome Dev Summit 2017)</a></li>
<li>[4] <a href="https://infrequently.org/2017/10/can-you-afford-it-real-world-web-performance-budgets/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Can You Afford It?: Real-world Web Performance Budgets</a></li>
<li>[5] <a href="https://support.google.com/adsense/answer/132618" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Above the fold</a></li>
<li>[6] <a href="https://www.windowscentral.com/first-batch-windows-10-progressive-web-apps-here" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">First Windows 10 Progressive Web Apps (PWA) published by Microsoft hit the Store</a></li>
<li>[7] <a href="https://whatwebcando.today/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">What Web Can Do Today</a></li>
</ul>
]]></content:encoded>
			</item>
		<item>
		<title>SkyWay ScreenShareを使ってWebRTCの画面共有機能を実装しよう</title>
		<link>/yusuke-naka/16445/</link>
		<pubDate>Fri, 28 Aug 2015 00:00:15 +0000</pubDate>
		<dc:creator><![CDATA[仲 裕介]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[SkyWay]]></category>
		<category><![CDATA[WebRTC]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=16445</guid>
		<description><![CDATA[連載： WebRTCプラットフォーム ”SkyWay” 入門 (4)連載4回目の今回は、7月28日にリリースされた、SkyWay ScreenShareのチュートリアルをお届けします。 SkyWay ScreenShar...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/skyway-tutorial/" class="series-314" title="WebRTCプラットフォーム ”SkyWay” 入門" data-wpel-link="internal">WebRTCプラットフォーム ”SkyWay” 入門</a> (4)</div><p>連載4回目の今回は、7月28日にリリースされた、<a href="https://github.com/nttcom/SkyWay-ScreenShare" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">SkyWay ScreenShare</a>のチュートリアルをお届けします。</p>

<p>SkyWay ScreenShareは、WebRTCのWebアプリケーションで画面共有を簡単に実装できるライブラリ、画面共有に必要なChrome・Firefox向けのExtensionが簡単に実装できるソースコードが含まれています。</p>

<h1>画面共有機能の概要</h1>

<p>WebRTCの画面共有機能は、ブラウザ画面やPCのデスクトップ画面をリアルタイムで相手に配信できる機能です。</p>

<div id="attachment_16475" style="width: 650px" class="wp-caption aligncenter"><a href="https://html5experts.jp/wp-content/uploads/2015/08/skyway_ss_sc1.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/08/skyway_ss_sc1-640x262.png" alt="Chromeでの画面共有の様子" width="640" height="262" class="size-large wp-image-16475" srcset="/wp-content/uploads/2015/08/skyway_ss_sc1.png 640w, /wp-content/uploads/2015/08/skyway_ss_sc1-300x123.png 300w, /wp-content/uploads/2015/08/skyway_ss_sc1-207x85.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a><p class="wp-caption-text">Chromeでの画面共有の様子</p></div>

<p>WebRTCの画面共有機能はChrome 34以上または、Firefox 33以上で利用可能です。</p>

<h4>Chromeでの実装</h4>

<p>画面共有機能は、Chrome 26で初めてブラウザに実装されました。当初は、Chromeの<code>chrome://flags</code>から<code>Enable screen capture support in getUserMedia()</code>というフラグをONにし、<code>getUserMedia()</code>のオプションを指定することで、実現できていました。しかし、セキュリティ上の問題からChrome 34でそのフラグが削除され、代わりにChrome Extensionをインストールするか、Chrome Appsからしか利用できなくなりました。</p>

<h4>Firefoxでの実装</h4>

<p>Firefoxについては、Firefox 33から画面共有機能が実装されています。Firefoxの場合は、Chromeとは方式が異なり、<code>about:config</code>の<code>media.getusermedia.screensharing.enabled</code>という設定を<code>true</code>に設定し、<code>media.getusermedia.screensharing.allowed_domains</code>という設定項目に、画面共有機能を許可するWebサイトのドメインを追加することで利用できるようになります。また、<code>media.getusermedia.screensharing.allowed_domains</code>には、Mozillaが許可したサービスのドメインが予め設定されています。こちらにドメインを追加してもらいたい場合は、<a href="https://wiki.mozilla.org/Screensharing" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">このサイト</a>の下部に掲載されているフォームから申請が可能です。（筆者は申請したことはありませんが、恐らく審査があると思われます）</p>

<h4>標準化の状況</h4>

<p>WebRTCのJavaScriptAPIの標準化はW3Cで行われています。この画面共有機能についても、今年の２月に仕様書が作られて標準化が進められています。仕様書は<a href="http://w3c.github.io/mediacapture-screen-share/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">「Screen Capture」</a>です。仕様書についての詳細な解説は割愛しますが、現在、ChromeとFirefoxで実装されている画面共有機能はブラウザベンダごとの独自実装であり、今後実装が変更になる可能性は高いと考えられます。</p>

<h1>SkyWay ScreenShareの使い方〜ビルド編〜</h1>

<p>ここからSkyWay ScreenShareの使い方を説明します。はじめに、<a href="https://github.com/nttcom/SkyWay-ScreenShare/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">github.com/nttcom/SkyWay-ScreenShare</a>からファイル一式をローカル環境にcloneして下さい。また、ここに書いている内容の詳細は<a href="https://github.com/nttcom/SkyWay-ScreenShare/blob/master/README_ja.md" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">README</a>にも掲載していますので、合わせてご覧ください。</p>

<h4>Chrome Extensionの作成</h4>

<p>まずはマニフェストファイルを修正します。JSONファイルのひな形にそって必要な項目を入力して下さい。アイコンファイルも必要です。</p>

<p></p><pre class="crayon-plain-tag">{
  "name": "Your extension name here",
  "short_name": "Your extension short_name here",
  "version": "Your extension version number here",
  "manifest_version": 2,
  "description": "Your extension description here",
  "icons": {
    "16": "icon16.png",
    "48": "icon48.png",
    "128": "icon128.png"
  },
  "permissions": [
    "desktopCapture",
    "tabs"
  ],
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "content_scripts": [{
    "matches": [""],
    "js": ["content.js"],
    "all_frames": true,
    "run_at": "document_end"
  }]
}</pre><p></p>

<p>尚、ここで重要なのは <code>matches</code>です。ここには、このExtensionのりようを許可するWebサイトのURLを記載します。必ずご自身のWebサイトのURLを指定して下さい。ワイルドカードを利用して複数のURLにマッチさせることも可能ですが、その場合は、あなたのExntensionを他のWebサイトで利用される可能性があります。セキュリティ上もよろしくありません。</p>

<p></p><pre class="crayon-plain-tag">例："matches": ["https://*.skyway.io/*"]</pre><p></p>

<p>次にビルドしましょう。SkyWay-ScreenShareではビルド用のgulpタスクとnpm-scriptでエイリアスコマンドを用意しています。SkyWay-ScreenShareディレクトリの直下で、次の２行のコマンドを実行します。npmコマンドは事前に使えるようにしておいて下さい。</p>

<p></p><pre class="crayon-plain-tag">npm install
npm run build-chrome</pre><p></p>

<p>ビルドが完了したら、出来上がったファイルをChromeに読み込ませましょう。<code>chrome://extensions/</code> にアクセスし、<code>デベロッパーモード</code>を有効にします。そして、<code>パッケージ化されていない拡張機能を読み込む</code>をクリックし、以下のディレクトリを指定します。</p>

<p></p><pre class="crayon-plain-tag">SkyWay-ScreenShare/chrome-extension/screenshare_chrome_extension/</pre><p></p>

<p>読み込むと以下のようになります。（この画像はChromeウェブストアからダウンロードしたものが写っています）</p>

<div id="attachment_16513" style="width: 650px" class="wp-caption aligncenter"><a href="https://html5experts.jp/wp-content/uploads/2015/08/skyway_ss_sc2.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/08/skyway_ss_sc2-640x386.png" alt="Chrome Extensionを読み込みます" width="640" height="386" class="size-large wp-image-16513" srcset="/wp-content/uploads/2015/08/skyway_ss_sc2.png 640w, /wp-content/uploads/2015/08/skyway_ss_sc2-300x181.png 300w, /wp-content/uploads/2015/08/skyway_ss_sc2-207x125.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a><p class="wp-caption-text">Chrome Extensionを読み込みます</p></div>

<p>また、ディレクトリと同一フォルダにある<code>screenshare_chrome_extension.zip</code>は、Chromeウェブストアにアップロードする際に利用できます。</p>

<p>これでChrome Extensionの作成は完了です。</p>

<h4>Firefox Extensionの作成</h4>

<p><small>（注意）SkyWay-ScreenShareのリポジトリには、「Firefox Add-On」という表記で記載しておりますが、画面共有機能を利用するために作成するモノは、Firefox Extension（拡張機能）となります。Add-OnはFirefoxの拡張機能やテーマ等全ての総称となるため、リポジトリの表記とは異なりますが、本記事中では、Firefox Extensionと表記を統一させて頂きます。</small></p>

<p>Firefox Extensionでは、メインプログラムとパッケージファイルの二つを修正します。まずは、メインプログラムです。</p>

<p></p><pre class="crayon-plain-tag">var pageMod = require('sdk/page-mod');
var self = require('sdk/self');
var __temp = require('chrome');
var Cc = __temp.Cc;
var Ci = __temp.Ci;

var domains_to_add = [''];
var addon_domains = [];
var allowed_domains_pref = 'media.getusermedia.screensharing.allowed_domains';
var enable_screensharing_pref = 'media.getusermedia.screensharing.enabled';

 ~~ 省略 ~~</pre><p></p>

<p>ここでは<code>domains_to_add = [''];</code>に、画面共有機能を有効にするWebサイトのドメインを指定して下さい。指定方法は以下のようになります。</p>

<p></p><pre class="crayon-plain-tag">例：domains_to_add = ['*.skyway.io']</pre><p></p>

<p>次にパッケージファイルを修正します。ここではExtensionの基本情報を入力していきます。ひな形にそって必要な情報を入力して下さい。アイコンファイルも必要です。</p>

<p></p><pre class="crayon-plain-tag">{
    "name": "your_add-on_name_here",
    "title": "Your add-on title here",
    "description": "Your add-on description here",
    "author": "Your add-on author here",
    "version": "Your add-on version number here",
    "license": "Your add-on license here",
    "homepage": "Your add-on homepage url here",
    "icon64": "icon64.png",
    "icon": "icon48.png"
}</pre><p></p>

<p>次にFirefox Extensionのビルドに必要なツール「cfx」をインストールします。インストール方法は<a href="https://dev.mozilla.jp/addon-sdk-docs/dev-guide/tutorials/installation.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">この</a>サイトを参考にして下さい。</p>

<p>ツールのインストールが完了したら、まずはプレビルド（pre build）を行います。ExtensionをビルドするためにはランダムなIDを予めパッケージファイルに記載しておく必要があるため、初回のプレビルドで、パッケージファイルにIDを挿入しています。</p>

<p></p><pre class="crayon-plain-tag">npm install
npm run pre-build-firefox</pre><p></p>

<p>初回のプレビルドでIDが挿入された場合、以下の様なエラーが発生します。これは問題ありません。</p>

<p></p><pre class="crayon-plain-tag">No 'id' in package.json: creating a new ID for you.
package.json modified: please re-run 'cfx xpi'</pre><p></p>

<p>再度以下の通り、ビルドを行って下さい。</p>

<p></p><pre class="crayon-plain-tag">npm run build-firefox</pre><p></p>

<p>ビルドが完了したら、Firefoxに読み込ませて動作確認を行いましょう。<code>about://addons</code>にアクセスし、作成したExtension本体である、<code>SkyWay-ScreenShare/firefox-addon/screenshare_firefox_addon.xpi</code>をドラッグ・アンド・ドロップさせます。</p>

<div id="attachment_16512" style="width: 650px" class="wp-caption aligncenter"><a href="https://html5experts.jp/wp-content/uploads/2015/08/skyway_ss_sc3.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/08/skyway_ss_sc3-640x484.png" alt="Firefox Extensionを読み込みます" width="640" height="484" class="size-large wp-image-16512" srcset="/wp-content/uploads/2015/08/skyway_ss_sc3.png 640w, /wp-content/uploads/2015/08/skyway_ss_sc3-300x227.png 300w, /wp-content/uploads/2015/08/skyway_ss_sc3-207x157.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a><p class="wp-caption-text">Firefox Extensionを読み込みます</p></div>

<p>Firefox Extensionの配布は、通常のWebサーバ上に上記xpiファイルを設置し行って下さい。</p>

<p>これでFirefox Extensionの作成は完了です。</p>

<h4>JavaScriptライブラリの作成</h4>

<p>SkyWay-ScreenShareには今まで作成したExtensionを利用するためのJavaScriptライブラリ「screenshare.js」が同梱されています。自分でビルドする場合は、以下のように行って下さい。</p>

<p></p><pre class="crayon-plain-tag">npm install
npm run build-library</pre><p></p>

<p>ビルドに成功すると、以下の通りライブラリが生成されます。</p>

<p></p><pre class="crayon-plain-tag">SkyWay-ScreenShare/dist/screenshare.js
SkyWay-ScreenShare/dist/screenshare.min.js</pre><p></p>

<p>また、ライブラリはCDNでも提供しています。</p>

<p></p><pre class="crayon-plain-tag">&lt;script src="https://skyway.io/dist/screenshare.js"&gt;&lt;/script&gt;
&lt;script src="https://skyway.io/dist/screenshare.min.js"&gt;&lt;/script&gt;</pre><p></p>

<p>最後に、ライブラリの修正や機能追加などは大歓迎です。TypeScriptのソースファイルを同梱していますので、その際はご利用下さい。Pull Reqestもお待ちしています！</p>

<h1>SkyWay ScreenShareの使い方〜アプリ開発編〜</h1>

<p>ExtensionとJavaScriptライブラリの準備ができたところで、同梱している<a href="https://github.com/nttcom/SkyWay-ScreenShare/blob/master/sample" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">サンプルアプリケーション</a>を例に、画面共有機能を使ったアプリの開発方法をご紹介します。</p>

<p>まず、newでオブジェクトを作成します。debugオプションを指定するとコンソールログにデバッグログが出力されます。</p>

<p></p><pre class="crayon-plain-tag">// スクリーンキャプチャの準備
var screen = new SkyWay.ScreenShare({debug: true});</pre><p></p>

<p>次に、<code>startScreenShare()メソッド</code>を利用して、画面共有機能を開始するためのコードを実装していきます。このメソッドの第一引数には、取得する映像の縦横サイズとフレームレートを指定します。第二引数のコールバック関数は、正しく取得できた場合に呼ばれ引数として<code>Stream Object</code>が返ってきます。これをVideo要素に入れてあげれば画面が表示されます。</p>

<p>また、第四引数についてはChromeのみ利用できるオプショナルなコールバック関数で、画面共有が何らかの方法で終了した場合に呼ばれます。Firefoxでは現状終了検知が出来ないため、Chrome限定です。</p>

<p><code>screen.isEnabledExtension()</code> はExtensionが利用しているブラウザで有効かどうか（インストール済みかどうかも含めて）を判定します。</p>

<p></p><pre class="crayon-plain-tag">// スクリーンシェアを開始
$('#start-screen').click(function () {
	if(screen.isEnabledExtension()){
			screen.startScreenShare({
					Width: $('#Width').val(),
					Height: $('#Height').val(),
					FrameRate: $('#FrameRate').val()
			},function (stream){
					$('#my-video').prop('src', URL.createObjectURL(stream));
					if(existingCall != null){
							var _peerid = existingCall.peer;
							existingCall.close();
							var call = peer.call(_peerid, stream);
							step3(call);
					}
					localStream = stream;

			},function(error){
					console.log(error);
			},function(){
					alert('ScreenShareを終了しました');
			});
	}else{
			alert('ExtensionまたはAddonをインストールして下さい');
	}

});</pre><p></p>

<p>次に、画面共有をプログラム側で終了させる場合のコードを実装していきます。現在は終了のための専用メソッドは用意していません。先ほど取得した<code>Stream Object</code>を保持しておき、終了したいタイミングで<code>stop()メソッド</code>を読んで下さい。これで、画面共有が止まります。いずれ、<code>Stream Object</code>の管理機能を実装する予定なので、その時には専用のメソッドを用意します。</p>

<p></p><pre class="crayon-plain-tag">// スクリーンシェアを終了
$('#stop-screen').click(function () {
	localStream.stop();
});</pre><p></p>

<p>アプリ開発方法の紹介は以上です。</p>

<h1>おわりに</h1>

<p>今回は、SkyWay-ScreenShareを使った、WebRTCの画面共有機能の実装方法をご紹介しました。画面共有機能は様々なユースケースで活用できる機能ですので、是非ご自身のアプリケーションに組み込んでみてください！</p>

<p>次回は、同じく7月28日にリリースされたSkyWay-DrivingVehicleについてのチュートリアルをお届けいたします。</p>
]]></content:encoded>
		
		<series:name><![CDATA[WebRTCプラットフォーム ”SkyWay” 入門]]></series:name>
	</item>
		<item>
		<title>SkyWay音声認識機能を使ってみよう！</title>
		<link>/iwase/16439/</link>
		<pubDate>Wed, 26 Aug 2015 00:00:22 +0000</pubDate>
		<dc:creator><![CDATA[岩瀬 義昌]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[SkyWay]]></category>
		<category><![CDATA[WebRTC]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=16439</guid>
		<description><![CDATA[連載： WebRTCプラットフォーム ”SkyWay” 入門 (3)連載3回目の今回は、SkyWayの付加機能としてリリースされているSkyWay音声認識機能の利用方法についてお届けいたします。SkyWay音声認識機能と...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/skyway-tutorial/" class="series-314" title="WebRTCプラットフォーム ”SkyWay” 入門" data-wpel-link="internal">WebRTCプラットフォーム ”SkyWay” 入門</a> (3)</div><p>連載3回目の今回は、SkyWayの付加機能としてリリースされているSkyWay音声認識機能の利用方法についてお届けいたします。SkyWay音声認識機能とは、クライアント（ブラウザ側）でマイク等を通じて入力した自由発話音声を、サーバ（SkyWay側）と連携して、文字列として受け取る機能のことです。いますぐ試してみたい方は、<a href="https://nttcom.github.io/SkyWay-SpeechRec/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">デモサイト</a>から試用可能です。(注：WebSocketが疎通する環境でないと、正常に動作しません)</p>

<p>同様の機能を実現するAPIとして、Speech Recognition APIがありますが、<a href="http://caniuse.com/#feat=speech-recognition" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">caniuse.com</a>でも示されるように対応するブラウザが限定されています。SkyWay音声認識機能では、標準では対応していないFirefox等のブラウザも対応可能です。</p>

<h2>準備</h2>

<p>以降で記載するサンプルコードの中で、SkyWayが提供しているAPIキーが必要となります。実際にお手元で試される場合は、<a href="http://nttcom.github.io/skyway/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">SkyWay公式サイト</a>から開発者登録を行ってください。本記事のサンプルで利用するには、利用可能ドメインに「localhost」と書いた、APIキーを取得する必要があります。</p>

<h2>今回作成するサンプル</h2>

<p>作成するサンプルは、「音声認識を開始するボタン」と「認識結果を表示するエリア」の2要素のみで構成するシンプルな音声認識アプリケーションです。</p>

<p>スクリーンショットはこちらです。</p>

<div id="attachment_16440" style="width: 583px" class="wp-caption alignnone"><a href="https://html5experts.jp/wp-content/uploads/2015/08/Screen-Shot-2015-08-11-at-11.40.08.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/08/Screen-Shot-2015-08-11-at-11.40.08.png" alt="SkyWay音声認識スクリーンショット" width="573" height="212" class="size-full wp-image-16440" srcset="/wp-content/uploads/2015/08/Screen-Shot-2015-08-11-at-11.40.08.png 573w, /wp-content/uploads/2015/08/Screen-Shot-2015-08-11-at-11.40.08-300x111.png 300w, /wp-content/uploads/2015/08/Screen-Shot-2015-08-11-at-11.40.08-207x77.png 207w" sizes="(max-width: 573px) 100vw, 573px" /></a><p class="wp-caption-text">SkyWay音声認識スクリーンショット</p></div>

<p>こちらを構成しているサンプルコードは以下の通りです。</p>

<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="ja"&gt;
&lt;head&gt;
	&lt;title&gt;SkyWay Speech Recognition Sample&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;!-- 音声認識開始用のボタン、および結果表示用のエリア --&gt;
&lt;button id="start_rec"&gt;start&lt;/button&gt;
&lt;div id="result"&gt;&lt;/div&gt;

&lt;!-- 必要なライブラリ群の読み込み  --&gt;
&lt;script src="https://code.jquery.com/jquery-1.11.3.min.js"&gt;&lt;/script&gt;
&lt;script src="https://skyway.io/dist/msgpack.codec.js"&gt;&lt;/script&gt;
&lt;script src="https://skyway.io/dist/libspeexdsp.js"&gt;&lt;/script&gt;
&lt;script src="https://skyway.io/dist/resampler.min.js"&gt;&lt;/script&gt;
&lt;script src="https://skyway.io/dist/speechrec.min.js"&gt;&lt;/script&gt;

&lt;!-- 音声認識用のコードサンプル --&gt;
&lt;script&gt;
SpeechRec.config({
   'SkyWayKey':'3969c30a-2789-4e46-9155-79a188256633',
   'OpusWorkerUrl':'libopus.worker.js'
});

$("#start_rec").click(function(){
	SpeechRec.start();
	console.log("音声認識を開始します");
});

SpeechRec.on_proc(function(info){
	console.log(info.volume);
});

SpeechRec.on_result(function(result){
    console.log(result.candidates);
    $("#result").text(result.candidates[0].speech);
});
&lt;/script&gt;

&lt;/body&gt;
&lt;/html&gt;</pre><p></p>

<p>上記HTMLを任意の名前で保存してください。本記事ではsample.htmlという名前で保存します。また、htmlを格納するディレクトリと同じ階層に</p>

<ul>
<li><a href="https://skyway.io/dist/libopus.js" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">libopus.js</a></li>
<li><a href="https://skyway.io/dist/libopus.worker.js" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">libopus.worker.js</a></li>
</ul>

<p>の2ファイルを保存して置いてください。音声認識に必要なライブラリとなります。　</p>

<h2>動かしてみよう</h2>

<p>既にApacheやNginxをインストールされている場合はそちらも活用できますが、今回はpythonからシンプルなWebサーバを起動してみます。コマンドは<code>python -m SimpleHTTPServer</code>です。</p>

<p>localhostの8000番でWebサーバが起動するので、<code>http://localhost:8000/sample.html</code>へ、Chrome/Firefox/Operaのいずれかでアクセスしてみましょう。画面が表示されたら、「start」ボタンをクリックすると、マイク使用許可確認のポップアップが表示されますので、Allow/許可を押下します。その後に自由に発話して、適当なタイミングで発話をやめてください。音声認識結果が上手くいくと、数秒以内に音声認識結果の文字列が表示されます。</p>

<h2>コードのポイント解説</h2>

<p>SkyWay音声認識機能を利用するためには、大きく分けて2つの処理が必要になります。</p>

<h3>1. コンフィグの設定・コールバックの設定</h3>

<p>まず<code>SpeechRec.config</code>関数を利用して、SkyWayKeyおよびlibopus.worker.jsへのパスを設定します。サンプルでは、以下のようにconfigを設定しています。</p>

<p></p><pre class="crayon-plain-tag">SpeechRec.config({
   'SkyWayKey':'3969c30a-2789-4e46-9155-79a188256633',
   'OpusWorkerUrl':'libopus.worker.js'
});</pre><p></p>

<p><code>SpeechRec.config</code>には、その他のパラメータも設定可能であり、<a href="https://github.com/nttcom/SkyWay-SpeechRec/blob/gh-pages/README.md#speechrecconfig" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ドキュメント</a>から確認できます。</p>

<p>次に各種コールバックの設定をします。サンプルでは2種類のコールバックを設定しています。</p>

<p></p><pre class="crayon-plain-tag">SpeechRec.on_proc(function(info){
	console.log(info.volume);
});

SpeechRec.on_result(function(result){
    console.log(result.candidates);
    $("#result").text(result.candidates[0].speech);
});</pre><p></p>

<p>1つ目の<code>on_proc</code>は、発話時の音声ボリュームを取得できた場合に発火するコールバック関数です。サンプルでは、コンソール画面に音量を表示するようにしています。</p>

<p>2つ目の<code>on_result</code>は、音声認識結果を取得できた場合に発火するコールバック関数です。サンプルでは、結果をコンソール画面に表示する処理、および<code>#result</code>で指定されるdivエリアに、音声認識結果を書き込む処理をしています。</p>

<p>サンプルでは分かりやすいように、コールバックを2つのみしか設定していませんが、実際にはさらに多くのコールバックを設定可能です。詳細は<a href="https://github.com/nttcom/SkyWay-SpeechRec/blob/gh-pages/README.md#コールバック関数一覧" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">コールバック関数一覧</a>をご確認ください。</p>

<h3>2. 開始・停止の実行</h3>

<p>コンフィグおよびコールバックの設定が完了したら、実際に音声認識を開始・停止するための関数を呼び出します。サンプルでは、<code>#start_rec</code>ボタンがクリックされた際に呼び出す<code>SpeechRec.start</code>が、音声認識を開始するための処理に該当します。</p>

<p></p><pre class="crayon-plain-tag">$("#start_rec").click(function(){
	SpeechRec.start();
	console.log("音声認識を開始します");
});</pre><p></p>

<p>なお、開始だけではなく任意のタイミングで音声認識を終了させる<code>SpeechRec.stop</code>等もあります(サンプルでは省略)。その他の関数は<a href="https://github.com/nttcom/SkyWay-SpeechRec#音声認識制御用関数の一覧" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ドキュメント</a>から確認いただけます。</p>

<h2>おわりに</h2>

<p>いかがでしたでしょうか。今回はSkyWayの付加機能である、音声認識機能について解説いたしました。</p>

<p>次回は画面共有を簡単に実現するSkyWayScreenShareライブラリについてお届けします。</p>
]]></content:encoded>
		
		<series:name><![CDATA[WebRTCプラットフォーム ”SkyWay” 入門]]></series:name>
	</item>
		<item>
		<title>SkyWay MultiPartyを使ってグループチャットを作ろう</title>
		<link>/sakkuru/16397/</link>
		<pubDate>Mon, 24 Aug 2015 00:00:21 +0000</pubDate>
		<dc:creator><![CDATA[本間 咲来]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[SkyWay]]></category>
		<category><![CDATA[WebRTC]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=16397</guid>
		<description><![CDATA[連載： WebRTCプラットフォーム ”SkyWay” 入門 (2)連載2回目の今回は、7月28日にリリースされたライブラリ、SkyWay MultiPartyのチュートリアルをお届けします。 SkyWay MultiP...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/skyway-tutorial/" class="series-314" title="WebRTCプラットフォーム ”SkyWay” 入門" data-wpel-link="internal">WebRTCプラットフォーム ”SkyWay” 入門</a> (2)</div><p>連載2回目の今回は、7月28日にリリースされたライブラリ、SkyWay MultiPartyのチュートリアルをお届けします。
SkyWay MultiPartyは、一言で言うと多人数によるビデオ・テキストチャットを『簡単に』作るためのライブラリです。</p>

<p>本ライブラリを使用することで、グループビデオチャットやテキストチャットを、
ほんの20行程度のJavaScriptコードで実装をすることができます。</p>

<p>サンプルコードを用意していますので、手元で実行しながら進めてみましょう。</p>

<h2>10行ビデオチャット</h2>

<p>以下のスクリーンショットをご覧ください。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/08/video-top.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/08/video-top-640x464.png" alt="videoチャットサンプル" width="640" height="464" class="alignnone size-large wp-image-16407" srcset="/wp-content/uploads/2015/08/video-top.png 640w, /wp-content/uploads/2015/08/video-top-300x218.png 300w, /wp-content/uploads/2015/08/video-top-207x150.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>まずはこのような複数人が参加できるビデオチャットシステムを、10行程度のJavaScriptコードで実装してみましょう。
サンプルコードを以下に記載します。</p>

<p></p><pre class="crayon-plain-tag">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;script src="https://code.jquery.com/jquery-1.11.3.min.js"&gt;&lt;/script&gt;
  &lt;script src="https://skyway.io/dist/0.3/peer.min.js"&gt;&lt;/script&gt;
  &lt;script src="https://skyway.io/dist/multiparty.min.js"&gt;&lt;/script&gt;
  
  &lt;style&gt; video { width:200px; } &lt;/style&gt;

&lt;/head&gt;
&lt;body&gt;

  &lt;div id="streams"&gt;&lt;/div&gt;

&lt;script&gt;

  // MultiParty インスタンスを生成
  multiparty = new MultiParty( {
    "key": "********-****-****-****-************"  /* SkyWay keyを指定 */
  });

  multiparty.on('my_ms', function(video) {
    // 自分のvideoを表示
    var vNode = MultiParty.util.createVideoNode(video);
    $(vNode).appendTo("#streams");
  }).on('peer_ms', function(video) {
    // peerのvideoを表示
    var vNode = MultiParty.util.createVideoNode(video);
    $(vNode).appendTo("#streams");
  }).on('ms_close', function(peer_id) {
    // peerが切れたら、対象のvideoノードを削除する
    $("#"+peer_id).remove();
  });

  // サーバとpeerに接続
  multiparty.start()

&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre><p></p>

<p>早速動かしてみましょう。</p>

<p>上のコードを、<code>videochat.html</code>という名前で保存します。</p>

<p>19行目でSkyWayのAPIキーが必要となりますので、使用する際は<a href="http://nttcom.github.io/skyway/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">SkyWay</a>から開発者登録を行ってください。
本サンプルで使用するには、利用可能ドメインに『localhost』と書いて、APIキーを取得する必要があります。</p>

<p>PCにApacheやNginxなどのサーバがインストールされている場合は、そちらで動かしても問題ありませんが、
入っていない場合は、以下の様にPythonのコマンドでWebサーバを起動できます。</p>

<p></p><pre class="crayon-plain-tag">python -m SimpleHTTPServer</pre><p></p>

<p>localhostの8000番ポートでWebサーバが起動するので、Chrome、Firefox、Operaのいずれかのブラウザでアクセスしてみましょう。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/08/video1.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/08/video1-640x464.png" alt="videoチャットサンプル" width="640" height="464" class="alignnone size-large wp-image-16406" srcset="/wp-content/uploads/2015/08/video1.png 640w, /wp-content/uploads/2015/08/video1-300x218.png 300w, /wp-content/uploads/2015/08/video1-207x150.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>次に別のタブやブラウザで、もう2、3個同じページを開いてみます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/08/video-all.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/08/video-all-640x309.png" alt="複数人のグループvideoチャット" width="640" height="309" class="alignnone size-large wp-image-16404" srcset="/wp-content/uploads/2015/08/video-all.png 640w, /wp-content/uploads/2015/08/video-all-300x145.png 300w, /wp-content/uploads/2015/08/video-all-207x100.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>複数人参加のビデオチャットが実装できていることがわかります。</p>

<h2>ビデオチャットのコード</h2>

<p>それではコードを見てみましょう。</p>

<p>今回はjQueryを使用するので、4行目でjQueryを読み込んでいます。
(SkyWay MultiPartyを使用するのにjQueryが必須というわけではありません)
5行目と6行目で、SkyWayライブラリ(peer.min.js)とSkyWay MultiPartyライブラリ(multiparty.min.js)を読み込んでいます。
13行目で、ビデオを表示するためのdivを1つ用意しています。</p>

<p>18〜33行目がJavaScriptコードです。大きくMultiPartyオブジェクトの生成部分と、イベントハンドラ部分に分かれています。</p>

<p>SkyWay MultiPartyでは、最初にコンストラクタを呼ぶことで MultiPartyオブジェクトを生成します。引数にはAPIキーが必要となります。</p>

<p></p><pre class="crayon-plain-tag">// MultiParty インスタンスを生成
  multiparty = new MultiParty( {
    "key": "********-****-****-****-************"  /* SkyWay keyを指定 */
  });</pre><p></p>

<p>続くコードがmultipartyオブジェクトのイベントハンドラになります。</p>

<p></p><pre class="crayon-plain-tag">multiparty.on('my_ms', function(video) {
    // 自分のvideoを表示
    var vNode = MultiParty.util.createVideoNode(video);
    $(vNode).appendTo("#streams");

  }).on('peer_ms', function(video) {
    // peerのvideoを表示
    var vNode = MultiParty.util.createVideoNode(video);
    $(vNode).appendTo("#streams");

  }).on('ms_close', function(peer_id) {
    // peerが切れたら、対象のvideoノードを削除する
    $("#"+peer_id).remove();
  });</pre><p></p>

<p>SkyWay MultiPartyでは、</p>

<p></p><pre class="crayon-plain-tag">multiparty.on('イベント名', コールバック関数)</pre><p></p>

<p>の形式で、イベントハンドラを設定することができます。</p>

<p>サンプルでは3つのイベントに対し、ハンドラを定義していることがわかります。</p>

<p>1つ目が<code>'my_ms'</code>で、これは自分のメディアストリームの準備が整った際に発生するイベントです。メディアストリームとは取得した映像や音声を扱うためのオブジェクトで、例えばPCのカメラやマイクから取得した映像・音声がこれにあたります。
コールバックとして呼ばれる関数には、メディアストリームから生成したオブジェクトURLとidがオブジェクトとして渡されます。
ライブラリにはそのオブジェクトからvideoノードを生成するユーティリティが用意されていますので、それを使用しvideoノードを生成・表示しています。</p>

<p>2つ目は、<code>'peer_ms'</code>というイベントに対するコールバックで、これはチャットの相手(peer)のメディアストリームを取得する準備が整った際に発生するイベントです。
こちらも自分のメディアストリームと場合と同様、videoノードを生成・表示しています。</p>

<p>3つ目のイベントは<code>'ms_close'</code>で、peerのメディアストリームの切断を検知した際に発生します。
このコールバックでは、peerのvideoノードを削除する処理を書いています。</p>

<p>以上で、ビデオチャット機能を実装することができました。</p>

<h2>10行テキストチャット</h2>

<p>続いてテキストチャット機能も実装してみましょう。</p>

<p>まず、テキストの入力と表示を行うためのHTML要素を追加します。
以下のコードを『&lt;div id=&quot;streams&quot;&gt;&lt;/div&gt;』の下に追加してみましょう。</p>

<p></p><pre class="crayon-plain-tag">&lt;div&gt;
    &lt;form&gt;
      &lt;input type="text"&gt;&lt;button type="submit"&gt;send&lt;/button&gt;
    &lt;/form&gt;
    &lt;div id="message"&gt;&lt;/div&gt;
  &lt;/div&gt;</pre><p></p>

<p>次に、以下のJavaScriptコードを、『&lt;/script&gt;』の前に追加します。</p>

<p></p><pre class="crayon-plain-tag">//テキストを入力し、submitしたとき
  $("form").on("submit", function(ev) {

    //onsubmitのデフォルト動作（reload）を抑制
    ev.preventDefault();

    //テキストを取得
    var $input = $(this).find("input[type=text]"); 
    var data = $input.val();
    $input.val("");

    //テキストを表示
    $("#message").append(data + "&lt;br&gt;");

    //peerにメッセージを送信
    multiparty.send(data);

  });

  // peerからテキストメッセージを受信したとき
  multiparty.on('message', function(mesg) {
    $("#message").append(mesg.data + "&lt;br&gt;");
  });</pre><p></p>

<p>それでは先ほどのページをリロードしてみましょう。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/08/text11.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/08/text11-640x536.png" alt="textチャットサンプル" width="640" height="536" class="alignnone size-large wp-image-16416" srcset="/wp-content/uploads/2015/08/text11.png 640w, /wp-content/uploads/2015/08/text11-300x251.png 300w, /wp-content/uploads/2015/08/text11-207x173.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>入力フォームが追加されたことがわかります。
文字を入力し、エンターキーを押すと、そのテキストが表示されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/08/text-all.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/08/text-all-640x382.png" alt="複数人のグループチャット" width="640" height="382" class="alignnone size-large wp-image-16403" srcset="/wp-content/uploads/2015/08/text-all.png 640w, /wp-content/uploads/2015/08/text-all-300x179.png 300w, /wp-content/uploads/2015/08/text-all-207x124.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>他のタブや、ブラウザから入力したテキストも表示できることが確認できます。</p>

<h2>テキストチャットのコード</h2>

<p>それではコードを見てみましょう。
テキストチャットのコードは、データを送信する際の処理と、データを受信する際の処理に分かれています。</p>

<p>以下のコードで、テキストが入力され、送信されるまでの処理を記述しています。</p>

<p></p><pre class="crayon-plain-tag">//テキストを入力し、submitしたとき
$("form").on("submit", function(ev) {

  //onsubmitのデフォルト動作（reload）を抑制
  ev.preventDefault();

  //テキストを取得
  var $input = $(this).find("input[type=text]"); 
  var data = $input.val();
  $input.val("");

  //テキストを表示
  $("#message").append(data + "&lt;br&gt;");

  //peerにメッセージを送信
  multiparty.send(data);

});</pre><p></p>

<p>multiparty.send()で、テキストをそのまま送信していることがわかります。</p>

<p>そして以下の部分で、メッセージを受信した際に発生するイベント<code>'message'</code>に対する、コールバックを設定しています。</p>

<p></p><pre class="crayon-plain-tag">// peerからテキストメッセージを受信したとき
multiparty.on('message', function(mesg) {
  $("#message").append(mesg.data + "&lt;br&gt;");
});</pre><p></p>

<p>簡易ではありますが、テキストチャットを実現することができました。</p>

<h3>おわりに</h3>

<p>今回は、SkyWay MultiPartyを使ったビデオ・テキストチャットの作り方をお届けしました。
少しのコードで簡単に実装できることがお分かりいただけたかと思います。</p>

<p>次回は、同じく7月28日にリリースされたSkyWay音声認識APIについてのチュートリアルをお届けいたします。</p>
]]></content:encoded>
		
		<series:name><![CDATA[WebRTCプラットフォーム ”SkyWay” 入門]]></series:name>
	</item>
		<item>
		<title>ビデオチャット＆テキストチャット作成チュートリアル！WebRTCを簡単＆柔軟に使える「SkyWay」を使ってみよう</title>
		<link>/katsura/16331/</link>
		<pubDate>Thu, 06 Aug 2015 00:00:06 +0000</pubDate>
		<dc:creator><![CDATA[桂健太]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[システム開発]]></category>
		<category><![CDATA[SkyWay]]></category>
		<category><![CDATA[WebRTC]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=16331</guid>
		<description><![CDATA[連載： WebRTCプラットフォーム ”SkyWay” 入門 (1)WebRTCを簡単に利用するためのプラットフォームSkyWayをご存知ですか？本連載では、WebRTCを簡単に利用するためのプラットフォームSkyWay...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/skyway-tutorial/" class="series-314" title="WebRTCプラットフォーム ”SkyWay” 入門" data-wpel-link="internal">WebRTCプラットフォーム ”SkyWay” 入門</a> (1)</div><p>WebRTCを簡単に利用するためのプラットフォームSkyWayをご存知ですか？本連載では、WebRTCを簡単に利用するためのプラットフォームSkyWayについて、基本的なチュートリアルから、各種ライブラリの紹介までしていきます。</p>

<p>連載第1回目である今回は、まず、WebRTCの基本的な説明をした後に、実際にSkyWayを使って、ビデオチャットの作成とデータチャンネルを使ったチャットの作成をしていきます。</p>

<h2>WebRTCとは</h2>

<p>WebRTCとは、ブラウザやアプリ間でビデオや音声、データのやり取りをP2P(Peer to Peer)で行うことを可能にする規格です。
従来のビデオチャットは互換性のない独自技術で実装されていましたが、WebRTCはオープン標準として仕様が作成・公開されており、相互接続が保証されています。</p>

<p>また、ブラウザで動作することから特別なアプリケーションをインストールする必要がありませんし、すでにあるウェブアプリケーションに埋め込むことで、シームレスにビデオチャットを動かすこともできます。さらに、オープンソースのコードを利用することで、ブラウザだけに限らず、ネイティブアプリにWebRTCを組み込むことも可能です。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/07/image_webrtc.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/image_webrtc.png" alt="image_webrtc" width="640" height="193" class="alignnone size-full wp-image-16352" srcset="/wp-content/uploads/2015/07/image_webrtc.png 640w, /wp-content/uploads/2015/07/image_webrtc-300x90.png 300w, /wp-content/uploads/2015/07/image_webrtc-207x62.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<h2>WebRTCの仕組み</h2>

<p>WebRTCはビデオ等のデータをP2Pでやり取りすることが出来ますが、実際にブラウザ間で直接接続をするためには、まず、互いに自分のIPアドレス／ポート番号等の情報を教え合わなければなりません。一般的に、この情報交換を行うためにシグナリングサーバというサーバを用意する必要があります。
<div id="attachment_16353" style="width: 650px" class="wp-caption alignnone"><a href="https://html5experts.jp/wp-content/uploads/2015/07/skyway_signaling.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/skyway_signaling-640x226.png" alt="交換する情報はIPアドレス、ポート番号以外にもいくつかあります。" width="640" height="226" class="size-large wp-image-16353" srcset="/wp-content/uploads/2015/07/skyway_signaling.png 640w, /wp-content/uploads/2015/07/skyway_signaling-300x106.png 300w, /wp-content/uploads/2015/07/skyway_signaling-207x73.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a><p class="wp-caption-text">※交換する情報はIPアドレス、ポート番号以外にもいくつかあります。</p></div></p>

<p>また、お互いがNATの内側に存在する場合やFirewallの内側にいる場合、シグナリングサーバだけでは接続することができません。そのために利用するのが、STUN／TURNサーバです。ここでは具体的な説明は省略しますが、作成したアプリケーションをユーザに広く使ってもらうためには、これらのサーバも用意する必要があります。</p>

<p>(詳細を知りたい方は、がねこまさしさんが書かれたコチラの記事をお読みください: <a href="https://html5experts.jp/mganeko/5554/" target="_blank" data-wpel-link="internal">壁を越えろ！WebRTCでNAT/Firewallを越えて通信しよう</a>)</p>

<h2>SkyWayとは</h2>

<p>今までの説明を見てWebRTCは「大変そうだ」と思った方は多いと思います。実際、シグナリングサーバやSTUN/TURNサーバを用意するのは容易ではないです。</p>

<p>そこで登場するのがWebRTC開発者向けプラットフォーム「SkyWay」です。SkyWayは、以下の図で示す通り、複雑なシグナリング処理を担うAPI郡とJavascriptライブラリ／Android,iOSライブラリ、STUN/TURNサーバで構成されています。</p>

<p>このSkyWayを利用することで、シグナリングサーバやSTUN/TURNサーバを独自に用意する必要はなく、開発者はP2P通信部分のプログラミングにのみ集中することができます。</p>

<h2>利用者登録が必要です</h2>

<p>SkyWayは現在トライアルサービス中で、誰でも無料で使うことができます。さっそくウェブサイトから利用者登録をしてみましょう。</p>

<p><a href="http://skyway.io/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">http://skyway.io/</a></p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/07/ss01.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/ss01.png" alt="ss01" width="640" height="445" class="alignnone size-full wp-image-16355" srcset="/wp-content/uploads/2015/07/ss01.png 640w, /wp-content/uploads/2015/07/ss01-300x209.png 300w, /wp-content/uploads/2015/07/ss01-207x144.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>「登録を行う」ボタンをクリックして、開発者登録画面に向かいます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/07/ss02.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/ss02.png" alt="ss02" width="640" height="445" class="alignnone size-full wp-image-16356" srcset="/wp-content/uploads/2015/07/ss02.png 640w, /wp-content/uploads/2015/07/ss02-300x209.png 300w, /wp-content/uploads/2015/07/ss02-207x144.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>必要事項を入力します。ここで入力するドメイン名は、セキュリティ向上を目的として行っているOriginチェックのために必要となっています。ここの<b>ドメイン名は開発者登録後に変更可能</b>ですので、まずは「localhost」とだけ入力しておいてください。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/07/ss03.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/ss03.png" alt="ss03" width="640" height="445" class="alignnone size-full wp-image-16357" srcset="/wp-content/uploads/2015/07/ss03.png 640w, /wp-content/uploads/2015/07/ss03-300x209.png 300w, /wp-content/uploads/2015/07/ss03-207x144.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>登録が正常に完了したら、ログインページへ行き、ログインしてください。ログインが完了すると以下の画面のような開発者ダッシュボードが表示されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/07/ss04.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/ss04-640x445.png" alt="ss04" width="640" height="445" class="alignnone size-large wp-image-16358" srcset="/wp-content/uploads/2015/07/ss04.png 640w, /wp-content/uploads/2015/07/ss04-300x209.png 300w, /wp-content/uploads/2015/07/ss04-207x144.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>右に表示されいるのがAPIキーです（上図ではマスクしています）。こちらをJavaScriptやiOS/Androidのコード内に埋め込み、SkyWayのAPIにアクセスします。</p>

<p>ちなみに、設定変更ボタンをクリックすると、利用ドメインの編集やRestAPIの有効無効の切り替え、そしてAPIキーの削除が可能です。</p>

<p>これでSkyWayを利用するための準備が整いました。早速ビデオチャットを実装してみましょう。</p>

<h2>簡易ビデオチャットの作成と実行</h2>

<p>まず、ビデオチャットを実装するにあたり、以下の環境をご用意ください。</p>

<ul>
<li>Chorme, Firefox, Operaのいずれかのブラウザ</li>
<li>カメラ／マイク （PCに接続可能なもの）</li>
</ul>

<p>まずは以下の内容で、HTMLを書きます。適当なフォルダに「videochat.html」というファイル名でHTMLファイルを作成してください。</p>

<p></p><pre class="crayon-plain-tag"><html>
<head>
    <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
    <script type="text/javascript" src="https://skyway.io/dist/v2/0.3/peer.js"></script>
    <script type="text/javascript" src="videochat.js"></script>
</head>
<body>
    <h1>Simple Video Chat</h1>
    <div>
        <video id="my-video" style="width: 300px;" autoplay></video>
        <video id="peer-video" style="width: 300px;" autoplay></video>
    </div>
    <div>
        <p>MyID: <span id="my-id">-</span></p>
        <p>PeerID: <span id="peer-id">-</span></p>
    </div>
    <div>
        <input type="text" placeholder="PeerID" id="peer-id-input">
        <button id="call-start">Start Call</button>
        <button id="call-end">End Call</button>
    </div>
</body>
</html></pre><p></p>

<p>HEADタグ内で、jQueryとSkyWayライブラリ、そして今回作成するビデオチャット用のJavaScriptを読み込んでいます。jQueryはボタンクリック時のイベントを設定するときに使用します。SkyWayライブラリは今まで説明してきたとおり、シグナリング部分の処理を全部行ってくれるライブラリです。</p>

<p>次にJavaScriptのコードを書きます。先ほどのHTMLと同じフォルダに、「videochat.js」というファイル名でJavaScriptのファイルを作成してください。ここで、APIキーは先ほど入手したものに置き変えて入力してください。</p>

<p></p><pre class="crayon-plain-tag">// カメラ／マイクにアクセスするためのメソッドを取得しておく
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;

var localStream;    // 自分の映像ストリームを保存しておく変数
var connectedCall;  // 接続したコールを保存しておく変数

// SkyWayのシグナリングサーバーへ接続する (APIキーを置き換える必要あり）
var peer = new Peer({ key: 'YourApiKey', debug: 3});

// シグナリングサーバへの接続が確立したときに、このopenイベントが呼ばれる
peer.on('open', function(){
    // 自分のIDを表示する
    // - 自分のIDはpeerオブジェクトのidプロパティに存在する
    // - 相手はこのIDを指定することで、通話を開始することができる
    $('#my-id').text(peer.id);
});

// 相手からビデオ通話がかかってきた場合、このcallイベントが呼ばれる
// - 渡されるcallオブジェクトを操作することで、ビデオ映像を送受信できる
peer.on('call', function(call){
  　
    // 切断時に利用するため、コールオブジェクトを保存しておく
    connectedCall = call;

    // 相手のIDを表示する
    // - 相手のIDはCallオブジェクトのpeerプロパティに存在する
    $("#peer-id").text(call.peer);

    // 自分の映像ストリームを相手に渡す
    // - getUserMediaで取得したストリームオブジェクトを指定する
    call.answer(localStream);

    // 相手のストリームが渡された場合、このstreamイベントが呼ばれる
    // - 渡されるstreamオブジェクトは相手の映像についてのストリームオブジェクト
    call.on('stream', function(stream){

        // 映像ストリームオブジェクトをURLに変換する
        // - video要素に表示できる形にするため変換している
        var url = URL.createObjectURL(stream);

        // video要素のsrcに設定することで、映像を表示する
        $('#peer-video').prop('src', url);
    });
});

// DOM要素の構築が終わった場合に呼ばれるイベント
// - DOM要素に結びつく設定はこの中で行なう
$(function() {

    // カメラ／マイクのストリームを取得する
    // - 取得が完了したら、第二引数のFunctionが呼ばれる。呼び出し時の引数は自身の映像ストリーム
    // - 取得に失敗した場合、第三引数のFunctionが呼ばれる
    navigator.getUserMedia({audio: true, video: true}, function(stream){

        // このストリームを通話がかかってき場合と、通話をかける場合に利用するため、保存しておく
        localStream = stream;

        // 映像ストリームオブジェクトをURLに変換する
        // - video要素に表示できる形にするため変換している
        var url = URL.createObjectURL(stream);

        // video要素のsrcに設定することで、映像を表示する
        $('#my-video').prop('src', url);

    }, function() { alert("Error!"); });

    // Start Callボタンクリック時の動作
    $('#call-start').click(function(){

        // 接続先のIDをフォームから取得する
        var peer_id = $('#peer-id-input').val();

        // 相手と通話を開始して、自分のストリームを渡す
        var call = peer.call(peer_id, localStream);
            
        // 相手のストリームが渡された場合、このstreamイベントが呼ばれる
        // - 渡されるstreamオブジェクトは相手の映像についてのストリームオブジェクト
        call.on('stream', function(stream){
            // 相手のIDを表示する
            $("#peer-id").text(call.peer);

            // 映像ストリームオブジェクトをURLに変換する
            // - video要素に表示できる形にするため変換している
            var url = URL.createObjectURL(stream);

            // video要素のsrcに設定することで、映像を表示する
            $('#peer-video').prop('src', url);
        });
    });

    // End　Callボタンクリック時の動作
    $('#call-end').click(function(){
        // ビデオ通話を終了する
        connectedCall.close();
    });
});</pre><p></p>

<p>これらはローカルのファイルとして開いても動作しません。ローカルPC上にサーバを立ててファイルをホスティングしてあげる必要があります。このためだけにローカルPCにApacheやNginxを入れるのもの大変なので、今回はPHP付属のビルトインサーバを利用します。
ターミナルを開いて次のコマンドを入力してください (要PHP5.4.0以上)</p>

<p></p><pre class="crayon-plain-tag">$ cd {HTML/Javascriptのあるフォルダ}
$ php -S localhost:8888</pre><p></p>

<p>これで準備が全て整いました。早速ブラウザで開いてみましょう。WebRTCは現在のところChrome, Firefox, Operaでしか動作しないため、それらのブラウザを利用する必要があります。また現在も開発が続けられている分野ですので、最新バージョンを利用するのが望ましいです。</p>

<p>今回は、ビデオ通話を開始する側と受ける側の両方を自分で試してみます。ですので、以下のURLを2つのウィンドウ（またはタブ）で開いてみてください。</p>

<p><a href="http://localhost:8888/videochat.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">http://localhost:8888/videochat.html</a></p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/07/ss05.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/ss05.png" alt="ss05" width="640" height="445" class="alignnone size-full wp-image-16359" srcset="/wp-content/uploads/2015/07/ss05.png 640w, /wp-content/uploads/2015/07/ss05-300x209.png 300w, /wp-content/uploads/2015/07/ss05-207x144.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>無事に表示されたでしょうか？</p>

<p>アクセス時に、カメラとマイクへのアクセスについて許可を求められるので、許可しておきましょう。許可すると、カメラ映像が画面左に表示されます。</p>

<p>それでは、早速通話を開始してみたいと思います。まず、接続相手のIDを渡す必要があります。ビデオ通話を受ける側のIDをコピーして、かける側のテキストボックスに貼り付けてください。相手のIDをちゃんと貼り付けることができたなら、隣の「Start Call」を押します。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/07/ss06.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/ss06.png" alt="ss06" width="640" height="445" class="alignnone size-full wp-image-16360" srcset="/wp-content/uploads/2015/07/ss06.png 640w, /wp-content/uploads/2015/07/ss06-300x209.png 300w, /wp-content/uploads/2015/07/ss06-207x144.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>2つの映像が表示されれば成功です。</p>

<p>以上が簡単なビデオチャットのチュートリアルでした。非同期処理が中心でかつ、通話を開始する側と受ける側の両方の処理を書く必要があるため、慣れるまでコードの理解が難しいですが、ここさえ乗り越えればスムーズにコードを書くことができますので、少しづつ理解してみてください。</p>

<h2>データ通信を使った文字ベースチャット</h2>

<p>続いてWebRTCを用いたデータ通信を使ったチャットアプリを作ってみたいと思います。既にビデオチャットを理解できていれば、全く難しいことはありません。</p>

<p>先ほどと同様に、以下の内容で、HTMLを書きます。適当なフォルダに「datachat.html」というファイル名でHTMLファイルを作成してください。</p>

<p></p><pre class="crayon-plain-tag"><html>
<head>
    <script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
    <script type="text/javascript" src="https://skyway.io/dist/v2/0.3/peer.js"></script>
    <script type="text/javascript" src="datachat.js"></script>
</head>
<body>
    <h1>Chat</h1>
    <div>
        <input type="text" placeholder="PeerID" id="peer-id-input">
        <button id="connect">Connect</button>
        <button id="close">Close</button>
    </div>
    <div>
        <p>MyID: <span id="my-id">-</span></p>
        <p>PeerID: <span id="peer-id">-</span></p>
    </div>
    <hr>
    <div>
        <input type="text" placeholder="Chat Message" id="message">
        <button id="send">Send</button>
    </div>
    <div id="messages"></div>
</body>
</html></pre><p></p>

<p>次はJavaScriptです。先ほどのHTMLと同じフォルダに「datachat.js」というファイル名でJavaScriptのファイルを作成してください。
APIキーについてもビデオ通話と同様に、先ほど入手したものに置き変えてください。</p>

<p></p><pre class="crayon-plain-tag">var conn;     // データ通信用connectionオブジェクトの保存用変数 

// SkyWayのシグナリングサーバーへ接続する  (APIキーを置き換える必要あり）
var peer = new Peer({ key: 'YourApiKey', debug: 3});

// シグナリングサーバへの接続が確立したときに、このopenイベントが呼ばれる
peer.on('open', function(){
    // 自分のIDを表示する
    // - 自分のIDはpeerオブジェクトのidプロパティに存在する
    // - 相手はこのIDを指定することで、通信を開始することが出来る
    $('#my-id').text(peer.id);
});
 
// 相手からデータ通信の接続要求イベントが来た場合、このconnectionイベントが呼ばれる
// - 渡されるconnectionオブジェクトを操作することで、データ通信が可能
peer.on('connection', function(connection){
  　
    // データ通信用に connectionオブジェクトを保存しておく
    conn = connection;

    // 接続が完了した場合のイベントの設定
    conn.on("open", function() {
        // 相手のIDを表示する
        // - 相手のIDはconnectionオブジェクトのidプロパティに存在する
        $("#peer-id").text(conn.id);
    });

    // メッセージ受信イベントの設定
    conn.on("data", onRecvMessage);
});

// メッセージ受信イベントの設定
function onRecvMessage(data) {
    // 画面に受信したメッセージを表示
    $("#messages").append($("<p>").text(conn.id + ": " + data).css("font-weight", "bold"));
}

// DOM要素の構築が終わった場合に呼ばれるイベント
// - DOM要素に結びつく設定はこの中で行なう
$(function() {

    // Connectボタンクリック時の動作
    $("#connect").click(function() {
        // 接続先のIDをフォームから取得する
        var peer_id = $('#peer-id-input').val();

        // 相手への接続を開始する
        conn = peer.connect(peer_id);

        // 接続が完了した場合のイベントの設定
        conn.on("open", function() {
            // 相手のIDを表示する
            // - 相手のIDはconnectionオブジェクトのidプロパティに存在する
            $("#peer-id").text(conn.id);
        });

        // メッセージ受信イベントの設定
        conn.on("data", onRecvMessage);
    });

    // Sendボタンクリック時の動作
    $("#send").click(function() {
        // 送信テキストの取得
        var message = $("#message").val();

        // 送信
        conn.send(message);

        // 自分の画面に表示
        $("#messages").append($("<p>").html(peer.id + ": " + message));

        // 送信テキストボックスをクリア
        $("#message").val("");
    });

    // Closeボタンクリック時の動作
    $("#close").click(function() {
        conn.close();
    });
});</pre><p></p>

<p>では、ローカルにHTTPサーバを立てて開いてみましょう。</p>

<p></p><pre class="crayon-plain-tag">$ cd {HTML/Javascriptのあるフォルダ}
$ php -S localhost:8888</pre><p></p>

<p><a href="http://localhost:8888/datachat.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">http://localhost:8888/datachat.html</a></p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/07/ss07.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/ss07.png" alt="ss07" width="640" height="445" class="alignnone size-full wp-image-16361" srcset="/wp-content/uploads/2015/07/ss07.png 640w, /wp-content/uploads/2015/07/ss07-300x209.png 300w, /wp-content/uploads/2015/07/ss07-207x144.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>先程と同様に、接続を開始する側と接続を受ける側の両方が必要なため、2つ開いてください。無事に表示されましたでしょうか？</p>

<p>それでは、データ通信を開始してみたいと思います。接続相手のIDをコピーして、接続を開始する側のテキストボックスに貼り付けて、Connectボタンを押してください。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/07/ss08.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/ss08.png" alt="ss08" width="640" height="445" class="alignnone size-full wp-image-16362" srcset="/wp-content/uploads/2015/07/ss08.png 640w, /wp-content/uploads/2015/07/ss08-300x209.png 300w, /wp-content/uploads/2015/07/ss08-207x144.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>相手のIDがお互いの画面に表示されれば接続できています。では、チャット欄に文字を入力してSendボタンを押してみましょう。
相手の画面と自分の画面、両方に表示されれば成功です。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/07/ss09.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/07/ss09.png" alt="ss09" width="640" height="445" class="alignnone size-full wp-image-16363" srcset="/wp-content/uploads/2015/07/ss09.png 640w, /wp-content/uploads/2015/07/ss09-300x209.png 300w, /wp-content/uploads/2015/07/ss09-207x144.png 207w" sizes="(max-width: 640px) 100vw, 640px" /></a></p>

<p>以上が簡単なテキストチャットのチュートリアルでした。WebRTCを使えば、テキストだけじゃなく、JavaScriptのオブジェクトやファイル等も送ることが可能です。</p>

<h2>おわりに</h2>

<p>今回はSkyWayを使った、簡単なビデオチャット／文字ベースチャットのチュートリアルをお届けしました。WebRTCは便利で高機能な反面、自分で実装しようとすると大変ですが、SkyWayを使うことで手軽に利用可能です。</p>

<p>次回はSkyWayを使って、Android/iPhoneでWebRTCを簡単に使う方法をお伝えしたいと思います。</p>
]]></content:encoded>
		
		<series:name><![CDATA[WebRTCプラットフォーム ”SkyWay” 入門]]></series:name>
	</item>
		<item>
		<title>【及川卓也・清水亮・羽田野太巳・藤村厚夫】すごい人達呼んで「Webは死ぬか？」をマジメに語り合ってもらった（後編）</title>
		<link>/shumpei-shiraishi/15207/</link>
		<pubDate>Mon, 29 Jun 2015 00:00:44 +0000</pubDate>
		<dc:creator><![CDATA[白石 俊平]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Webアプリ]]></category>
		<category><![CDATA[ブラウザ]]></category>
		<category><![CDATA[及川卓也]]></category>
		<category><![CDATA[清水亮]]></category>
		<category><![CDATA[藤村厚夫]]></category>

		<guid isPermaLink="false">/?p=15207</guid>
		<description><![CDATA[スゴい人たちに集まってもらって、「Webは死ぬか」について語り合っていただいたスペシャル企画。前半は「Webメディア・コンテンツ」について、それぞれのご意見を伺いました。 メディアビジネスからCookie、ディープラーニ...]]></description>
				<content:encoded><![CDATA[<p><style>
h2 {
  clear: both;
}
.post-detail-contents p {
  text-indent: 0;
  clear: left;
}
b.speaker {
  background-size: 48px;
  display: inline-block;
  width: 48px;
  height: 18px;
  float: left;
  padding-right: 8px;
  padding-top: 48px;
  text-align: center;
  margin-bottom: 4px;
  font-weight: normal;
}
b.speaker.oikawa {
  background: url('/wp-content/uploads/2015/06/oikawa.png') no-repeat;
}
b.speaker.siraisi {
  background: url('/wp-content/uploads/2015/06/siraisi.png') no-repeat;
}
b.speaker.hatano {
  background: url('/wp-content/uploads/2015/06/hatano.png') no-repeat;
}
b.speaker.simizu {
  background: url('/wp-content/uploads/2015/06/simizu.png') no-repeat;
}
b.speaker.fujimura {
  background: url('/wp-content/uploads/2015/06/fujimura.png') no-repeat;
}
</style></p>

<p><style>.post-detail-contents p { text-indent:0; } #contents #post-detail .block-contents img[width="70"] { display: inline-block; float: left; margin-right: 1em; width: 48px; } #contents #post-detail .block-contents p { overflow: hidden; } #contents #post-detail .block-contents p strong { font-weight: bold; } #contents #post-detail .block-contents p > br { display: none; } .post-detail-contents p > span { display: block; min-height: 48px; }</style></p>

<p>スゴい人たちに集まってもらって、「Webは死ぬか」について語り合っていただいたスペシャル企画。前半は「Webメディア・コンテンツ」について、それぞれのご意見を伺いました。</p>

<p>メディアビジネスからCookie、ディープラーニングまで──ビジネス面に注目した <a href="https://html5experts.jp/shumpei-shiraishi/15147" data-wpel-link="internal">前半</a>とは異なり、後半はWebのテクノロジー面にフォーカスして、「死ぬか？」を論じていただきたいと思います。今回は、（含蓄を多量に含んだ）脱線多めで失礼します！</p>

<p><img src="/wp-content/uploads/2015/06/DSC040331.jpg" alt="" width="640" height="354" class="aligncenter size-full wp-image-16028" srcset="/wp-content/uploads/2015/06/DSC040331.jpg 640w, /wp-content/uploads/2015/06/DSC040331-300x166.jpg 300w, /wp-content/uploads/2015/06/DSC040331-207x114.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<h2>「ブラウザ」の存在感が薄れていく時代</h2>

<p><b class="speaker siraisi">白石</b>  <a href="https://html5experts.jp/shumpei-shiraishi/15147" data-wpel-link="internal">前半</a>はビジネス面に注目してお話いただいたので、後半はテクノロジー面にフォーカスしていきたいと思います。いわば、「Webテクノロジーは死ぬか？」というお話になるかと思います。例えばよく取り沙汰されるのがネイティブ vs Web、みたいな話ですが…</p>

<p><b class="speaker hatano">羽田野</b> そういう話もいいですが、僕はWebの位置付けから話したいですね。Webというものを一般の人々がどう見るか、がここ数年でずいぶん変わったんじゃないかと思うんです。</p>

<p>昔はWebにアクセスしようとすると、ブラウザをまず立ち上げていました。でも今はそうじゃなくて、モバイルで何かしようとするとまずアプリを立ち上げますよね。</p>

<p><b class="speaker siraisi">白石</b> <strong>「Webブラウザを（意識的に）立ち上げる」という行動は、モバイルデバイス上ではめちゃくちゃ減ってそう</strong> ですよね。検索するときくらいでしょうか？検索って行動自体、スマホユーザはそれほど頻繁に行っているのかどうかも疑問ですが…うちの妻なんかは、だいたいLINEかゲームか、という感じです(笑)。</p>

<p><b class="speaker hatano">羽田野</b> それは人によりそうですよね。うちの家族なんかは、割と検索はしてるみたいです。でも、ブラウザという言葉は知らないでしょうね。たぶんうちの子供なんかは、Webという言葉も知らない。</p>

<p><b class="speaker siraisi">白石</b> こういうお話って、ブラウザ作ってる方からするとどうですか。少なくとも消費者にとっては、「ブラウザ」という存在がかつてほど重要じゃなくなっているのではないか、という指摘だと思いますが。</p>

<p><b class="speaker oikawa">及川</b> そうですね…まずはWebをどう捉えるか、「Webとは何か？」という話から始める必要があると思います。その上で、ブラウザとは何なのか？を考えてみる。</p>

<p>僕はここ数年、Webとは何か、Web技術とは何かをずっと考えてきました。例えば「プロトコルとしてのHTTPを使っていればWebである」という話もあれば、コンテンツやアプリのプラットフォームという側面もある。コンテンツという点で言えば、セマンティック性を持つHTMLという技術は未だに非常に重要だし、（Webは）それに依存している。だからクローラがHTMLを機械的に処理することもできる。検索エンジンそのものも、HTMLに深く依存しているし、いまだにスケールしているところであると。</p>

<p><img src="/wp-content/uploads/2015/06/DSC04075.jpg" alt="" width="640" height="347" class="aligncenter size-full wp-image-16026" srcset="/wp-content/uploads/2015/06/DSC04075.jpg 640w, /wp-content/uploads/2015/06/DSC04075-300x163.jpg 300w, /wp-content/uploads/2015/06/DSC04075-207x112.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p>もう一方で、どうやってユーザにそれ（コンテンツ）をリーチさせるかというところに関してはどうでしょう。例えば、RSSがなくなりつつある。そもそも（RSS）フィードと呼ばれるものだって、あれはパーマネントなリンクってものの集まりだったなわけじゃないですか。そうすると、URL、URIが持つ強みってところが非常に大きいんですよ。</p>

<p>例えばある人から見た場合には、中身、コンテンツはなんでもいいんですよ。もしかしたら、HTMLが書かれていなくてもいいかもしれない。CSVでもいいかもしれない。単なるテキストでもいいかもしれない。<strong>URI/URLの、インターネットという巨大な名前空間の中で、一意に特定できるというパワーはすごい</strong> わけです。</p>

<p><b class="speaker siraisi">白石</b> なるほど。</p>

<p><b class="speaker oikawa">及川</b> 考えてみた場合、HTMLとURIはどちらもすごく重要だし、いまだにリプレースできるものはないくらいの存在なわけですね。少なくとも技術という面で見た場合、この二つ（HTMLとURI）は非常に強力だし、今後も生き続けていくんじゃないかと思います。</p>

<p><strong>そしてブラウザ云々というのはここにまさしく関わっていて、その両方をパッケージとしたものだったわけです</strong>。ここ20年近く使われている、いわゆるWebといったものを使うためには、ブラウザというものがフロントエンドに必要だった。しかしその一部しか使わないのならば、そのフロントエンド部分というのは、ネイティブアプリでもいいし、何でもいい。それでもWeb技術を使っているのは間違いない。</p>

<p>例えばIoTの文脈でも、デバイス間がつながるというところでURIを使いましょう、というのをGoogleが実験的に提唱しているんですが…。</p>

<p><b class="speaker siraisi">白石</b> <a href="https://google.github.io/physical-web/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Physical Web</a>ってやつですね。</p>

<p><b class="speaker oikawa">及川</b> そうです。例えばそれを使うとなった場合、「Web技術を使ってるでしょ」と言われればまさしくその通り、というわけです。</p>

<h2>Webの本質とは何か？</h2>

<p><b class="speaker hatano">羽田野</b> Webって言葉がすごく曖昧ですよね。ある人にとってはプロトコルですが、僕らにとってはブラウザの上で動くアプリのことだったりするし。</p>

<p><b class="speaker oikawa">及川</b>極端な話をすると、Webアプリを作るぞとなったときに、HTTPじゃなくてWebSocketを使うことにして、さらにそこにバイナリを流して…ってなったら、ほぼUnixのソケットアプリケーションみたいになるわけですよ。そしてバイナリを紐解くところに例えばNative Client (※)を使うとなったら、HTMLもJavaScriptも使っていないわけです。それは果たしてWebなんでしょうか？でも、ブラウザで動いているわけですよね。</p>

<p>こう考えると、Webの本質というのは考えてみると難しくて。何を持ってWebと呼ぶか？先ほど僕は、HTMLとURIはどちらも重要と申し上げましたが、HTMLを使わないWebは容易に考えうるわけです。</p>

<p>だから僕が最近思うのは、<strong>Webの本質ってURIかな、と思っています</strong>。「一意に決まる」ということ。</p>

<p><b class="speaker siraisi">白石</b> Webから、代替可能なものを全て削ぎ落とすと、URIが残るという感じでしょうか。</p>

<p><b class="speaker oikawa">及川</b> そうですね。<strong>そもそもインターネットって、シンプリシティ（単純さ）から始まっている</strong> んですよ。OSI参照モデルって昔やってたんですけど、OSIってとてつもなく分厚い技術書があるわけです。あんなの実装できるわけないんだけど─4年くらいかかって実装したDECだとか、大変な目にあったわけですが。（※及川さんは元DEC）</p>

<p><strong>一同</strong>: (笑)。</p>

<p><b class="speaker oikawa">及川</b> ああいうのをやっていた当時の技術者からすると、そこに出てきたTCP/IPなんていうのは、当時の技術者からすると「バカにしてんのか？」っていうくらいシンプルだった。テキストでTelnetでつないでサーバと会話できちゃう、っていう。「なんだこれ？」の世界ですよ。でも、あのシンプリシティが「勝った」わけですね。</p>

<p>RESTに関しても、2000年代前半にあったいわゆる「（XML） Webサービス」も、今やほとんど使われてなくて、ほとんどの場合RESTが使われるようになっている。それも単純さが持つ力です。そうした単純さを突き詰めると、結局Webの本質は、URI/URLというところに行き着くのかな、と思っています。</p>

<p><b class="speaker hatano">羽田野</b> まさに、IoTの世界にもURI/URLは食い込もうとしていますしね。誰も異論はないところかな、と思いますよ。</p>

<p><b class="speaker simizu">清水</b> HTTPも2になっちゃうと、ずいぶん変わっちゃうわけで。もはや、僕らが知っている牧歌的なHTTPではない。Webと言った場合、もはやプロトコルすら指していないんじゃないかとは思いますね。</p>

<p><b class="speaker oikawa">及川</b> そのとおりですね。HTTP/1って今の時代には必ずしも最適化されていないんです。SPDYを始め、2も出てきていて、そこ（プロトコル）もリプレースされていくのはそのとおりだと思いますね。Googleも、まだ標準化の方には進めていないですが、<a href="http://ja.wikipedia.org/wiki/QUIC" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">QUIC</a>(※)なんてプロトコルも作っていたりしますし。</p>

<p><small>
※ Native Client…Googleが開発した、Webページ上でC/C++のコードを安全に実行するための仕組み（<a href="http://ja.wikipedia.org/wiki/Google_Native_Client" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Wikipedia</a>）<br>
※ QUIC…Googleが開発している実験的なトランスポートレイヤーネットワークプロトコル（<a href="http://ja.wikipedia.org/wiki/QUIC" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Wikipedia</a>）
</small></p>

<h2>エンジニアにとってのWebの「安心感」</h2>

<p><b class="speaker simizu">清水</b> ところで急にエンジニアっぽくないことを言うんですが、<strong>Webの安心感ってすごい</strong> んですよね。</p>

<p><b class="speaker siraisi">白石</b> 安心感？どういう意味ですか？</p>

<p><b class="speaker simizu">清水</b> 例えば今、ディープラーニングとかやっていて、Facebookが作った<a href="http://torch.ch/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Torch</a>ってやつとか、NVIDIAの<a href="https://developer.nvidia.com/digits" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">DIGITS</a>っていうツールセットとかあるんですが、フロントエンドがWebなんです。</p>

<p>インストールして起動するとnginxが立ち上がって、操作は全部Webブラウザからしてください、と。CUIもあって、コマンドラインはコマンドラインである種の安心感あるんだけど、Web（画面）が出てきた時の安心感ってすごくて(笑)。「（エンジニアが）ハンドルできる」っていうのが伝わってくるっていうか。この安心感って、Webが持ってる強力な力かな、と。</p>

<p>あともう一つは、先ほどの及川さんの「単純さ」の意見に賛同するものですが、一回画面レンダリングしたら終わり、っていう世界観が元々のWebにはあったわけで。それって、書いてる方もすごく安心なんですよね。</p>

<p>今うちの会社は、紆余曲折あってPHPを全社的に使っているんですが、画面を一回書けばおしまいっていうのが、可用性的に安心して使えるんです。これがJavaだったら、どこか一箇所に間違いがあったらシステム全体デプロイしなおさなくちゃいけないところが、PHPだったら、「今見てる人は前のバージョン、次来た人は新しいバージョン」っていう割り切りができる。リクエストごとにトランザクションが終了する、っていうのが、実はシンプルかつ強力な機能なんです。</p>

<p><img src="/wp-content/uploads/2015/06/webnoend-241.jpg" alt="" width="640" height="407" class="aligncenter size-full wp-image-15659" srcset="/wp-content/uploads/2015/06/webnoend-241.jpg 640w, /wp-content/uploads/2015/06/webnoend-241-300x191.jpg 300w, /wp-content/uploads/2015/06/webnoend-241-207x132.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p><strong>React（の仮想DOM）なんかは、そこまでもバーチャルにして効率的なやりとりをしましょう、というのはわかりつつも、そもそも元々Webが持っているパラダイム、頭からお尻まで書いてトランザクション終了、っていう思想を、今風にカッコよくしただけのものだとも思っています</strong>。</p>

<p>それくらいWebが持っていたシンプリシティっていうのはすごく強力で、Webで操作できるってことはつまり、プロトコルがRESTで用意されているってこと。ってことは、プログラム同士も繋げられるし、サービス同士も繋げられるし、要はマッシュアップできるっていう。Webが流行り始めてもう20年くらいになると思うんですが、この20年でそういう傾向ってますます強くなってると思うんです。</p>

<p><b class="speaker oikawa">及川</b> ユニバーサルだというのはすごい強みですよね。何でも繋げる安心感、と清水さんはおっしゃいましたが、例えば家電でも何でもいいんですが、ネット接続をしたいと思った時に、ちゃちいWebサーバを内蔵しておけばいいんですよね。アクセスポイントがその代表例ですが、（HTMLで書けるので）設定画面を用意する労力も大したことないですし。</p>

<h2>アプリ内ブラウザのセキュリティ</h2>

<p><b class="speaker siraisi">白石</b> ちなみに、僕らにとってURIって絶対なくならないものですし、Webの本質であるというご意見にも賛成です。が、ユーザからするとURIって全然見えないものになっているのではないかと思うんですが。</p>

<p><b class="speaker oikawa">及川</b> それは全然構わないんじゃないでしょうか。先ほどお話しあったように、ブラウザが使われなくなってきていて、アプリの中で使われるようになってきているのなら、URIは裏で使われるというので全然構わないと思います。</p>

<p><b class="speaker siraisi">白石</b> いきなりあんまり関係ない話なんですが、今まで誰かに聞きたかったんで聞いちゃいます。今までフィッシング詐欺防止のために、ブラウザベンダーは一生懸命アドレスバーの表示方法を工夫していたかと思うんですが、<strong>アプリ内ブラウザ（WebView）の場合、URLが全く見えない状態になります。それって、セキュリティ上大丈夫なんでしょうか？</strong></p>

<p><b class="speaker oikawa">及川</b> それは、アプリ内ブラウザ作ってる人に聞いてほしいですが(笑)。でもやっぱりモバイルになると、スクリーンが小さいという制限があって、セキュリティをきちんと確保して安心だと言いつつ、でも不必要な情報を出さないようにしなくちゃいけない。アドレスをユーザが確認できるようにしたところで、アドレスがすごく長かったりしたら、どこか1文字違っていたりしても絶対にわからないわけです。</p>

<p>だから、アドレスを全部表示するのがセキュリティ上優しいわけでもないという前提で、そこをどうすればいいかというのを、アプリ内ブラウザであっても普通のブラウザも考えなくちゃいけない所です。</p>

<p>最近はセキュリティめちゃくちゃ厳しくなってきてます。例えばWebをHTTPSオンリーにしようという議論がなされていたり、HTTPSにしたとしても怪しいSSL証明書なんて山のようにあるので、それらを全部banしていくようにしたり。要は、ユーザがサイトの安全性を目で確認する、という時代じゃなくなってるんですよね。<strong>むしろ、そうしない限りはWebが破綻します</strong>。</p>

<h2>アプリにも、URI（つまりWeb）の力が必要だ</h2>

<p><b class="speaker oikawa">及川</b> あと、前半藤村さんがリンクの透過性の話をしていらっしゃいました。あれは結局のところ、<strong>アプリにもURIの力が必要だ</strong>、という話なんですよね。モバイルアプリを皆さん一生懸命作りますが、実際にユーザが何個入れているか、そのうちのいくつをアクティブに使っているかというと、すごく少ない。USのデータで見ると、確か31個とかしか入れていなくて、そのうちの10個くらいしか日常的に使っていない。</p>

<p>でも、世の中にはアプリなんて山のようにあって、ランキングが上の方のやつしかインストールされない。ランキングが下の方のやつなんて、一生懸命作ってもインストールさえされない。</p>

<p>彼らがもしWebをやめちゃったら、ユーザにリーチさえできなくなるし、エンゲージできなくなりますよね。そこをブーストさせるには、もしかしたら検索エンジンでロングテールのコンテンツにリーチさせるのと同じ論理が働くんじゃないかというところで、<a href="https://developers.google.com/app-indexing/?hl=ja" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">App Indexing</a>だったり、<a href="http://applinks.org/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">App Links</a>みたいな話になるわけです。</p>

<p>検索した結果、「こんなアプリもあります」とアプリのインストールをうながしたり、インストールされていたならば「ここから先はアプリで見ませんか」とユーザーをナビゲートしてあげる。ここはハイブリッドなアプローチが必要です。ここでいうハイブリッドというのは、WebViewを使う云々の話だけじゃなくて、<strong>ユーザリーチ、ユーザとのエンゲージメントという点においても、Webとのハイブリッドなものが必要になる</strong> ということです。</p>

<p><b class="speaker hatano">羽田野</b> そういう点だと、Webの方が安心ですね。アプリの中で競争に勝てと言われると、ちょっとつらい。膨大なアプリの中で、自分の作ったアプリがユーザにリーチする確率がどれほどかと考えると、かなり厳しい。
僕から見ると、アプリの世界ってゼロかイチの世界に見えます。</p>

<p>一方Webは、良くも悪くも分散しているので、しょぼいサイトを作ったとしても、ニーズにマッチしてさえいればそれなりに人が集まる。ゼロにはなりません。スモールスタートをやるには、Webってすごいいいな、と思います。今はアプリの世界は、スモールビジネスが成り立たない世界になっちゃっているかな、と。</p>

<p><b class="speaker simizu">清水</b> 探したくもならないもん。こういうアプリあるかな、と思って探したらいっぱい出てきすぎちゃって、嫌になっちゃう。</p>

<p><b class="speaker siraisi">白石</b> 確かに…。</p>

<h2>Web技術は、21世紀のマシン語である</h2>

<p><b class="speaker siraisi">白石</b> ただここで、あえてWebに不利な論調を持ち込んでみたいです。せっかく「Webは死ぬか？」を話す機会なので。最近僕の知り合いがプログラミングの教育ビジネスをやってるんですけど、Web教えないんですよね。AnrdoidやiPhoneアプリの作り方から教えるんです。これでは、Web技術が広まっていかないぞ、と…</p>

<p><b class="speaker oikawa">及川</b> でも、僕もそうですよ(笑) 。今でも東日本大震災の被災地の方でたまに教えていたりするんですけど、<a href="https://coronalabs.com/products/corona-sdk/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Corona SDK</a>っていうのを使ってスマホアプリ教えてます。</p>

<p><b class="speaker siraisi">白石</b> えー(笑)。</p>

<p><b class="speaker hatano">羽田野</b> 僕、思いますけど、ゼロから覚えるならアプリのほうが楽なんですよ。</p>

<p><b class="speaker oikawa">及川</b> なんでかわかります？<strong>Webは自由度が高すぎる</strong> んですよ。スクリーンサイズから何から、前提とするものが少なすぎる。でも子どもたちがやりたいのは、自分が持ってるスマホで、自分のアプリを動かしたいだけなんです。どんな簡単なものであっても、自分の持っているスマホで動くと嬉しい訳ですよね。</p>

<p>Corona SDKとかって、簡単な物理エンジンが乗っかっていて、高校生くらいなら1日もやればそれなりのものが作れるんですよ。教科書通りに写経して、ちょっとここ変えようね、くらいのレベルであれば。はじめて作ったものが、自分の手元でコントロールできる喜びっていうのは、やっぱりアプリのほうが上なんですよね。</p>

<p><b class="speaker hatano">羽田野</b> 僕は自分の息子や娘にWeb技術教えられるかって言うと、ちょっとつらいですよね。だったら、Androidアプリとか教えるほうが手っ取り早い。だって、HTMLの構文教えるだけでも結構大変ですよ。それに加えて、CSS教えて、JavaScript教えて、なんて言ったら…</p>

<p><b class="speaker simizu">清水</b> そこは僕一つ考えがあって。<strong>今のHTML, CSS, JavaScriptっていうのは、21世紀のマシン語</strong> なんですよ。概念的にも、実際的にも。</p>

<p>実際UnityのHTML5プレイヤーなんてまさにそうで、<a href="http://ja.wikipedia.org/wiki/Emscripten" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Emscripten</a>(※)使って、人間が読むことを想定しないコードを吐き出している。それがV8 (※)とかでJITコンパイルされながら動くわけですよね。これ、昔の「べーしっ君」（※）ですよ。</p>

<p>もう、今のWeb技術はマシン語だから。HTMLからやれっていうのは、マシン語からやれって言ってるのと一緒なんですよ。
それにWeb技術って、いろんな歴史の澱（おり）が積み重なってる。<strong>86でいうセグメントみたいな。呪われた概念っていうか</strong>（笑）</p>

<p><small>
※ Emscripten…C/C++のコード（厳密にはLLVMコード）からJavaScriptを出力するコンパイラ<br>
※ V8…Googleがオープンソースで開発するJavaScriptエンジン。Google ChromeやNode.jsで利用されている。<br>
※ べーしっ君…ASCIIが発売していたBASICのJITコンパイラ
</small></p>

<h2>Extensible Webの可能性</h2>

<p><b class="speaker oikawa">及川</b> たしかに現状、Webの後方互換性を保つためのレガシーなコードが、ブラウザにはたくさん入っている。今改めて必要な要素技術を考えるとしたら、ブラウザに今入っているものとは大きな隔たりが出てくるでしょう。</p>

<p>でも今おもしろいのは、<strong>Extensible Web</strong> の考え方です。</p>

<p>低レベルのAPIを整備して、なんか新しいAPIだったり要素だったりを作るとしても、それらの組み合わせで作れるようにしましょう、ってところから始まっている。そうなると、今後はAPIのレイヤー化が進むはずです。そうなると、下のレイヤーがどんどんマシン言語化していくってことですよね。で、上のレイヤーっていうのは、どんどんいろんなモノが乗っかって、その時に一番ポピュラーだったやつだけがブラウザに初めから組み込まれている、ビルトインされているって形になるかもしれないですね。</p>

<p><b class="speaker hatano">羽田野</b> 将来のブラウザに期待したいのは、下位互換性を全て捨てた新しい、軽いブラウザが欲しいですね。marqueeとか、古い要素の実装もすべてない。Web閲覧のためのWebブラウザと、アプリの実行環境としてのWebブラウザって、用途が違うじゃないですか。アプリの実行環境として使うのであれば、古いものがなくたって困らない。そういう実装があってもいい気はしますね。</p>

<p><img src="/wp-content/uploads/2015/06/DSC04092.jpg" alt="" width="640" height="410" class="aligncenter size-full wp-image-16024" srcset="/wp-content/uploads/2015/06/DSC04092.jpg 640w, /wp-content/uploads/2015/06/DSC04092-300x192.jpg 300w, /wp-content/uploads/2015/06/DSC04092-207x133.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p><b class="speaker oikawa">及川</b> Extensible Webの考え方が進んで、レイヤー化されてコンポーネント化されたものが許されるならば、それもあり得るかもしれませんね。ブラウザには、デフォルトでは本当にミニマムなエンジンだけが入っていて、必要に応じてレガシーな要素のコードがダウンロードされるみたいな。</p>

<p><b class="speaker siraisi">白石</b> Extensible Webは、そこまでの未来を志向しているんでしょうか？</p>

<p><b class="speaker oikawa">及川</b> そこまではまだわかりません。ただ、<strong>今Webの機能って、APIができたんだけど使わない、使えないっていうものが山ほどある</strong> わけですよ。よく言われるのがEditing。<strong>contentEditable (※)なんてのは最悪</strong> です。あれでほんとにベーシックなエディタ機能を作ろうと思ったって作れないわけですよ。</p>

<p>結局みんなどうしているかって、みんなそんなの諦めちゃって、みんな何千行か何万行かあるJavaScriptエディタを一生懸命書いてるわけですよね。だとしたらそんなの（contentEditable）全部なくしちゃえ、そのほうがブラウザ軽いし、と。むしろ、そういうエディタたちが持っているミニマムな機能を標準化して、互換性のある形で全てのブラウザに入れてください、のほうがハッピーなわけです。</p>

<p>contentEditableが代表例ですが、要は入っていても使われないとか、使えない機能がたくさんある。</p>

<p><small>
※ contentEditable…HTML5で規定された、編集可能なWebページを作成するための<a href="http://www.w3.org/TR/html5/editing.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">仕様</a>。
</small></p>

<h2>ハイブリッドアプリの現状</h2>

<p><b class="speaker siraisi">白石</b> ここで、Webテクノロジーとモバイルといえば絶対に外せない話題として、アプリカン (※) というハイブリッドアプリのフレームワークを作っていらっしゃる羽田野さんにお聞きしたいんですけど、ハイブリッドアプリの現状はいかがでしょう？</p>

<p><b class="speaker hatano">羽田野</b> 正直なところ、現状はやはりそれほど盛り上がってはいないですね。</p>

<p><b class="speaker siraisi">白石</b> 一番のネックはUIのパフォーマンスだったと思うんですけど、現在どうなんでしょう。</p>

<p><br>
<img src="/wp-content/uploads/2015/06/DSC04084.jpg" alt="" width="640" height="356" class="aligncenter size-full wp-image-16022" srcset="/wp-content/uploads/2015/06/DSC04084.jpg 640w, /wp-content/uploads/2015/06/DSC04084-300x167.jpg 300w, /wp-content/uploads/2015/06/DSC04084-207x115.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p><b class="speaker hatano">羽田野</b> やはり、時代が進むにつれて、ほぼ問題はなくなっていっています。今のスマホって、マシンパワーすごいじゃないですか。今でもAndroid2をサポートしなくちゃならないというお客さまにとっては、WebViewだときついですけどね。例えば無限スクロールのない情報表示系アプリとかであれば、全く問題のないレベルです。であれば、マルチデバイスで動作するWeb技術には大きなメリットがあるというのが、僕らの想いです。</p>

<p><b class="speaker simizu">清水</b> 日本はゲームアプリが多いから、パフォーマンス上の要件も厳しいってのもあると思いますけどね。うちの会社で、enchant.jsで作ろうって提案すると、社員に反対されるんですよ（笑）。「（エフェクトとか）いっぱい出すと重くなるからダメです」って。ゲーム作る人間は、ギリギリまでパフォーマンス追求したいんです。</p>

<p><small>
※アプリカン…<a href="http://www.applican.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">http://www.applican.com/</a>
</small></p>

<h2>いい機会なので、清水亮にenchantMOONについても聞いてみる。</h2>

<p><b class="speaker siraisi">白石</b> 清水さん、自己紹介の時にオーサリングツールとして<a href="http://enchantmoon.com/ja/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">enchantMOON</a>を作ったとおっしゃってましたけど、それって、先ほどの「Web技術はマシン語だ」というところとつながるんでしょうか？Web技術には、オーサリングツールが必要だと？</p>

<p><b class="speaker simizu">清水</b> 必要かどうかはわからないですが、<strong>プログラミングとかオーサリングとかのハードルを下げたい</strong> という想いはありますね。</p>

<p>コンピュータの性能がここまで上がってしまって、人間の何百倍の性能になってしまっているときに、コンピュータを使う方法って、アプリケーションじゃないだろう、と思っている。今って、例えばワープロにしても、「コンピュータに使われている」みたいな状態になってると思う。「コンピュータが提出する文章をお前さんが書きなさい、この枠組みで」みたいな。そこを逆に人間が主体になって、「おれはこういう情報がほしい」とか「こういうのが書きたい」みたいなことをこいつ（コンピュータ）に命令して、こいつが書くようにならなきゃいけない、みたいな一つの思いがあって。</p>

<p><b class="speaker siraisi">白石</b> なるほど。それがハードルを下げたい、っていうことなんですね。</p>

<p><b class="speaker simizu">清水</b> 僕ブログ流行った時に、「こんなに書きたい人が世の中にいるんだ」って感動したんですよ。それまではHTML書かなきゃダメって世界だったものが、誰でも普通に書けるようになって、いろんな人が書くようになったと。そういう意味では、その中で実はみんな自分を表現したいという人は、実はたくさんいるんじゃないかなと。</p>

<p>ただ、まだやっぱりハードルが高い。文章書くのは難しいとか、写真撮るだけだったらできる、っていうんでTwitterやInstagramが流行る。で、<strong>簡単だからやってるっていう話と、文章書くの難しいとかプログラミング難しいって話はリンクしてるなあ</strong> と思っていて。</p>

<p>だったら、もう少しそこら辺のハードルを下げてあげる。プログラミングとかオーサリングとかのハードルを下げてあげた時に何が起きるんだろう、っていうのが僕が思っているところで。ちなみにこれは僕のシンギュラリティ (※) に向けた心構えでもあるんですけど、<strong>プログラミングを克服しないと人類は次の世代にいけない</strong> と思っています。</p>

<p>enchantMOONはもともと、「パソコン大好きオジサンが怖いもの見たさで買う」というターゲティングでした。とはいえ、買った人はほとんど使いこなせていないんです。むしろすごく使いこなした人たちっていうのが、女子中学生なんです。</p>

<p><img src="/wp-content/uploads/2015/06/DSC040801.jpg" alt="" width="640" height="367" class="aligncenter size-full wp-image-16023" srcset="/wp-content/uploads/2015/06/DSC040801.jpg 640w, /wp-content/uploads/2015/06/DSC040801-300x172.jpg 300w, /wp-content/uploads/2015/06/DSC040801-207x119.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p><strong>一同</strong>: へえ！！</p>

<p><b class="speaker simizu">清水</b> 品川女子学院で、貸してくれって言うから貸してあげたんです。一時間くらいしか説明しなかったんですけど、気がついたら爆発的にデカいコンテンツ作ってる。</p>

<p>で、逆にそれをプログラマとかに渡すと、作れないんですよ。自分で作ったほうが速いから。でも文化系とか、コンピュータリテラシ高くない人に渡すと、ものすごいエネルギーでもってなんか作り始めるっていうのが、MOONを作って一番感じたターニングポイントです。</p>

<p>自分が表現したいこと、迷路を作ったりとか、ブロックを組み合わせてシューティングゲーム作ったりとか、そういうものを自分たちの力で作れるっていうのに、魅力を感じてくれたみたいで。そういう人たちにとっては、遅いとか重たいとかほぼ問題にならなくて。取り合いになったって聞いて、すごく嬉しかったです。文化祭とかあれで発表するみたいな。小さな話ではあるんだけど、僕にとっては自信になりました。</p>

<p>だから例えば、仮に今のWeb技術というのがマシン語であるならば、それに対するライトウェイト言語みたいな、ハードルを格段に下げる方法があったならば、コンテンツのビッグバンっていうのはもっと起きるんじゃないかと。</p>

<p>商業メディアって滅ぶ方向にいくんじゃないかという話をしました。でも、もっとハードルが下がって、もっと表現力が上がって、もっと人々に開放されることによって、もっといろんな人がそこに参加してきて、大きな流れが起こっていくんじゃないかな、っていうことを漠然と思っています。</p>

<p><small>
※ シンギュラリティ…人工知能が人間の能力を超える、とされている特異点のこと（<a href="http://ja.wikipedia.org/wiki/%E6%8A%80%E8%A1%93%E7%9A%84%E7%89%B9%E7%95%B0%E7%82%B9" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Wikipedia</a>）
</small></p>

<h2>まとめ、感想、エトセトラ</h2>

<p><b class="speaker siraisi">白石</b> ではそろそろお開きにしたいと思います。今回の対談に関する感想をお願いできますか？</p>

<p><b class="speaker oikawa">及川</b> えーと、Webは死にません！（笑）。楽しかったです。いろんな見方があるな、と。</p>

<p><b class="speaker fujimura">藤村</b> 僕は後半、ちょっと食い足りないところがありましたね。話をちょっと戻せなかったんだけど、基本僕ら（スマートニュース）が作っているネイティブアプリは、圧倒的にモノづくりの人にとっての利便性というよりも、消費者にとっての完成度みたいなのが問われるところがあって。消費者にとっての消費財って、モノづくりの人にとっての利便性ってどうでもいいんですよね。</p>

<p>そこでどのくらい完成度の高いものを作れるかってこだわって作っていく時に、Webってこういう風に作れるって聞いてても、ピンと来ないところが僕にはあって。良い反応速度を出そうとギリギリまで頑張っているっていうのが、ネイティブアプリを選択している我々の中には重要な要素なんですよね。そういうところをもう少しうまく言えればよかったな、と。</p>

<p>後半の文脈って、開発する人にとってのWebの意味、みたいなところが割と語られていたんだけど、使う人とか楽しむ人とか、ゲームやる人にとっての視点だったらどうだったのかっていうのは、ちょっと語りきれていない気がしています。</p>

<p><b class="speaker siraisi">白石</b> スマートニュースなんかは、UXにすごくこだわっていると評判のアプリですもんね。</p>

<p><b class="speaker fujimura">藤村</b> 羽田野さんもさっき言われていましたが、スマホの上では圧倒的にネイティブが採用されているという事実もあるわけで。ゲームがたくさん時間をとっているからだ、っていういろんな解釈はあるんだけど、そうはいってもアプリが選択されちゃっているということに、踏み込まなきゃいけなかったんだけど、そこには踏み込み足りなかったと…悔いが残ります。</p>

<p><b class="speaker siraisi">白石</b> そこはこちらも突っ込んで聞きたいところでした。ぜひまた、次の機会にお願いします。では、清水さんいかがですか？</p>

<p><b class="speaker simizu">清水</b> さっき結構しゃべったんで、特にないです(笑) 。まあ、Webは死なないでしょう。
個人的には、もっとマシン語化が進んでいくかな、と思いますね。</p>

<p><b class="speaker siraisi">白石</b> もっと上位レイヤーが充実してくるという感じですか。</p>

<p><b class="speaker simizu">清水</b> いや、まだ効率が悪いので。WebGLとCSS3の住み分けとかもまだ微妙な感じですし。そこらへんがもっとスマートになればいいな、と。あと、主流になるかは怪しいですが、<a href="https://www.microsoft.com/microsoft-hololens/en-us" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">HoloLens</a>とか<a href="https://www.oculus.com/ja/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Oculus</a>とか、あの手のコンテンツをWebで書く日が来るのかなあ、と漠然と。</p>

<p><b class="speaker siraisi">白石</b> Mozillaが、<a href="http://mozvr.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">MozVR</a>っていうのやってますよね。</p>

<p><b class="speaker oikawa">及川</b> Googleも<a href="https://vr.chromeexperiments.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Chrome ExperimentsでCardBoard向けのやつがあります</a>。</p>

<p><b class="speaker simizu">清水</b> あと一つ言い忘れていたのは、Webの良い点は、フロントエンドからバックエンドまで全てオープンソースだということですね。JavaScriptの実行エンジンから、レンダリングエンジンから、Webサーバから、全部オープンソース。フロントエンドから全てオープンソースっていうのはすごいな、と。ありそうでなかった画期的なもので、だから、エンジニアとしてはWebは安心して使える。少なくとも僕が死ぬまでは、こうした知見が活かせるんじゃないかと、僕は結構楽観的に考えていて。</p>

<p>っていうのは、Unixが出てきて40年経ったけど、結局まだみんなUnix使っているわけですよ。<strong>オープンソースで枯れているコードって使われ続けていくので、Webも同様の理由で、あと半世紀残っても全然おかしくないな、と思ってますけどね。残ってほしい、死なないでほしい</strong>、という願望もありますが。</p>

<p><b class="speaker hatano">羽田野</b> OperaのCTOで、CSSの発明者である<a href="http://ja.wikipedia.org/wiki/%E3%83%9B%E3%83%BC%E3%82%B3%E3%83%B3%E3%83%BB%E3%82%A6%E3%82%A3%E3%82%A6%E3%83%A0%E3%83%BB%E3%83%AA%E3%83%BC" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ホーコン・リー</a>さんも、「<strong>活版印刷は500年使われている。Webも今後500年使われるだろう</strong>」という言葉を残していらっしゃいますね。</p>

<p><b class="speaker siraisi">白石</b> では最後に、羽田野さん、今日の感想をお願いします。</p>

<p><b class="speaker hatano">羽田野</b> これ以上何もありません。同じWeb側の人なのに、見え方が違ってるんだな、と。特に僕的にウケたのは、JavaScriptはマシン語であるというご意見でした。時代が変わるって怖いな、と。（マシン語でのコーディングにこだわる）老害的な存在になってしまわないよう気をつけないと。「DOMを直接叩け！」とか言ってたら疎まれる時代がそのうち来るんでしょうね(笑)。</p>

<p><b class="speaker siraisi">白石</b>
では、本当に名残惜しいんですが、そろそろお開きにしたいと思います。本日は本当に、ありがとうございました！</p>
]]></content:encoded>
			</item>
		<item>
		<title>【及川卓也・清水亮・羽田野太巳・藤村厚夫】すごい人達呼んで「Webは死ぬか？」をマジメに語り合ってもらった（前編）</title>
		<link>/shumpei-shiraishi/15147/</link>
		<pubDate>Thu, 25 Jun 2015 03:00:59 +0000</pubDate>
		<dc:creator><![CDATA[白石 俊平]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Cookie]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Webアプリ]]></category>
		<category><![CDATA[及川卓也]]></category>
		<category><![CDATA[清水亮]]></category>
		<category><![CDATA[藤村厚夫]]></category>

		<guid isPermaLink="false">/?p=15147</guid>
		<description><![CDATA[今また、「Webの死」を予言する論調をそこここに見かけます。モバイルやウェアラブルといった新たなコンテキストが、プラットフォームネイティブな技術の優位性を後押ししているだけではなく、Webコンテンツの消費の仕方を大きく変...]]></description>
				<content:encoded><![CDATA[<p><style>
.post-detail-contents p {
  text-indent: 0;
  clear: left;
}
b.speaker {
  background-size: 48px;
  display: inline-block;
  width: 48px;
  height: 18px;
  float: left;
  padding-right: 8px;
  padding-top: 48px;
  text-align: center;
  margin-bottom: 4px;
  font-weight: normal;
}
b.speaker.oikawa {
  background: url('/wp-content/uploads/2015/06/oikawa.png') no-repeat;
}
b.speaker.siraisi {
  background: url('/wp-content/uploads/2015/06/siraisi.png') no-repeat;
}
b.speaker.hatano {
  background: url('/wp-content/uploads/2015/06/hatano.png') no-repeat;
}
b.speaker.simizu {
  background: url('/wp-content/uploads/2015/06/simizu.png') no-repeat;
}
b.speaker.fujimura {
  background: url('/wp-content/uploads/2015/06/fujimura.png') no-repeat;
}
</style></p>

<p><style>.post-detail-contents p { text-indent:0; } #contents #post-detail .block-contents img[width="70"] { display: inline-block; float: left; margin-right: 1em; width: 48px; } #contents #post-detail .block-contents p { overflow: hidden; } #contents #post-detail .block-contents p strong { font-weight: bold; } #contents #post-detail .block-contents p > br { display: none; } .post-detail-contents p > span { display: block; min-height: 48px; }</style></p>

<p>今また、「Webの死」を予言する論調をそこここに見かけます。モバイルやウェアラブルといった新たなコンテキストが、プラットフォームネイティブな技術の優位性を後押ししているだけではなく、Webコンテンツの消費の仕方を大きく変え、Web上で成り立っていたビジネスモデルをも脅かしつつあります。</p>

<p>本当にWebはヤバいのか、気になってしょうがないので、スゴい人たちに集まってもらって、「Webは死ぬか」について語り合っていただきました。Webを取り巻く様々な論点を包括的に議論でき、貴重な場になったのではないかと自負しております。
Webに関わる人にとっては必読の対談だと思います！でもこの記事、長くて濃いので、心してかかってくださいね:-)</p>

<p><img src="/wp-content/uploads/2015/06/DSC04137.jpg" alt="" width="640" height="410" class="aligncenter size-full wp-image-15824" srcset="/wp-content/uploads/2015/06/DSC04137.jpg 640w, /wp-content/uploads/2015/06/DSC04137-300x192.jpg 300w, /wp-content/uploads/2015/06/DSC04137-207x133.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" />　▲左から藤村厚夫さん、清水亮さん、羽田野太巳さん、筆者・白石俊平、及川卓也さん</span></p>

<h2>メンバー紹介</h2>

<p><b class="speaker siraisi">白石</b>
皆さま、このたびはお集まりいただき、ありがとうございます。まずは自己紹介からお願いできますでしょうか。</p>

<p><b class="speaker oikawa">及川</b> <strong>及川卓也</strong> です。Google Chromeのエンジニアリングマネージャーを務めています。ChromeのうちのBlinkと呼ばれるレンダリングエンジンだったり、WebのDeveloper FacingなAPIを開発する、といったことをずっとやっています。立ち位置としては、「Webを推進する」ということをやっていますので、Webには未来を感じています。特にこの2～3年、技術面から「Webとは何なんだろうな」とずっと考えていたので、それにも通じる話かなと思っています。</p>

<p><b class="speaker fujimura">藤村</b><strong>藤村厚夫</strong> です。以前はアイティメディアという会社の経営に携わっていましたが、現在はスマートニュースという会社で、メディア事業開発という立ち位置で働いています。スマートニュースは、検索エンジンと同じく、Webをクロールしてアプリで表示するということを全自動で行います。とはいっても、そのコンテンツを作り出した方々との良好な関係を持たないと、コンテンツを使い続けるわけにもいきません。なので、多くのコンテンツホルダーの方々とパートナーシップ、または交渉するといったことがメインの仕事になります。</p>

<p>業界全体で見ると、メディアで飯を食っていける仕組みを作り出さなくてはならない、ビジネスとしてのコンテンツの流通というものを考えなくてはならない、自分たちだけではなく、コンテンツを作っている方々と我々の中でビジネスの構造を作っていかなくてはならない…こうした中で、これからのデジタルメディアを考えていかなくてはならない。そのためにはどうしたらいいか…というのが普段からの問題意識です。</p>

<p><b class="speaker simizu">清水</b> <strong>清水亮</strong> です。僕自身はもともとマイクロソフトっていう会社で開発をしていて。その後ドワンゴという会社の立ち上げでモバイルウェブというのがカネになる——僕はなるとは思ってなかったんですが——というムーブメントを体験し、その後自分の会社を作ったあとも、モバイルウェブで食わしていただいて。その後スマートフォンが出てきた時は、モバイル公式サイトってビジネスモデルが崩壊しちゃう、どう立ち居振舞えばいいのかってところでアプリを作ったりしていました。</p>

<p>最近はHTML5が出てきたんで、<a href="http://enchantjs.com/ja/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">enchant.js</a>というゲームエンジンを作ったりしていて、アプリを作るのはほとんどやめちゃいました。HTML5については、情報を見るのは誰でもできるのだけど、作るのはまだまだ難しい、という非対称性があると考えていて、その問題に一石を投じるため、enchantMOONというオーサリングツールを作っています。
最近は仕事でディープラーニングに触れたりしています。</p>

<p><b class="speaker hatano">羽田野</b>
<strong>羽田野太巳</strong> と申します。個人会社として<a href="http://www.futomi.com/other/aboutus.html" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">有限会社futomi</a>をやっています。そちらはもともとCGIというのが流行っていた時代に始まっていて、サーバサイドのシステム開発を主に行っていました。それがどんどんアプリケーション寄りになってきて、いつの間にかHTML5をやっていたと。今ではほとんどが、ブラウザの上で動くアプリとしてのWebの仕事が中心になっています。一言で申しますと、私はビジネスというよりはWebデベロッパーというカテゴリに入るのかなと思います。</p>

<p>もう一方で私は、<a href="http://www.newphoria.co.jp/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">ニューフォリア</a>という会社の役員もやっておりまして、そちらではWebアプリの開発もやるんですが、デジタルサイネージも手がけておりまして。デジタルサイネージは実はプロプライエタリなシステムだらけ、互換性もなく閉鎖的なシステムで運用されているのが実情なんですが、実際に街中でご覧になって分かる通り、仕組みとしてはとてもシンプルなんですね。一言で言うとスライドショー。「こんなのWebでいいじゃん」という発想から、いわゆるサイネージプレイヤーを全部JavaScriptベースでブラウザの上で動かすというチャレンジを、ニューフォリアではやっております。</p>

<p><b class="speaker siraisi">白石</b> 私も対談に参加する人間として、自己紹介させていただきます。
HTML5 Experts.jpの編集長、<strong>白石俊平</strong> です。昨年まではhtml5jというコミュニティのリーダーもやっておりましたがそこからは引退しまして、今は自分の会社を大きくしていくことに注力しようとしているところです。</p>

<p>では、いよいよ本題に入らせていただきたいと思います。</p>

<p><strong>今回は大きく2つに分けてディスカッションを行いたい</strong> と思います。</p>

<p><strong>前半はビジネス寄りの話を中心にしたい</strong> と思います。「Webビジネスは死ぬか？」って話ですね。これって、ECとかが死ぬことはないと思うんですが、最近危ういなと思うのはメディアを中心とした広告ビジネスですね。モバイルの時代になり、コンテンツの消費のされ方も変わってきましたし、アプリ中心の世界ではCookieによるターゲティング広告がうまく機能しなくなってきたという話もあります。そうした話題を中心として。</p>

<p><img src="/wp-content/uploads/2015/06/webnoend-92.jpg" alt="" width="640" height="406" class="aligncenter size-full wp-image-15645" srcset="/wp-content/uploads/2015/06/webnoend-92.jpg 640w, /wp-content/uploads/2015/06/webnoend-92-300x190.jpg 300w, /wp-content/uploads/2015/06/webnoend-92-207x131.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p><strong>後半はテクノロジー寄りの話</strong> として、よく言われるネイティブ vs Webの話をはじめとして、いろいろとお聞きできればと思います。</p>

<p>先に言っておきますが、まあ現実問題として、「Webは（そうそう）死なない」って結論が出るのはなんとなくわかっております(笑)。ただ、「死ぬか？」という問題提起をすることで、現在のコンピューティングの課題や最前線の話題を浮き彫りにしたい、それが本企画の趣旨になります。</p>

<p>ではまず、「Webメディア・コンテンツ」といった話題を中心に、話し合っていただきましょう！</p>

<h2>コンテンツプラットフォームとしてのWebは死ぬか？</h2>

<p><b class="speaker hatano">羽田野</b> まず最初に伺っておきたいんですが、皆さん「Web寄り」の人でしょうか？立場が似通ってて、おんなじような意見の方ばっかりだったら面白くならないな、と思って。</p>

<p><b class="speaker fujimura">藤村</b> 私は違うかも…。孤立感を感じております(笑)。</p>

<p><b class="speaker oikawa">及川</b> でも、スマートニュースこそ、コンテンツプラットフォームとしてのWebに強く依存しているわけですよね。コンテンツプラットフォームとしてのWebが死んじゃったら、スマートニュース成り立たなくなっちゃう。</p>

<p><b class="speaker simizu">清水</b> 僕は、スマートニュース危ないと思ってて。</p>

<p><b class="speaker siraisi">白石</b> 早速爆弾ですね(笑)。</p>

<p><b class="speaker simizu">清水</b> 結構付き合いの長いKADOKAWAって会社が、電子化に専念して、（週刊アスキーが）近々紙をやめるってことらしいんです（注: 取材を行ったのは2015年5月18日）。ただ、今回の電子化っていうのは、各種ブックストアで販売される電子書籍版だけにするって話なんですよね。Webだけっていう話じゃなくて（編集部注: 詳しくは、週アスのサイトに掲載されている「<a href="http://weekly.ascii.jp/elem/000/000/331/331685/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">『週刊アスキーがウェブ/電子版に完全移行』ってどゆこと？発表後1ヵ月の機会にまとめてみた</a>」という記事をどうぞ）。</p>

<p><b class="speaker siraisi">白石</b> そうなんですか、知らなかった。てっきりWebだけにするもんだとばかり思ってました。</p>

<p><b class="speaker simizu">清水</b> これは一例なんですが、そういう電子書籍とかって、スマートニュースとかじゃまだカバーできない領域ですよね。</p>

<p>一方で週刊アスキーのWebメディア、週アスプラス（編集部注: 現在は「週刊アスキー」）が儲かっているのか、というと多分そこまで儲かってない。少なくとも紙の週刊アスキー時代のように、莫大な海外出張費が出るほどには全然儲かってない。</p>

<p>例えばこないだの<a href="http://www.buildwindows.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Build</a>（米国で開催されたマイクロソフトのカンファレンス）で、知り合いのジャーナリストとかに聞いてみると、みんな自腹で来ているわけです。何十万もかけて渡米する費用が、原稿料でペイできるのか？できるわけがない。<strong>「ライターは食えない」という状況の中で、今って（よほどの売れっ子以外は）惰性で書いてるか、副業で書いているか、っていう人しか残ってないと思う</strong>。</p>

<p>これって、Webメディアっていうビジネスが総じて成り立たなくなりつつあるんじゃないかと思うんですよね。モバイルコンテンツの時とかは、300円とかをユーザがなし崩し的に払ってくれていたわけですが、今はかつてのスケールで収益化に成功しているメディアは存在してないと思うんです。</p>

<p>で、Webメディアが成り立たなくなったら、スマートニュースみたいなキュレーションメディアも成り立たない。</p>

<h2>Webメディアというビジネスは今後も成り立つのか</h2>

<p><b class="speaker fujimura">藤村</b> 2000年にWeb専業のメディア（＠IT）を立ち上げて、Webプラットフォームの上にいわゆる出版社を作ってやってきた立場から言うと、「Webメディアが儲からない」ということはないと思います。株式公開もしましたし、現時点でも、事業として利益を出し継続性を持ってやっている。ただ、<strong>儲かることの意味というのは変わっている</strong> と思います。</p>

<p>例えば、パブリッシングプラットフォームとか、コンテンツのロジスティックス —— 先ほど私は「流通」という言葉を使ったかもしれませんが —— 大量のコンテンツに的確にユーザがリーチする、もしくはその逆で、ユーザに的確にコンテンツを届けるといった、「コンテンツの交通整理」みたいなものが必要になっていると思いますし、それをマネタイズするための手法も、Webの上でいろいろ出てきています。そして、それぞれの機能が、それぞれ成熟してきていると僕は思っているんですね。</p>

<p>例えば、以前は（メディア企業は）CMSを自分たちで作っていたわけですよ。我々もそうだったんですが、CMSを作ることから始める、広告を表示する仕組みから開発してビジネスの仕方を考えていた。しかし言ってみれば、自分たちでそれらを作ことの効率の悪さみたいなのに気づいて、そこに一つの「レイヤーキング」みたいな構造ができあがった。それが先ほどの、ライターは食える食えないとか、いろいろな事象に繋がっている。それは、Web専業メディアが出てきた1995年くらいから20年経って、従来のモデルがそのままでは通用しなくなってきたという事実なんだと思います。</p>

<p><img src="/wp-content/uploads/2015/06/DSC04057.jpg" alt="" width="640" height="377" class="aligncenter size-full wp-image-15828" srcset="/wp-content/uploads/2015/06/DSC04057.jpg 640w, /wp-content/uploads/2015/06/DSC04057-300x177.jpg 300w, /wp-content/uploads/2015/06/DSC04057-207x122.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p>様々なレイヤーでパワープレイヤーが出てきて、ビジネスの仕組みを変えざるを得ないという段階に到達したと。これからそういう組み換えと、新しいトレンドの中で、どういうビジネスが有効であるかと考える時期かなと。それが、コンテンツプラットフォームとしてのWebというところにおける自分の問題意識です。</p>

<p>ですから一般論として、<strong>食えないというものではないけれども、「やってりゃどうにかなる」というものでもない</strong>。
なので、変わっていこうとしている途上なので、新しいものを見通そうと思うと、いろんな課題がある。<strong>私は、メディアビジネスが生き残っていくにはオンラインしかないと思っている。それは20年間、認識は変わっていません。</strong></p>

<p>しかし例えばそれが、自立的に生きていくのか、FacebookのようなWalled Gardenを持っているところと組まなければならないのかとか、Webの自律性とかそういうところだけでは答えが出せない、という段階に差しかかっていると思います。コンテンツプラットフォームとしてのWebを語る上では、そういう論点を整理していかなくてはならないかなと思いました。</p>

<h2>ライターは儲からない、ブロガーは儲かる！？</h2>

<p><b class="speaker hatano">羽田野</b> 「4大メディア」時代からウェブになって、食える人が大きく変わってしまったんじゃないでしょうか。儲かる人が変わっちゃっただけで、ある人はWebのせいで儲からなくなったけど、ある人はWebで儲かるようになったっていう。</p>

<p><b class="speaker simizu">清水</b> ただ、ライターって立場から見ると、明らかに「儲からなくなった」と言えます。
僕はライター出身ですが、<strong>今の時代ライターで食っていこうとは考えられないくらい、原稿料が安い</strong>。昔は1ページ2～3万だったのが、今は1記事5,000円とかです。5,000円じゃ生活できないですよ。しかも、雑誌とかの部数は割と横ばいなんです。メディアとしての稼ぐ力が全体的に下がっちゃったんでしょうね。だから、今これからライターになろうとする人は、めちゃくちゃ大変です。ほとんど仙人目指すみたいな(笑)。</p>

<p><b class="speaker siraisi">白石</b> 今までのお話を踏まえると、紙も儲からない、Webも儲からないとなると、全体的に「出版」という市場は縮小している、ということになるんでしょうか？</p>

<p><b class="speaker simizu">清水</b> どこまでを「出版」と捉えるかによると思いますね。例えばKindle本でいうと、部数は紙ほど出ませんが…100分の1とかそんなもんじゃないでしょうか。印税としての実入りは大きい。<strong>まとまった情報にお金を払うというカルチャーはまだ生きていて、ただそれが、今のところWebではない</strong> というだけです。まあ電子書籍も、「EPUBはWeb技術だ」って話もあるかもしれませんけども。</p>

<p>他にはブログ、これは今後もずっと生き残ると思います。ちなみにブログやってて面白い発見があったんですが、僕はアフィリエイトべたべた貼ってるんですけど、紙の本と電子書籍、紹介した時の売上が100倍違うんですよ。</p>

<p><b class="speaker siraisi">白石</b> どっちがよく売れるんですか？</p>

<p><b class="speaker simizu">清水</b> <strong>電子書籍です。電子書籍のほうが100倍売れる。</strong></p>

<p><br>
<b class="speaker">全員</b> へえー！</p>

<p><b class="speaker simizu">清水</b> 僕のブログを読んで、「この本を読みたい」と思った人は、すぐその場で読みたいんですね。明日まで待たない。でもね、僕のブログ経由の売上がAmazonのランキングを左右するようなレベルなんです。要は数百部の売上がランキングを左右するような世界。3,000部から、っていう紙の世界から考えると、まだまだ電子書籍のスケールって小さい。</p>

<p><b class="speaker siraisi">白石</b> ちなみに今のお話を聞いて、<a href="http://d.hatena.ne.jp/shi3z/20150111" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">「ジョナサン・アイブ」の本を清水さんのブログ経由で購入した</a>のを思い出しました(笑)。</p>

<p><b class="speaker simizu">清水</b> それはどうもありがとうございます(笑) 。<strong>個人的な体験で言うと、ライターを一生懸命やってた頃より、実は今のアフィリエイト収入のほうが大きいです</strong>。楽して同じ収入稼げるという意味では、出版社に頼ってた頃より今のほうが自由かもしれません。出版社に「書きすぎ」とかって止められることもありませんしね。</p>

<p>今は月に1回10万ビューくらいの記事を書くだけで、数万円って収入になってしまうので。ライターを超頑張ってた頃よりは、稼ぎやすくはなってると思います。まあ、正直記事の質は下がってますけどね。書き散らかしているので…。</p>

<p><img src="/wp-content/uploads/2015/06/DSC040601.jpg" alt="" width="640" height="349" class="aligncenter size-full wp-image-15836" srcset="/wp-content/uploads/2015/06/DSC040601.jpg 640w, /wp-content/uploads/2015/06/DSC040601-300x164.jpg 300w, /wp-content/uploads/2015/06/DSC040601-207x113.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<h2>Webメディアは（むしろ）ゴールドラッシュ！？</h2>

<p><b class="speaker siraisi">白石</b> ちょっと今までのお話を総合すると、Webメディアのビジネスというのがこの先も成り立つのか？というところがグレーだと。</p>

<p><b class="speaker simizu">清水</b> 僕は成り立たないと思うんですよねえ。</p>

<p><b class="speaker siraisi">白石</b> 僕も一時期ライター専業だったので、お気持ちわかります。辞めたのも、食ってけないのが明白だったからでしたし…。なのでまず、Webメディアというビジネスモデルが今後も成り立つのか。そしてスマートニュースのような、「その上」に成り立っているキュレーションメディアはどうなるのか、と。また昔ながらのWebメディアというのとはまた違った形態、例えば電子書籍やブログならば活路はあるのではないか…という流れかと思います。</p>

<p>ここまでの流れを受けて、藤村さんいかがですか？</p>

<p><b class="speaker fujimura">藤村</b> うーん、いろんな論点があるので、絞って解いていかなければいけないんだと思いますけど。ただお金という観点で言うと、Webの上で大きく動いているのは間違いない。それをうまく集められる存在が、かつては出版社でした。しかし今はGoogleやFacebookのような存在が、お金を大きく集めている。お金のシフトが生じている。</p>

<p><strong>お金を集められるパワープレイヤーと、お金を分配する仕組みが、かつてのような生態系とは違ってきている</strong>わけです。
こうした変化の中で、ある人にとっては食えたもんじゃないという話になるわけです。その一つが、コンテンツを一生懸命作ってきた事業体が、なぜ金巡りが悪くなって続かなくなるんだ、みたいな。</p>

<p><b class="speaker hatano">羽田野</b> 既存の出版社からすると、今のWebのビジネスって、すごく小粒なものなんじゃないでしょうか。非常に小粒で、分散してしまっている感じ。足すとあまり変わっていないのかもしれませんけど。</p>

<p><b class="speaker fujimura">藤村</b> おっしゃるとおり、メディアビジネスを営んでいる存在は、昔に比べてすごく多いと思います。スマートニュースで、私は媒体社さんとのお付き合いという仕事が中心ですが、やってもやっても追いつかないくらい新しい媒体が生まれてきている。</p>

<p>お金の流れ方、ビジネスのスタイルが変わってきている。ある人は過去との比較で、「とうてい食えたもんじゃない」とおっしゃるかもしれない。でも、これまでメディアをやって来なかったような人たちによる新しい参入が引きも切らない。例えば、バイラルメディアとかはものすごいブームで。語弊があるかもしれませんが、ある意味、イージーにメディアのビジネスをスタートできる環境も整ってきている。</p>

<p><b class="speaker simizu">清水</b> 参入障壁は明らかに下がってますよね。</p>

<p><b class="speaker fujimura">藤村</b> 自分は、メディアで苦しい思いをされている方々がいるのは知りつつも、<strong>ある種のゴールドラッシュの体をなしている部分があると思っています</strong>。</p>

<h2>今日のWebメディアは、プラットフォームを抜きにして語れない</h2>

<p><b class="speaker siraisi">白石</b> 僕はFacebookの藤村さんの投稿とかよく眺めているんですが、例えばバイラルメディアブームの火付け役になったBuzzFeedは、今でも話題を振りまいていますね。</p>

<p><b class="speaker fujimura">藤村</b> <strong>強力なユーザーリーチを持っているプラットフォームというのが、一つではなく、いくつか分散して存在するようになってきています。</strong>少し前までは、検索エンジンを軸に生態系ができていました。ハッキリ言えば、Googleをターゲットにして、コンテンツの作り方やマーケティングの仕方が研究されていました。今はそれが変わろうとしています ―― Googleの及川さんの前でこんなことを言うのもなんですが(笑)。今は例えば、Facebookにぴったり寄り添ってコンテンツを作ると、Facebookが持っている巨大なユーザーリーチの恩恵を受けられるようになるわけです。BuzzFeedがまさにその典型です。</p>

<p><b class="speaker siraisi">白石</b> Facebookといえば先日、<a href="http://instantarticles.fb.com/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Instant Articles</a>という取り組みを発表しましたね。これって端的にいうと、メディアのコンテンツがFacebookに自動で転載される仕組みなんだと思っています。僕はそれを見て、コンテンツの「コピー」が大量にWeb上に流通する…という現象が連想されまして。昨今のバイラルメディアブーム然り、今毎日のように問題になっている「引用か、盗用か」という議論も然りで。</p>

<p><b class="speaker fujimura">藤村</b> <strong>理想的な意味での、Webにオリジナルコンテンツを作れば誰もがそこに集まってきて、自分たちのブランドの上で成長していく…というシナリオが難しくなってきている</strong>というのが、おっしゃられた事象の背景にあると思います。</p>

<p>検索エンジンだけを考えていれば良かった時代においては、「良いコンテンツを作ればそこに人が集まってきてくれる」という方程式を描きやすかった。しかしそこを今、少し見直さなくちゃならない時期なのかもしれません。</p>

<p><img src="/wp-content/uploads/2015/06/DSC04048.jpg" alt="" width="640" height="361" class="aligncenter size-full wp-image-15832" srcset="/wp-content/uploads/2015/06/DSC04048.jpg 640w, /wp-content/uploads/2015/06/DSC04048-300x169.jpg 300w, /wp-content/uploads/2015/06/DSC04048-207x117.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<p>例えばFacebookのニュースフィードにピタっとハマったコンテンツを作らないと、中々ビジネスの上げ潮に乗れないとか、そういうことが実際に起きている。そういう事実を受け入れられない方々にとっては、こんなヒドイ時代はないというかもしれない。でも逆に、そういうアルゴリズムを理解して活用できる人々は、すごい成長力を持てる時代に入ってきている。いい意味でも悪い意味でも、巨大なリーチを持ったパワープレイヤーの存在との関係性は避けて通れないんです。Google,Facebook,Twitter,Pinterest,Instagram…そうした大小のプラットフォームが今は並存している時代。</p>

<p><b class="speaker siraisi">白石</b> BuzzFeedなんかは、「自分たちがメディアを保有する必要性すらない」と言っていたりしますよね。</p>

<p><b class="speaker fujimura">藤村</b> そういう言い方もし始めていますね。BuzzFeedなんかは、そもそもがFacebookにものすごく依存していたりするわけです。自分たちのサイトは持っているけど、Facebookが自分たちのビジネスに占めるインパクトがあまりにも大きいので、自分たちでサイトを運営するコストを全て排して、Facebookに記事を配信するというモデルでもやっていけるぞ、と。もともと通信社などのビジネスモデルもそういうものですし、以前からそういうモデルはあったんですけどね。今の時代に、改めてそういう考え方が出てきている。</p>

<p><b class="speaker siraisi">白石</b> ちなみに、Facebookに直接記事を書くぞとなったら、どうやって稼げるんでしょう？</p>

<p><b class="speaker fujimura">藤村</b> 2つやり方があります。Facebook自体が<a href="https://developers.facebook.com/docs/audience-network/native-ads" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Native Ads</a>っていうパワフルな広告ビジネスを営んでいます。投稿されたコンテンツの間にFacebookが広告を配信して、そこで上がった売上を分け合うというモデル。もしくは、自分たちが広告主を連れてきたのだったら、100%取っていっていいってモデルです。</p>

<p>BuzzFeedはさらに、自分たちが広告コンテンツも作ってFacebookに流しちゃえ、なんて大胆なことを言っている。ここまで議論しているとディープな話になりますけどね(笑)。</p>

<p><b class="speaker siraisi">白石</b> そうですね、ちょっとFacebookやBuzzFeedに突っ込んだ話から戻りますか。</p>

<p><b class="speaker fujimura">藤村</b> 僕が気になっているのは、一人のライターさんが執筆したとして、それをマネタイズする仕組みが大きく変わっているんじゃないかということ。</p>

<p><b class="speaker hatano">羽田野</b> 執筆のマネタイズというと、広告以外マネタイズが思いつかないなあ…。</p>

<p><b class="speaker fujimura">藤村</b> あ、僕が関心持ってるのはですね、「結局プラットフォームが牛耳ってる」とか、FacebookのようにWalled（壁に囲まれた）な世界が出来上がることは、<strong>Webの開放空間の可能性を信じる人にとっては気持ちのいいことじゃないはず。でも、ビジネスという点から言うと、実際そういう世界になりつつある</strong>ってところです。
「開放空間は、開放的で気持ちはいいんだけど、お金にはならないね」「結局閉鎖系みたいなところがお金にはなりやすいね」という話になっていってしまうのか。僕はそこがシンプルに知りたいところ。</p>

<p><b class="speaker hatano">羽田野</b> ブログブームで、あれだけ発信したい人が世の中にいたというのは個人的には驚きでしたけど、今はそれほどの盛り上がりではないように思います。開放空間でまとまった情報を発信するというのは、ハードルがすごく高かったのかな、と。</p>

<p>結局のところ、<strong>閉鎖的な空間で、ある程度見知った人々と情報をやりとりするというニーズのほうが、はるかに大きかったのではないでしょうか</strong>。少なくとも、ブログを書いて発信しようとする人よりも、SNSで発信している人々のほうが母数が大きい。（メッセージングアプリとかを含めると）インターネットユーザ全体と言ってもおかしくない。そこが、FacebookなどのSNSやメッセージングアプリが、莫大なユーザーリーチを得ている理由じゃないでしょうか。</p>

<p><img src="/wp-content/uploads/2015/06/DSC04134.jpg" alt="" width="640" height="388" class="aligncenter size-full wp-image-15834" srcset="/wp-content/uploads/2015/06/DSC04134.jpg 640w, /wp-content/uploads/2015/06/DSC04134-300x182.jpg 300w, /wp-content/uploads/2015/06/DSC04134-207x125.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<h2>Cookieは死ぬか？</h2>

<p><b class="speaker siraisi">白石</b> 「Webは死ぬ」という文脈でよく取り沙汰されるのが、<strong>Cookieに以前ほどの力がなくなってきた</strong>こともあるかと思います。モバイルアプリの上では、アプリがそれぞれWebViewでWebコンテンツを開くことも多く、Cookieによるユーザセッションがそれぞれ分断してしまう。</p>

<p><b class="speaker fujimura">藤村</b> 要は、ターゲティング広告、リターゲティング広告が使えなくなる、ということですね。広告ビジネスとしては機能不全になってしまう。Webの世界では通用していた広告ビジネスが、アプリ経由では使えなくなると。</p>

<p><b class="speaker siraisi">白石</b> <a href="http://jp.techcrunch.com/2014/10/31/20141030cookies-are-dead-user-based-attribution-models-are-the-only-way-forward/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">TechCrunchでも、Cookieは死んだという記事が掲載されたりしていました</a>。</p>

<p><b class="speaker fujimura">藤村</b> <strong>Cookieが通用しなくなりつつあるかと言われれば、実際そうじゃないでしょうか</strong>。でもね、あたかもCookieがお金であるかのような扱われ方、Cookieでユーザをひたすら追いかけて…というモデルが「健全」であるかというと、ちょっと疑問を感じます。</p>

<p><b class="speaker siraisi">白石</b> ユーザの立場からすると、ちょっと気持ち悪いですよね。</p>

<p><b class="speaker fujimura">藤村</b> <strong>Webとアプリの間に断絶が起きていることは間違いありません。その断絶の中で失われるものがいくつかあって、そのうちの一つがCookieです</strong>。じゃあCookieみたいなものが失われることを嘆き悲しむべきかどうかは、僕は相対的なものだと思っています。Cookieが失われるのであれば、もっとユーザの利便性も考えた上で、次にできることが求められるんじゃないかと思う。</p>

<p><b class="speaker siraisi">白石</b> なるほど。<br><br></p>

<h2>失われた透過性</h2>

<p><b class="speaker fujimura">藤村</b> マーケティングとかリタゲとかそういう概念からは少し離れるかもしれませんが、Webとアプリの間の断絶でもう一つ失われているものがあって、それが僕には気になっています。それは <strong>透過性</strong> です。</p>

<p><b class="speaker siraisi">白石</b> というと？</p>

<p><b class="speaker fujimura">藤村</b> 端的にいうと、リンクの問題ですね。ディープリンクみたいなものはいろんなところから提供されつつありますが、Webの中で成立していたリンクの関係ほど自由じゃない。透明性が高くありません。そうなると、<strong>「自分たちのコンテンツの魅力によって人を引き寄せよう」という世界は、アプリの中では作りにくい</strong>んです。このことが、コンテンツがお金に変わるような価値を持ちきれない一つの理由であり、問題を難しくしている気がしています。</p>

<p>アプリとWeb, Webとソーシャル、そういうものの間に、透過性を阻害するような要因がたくさん出てきていて、そこはすごく力を持つ時代でもあります。そこを克服する考え方なり、技術的な手法、標準作りとかはすごく重要じゃないかと思います。</p>

<p><b class="speaker siraisi">白石</b> リンクの不自由さが、アプリとWebの世界の行き来をしにくくしている原因の一つなんですね。</p>

<p><b class="speaker fujimura">藤村</b> アプリのプラットフォームが分かれているのも、そういうのをスムーズにさせない理由だと思います。Webの上では、自由な往来が許容されていました。しかしアプリではそうではありません。そうなると、<strong>結局マーケティングの仕組みが前時代的になるんですよ</strong>。</p>

<p>Webだったら、良いコンテンツが検索エンジンを通じて伝わることを期待できる、そういう、かなり信頼できる方程式がありました。アプリでは、それは絶対に伝わりません。そうなると、無理やりお金を使って、大昔に流行ったようなマーケティングをまたやらなくてはならない。そういうことが当たり前のように起きている。すごい課題だと思うし、不健全なところだと思う。お金を払ってインストールさせるブースト広告とか、今の時代に変じゃないですか、と。あまりにも前時代的だと思います。</p>

<p><img src="/wp-content/uploads/2015/06/DSC04065.jpg" alt="" width="640" height="339" class="aligncenter size-full wp-image-15835" srcset="/wp-content/uploads/2015/06/DSC04065.jpg 640w, /wp-content/uploads/2015/06/DSC04065-300x159.jpg 300w, /wp-content/uploads/2015/06/DSC04065-207x110.jpg 207w" sizes="(max-width: 640px) 100vw, 640px" /></p>

<h2>人工知能の「学び」は個人情報か？</h2>

<p><b class="speaker siraisi">白石</b> ちょっと戻ると、Cookieのパワーは今後落ちていく。で、それに代わるものは出てくる、と。</p>

<p><b class="speaker fujimura">藤村</b> そうですね。で、何がどこに出てくるかによって、今後の世界は大きく違ってくると思います。</p>

<p><b class="speaker simizu">清水</b> 結局のところ、Cookieはそこまでいいもんじゃなかったでしょ、って言ってもいいんじゃないですか？広告のあり方としては、（リタゲでひたすら追いかけられるより）今のスマートニュースとかのほうが健全だと思います。今やっているかどうかは知りませんが、パーソナライズもできるし、自然に目に入ってくるけど、クリックしたくなければしなければいいわけで。Cookieで同じ広告何度も見せるというのは、理屈の上では合っているのかもしれないけど、不健全な気はする。</p>

<p><b class="speaker hatano">羽田野</b> ところでパーソナライズって、便利な局面と、便利じゃない局面がありますよね。
例えばパーソナライズド検索とかって、言ってみれば「マイブーム」でしかないし。そうじゃなくて、<strong>「私」というフィルターを通さない世界を見たい時もある</strong> わけで。なんでもパーソナライズがいいわけじゃないだろう、と。Facebookとか、パーソナライズが行き過ぎてて気持ち悪く感じちゃうときもあります。さっきの広告の話もそうですけど。</p>

<p><b class="speaker simizu">清水</b> でもそれも、ハッキリ言うと慣れじゃないかな。今の若い子たちって、最初からそういう世界に慣れきっちゃってて、そんな気持ち悪さとかとは無縁だと思いますよ。</p>

<p><b class="speaker oikawa">及川</b> パーソナライズって、どんどん良くなっていくって性質のものですしね。ユーザが快適に感じるように、というふうに調整されていくんです。</p>

<p><b class="speaker hatano">羽田野</b> でもそこにはジレンマがあるような気がします。的確なパーソナライズを行うためには、サービスにどんどん個人情報を渡していかなくてはならない。そこも慣れなんでしょうか。</p>

<p><b class="speaker simizu">清水</b> 慣れの問題もあると思いますし、あと、個人情報と思われているものも、個人情報じゃなくなってくる可能性もあるんじゃないかと思いますね。例えば <strong>統計情報って、個人情報とは見なされにくい</strong> じゃないですか。</p>

<p>結局のところサービス側が欲しいのって、ユーザの行動履歴そのものじゃなくて、「ユーザが何に関心を抱いているか」という点なんですよね。だからユーザの行動履歴 、例えばユーザが見ているページの特徴量だけを抽出して、ニューラルネットワークに学習させていくと、<strong>ニューラルネットワークには重みしか残らない。そうなるとそれって、もはや個人情報とは呼ばれなくなる可能性もあるんじゃないでしょうか</strong>。</p>

<p>今までのように、原始的にキーワードを抜き出したり、単純な履歴から類推するんじゃなくて、全体的にこの人は何に関心があるんだろう、どういう話題だったら長く見てるんだろうかってことを、人工知能が総合的に判断するわけです。</p>

<h2>ブラウザは人工知能を搭載していく</h2>

<p><b class="speaker simizu">清水</b> 僕は、<strong>MicrosoftがEdgeにCortanaを搭載するのって、それも狙いの一つじゃないかと思う</strong> んですよね。ブラウザ上の行動を逐一観察することができる。どういうWebページに長く滞在しているか、どこらへんでスクロールを止めたか、などなど。</p>

<p>そういう情報をとった上でサービスが記憶するものが個々の閲覧履歴じゃなくて、「何に関心があるか」というメタデータであれば、それは個人情報とは言えないのではないでしょうか。</p>

<p><b class="speaker hatano">羽田野</b> EdgeはWebページにマーキングを行うことができますが、それもまさに、そういうことかもしれませんね。ユーザの関心事を浮き彫りにするための機能。</p>

<p><b class="speaker simizu">清水</b> そうそう。積極的にユーザとインタラクションしつつ、人工知能が搭載されているブラウザ。これって、ある意味ではすごく安全です。一番怖いのって、自分のWeb閲覧履歴が第三者に握られてしまって、しかもそれがいつかどこかに流出してしまうっていう危険性ですからね。</p>

<p>ディープ・ラーニングがここまで進んでいる世界で、ユーザの行動履歴を大量に学習させていくことで、サービスは「私が何に関心を持っているか」を学びます。個人情報として、履歴が残って気持ち悪いのは、個々の行動履歴が残るからキモチワルイのであって、ニューラルネットワークに残された重み付け情報であれば、もしかするとそれほど抵抗感はないのかもしれません。</p>

<p><b class="speaker siraisi">白石</b> いやー、メディアビジネスからCookie、ディープラーニングに至るまで、盛りだくさんですね。一旦ここで、前半のビジネスっぽい話題は終わりにして、Webテクノロジーを中心にした話に移りましょうか。
なんかビジネスっぽい話題だと、及川さんの発言が奮わないし(笑)。</p>

<p><b class="speaker oikawa">及川</b> いや、言いたいことはたくさんあるんですが、ぼくが話しだすと止まらなそうな話題なので自重してたんです(笑)。喉元まで何度も出かかってるんですけどね。</p>

<p><b class="speaker siraisi">白石</b> (笑) では、及川さん大活躍の<a href="https://html5experts.jp/shumpei-shiraishi/15207/" target="_blank" data-wpel-link="internal">[後編]</a>に続きます！</p>
]]></content:encoded>
			</item>
		<item>
		<title>HTMLとJavaScript、CSSだけで作ろう！Firefox OSアプリ</title>
		<link>/chikoski/13697/</link>
		<pubDate>Thu, 16 Apr 2015 03:00:15 +0000</pubDate>
		<dc:creator><![CDATA[清水智公]]></dc:creator>
				<category><![CDATA[最新動向]]></category>
		<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Mozilla]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=13697</guid>
		<description><![CDATA[連載： HTML5 Conference 2015 特集 (5)こんにちは、清水です。先日のHTML5 ConferenceでFirefox OS上で動作するアプリの開発と、Firefox Marketplaceの公開に...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/h5conf2015/" class="series-257" title="HTML5 Conference 2015 特集" data-wpel-link="internal">HTML5 Conference 2015 特集</a> (5)</div><p>こんにちは、清水です。先日のHTML5 ConferenceでFirefox OS上で動作するアプリの開発と、Firefox Marketplaceの公開に関する講演をさせていただきました。今回はその講演内容のうち、アプリ作成に関する部分を重点的に説明します。</p>

<h2>すべてWeb技術で</h2>

<p>Firefox OSの特徴は、ユーザの目にする部分は全てHTML5で実装されている点にあります。音楽アプリ、カメラ、ギャラリーといったプリインストールされているものはもちろん、ダイヤラーや、SMS、スマホのロックスクリーンや、ホーム画面といったシステムよりのアプリもすべてHTMLとJavaScript、CSSだけで実装されています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/01-html5.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/01-html5-300x225.png" alt="Firefox OSのアプリ、UIはWeb技術のみでできています" width="300" height="225" class="aligncenter size-medium wp-image-13700" srcset="/wp-content/uploads/2015/03/01-html5-300x225.png 300w, /wp-content/uploads/2015/03/01-html5.png 640w, /wp-content/uploads/2015/03/01-html5-207x155.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<h2>Firefoxをインストールして、開発スタート</h2>

<p>Firefox OSのアプリ開発に必要なことはただ一つ、Firefoxのインストールです。開発者アカウントの作成も、ディベロッパープログラムへの登録も、専用SDKのインストールも必要ありません。</p>

<p>FirefoxにはWebIDEという機能があります。これはアプリ開発ツールとして必要な機能を一通り持っています：</p>

<ul>
<li>ファイルの作成・編集機能、シンタックスハイライト</li>
<li>デバッガ、インスペクタ</li>
<li>シミュレータの起動、</li>
<li>実機との接続管理、アプリの転送機能</li>
</ul>

<p>リリース版のFirefoxでも十分開発に耐えますが、開発をするなら <a href="https://www.mozilla.org/firefox/developer/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firefox Developer Edition</a>の利用をお勧めします。Mozillaの提供する開発者向けの機能をいち早く利用できる点が特徴です。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/02-fireox-developer-edition.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/02-fireox-developer-edition-300x210.png" alt="Firefox Developer Editionの起動画面" width="300" height="210" class="aligncenter size-medium wp-image-13699" srcset="/wp-content/uploads/2015/03/02-fireox-developer-edition-300x210.png 300w, /wp-content/uploads/2015/03/02-fireox-developer-edition.png 640w, /wp-content/uploads/2015/03/02-fireox-developer-edition-207x145.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>Firefox Developer Editionは、リリース版とは異なる場所にインストールされます。また初回起動時に開発用のプロファイルを作成するため、リリース版との併用が可能です。<a href="https://mozilla.org/firefox/sync/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firefox Sync</a>を利用して同期しておけば、ブックマークや履歴、パスワードは通常利用しているものと共有できます。</p>

<h2>Hello World!</h2>

<p>ではさっそく、WebIDEを利用してHello Worldしてみましょう。Firefoxのメニューから「Web 開発」→「Web IDE」と進んでWeb IDEを起動します。起動すると次のような画面が表示されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/04-webide.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/04-webide-300x241.png" alt="04-webide" width="300" height="241" class="aligncenter size-medium wp-image-14196" srcset="/wp-content/uploads/2015/03/04-webide-300x241.png 300w, /wp-content/uploads/2015/03/04-webide.png 640w, /wp-content/uploads/2015/03/04-webide-207x167.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>画面の左上にある「アプリを開く」をクリックすると展開されるメニューから「新規アプリ」を選びます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/05-newapp.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/05-newapp-300x145.png" alt="05-newapp" width="300" height="145" class="aligncenter size-medium wp-image-14197" srcset="/wp-content/uploads/2015/03/05-newapp-300x145.png 300w, /wp-content/uploads/2015/03/05-newapp.png 640w, /wp-content/uploads/2015/03/05-newapp-207x100.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>選ぶとテンプレートの選択を求められます。「HelloWorld」テンプレートを選び、プロジェクト名にアプリの名前を入力して、「OK」ボタンを押すとアプリのテンプレートが作成されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/06-helloworld.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/06-helloworld-300x232.png" alt="HelloWorldテンプレートを利用して新規にアプリを作成する例" width="300" height="232" class="aligncenter size-medium wp-image-14198" srcset="/wp-content/uploads/2015/03/06-helloworld-300x232.png 300w, /wp-content/uploads/2015/03/06-helloworld.png 640w, /wp-content/uploads/2015/03/06-helloworld-207x160.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<h2>シミュレータのインストール</h2>

<p>次にシミュレータをインストールします。シミュレータはブラウザのアドオンとして提供されています。画面右上のメニューから「シミュレータをインストール」を選び、表示された画面の中から開発を行う Firefox OSのバージョンに合わせたシミュレータをインストールします。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/07-simulator-installation.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/07-simulator-installation-300x232.png" alt="シミュレータのインストール画面" width="300" height="232" class="aligncenter size-medium wp-image-14199" srcset="/wp-content/uploads/2015/03/07-simulator-installation-300x232.png 300w, /wp-content/uploads/2015/03/07-simulator-installation.png 640w, /wp-content/uploads/2015/03/07-simulator-installation-207x160.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>KDDIから販売されているFirefox OS端末、Fx0はFirefox OS 2.0で動作しています。国内向けにアプリを書く場合は、Firefox OS 2.0のシミュレータをインストールするとよいでしょう。</p>

<h2>アプリの起動と修正の反映</h2>

<p>作成したテンプレートを、インストールしたシミュレータ上で実行します。WebIDE上部にある「実行ボタン」を押すと、実行できます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/08-app-execution.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/08-app-execution-300x75.png" alt="08-app-execution" width="300" height="75" class="aligncenter size-medium wp-image-14200" srcset="/wp-content/uploads/2015/03/08-app-execution-300x75.png 300w, /wp-content/uploads/2015/03/08-app-execution.png 640w, /wp-content/uploads/2015/03/08-app-execution-207x52.png 207w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>実行すると、次のような画面が表示されます。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/09-helloworld.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/09-helloworld-180x300.png" alt="09-helloworld" width="180" height="300" class="aligncenter size-medium wp-image-14201" srcset="/wp-content/uploads/2015/03/09-helloworld-180x300.png 180w, /wp-content/uploads/2015/03/09-helloworld.png 385w, /wp-content/uploads/2015/03/09-helloworld-125x207.png 125w" sizes="(max-width: 180px) 100vw, 180px" /></a></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;meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1"&gt;
    &lt;title&gt;Hello World&lt;/title&gt;
    &lt;link rel="stylesheet" href="app.css"&gt;
    &lt;script src="app.js" defer&gt;&lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;h1&gt;こんにちは世界！&lt;/h1&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p></p>

<p>また、app.jsを次のように修正すると、アプリのロードが終了した時点でアラートダイアログが表示されます。</p>

<p></p><pre class="crayon-plain-tag">window.addEventListener("load", function() {
  alert("Hello World!");
});</pre><p></p>

<p>WebIDEの実行ボタンをもう一度押すと、これらの修正が実行中のアプリに反映されます。</p>

<h2>アプリの構造</h2>

<p>テンプレートに従って作成されるファイルは以下のような構造をしています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/03-files-of-helloworld.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/03-files-of-helloworld-300x251.png" alt="Hello World テンプレートによって展開されたファイル" width="300" height="251" class="aligncenter size-medium wp-image-13698" srcset="/wp-content/uploads/2015/03/03-files-of-helloworld-300x251.png 300w, /wp-content/uploads/2015/03/03-files-of-helloworld-207x173.png 207w, /wp-content/uploads/2015/03/03-files-of-helloworld.png 600w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>

<p>HTMLやJavaScriptに加えて、&#8221;manifest.webapp&#8221;というファイルがあります。これはアプリに関するメタデータで、これはアプリのインストールや、Mozillaの提供するアプリストアであるFirefox Maretplaceにアプリを登録時に参照されます。</p>

<p>manifest.webappの実体は次のようなJSONファイルです。</p>

<p></p><pre class="crayon-plain-tag">{
  "name": "こんにちは世界",
  "description": "A Hello World app",
  "launch_path": "/index.html",
  "icons": {
    "16": "/icons/icon16x16.png",
    "48": "/icons/icon48x48.png",
    "60": "/icons/icon60x60.png",
    "128": "/icons/icon128x128.png"
  },
  "type": "privileged",
  "permissions": {}
}</pre><p></p>

<p>各項目の詳細については、<a href="https://developer.mozilla.org/Apps/Manifest" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Mozilla Developer Networkのアプリマニフェスト</a>
をご覧いただくのが確実ですが、上記の例にある項目は以下のような意味を持ちます。</p>

<table>
<thead>
<tr>
  <th>項目名</th>
  <th>説明</th>
</tr>
</thead>
<tbody>
<tr>
  <td>name</td>
  <td>人間が読むための、アプリ名。最長 128 文字</td>
</tr>
<tr>
  <td>description</td>
  <td>人間のためのアプリ説明文。最長 1024 文字</td>
</tr>
<tr>
  <td>launch_path</td>
  <td>アプリ起動時に読み込まれるHTMLファイルのパス。上記の例では、manifest.webappと同じフォルダにあるindex.htmlが読み込まれる</td>
</tr>
<tr>
  <td>icons</td>
  <td>アイコンのリスト。128ピクセルx128ピクセルのアイコンは必須。また 512ピクセルx512ピクセルのものも含めることが推奨されている</td>
</tr>
<tr>
  <td>type</td>
  <td>アプリの種別。特権アプリの場合は、privilegedと記入する。一般アプリの場合は省略可能だが、明示する場合はwebと記入する</td>
</tr>
<tr>
  <td>permissions</td>
  <td>Camera APIやDevice Storage APIのように、注意が必要なAPIを利用する場合は、ここに列挙する</td>
</tr>
</tbody>
</table>

<p>以上のように、HTML、CSS、JavaScriptにmanifest.webappを足したものが、Firefox OSアプリの最小構成となります。</p>

<h2>Firefox OS で利用できる API</h2>

<p>Firefox OS のアプリは、すべてJavaScriptで記述します。そのため カメラやGPSといったセンサー類へのアクセスや、バイブのコントロール、SDカードへのデータ保存などは、HTML5で利用できるAPIを通して行います。利用できるAPIの一部分を挙げると、以下のようになります。</p>

<ul>
<li>Ambient Light Sensor API：環境光センサーを利用して周囲の照度を取得できる</li>
<li>Geolocation API：端末の物理的な位置を取得できる</li>
<li>Vibration API：ゲームなどのフィードバックのために、バイブレーションをコントロールできる</li>
<li>Camera：デバイスに内蔵されたカメラを利用して動画や、写真を撮影できる</li>
<li>Contacts：連絡先データベースへのアクセスが可能になる</li>
<li>Device Storage：SD カードなど、端末の持つストレージに対して読み書きが行える</li>
</ul>

<p>例えばDevice Storage APIを利用して、SDカード中のファイルをすべてコンソールに出力するプログラムは、次のようになります。</p>

<p></p><pre class="crayon-plain-tag">var sdcard = navigator.getDeviceStorage("sdcard");
var cursor = sdcard.enumerate();
cursor.onsuccess = function(){
  var file = this.result;
  console.log(file.name);
  if(!this.done){
    this.continue();
  }
};</pre><p></p>

<h2>WebActivities：アプリの機能を利用する API</h2>

<p>音楽のライブラリや、写真のギャラリー、カメラでの撮影といった機能を実装する方法は2つあります。1つは上記にあげたAPIを利用して1から機能を作る方法、もう1つはWebActivitiesを利用して他のアプリを呼び出す方法です。</p>

<p>標準でインストールされている音楽アプリや、ギャラリー、カメラアプリは、「ライブラリから音楽の選択する」「ギャラリーから写真を選ぶ」「写真を撮る」といったアプリの機能の一部を他のアプリから利用できるようになっています。</p>

<p>これを利用しているアプリの例には、<a href="https://marketplace.firefox.com/app/cameran" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Cameran</a> があります。Cameranは写真にフィルタや効果を追加するアプリなのですが、自分で写真撮影や管理機能を実装しているのではなく、インストールされている他のアプリの提供する「画像を選ぶ機能」を利用しています。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/10-webactivities.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/10-webactivities-169x300.png" alt="10-webactivities" width="169" height="300" class="aligncenter size-medium wp-image-14203" srcset="/wp-content/uploads/2015/03/10-webactivities-169x300.png 169w, /wp-content/uploads/2015/03/10-webactivities.png 360w, /wp-content/uploads/2015/03/10-webactivities-116x207.png 116w" sizes="(max-width: 169px) 100vw, 169px" /></a></p>

<p>他のアプリが提供している機能を、自分のアプリから呼び出して利用するためのAPIが、WebActivitiesです。例えば、他のアプリが提供するJPEG形式の画像を選択する機能の呼び出しは、次のようにWebActivitiesを利用して実現できます。</p>

<p></p><pre class="crayon-plain-tag">var activity = new MozActivity({
  name: "pick",
  data: {
    type: "image/jpeg"
  }
});
activity.onsuccess = function() {
  var picture = this.result;
  console.log("A picture has been retrieved");
};</pre><p></p>

<p>尚、WebActivitiesを利用して呼び出せるのは機能の名前であって、アプリではありません。おなじ名前の機能が複数のアプリから提供されている場合、どのアプリを利用するかはユーザの選択に任されます。</p>

<p>WebActivitiesの詳細、特に標準でインストールされているシステムアプリが提供する機能名については、<a href="https://developer.mozilla.org/docs/Web/API/Web_Activities" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Mozilla Developer Network の Web アクティビティ</a>をご覧ください。</p>

<h2>アプリケーションの権限</h2>

<p>上記のAPIすべてを、アプリから利用できるわけではありません。強力なAPIの利用には、それに見合った権限が必要となります。</p>

<p>Firefox OSのアプリは権限に応じて次の3つに分類されます。</p>

<ul>
<li>一般のアプリ (type:web)</li>
<li>特権アプリ (type: privileged)</li>
<li>内部アプリ (type: certified / internal)</li>
</ul>

<p>最後の内部アプリ、以前は認定アプリ (Certified App)と呼ばれていたアプリは、キャリアもしくはそれに準じるベンダしか作成を許されていません。そのため私たちが作成するアプリは、一般アプリもしくは特権アプリのどちらかになります。</p>

<p>権限と、利用できるAPIの対応関係は、OSのバージョンによって異なります。対応関係はWebIDEの「許可設定一覧」で確認できます。</p>

<p>許可設定一覧は以下のようになっています。</p>

<p>✓は利用可能、✕ は不可能、! は利用可能だが利用時にユーザに対して通知されることを表しています。</p>

<p>以下の例では、Camera APIを利用するためには、アプリを特権アプリとしなければならないことがわかります。</p>

<table>
<thead>
<tr>
  <th>名前</th>
  <th>type:web</th>
  <th>type:privileged</th>
</tr>
</thead>
<tbody>
<tr>
  <td>geolocation</td>
  <td>!</td>
  <td>!</td>
</tr>
<tr>
  <td>camera</td>
  <td>✕</td>
  <td>!</td>
</tr>
<tr>
  <td>alarms</td>
  <td>✓</td>
  <td>✓</td>
</tr>
</tbody>
</table>

<h2>実際に作ってみよう</h2>

<p>以上がFirefox OSアプリの概要でした。これを踏まえて、ボイスレコーダーアプリの作成を例に、アプリの作成例をみてみましょう。</p>

<p>今回作成するアプリは次のような1画面のアプリとなります。画面をタップすると録音を開始し、もう1度のタップで録音を終了します。録音した音声は ogg ファイルとして音楽ライブラリに保存されるものとします。</p>

<p><a href="https://html5experts.jp/wp-content/uploads/2015/03/11-recorder.png" data-wpel-link="internal"><img src="/wp-content/uploads/2015/03/11-recorder-169x300.png" alt="作成するボイスレコーダーアプリの実行画面" width="169" height="300" class="aligncenter size-medium wp-image-14202" srcset="/wp-content/uploads/2015/03/11-recorder-169x300.png 169w, /wp-content/uploads/2015/03/11-recorder.png 360w, /wp-content/uploads/2015/03/11-recorder-116x207.png 116w" sizes="(max-width: 169px) 100vw, 169px" /></a></p>

<p>なお今回作成したサンプルは、 <a href="https://gist.github.com/chikoski/00bbcb2cff65293869a0" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">gist</a>で公開しています。
こちらもご利用ください。</p>

<h2>使用するAPIとアプリの権限</h2>

<p>今回は次のAPIを利用します。</p>

<table>
<thead>
<tr>
  <th>API名</th>
  <th>目的</th>
  <th>Firefox OS 2.0で必要な権限</th>
</tr>
</thead>
<tbody>
<tr>
  <td>GetUserMedia</td>
  <td>マイクからの音声入力を扱うため</td>
  <td>通常</td>
</tr>
<tr>
  <td>MediaRecorderAPI</td>
  <td>音声を録音するため</td>
  <td>通常</td>
</tr>
<tr>
  <td>Web Audio API</td>
  <td>音声の分析を行うため</td>
  <td>通常</td>
</tr>
<tr>
  <td>DeviceStorage API</td>
  <td>音声をファイルとして保存するため</td>
  <td>特権</td>
</tr>
</tbody>
</table>

<p>DeviceStorage APIを利用するためには、アプリの種別を特権アプリとする必要があります。またいくつかのAPIを利用するためには、manifest.webappのpermissionsの項目に記述を行う必要があります。そのため manifest.webappを以下のように記述します。typeと permissionsの項目が、それぞれ設定されていることを確認してください。</p>

<p></p><pre class="crayon-plain-tag">{
  "name": "audio-caputre-sample",
  "description": "An sample app to capture audio through microphone",
  "launch_path": "/index.html",
  "icons": {
    "16": "/icons/icon16x16.png",
    "48": "/icons/icon48x48.png",
    "60": "/icons/icon60x60.png",
    "128": "/icons/icon128x128.png"
  },
  "type": "privileged",
  "permissions": {
    "audio-capture": {
      "description": "To record audio"
    },
    "device-storage:music": {
      "description": "To store captured audio",
      "access": "readwrite"
    }
  }
}</pre><p></p>

<h2>HTML と CSS の記述</h2>

<p>アプリのビューは HTML と CSS で定義します。今回のアプリでは次のものを利用しました。</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;meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1"&gt;
    &lt;title&gt;audio capture test&lt;/title&gt;
     &lt;script src="app.js" defer&gt;&lt;/script&gt;
    &lt;link rel="stylesheet" href="app.css"&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;canvas id="canvas"&gt;&lt;/canvas&gt;
    &lt;p id="recording"&gt;●REC&lt;/p&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre><p></p>

<p>CSS は以下のようになっています。</p>

<p></p><pre class="crayon-plain-tag">body{
   margin: 0;
   padding: 0;
 }
 #canvas{
   width: 100%;
   height: 400px;
   margin: 0;
   padding: 0;
   box-sizing: border-box;
 }
 #recording{
   color: red;
   position: fixed;
   top: .5em;
   left: .5em;
   display: none;
 }</pre><p></p>

<h2>JavaScript を使った録音</h2>

<p>コードの全体像は <a href="https://gist.github.com/chikoski/00bbcb2cff65293869a0" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">gist に公開したもの</a>をご覧いただくこととして、
ここではマイクからの入力ストリームの取得、録音、そしてファイルへの出力部分について解説します。</p>

<p>まずは、マイクからの入力ストリームの取得方法です。manifest.webapp中のpermissionsの項目に&#8221;audio-capture&#8221;を追加すると、
つぎのようにGetUserMediaを使っ、てマイクからの入力を扱うための入力ストリームを取得できます。</p>

<p></p><pre class="crayon-plain-tag">navigator.getUserMedia({video: false, audio: true}, 
                       streamAquired, 
                       error =&gt;{
                         console.log(error);
                       });</pre><p></p>

<p>この実行が成功すると、コールバック関数が呼ばれます。取得した入力ストリームは、関数の第1引数として与えられます。上記の例では streamAquired という関数が呼ばれます。この関数は入力ストリームを利用する様々なオブジェクトの初期化を行います。</p>

<p>ここで初期化されるオブジェクトの中には MediaRecorder オブジェクトがあります。初期化は次の様に行われています。</p>

<p></p><pre class="crayon-plain-tag">var initRecorder = function(stream){
  recorder = new MediaRecorder(stream);
  recorder.ondataavailable = (event) =&gt; {
    console.log(event); 
    if(storage != null){
      var filename = createFileName(event);
      console.log("attempt to save as " + filename);
      var req = storage.addNamed(event.data, filename);
      req.onsuccess = function(){
        console.log("saved as " + this.result);
      };
      req.onerror = function(){
        console.log(this.error.name);
      };
    }
  };
};</pre><p></p>

<p>MediaRecorderオブジェクトは、その名の通りメディアデータの記録を行うオブジェクトです。startメソッドを実行すると記録を開始し、stopメソッドを実行すると記録を停止し、記録したデータを用意します。データの用意できると、dataavailableイベントが発生します。用意されたデータは、dataavailableのdata属性でBlobとして参照できます。</p>

<p>上記の例では取得したBlobオブジェクトを、DeviceStorage APIのaddNamedメソッドを使って保存をしています。ここで利用しているstorageオブジェクトは次の様に作成されています。</p>

<p></p><pre class="crayon-plain-tag">var storage = navigator.getDeviceStorage("music");</pre><p></p>

<p>これは音楽データ用のストレージを取得しています。取得できるストレージの種類は次の4種類です。これ以外にもappsというアプリ用ストレージがありますが、これはシステムアプリからのみアクセスが許可されており、我々の作成するアプリは操作できません。</p>

<table>
<thead>
<tr>
  <th>ストレージ名</th>
  <th>役割</th>
</tr>
</thead>
<tbody>
<tr>
  <td>music</td>
  <td>音楽データ用ストレージ</td>
</tr>
<tr>
  <td>pictures</td>
  <td>写真データ用ストレージ</td>
</tr>
<tr>
  <td>videos</td>
  <td>動画データ用ストレージ</td>
</tr>
<tr>
  <td>sdcard</td>
  <td>汎用データストレージ</td>
</tr>
</tbody>
</table>

<p>取得したストレージに対してメソッド呼び出しを行うと、DOMRequestオブジェクトを返します。このオブジェクトのonsuccess属性やonerror属性に関数を登録することで、その操作が成功したか、失敗したかを知ることができます。上記の例では単に成否をログに出力しているだけですが、エラー処理が必要な場合などは、こちらにその処理を記述することになります。</p>

<h2>気軽に作ろう！</h2>

<p>以上 Firefox OSアプリの構成と作成方法について概観しました。</p>

<p>Firefox OSに向けたアプリの作成についてまとめると、次の3点になるかと思います。</p>

<ul>
<li>Firefoxがあれば開発をはじめられる</li>
<li>Firefox OSアプリ = HTML + JS + CSS + manifest.webapp </li>
<li>ライブラリの追加なしで、ハードウェアをコントロールできる</li>
</ul>

<p>とにかく開発を始めるための敷居が低く、HTMLや CSS、JavaScriptといったWeb標準技術のみで、ハードウェアへアクセスし、コントロールするようなアプリが作れます。</p>

<p>しかもブラウザエンジンがOSに組み込まれているため、作成したアプリのコンパイルやビルドが必要ありません。Webページを作るように、修正したアプリを再読み込みして即座に実行できます。また本文中では解説しませんでしたが、実機へのアプリの転送やデバッグもシミュレータと同様の手順で行えます。</p>

<p>このように開発の敷居が低く、簡単にアプリを作り始められるFirefox OSで、みなさんも作る自由を謳歌してください。</p>

<p>当日のセッションの動画・スライドは、こちらからご覧ください。</p>

<div class="aligncenter">

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

</div>

<p><a href="https://www.youtube.com/watch?v=zi4u7eMfmKY" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Youtube</a> /
<a href="http://www.slideshare.net/chikoski/firefox-os-43867933" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Slideshare</a></p>

<h2>参考資料</h2>

<ul>
<li><a href="https://www.mozilla.org/firefox/developer" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firefox Developer Edition</a></li>
<li><a href="https://mozilla.org/firefox/os/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Firefox OS</a></li>
<li><a href="https://developer.mozilla.org/Apps" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Mozilla Developer Networkのアプリセンター</a></li>
<li><a href="https://developer.mozilla.org/docs/WebAPI" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">WebAPI</a></li>
<li><a href="https://developer.mozilla.org/docs/Web/API/Navigator/getUserMedia" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">GetUserMedia</a></li>
<li><a href="https://developer.mozilla.org/docs/Web/API/Device_Storage_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">DeviceStorage API</a></li>
<li><a href="https://developer.mozilla.org/docs/Web/API/MediaRecorder_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">MediaRecorder API</a></li>
<li><a href="https://developer.mozilla.org/docs/Web/API/Web_Audio_API" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">Web Audio API</a></li>
<li><a href="https://developer.mozilla.org/Apps/Manifest" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">アプリマニフェスト</a></li>
</ul>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Conference 2015 特集]]></series:name>
	</item>
		<item>
		<title>WebGLとWebSocketによる3Dオンラインレースゲーム「JS-Racing」の全て！（後編）</title>
		<link>/knockknockjp/10481/</link>
		<pubDate>Tue, 02 Sep 2014 00:00:00 +0000</pubDate>
		<dc:creator><![CDATA[西田慎吾]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[WebSocket]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=10481</guid>
		<description><![CDATA[連載： HTML5 Japan Cup 特集 (6)WebGLとWebSocketによる3Dオンラインレースゲーム「JS-Racing」の全て！（後編） 前回に引き続きHTML5 Japan Cup 2014にてWebG...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/5jcup-2/" class="series-207" title="HTML5 Japan Cup 特集" data-wpel-link="internal">HTML5 Japan Cup 特集</a> (6)</div><p>WebGLとWebSocketによる3Dオンラインレースゲーム「JS-Racing」の全て！（後編）</p>

<p><a href="https://html5experts.jp/knockknockjp/10226/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">前回</a>に引き続き<a href="https://5jcup.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">HTML5 Japan Cup 2014</a>にて<strong>WebGL賞</strong>と<strong>優秀賞</strong>をいただいたオンラインレースゲーム、<a href="http://js-racing.knockknock.jp/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">JS-Racing</a>の技術解説をさせていただきます。</p>

<p><img src="/wp-content/uploads/2014/08/img14.jpg" alt="img14" width="630" height="484" class="alignnone size-full wp-image-10498" srcset="/wp-content/uploads/2014/08/img14.jpg 630w, /wp-content/uploads/2014/08/img14-300x230.jpg 300w, /wp-content/uploads/2014/08/img14-207x159.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<h2>サーバサイドの使用技術</h2>

<p>サーバサイドの技術として<a href="http://nodejs.jp/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Node.js</a>を使用しています。Node.jsはサーバーサイドで動作するJavaScriptで、<strong>ノンブロッキングI/Oというモデルを採用しています。非同期処理でデータベースへのアクセスとWebページの表示を別々に行ってくれる</strong>ので、ストレスなく大量のページの表示が出来ます。また、Socket.ioというライブラリを扱うことで、WebSocketを使用したリアルタイム通信を実現するができます。</p>

<p>Node.jsでWebアプリケーションを構築する場合、実験的にローカルのみの開発の場合は問題ありませんが、公開するとなると、Node.jsをインストールして実行できるサーバが必要になります。そのためには共有サーバのレンタルではなく、<strong>管理者権限 (root) が付与される専用サーバや、仮想専用サーバ（VPS）のレンタルが必要</strong>になると思います。管理者権限のため自由に環境をセットアップする事ができるために、そのWebアプリケーションに合わせた環境構築が可能になります。</p>

<h3>ExpressによるWebアプリケーションフレームワークの利用</h3>

<p>Node.jsで作成したWebアプリケーションの場合、リクエストURIの解析からファイルの配信など、HTTPサーバの機能を実装しなくてはいけません。これらの<strong>基本機能が備わったWebアプリケーションフレームワークを利用することで、非常に手軽にWebアプリケーションを作成</strong>できます。今回は、多数開発されているWebフレームワークのなかでも、有名で多く利用されている<a href="http://expressjs.com/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Express</a>を利用しました。</p>

<p></p><pre class="crayon-plain-tag">var express = require("express");
var app = express();
// HTMLエンジンとしてjadeを使用
app.set("view engine", "jade");
app.set("views", __dirname + "/views");
app.use(express.static(__dirname + "/public"));
// js-racing.knockknock.jp/にアクセスがあった場合、
// /views/index.jadeに「title=JS Racing」と「version=ver1.2」の値を渡して、HTMLを表示
app.get("/", function(req, res) {
    res.render("index", {
        title: "JS Racing",
        version: "ver1.2"
    });
});
// js-racing.knockknock.jp/controller.htmlにアクセスがあった場合、
// /views/controller.jadeに「title=JS Racing」と「version=ver1.2」と「id=URLパラメータのidの値」の値を渡して、HTMLを表示
app.get("/controller.html", function(req, res) {
    res.render("controller", {
        title: "JS Racing",
        version: "ver1.2",
        id: req.query.id
    });
});
app.set("port", process.env.PORT || 3000);
var server = require("http").createServer(app);
server.listen(app.get("port"), function(){
    console.log("Express server listening on port " + app.get("port"));
});</pre><p></p>

<p>22行目の<code>req.query.id</code>は<code>http://js-racing.knockknock.jp:3000/controller.html?id=000000</code>として渡された、URLパラメータのidの値が参照できます。この値は、ソケット通信時に発行されたソケットIDの値で、PCから発行されたスマフォ用のURL（QRコードか短縮URL）にURLパラメータとして付加されたもので、この値を元にPCとスマートフォンとのペアリングを行います。</p>

<p><strong>ExpressはHTMLのテンプレートエンジンとして<a href="http://jade-lang.com/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Jade</a>か、<a href="http://embeddedjs.com/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">ejs</a>を選択</strong>することができます。Jadeはインデントが必須です。閉じタグを省略できる代わりに、DOMの入れ子構造に沿って適切にインデントを使用する必要があります。基本的な記法がHTMLとは違うために、HTMLに親しんだマークアップエンジニアからすれば、慣れるまで違和感があるものだと思います。ejsはJadeとは違い、基本的な記法はHTMLをベースにしていますので、ローカルでくみ上げたHTMLをejsに組み込むことが容易です。今回はより楽にコード量を少なくHTMLを構築したいという点で、閉じたタグなしで記述できるJadeを選択しています。</p>

<p></p><pre class="crayon-plain-tag">// オープニングタイトル表示部分
section#sceneOpening.scene-opening(style="display: none;")
    div.scene-opening__inner
        div.scene-opening__box5
            h1.scene-opening__ttl
                // expressから受け取ったパラメータ、titleの値を挿入
                span.scene-opening__ttl__txt #{title}
                    br
                // expressから受け取ったパラメータ、versionの値を挿入
                span.scene-opening__ttl__txt2 &amp;nbsp;#{version}</pre><p></p>

<p>Jadeはこのようにインデントによって、要素の入れ子構造を定義しています。そのため閉じタグが不要で、<strong>HTMLを非常に簡略化</strong>して記述することが可能になります。HTMLを簡略化できるだけがJadeの特徴ではありません。<strong>HTMLをコンポーネント化して再利用</strong>したり、条件分岐をさせたり、繰り返し処理をさせたり、これまでサーバサイドで行っていたようなことがNode.jsで可能になります。ちなみにCSSはSass（Compass）を使い、記法にはBEMという命名規則を採用しています。</p>

<h3>Socket.ioによるリアルタイム通信</h3>

<p>車の同時走行と、スマートフォンからの車の操作を実現するためには、ブラウザとサーバ双方から、任意のタイミングでデータを送受信する必要があります。このリアルタイム通信を実現するために、<a href="http://socket.io/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Socket.io</a>を利用しています。Socket.ioは<strong>WebSocketなどのリアルタイム通信技術をラップして、シンプルなAPIを提供しているため、通信部分の煩雑さを意識することなく、リアルタイム通信を簡単に構築</strong>することができます。</p>

<p>スマートフォンからの車の操作を実現するために、接続時に発行されたソケットIDを共有することで、スマートフォンとPCをペアリングして相互通信しています。サーバを介しての通信なので、若干のタイムラグが発生する懸念もあったのですが、現状ではタイムラグを感じることはありませんでした。環境に依存することですので、あくまで今回の場合はということですが。</p>

<p></p><pre class="crayon-plain-tag">var socketArr = [];
io.sockets.on("connection", function(socket){
    // Socket.IDをPCに送信
    socket.emit("emit_id_form_server", socket.id);
    // PCから車の状態を受信
    socket.on("emit_carcondition_form_client", function(data){
        // 受信した車の状態
        var info = {
            id: socket.id,
            name: data.name,
            x: data.x,
            y: data.y,
            bodyAngle: data.bodyAngle,
            wheelAngle: data.wheelAngle,
            speed: data.speed,
            colorBody: data.colorBody,
            colorWing: data.colorWing,
            colorDriver: data.colorDriver
        };
        // 接続しているクライアントごとの情報を更新
        var flg = true;
        var i = 0, max;
        for (i = 0, max = socketArr.length; i &lt; max; i = i + 1) {
            if (socketArr[i].id == info.id) {
                socketArr[i] = info;
                flg = false;
            }
        }
        if (flg) {
            socketArr.push(info);
        }
    });
    // スマートフォンからの操作情報を受信
    socket.on("emit_controller_data_form_client", function(data){
        var id = data.id;
        var event = data.event;
        var value = data.value;
        var flg = false;
        var sockets = io.sockets.sockets;
        var i = 0, max;
        for (i = 0, max = sockets.length; i &lt; max; i = i + 1) {
            // ソケットIDが一致したクライアントに操作情報を送信
            if (sockets[i].id == id) {
                sockets[i].emit("emit_controller_data_from_server", {
                    id: id,
                    event: event,
                    value: value
                });
                flg = true;
            }
        }
        // ソケットIDが一致したクライアントが存在しなかった場合はスマートフォンに接続解除イベントを送信
        if (!flg) {
            socket.emit("emit_disconnect_client_from_server");
        }
    });
    // 接続しているクライアントの情報を1秒間に3回、接続しているクライアント全てに送信
    setInterval(function(){
        socket.emit("emit_other_carcondition_from_server", socketArr);
    }, 1000 / 3);
});</pre><p></p>

<p>接続している全てのクライアントに、接続している全てのクライアントの情報を送信するイベントは、ネットワークの負荷を考えて、1秒間に3回と制限をかけています。つまり3FPSのタイミングで同期をとることになりますが、クライアント側では30FPSでゲームが進行しているために、タイムラグが発生してしまいます。タイムラグによって発生する違和感をなくすために、クライアント側ではサーバ側から配信されるクライアント情報を元に、前回配信された情報との差分を10で割った値を算出して、クライアント側の1FPS毎の値として反映させ、違和感を解消しています。</p>

<h3>MongoDBでラップタイムの保存と走行データの保存</h3>

<p>ラップタイムを保存したり、走行データを保存するのにデータベースとして<a href="http://www.mongodb.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">MongoDB</a>を利用しています。MongoDBは、<strong>オープンソースのドキュメント指向データベース</strong>です。RDBMSのようにレコードをテーブルに格納するのではなく、ドキュメントと呼ばれる構造的データをオブジェクト形式でデータを管理します。
ちなみにNode.jsから<a href="http://mongoosejs.com/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Mongoose</a>を利用し、MongoDBに接続しています。Mongooseでは、Schemaインスタンスを通してModelを定義する事ができます。以下のようなオブジェクト形式でデータを管理出来るのが、MongoDBの特徴です。</p>

<p></p><pre class="crayon-plain-tag">var UserSchema = new mongoose.Schema({
    id:String, // ソケットID
    name:String, // 名前
    date:String, // 登録日
    time:Number, // ラップタイム
    comment: String, // コメント
    color: {
        body: String, // ボディカラー
        wing: String, // ウィングカラー
        driver: String // ドライバーカラー
    },
    runningPath: Array // 走行データ
});
var Users = db.model("user", UserSchema);</pre><p></p>

<p>走行データは1秒間に30回、車の位置と角度を記録した配列ですので、全てのユーザーの分だけ保存すると、データ量が肥大してしまう可能性があります。データ量を押さえるために、ラップタイムでソートして10位圏外の走行データは保持していません。</p>

<p>サーバサイドではNode.jsのおかげで、Webアプリケーションを構築する環境がとても整ってきていると思います。
基本的な言語はJavaScriptですので、サーバサイドもフロントエンドエンジニアが押さえるべき領域になっているのではと思います。</p>

<h2>その他の技術的トピック</h2>

<p>サーバサイド、クライアントサイドの技術それぞれの紹介を軸として、説明させていただきましたが、これ以外にもいくつか工夫した、技術的なポイントがありますので、紹介します。</p>

<h3>コースデータの共有</h3>

<p>3D表現を利用するために使用したthree.jsと、ゲームエンジンとして使った2D物理エンジンBox2DJSで、コースデータを共有するために2次元配列を使用しました。各値には数値を格納して、数値によってthree.jsでは壁、道路、芝、タイヤ、木、等の3Dモデルが配置され、Box2DJSでは3Dモデルの形状に沿った障害物を配置します。ちなみに開発当初、コースエディット機能や、SNSでコース共有機能等を考えていましたので、テキストデータとして扱いやすい2次元配列をコースデータとして採用したという経緯があります。</p>

<p></p><pre class="crayon-plain-tag">module imjcart.logic.map.value {
    export class MapConst {
        // コースデータ用の2次元配列
        static MAP:any = [           
　　　　　　[1,1,1,1,1,1,1,1,1,　〜省略〜　1,1,1,1,1,1,1,1,1,1,1], 
　　　　　　[1,4,4,4,4,4,4,4,4,　〜省略〜　4,4,4,4,4,4,4,4,4,4,1],
           〜省略〜　　　　　　
　　　　　　[1,1,1,1,1,1,1,1,1,　〜省略〜　1,1,1,1,1,1,1,1,1,1,1]
        ]
        // コースデータ配列内の各値が、何を表しているかの定数
        static MAP_KEY_NONE:number = 0; // アスファルト
        static MAP_KEY_WALL:number = 1; // 外壁
        static MAP_KEY_BLOCK:number = 2; // ブロック
        static MAP_KEY_TIRE:number = 3; // タイヤ
        static MAP_KEY_GRASS:number = 4; // 芝
        static MAP_KEY_TREE:number = 5; // 木
        static MAP_KEY_CAR_START_POSITION:number = 6; // 車のスタート位置
        static MAP_KEY_LAP_MEDIAN_CENTER_02:number = 7; // ゴールライン（逆走制御）
        static MAP_KEY_LAP_MEDIAN_CENTER_01:number = 8; // ゴールライン（逆走制御）
        static MAP_KEY_LAP_START_POINT:number = 9; // ゴールライン
        static MAP_KEY_SAND:number = 10; // 砂地
    }
}</pre><p></p>

<p>ただ、このような膨大な量の2次元配列を、テキストエディタで作成、編集するのは非常に非効率だと考えて、途中からExcelによって管理する方法に切り替えました。Excelでは条件付き書式を設定して、セルの値によって、わかりやすいように色づけするように設定しています。データ書き出しの際には、ExcelからCSVデータとしてテキストデータを書き出して、CSVデータをテキストエディタで置換して2次元配列にしています。</p>

<p><img src="/wp-content/uploads/2014/08/img12.gif" alt="img12" width="630" height="300" class="alignnone size-full wp-image-10487" /></p>

<h3>コースの装飾</h3>

<p>コースは直線と直角だけではなく、カーブ等の曲線も再現できなくてはいけません。2次元配列をコースデータとして利用する場合は、この点を補完する必要があります。また、コースというのは大抵、両脇のシケインとの境目にラインが引いてあります。こういったアスファルトや芝生といった要素以外の装飾を、周りの要素の配置条件に応じて追加することで、よりコースらしい外観を作る事ができます。下のキャプチャが装飾やカーブの補完をかけている物と、コースデータをそのまま表示したものとの違いです。</p>

<p><img src="/wp-content/uploads/2014/08/img13.jpg" alt="img13" width="630" height="254" class="alignnone size-full wp-image-10492" srcset="/wp-content/uploads/2014/08/img13.jpg 630w, /wp-content/uploads/2014/08/img13-300x120.jpg 300w, /wp-content/uploads/2014/08/img13-207x83.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<h2>まとめ</h2>

<p>以上が今回作成したJS-Racingの主な技術解説になります。Webアプリケーションを構築するには、今回解説したように多くの技術が必要となります。ご紹介した技術は、たくさんある中から必要なものを取捨選択した結果ですので、当然コンテンツが変われば、必要となる技術も変わります。このコンテンツで使用した主な技術の全体図をまとめました。</p>

<p><img src="/wp-content/uploads/2014/08/img02.jpg" alt="使用技術概要" width="630" height="400" class="alignnone size-full wp-image-10250" srcset="/wp-content/uploads/2014/08/img02.jpg 630w, /wp-content/uploads/2014/08/img02-300x190.jpg 300w, /wp-content/uploads/2014/08/img02-207x131.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>オンラインレースゲームというシンプルな内容のコンテンツですが、プラットフォームとしてWebブラウザを使用している点に注目していただけると嬉しいです。今までご紹介した技術は、オンラインゲームを作るだけの技術ではなく、Webコンテンツを作る上で、大きな可能性を持っている技術になります。私はゲームを作る上でこれらの技術を利用していますが、Web上の様々なサービスと連携をとることで、もっと広がりを持つコンテンツを作ることができると思います。ぜひ皆さんも、HTML5とJavaScript（クライアントサイド、サーバサイド含む）を使って、Webアプリケーションを作ってみてください。</p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Japan Cup 特集]]></series:name>
	</item>
		<item>
		<title>WebGLとWebSocketによる3Dオンラインレースゲーム「JS-Racing」の全て！（前編）</title>
		<link>/knockknockjp/10226/</link>
		<pubDate>Fri, 29 Aug 2014 00:00:58 +0000</pubDate>
		<dc:creator><![CDATA[西田慎吾]]></dc:creator>
				<category><![CDATA[プログラミング]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[TypeScript]]></category>
		<category><![CDATA[WebGL]]></category>
		<category><![CDATA[Webアプリ]]></category>

		<guid isPermaLink="false">/?p=10226</guid>
		<description><![CDATA[連載： HTML5 Japan Cup 特集 (5)今回はHTML5JapanCup2014にてWebGL賞と優秀賞を受賞したオンラインレースゲーム、JS-Racingの技術解説を書かせていただきます。 このコンテンツは...]]></description>
				<content:encoded><![CDATA[<div class="seriesmeta">連載： <a href="https://html5experts.jp/series/5jcup-2/" class="series-207" title="HTML5 Japan Cup 特集" data-wpel-link="internal">HTML5 Japan Cup 特集</a> (5)</div><p>今回は<a href="https://5jcup.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">HTML5JapanCup2014</a>にて<strong>WebGL賞</strong>と<strong>優秀賞</strong>を受賞したオンラインレースゲーム、<a href="http://js-racing.knockknock.jp/" data-wpel-link="external" target="_blank" rel="follow external noopener noreferrer">JS-Racing</a>の技術解説を書かせていただきます。</p>

<p><img src="/wp-content/uploads/2014/08/img03.jpg" alt="JS-Racing" width="630" height="397" class="alignnone size-full wp-image-10255" srcset="/wp-content/uploads/2014/08/img03.jpg 630w, /wp-content/uploads/2014/08/img03-300x189.jpg 300w, /wp-content/uploads/2014/08/img03-207x130.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>このコンテンツは<strong>WebGLの3D表現を活かした3Dレースゲーム</strong>です。<br>
また、<strong>WebSocketを使用しサーバを介して、複数のクライアントでの同時走行が可能なオンラインゲーム</strong>になっています。同時に、ソケット通信時に発行されるソケットIDをPCとスマートフォンで共有することで、<strong>スマートフォンからPC上の車を操作することも可能</strong>です。</p>

<p><img src="/wp-content/uploads/2014/08/img04.jpg" alt="JS-Racing" width="630" height="500" class="alignnone size-full wp-image-10264" srcset="/wp-content/uploads/2014/08/img04.jpg 630w, /wp-content/uploads/2014/08/img04-300x238.jpg 300w, /wp-content/uploads/2014/08/img04-207x164.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<h2>クライアントサイドの使用技術</h2>

<p>クライアントサイドの構築において、目的・用途に応じて使用した言語やライブラリに関して解説します。</p>

<h3>TypeScriptによるクラス設計</h3>

<p>クライアントサイドのメインとなるロジックを<a href="http://www.typescriptlang.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">TypeScript</a>を使用して設計しました。TypeScriptはマイクロソフトによって開発されたフリーでオープンソースのプログラミング言語です。<strong>大規模JavaScriptアプリケーションに向けて開発</strong>されたTypeScriptは、これまでのJavaScriptにはない以下の機能を有しています。</p>

<ul>
    <li><strong>型注釈とコンパイル時の型チェック</strong></li>
    <li><strong>クラス</strong></li>
    <li><strong>インターフェイス</strong></li>
    <li><strong>モジュール</strong></li>
</ul>

<p>TypeScriptはコンパイルして最終的にJavaScriptに出力することができます。今回のように多くの機能の実装が必要になるWebアプリケーションでは、クラスベースのオブジェクト指向言語的な特徴を持つTypeScriptは、設計しやすく非常に有効なものになります。</p>

<p>ActionScript3と同じように、1つのTSファイル（TypeScriptファイル）にクラスを1つだけ記述して、ファイル名とクラス名を一致させました。また、モジュール毎にディレクトリを作成して、クラスを格納しています。これにより<strong>機能毎にモジュールとクラスを整理</strong>する事ができ、再利用しやすく見やすいコードになりました。最終的には、クラス毎に作成したTSファイルを、クラス毎のJavaScriptファイルに出力（コンパイル）し、<a href="http://gruntjs.com/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Grunt</a>で結合、圧縮して、実際に読み込むJavaScriptファイルにしています。</p>

<p><img src="/wp-content/uploads/2014/08/img05.gif" alt="img05" width="630" height="670" class="alignnone size-full wp-image-10419" /></p>

<p>今回の場合、モジュールの分け方は、まず表示要素とロジックにモジュールを分けました。表示要素はゲームの各シーンや、3D描画、画面下部のランキング表示というように、表示要素単位でさらにモジュールを細分化していきます。ロジックは、イベントや値管理、定数、ユーティリティ、コースデータ管理、物理演算、リアルタイム通信といった、機能単位でモジュールを細分化していきます。このようにモジュールを分けていくことで、大規模なコンテンツ開発の際には、<strong>各クラスの責任範囲が明確化でき、バグが発生した際にも、原因を特定しやすく、さらには仕様変更にも強く</strong>なります。</p>

<p>TypeScriptは大規模開発においては、非常に設計しやすく、クラスベースのオブジェクト指向言語のメリットを最大限に享受できるものだと思います。ただその分、設計における手間と、なによりコード記述量が多くなります。中規模以下の案件では、最低限の設計で手軽に構築できる<a href="http://coffeescript.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">CoffeeScript</a>も、よい選択肢ではないかと思います。</p>

<h3>Box2DJSを使った2D物理演算</h3>

<p>車を走らせたり、障害物と衝突したりといった、ゲームの中核となるロジックは<a href="http://box2d-js.sourceforge.net/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Box2DJS</a>を使用しています。Box2DJSは、<strong>質量・速度・摩擦をシミュレーションするJavaScriptの2D物理演算エンジン</strong>です。</p>

<p>表現方法自体は3Dですが、物理演算エンジンは2Dを使用しました。今回のようなシンプルなゲームを作るには、3Dの物理演算エンジンより、2Dの物理演算エンジンの方が、ゲームバランスや操作感において向いていると感じます。コンシューマーゲームなどの本格的なゲームとなると、3D物理演算エンジンによる処理は、必要不可欠なものだとは思いますが、その分、マシンへの負荷も高くなります。</p>

<p>物理演算に関しては、別途サンプルを作成して、チューニングしていきました。ゲームの中核となる部分ですので、まずこのサンプルで楽しいと思えるかどうかで、最終的なゲームのゴールが見えてくると思います。可能な限りゲーム性向上のためのチューニングしていくことが大切です。</p>

<p><a href="http://www.knockknock.jp/sample/20140127/02/index.html" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer"><img src="/wp-content/uploads/2014/08/img06.gif" alt="img06" width="630" height="473" class="alignnone size-full wp-image-10421" /></a></p>

<p>初期段階のモックアップのイメージですが、まずはこのようにBox2Dを使って、2Dレースゲームを構築しました。この2Dレースゲームの情報を3D表示部分や情報部分（スピードメーター等）やコースデータ管理ロジック、リアルタイム通信ロジックに渡します。</p>

<p>物理演算クラス<code>imjcart.logic.physics.Physics</code>にて、マップ情報を元に<code>new Car</code>で車インスタンスを生成し、車の状態が変更したイベント<code>CHANGE_CAR_CONDITION_EVENT</code>をキャッチして、イベントを発行します。</p>

<p></p><pre class="crayon-plain-tag">public createCar() {
    // マップ情報を元に車を生成
    var x = 0;
    var y = 0;
    var i, j, max, max2;
    for (i = 0, max = imjcart.logic.map.value.MapConst.MAP.length; i &amp;amp;amp;lt; max; i = i + 1) {
        for (j = 0, max2 = imjcart.logic.map.value.MapConst.MAP[i].length; j &amp;amp;amp;lt; max2; j = j + 1) {
            if (imjcart.logic.map.value.MapConst.MAP[i][j] == imjcart.logic.map.value.MapConst.MAP_KEY_CAR_START_POSITION) {
                y = imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE * i;
                x = imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE * j;
                break;
            }
        }
    }
    this._car = new Car(this._context, this._world, x, y);
    // 車状態変更イベント
    this._car.addEventListener(event.PhysicsEvent.CHANGE_CAR_CONDITION_EVENT, (evt) =&amp;amp;amp;gt; {
        this.dispatchEvent(imjcart.logic.physics.event.PhysicsEvent.CHANGE_CAR_CONDITION_EVENT, {
            x: evt.x,
            y: evt.y,
            bodyAngle: evt.bodyAngle,
            wheelAngle: evt.wheelAngle,
            speed: evt.speed,
            power: evt.power,
            gear: evt.gear,
            direction: evt.direction
        });
    });
}</pre><p></p>

<p><code>imjcart.logic.physics.Car</code>クラスでは、<code>update</code>関数が実行されると、入力されている値をホイールに反映し、車の状態に変化を与えます。変化した車の情報を付加して、車の状態が変更したイベント<code>CHANGE_CAR_CONDITION_EVENT</code>を発行します。</p>

<p></p><pre class="crayon-plain-tag">public update() {
    // ホイールに力を適応
    var i = 0, max;
    for (i = 0, max = this._frontWheels.length; i &lt; max; i = i + 1) {
        var wheel = this._frontWheels[i];
        var direction = wheel.GetTransform().R.col2.Copy();
        direction.Multiply(this._enginePower);
        wheel.ApplyForce(direction, wheel.GetPosition());
    }
    // ホイールと車をつなぐジョイント部分に角度を適応
    for (i = 0, max = this._frontWheelJoints.length; i &lt; max; i = i + 1) {
        var wheelJoint = this._frontWheelJoints[i];
        var angleDiff = this._steeringAngle - wheelJoint.GetJointAngle();
        wheelJoint.SetMotorSpeed(angleDiff * this._steerSpeed);
    }
    // 車状態変更イベントの発行
    var position = this._body.GetPosition();
    var velocity = this._body.GetLinearVelocity();
    var speedX = Math.abs(velocity.x);
    var speedY = Math.abs(velocity.y);
    var speed = 0;
    if (speedX &lt; speedY) {
        speed = speedY;
    } else {
        speed = speedX;
    }
    this.dispatchEvent(imjcart.logic.physics.event.PhysicsEvent.CHANGE_CAR_CONDITION_EVENT, {
        x: position.x,
        y: position.y,
        bodyAngle: this._body.GetAngle(),
        wheelAngle: this._frontWheelJoints[0].GetJointAngle(),
        speed: speed,
        power: this._enginePower,
        gear: this._gear,
        direction: this._engineDirection
    });
}</pre><p></p>

<p><code>dispatchEvent</code>メソッドは、イベントを発行する<code>lib.event.EventDispacher</code>クラス（オリジナルで作成）に定義されたメソッドです。表示要素のクラスはこの<code>lib.event.EventDispacher</code>クラスを継承しています。</p>

<h3>three.jsの3D表現</h3>

<p>WebGLを使った3D表示部分には<a href="http://threejs.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">three.js</a>を使用しています。three.jsは、<strong>WebGLを扱うライブラリとしては、最もよく使われているJavaScriptライブラリ</strong>です。</p>

<p><a href="http://www.blender.org/" target="_blank" data-wpel-link="external" rel="follow external noopener noreferrer">Blender</a>というオープンソースの3次元コンピュータグラフィックスソフトウェアを使って、3Dモデルの作成を作成し、three.jsで読み込んで表示しています。Blenderで作成する3Dモデルデータ（今回のモデルデータはOBJ形式）は、ジオメトリ（形状）とUVテクスチャのみで、three.jsを使って、質感などの調整をしています。</p>

<p><img src="/wp-content/uploads/2014/08/img07.jpg" alt="img07" width="630" height="380" class="alignnone size-full wp-image-10422" srcset="/wp-content/uploads/2014/08/img07.jpg 630w, /wp-content/uploads/2014/08/img07-300x180.jpg 300w, /wp-content/uploads/2014/08/img07-207x124.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>また、今回のように実行環境が制限しづらいWebアプリケーションでは、なるべく多くのユーザーが利用できるように、マシンへの負荷は極力減らさないといけません。特にレースゲームは、現在走っているコースの先が見える必要があり、視野を広くしなければならないために、処理するデータ量が増え、より負荷がかかってしまいます。この<strong>負荷軽減</strong>のために、以下のことを考慮しています。</p>

<ol>
    <li><strong>ポリゴンが少なくても成り立つデザイン</strong></li>
    <li><strong>影をつけない</strong></li>
    <li><strong>ジオメトリ（形状）の結合</strong></li>
    <li><strong>負荷の少ないマテリアル（質感）を選択</strong></li>
</ol>

<p>1つめの<strong>ポリゴンが少なくても成り立つデザイン</strong>に関しては、下のタイヤのサンプルで、左のタイヤはポリゴン数を極端に減らしていますので、光や深度の計算が少なくなり、マシンへの負荷も小さくなります。右のタイヤはリアルなタイヤを再現したために、ポリゴン数も多く、マシンへの負荷も大きくなります。配置する量が少数ならそれほど問題になりませんが、コースデータに沿って多数配置する障害物ですので、マシン負荷は大きくなります。ただ、ポリゴン数が少ない分、リアルな表現からは遠く離れてしまっています。コース全体のデザインも含めてですが、リアルな表現を求めないポップなデザインを採用することで、低ポリゴンでも違和感のないようにしています。</p>

<p><img src="/wp-content/uploads/2014/08/img10.jpg" alt="img10" width="630" height="247" class="alignnone size-full wp-image-10425" srcset="/wp-content/uploads/2014/08/img10.jpg 630w, /wp-content/uploads/2014/08/img10-300x117.jpg 300w, /wp-content/uploads/2014/08/img10-207x81.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>2つめの<strong>影をつけない</strong>ですが、下のキャプチャを見ていただければ、影がない左側のキャプチャと影がある右側のキャプチャでは、3D空間としての説得力にだいぶ違いが出てしまっているかと思います。ここは苦渋の決断ですが、影をつけることはthree.jsではとても負荷のかかる処理なので、より多くのユーザにストレスなく遊んでもらうためにも影をつけない方を採用しました。</p>

<p><img src="/wp-content/uploads/2014/08/img08.jpg" alt="img08" width="630" height="227" class="alignnone size-full wp-image-10423" srcset="/wp-content/uploads/2014/08/img08.jpg 630w, /wp-content/uploads/2014/08/img08-300x108.jpg 300w, /wp-content/uploads/2014/08/img08-207x74.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>ちなみに影を出すには、レンダラーの<code>shadowMapEnabled</code>を<code>true</code>にして、光源の<code>castShadow</code>を<code>true</code>にします。そして影を作る側の物体の<code>castShadow</code>を<code>true</code>にして、影を受ける側の物体の<code>receiveShadow</code>を<code>true</code>にします。デフォルトでは<code>false</code>のため影が出ません。</p>

<p></p><pre class="crayon-plain-tag">// レンダラー
renderer.shadowMapEnabled = true;
// 光源
light.castShadow = true;
// 影を作る側
mesh.castShadow = true;
// 影を受ける側
mesh.receiveShadow = true;</pre><p></p>

<p>3つめの<strong>ジオメトリの結合</strong>に関してですが、WebGLコンテンツの様にGPUを使用するコンテンツは、ジオメトリの数だけGPUに対してドローコール（描画命令）をします。このドローコールの回数はパフォーマンスに大きく影響します。ジオメトリを<code>THREE.GeometryUtils.merge(geometry, mesh)</code>メソッドで結合することで、不要なドローコールの発生を少なくすることができます。注意点としては、結合したものは個別に動かすことや、マテリアルを個別に設定することはできませんので、今回は壁やコースなど、個別に動くことのない、大量に描画する必要のある要素に対してジオメトリの結合をしています。</p>

<p></p><pre class="crayon-plain-tag">var geometry = new THREE.Geometry(); // 空のジオメトリを作成
var meshArr = [];
// モデルデータとマテリアルを読み込む
var loader = new THREE.OBJMTLLoader();
loader.load("models/block03/block03.obj", "models/block03/block03.mtl", (object) =&gt; {
    object.traverse(function (child) {
        if (child instanceof THREE.Mesh) {
            child.material = new THREE.MeshLambertMaterial(child.material);
            child.material.ambient = new THREE.Color(imjcart.display.main.view3d.value.View3dConst.AMBIENT_COLOR);
            meshArr.push({
                mesh: child,
                material: child.material
            });
        }
    });
    // 読み込んだモデルデータをマップデータに沿って、クローンして配置。
    var i, j, max, max2;
    for (i = 0, max = imjcart.logic.map.value.MapConst.MAP.length; i &lt; max; i = i + 1) {
        for (j = 0, max2 = imjcart.logic.map.value.MapConst.MAP[i].length; j &lt; max2; j = j + 1) {
            if (imjcart.logic.map.value.MapConst.MAP[i][j] == imjcart.logic.map.value.MapConst.MAP_KEY_BLOCK) {
                var tagX = imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE * j + (imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE / 2);
                var tagY = 1;
                var tagZ = imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE * i + (imjcart.logic.map.value.MapConst.MAP_BLOCK_SIZE / 2);
                var mesh = meshArr[1].mesh.clone();
                mesh.position.set(tagX, tagY, tagZ);
                THREE.GeometryUtils.merge(geometry, mesh); // 空のジオメトリにマージして結合していく
            }
        }
    }
    this._block = new THREE.Mesh(geometry, meshArr[1].material);
    this._scene.add(this._block);
});</pre><p></p>

<p>最後に4つめの<strong>負荷の少ないマテリアル（質感）の選択</strong>は、表面の質感を上げるマテリアルを選択すると、その分マシンへの負荷が上がるということです。マテリアルの種類は代表的なもので、以下のメリットがあります。</p>

<ol>
<li><strong>MeshBasicMaterial</strong> : 光の影響を受けない
<li><strong>MeshLambertMaterial</strong> : 影や光の反射などを描画できる（ランバート反射モデル）
<li><strong>MeshPhongMaterial</strong> : 影や光の反射などをより綺麗に描画できる（フォンシェーディング）
</ol>

<p>マシンへの負荷に関しては1、2、3の順に次第に高くなります。選択したマテリアルの違いもマシン負荷への影響は大きいですが、マテリアルにバンプマップを使うかどうかもマシン負荷への影響は大きくなります。バンプマップは表面に細かな凹凸を表現します。下のキャプチャはアスファルトにバンプマップを適応したもの（右）と、適応していないもの（左）の違いです。表現力を上げるためには、バンプマップを採用したいところですが、ここでもマシン負荷を考慮してバンプマップを使っていません。</p>

<p><img src="/wp-content/uploads/2014/08/img09.jpg" alt="img09" width="630" height="400" class="alignnone size-full wp-image-10424" srcset="/wp-content/uploads/2014/08/img09.jpg 630w, /wp-content/uploads/2014/08/img09-300x190.jpg 300w, /wp-content/uploads/2014/08/img09-207x131.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>リアルな表現に近づければ近づけるほど、マシンへの負荷が増えてしまいます。ある程度の表現力は確保しながら、どれだけ負荷を減らせるかの調整は、これくらいのスペックなら問題なく表示できるようにしたいというターゲットとなるマシンを決めて、そのマシンで最低限確保したいフレームレートを決めます。あとは都度、フレームレートを確認しながら調整するということの繰り返しになります。マシンスペックだけでなく、ブラウザによっても表示速度に差異があることを意識していなければなりません。</p>

<h3>HTML5のAPIによる新しい表現力</h3>

<p>WebGL以外のHTML5の要素も、それぞれの特徴にあわせて適宜使用しています。</p>

<ul>
    <li>Canvas：コースマップ（コース縮尺図）</li>
    <li>SVG：スピードメーター</li>
    <li>WebFont：タイトルやテキスト全般</li>
    <li>CSS3：角丸やドロップシャドウやボタンデザイン</li>
</ul>

<p><img src="/wp-content/uploads/2014/08/img11.jpg" alt="img11" width="630" height="336" class="alignnone size-full wp-image-10446" srcset="/wp-content/uploads/2014/08/img11.jpg 630w, /wp-content/uploads/2014/08/img11-300x160.jpg 300w, /wp-content/uploads/2014/08/img11-207x110.jpg 207w" sizes="(max-width: 630px) 100vw, 630px" /></p>

<p>WebGLによる3D表示をしているCanvasの上に、各要素を配置していますが、上に乗っかっている要素を動かしたり、形状を変更させる場合には、背景に不透明な物を敷くなどの工夫が必要になります。そうしないと上に乗っかっている要素に変更があるたびに、下のCanvas全体まで、不要な再描画処理がかかってしまい、描画のパフォーマンスを著しく低下させてしまいます。</p>

<h2>まとめ</h2>

<p>以上が今回作成したJS-Racingで利用した、主なクライアントサイド技術になります。</p>

<p>3D表現として利用したWebGLは、IE11の対応によって最新のモダンブラウザでは、ほぼ実行可能な環境が揃ってきていると思います。</p>

<p>ユーザーのマシンスペックや、WebGL対応ブラウザの普及率を考えると、まだある程度ユーザーをしぼる必要がありますが、最近では話題を呼んでいる3Dコンテンツも次第に増えてきたように感じます。</p>

<p>次回は<strong>サーバサイドの使用技術</strong>と、その他の<strong>技術トピック</strong>に関して解説する予定です。</p>
]]></content:encoded>
		
		<series:name><![CDATA[HTML5 Japan Cup 特集]]></series:name>
	</item>
	</channel>
</rss>
