Webとスマホネイティブの間にある技術（ガワネイティブやハイブリッド、クロスプラットフォームなど）

## 動機

「スマホ用Webサイトが既にあるんだけど、それを上手く使ってアプリ化出来ない？」という話は、まだ一定数存在します。

その時に、「結局個別にKotlin/Swiftで実装するのが一番良いですよ」と反論したいアプリエンジニアも一定数いると思います。

私もその一人なので、理論武装のためにまとめました。
ただ、ほとんどの技術要素については実運用の経験が少ないため、間違いが含まれている可能性があります。
その際は、コメントや編集リクエストで教えて頂けると助かります :bow: 

## 方針一覧

1. Web (PWAを利用し、アプリっぽく見せる)
2. ガワネイティブ (アプリ内WebViewで、サーバがレンダリングしたHTMLを表示する）
3. ハイブリッド (Cordovaなど、HTMLなどをアプリ内に組み込み、XHRなどでサーバと通信する）
4. クロスプラットフォーム (Xamarin, React Native, Flutterなど)
5. ネイティブ (AndroidならKotlin, iOSならSwift)

上から、Web -> ネイティブ[^1]に近づいていくイメージです。
[^1]: ARTやLLVM上で動作しているのが"ネイティブ"と言えるか？というのはありますが、わかりやすいので"ネイティブ"と書いています。

以下では、それぞれのメリット・デメリットを記載していきます。

### Web

スマホ用Webサイトがあるのであれば、それをそのまま利用しよう、という発想。

PWAという流れが最近流行ってきており、
Web App Manifestを追加してホーム画面への追加、そこからの起動時の見た目をアプリに寄せたり、
Service Workerを利用して、オフライン対応をしたり。（SPAで作成されている必要がある？要確認）

**メリット**

- PWAの仕組みにより、アプリのような操作感を提供できる。
- 外部サービスとの連携についても、Webで実装しているまま利用できる。（OAuth、決済システム連携など）
- アプリストア（Google PlayやApp Storeなど）の申請・更新などが必要なく、随時アップデート可能。
- 課金について、アプリストアに中間手数料を払わなくて良い。

**デメリット**

- ネイティブ独自の機能は利用できない。（ただし、ブラウザ側でサポートされているカメラなどは利用できる）
- ネイティブ用として用意されているSDKが利用できない。（アプリであれば、Facebook SDKを利用して、Facebookアプリの認証を利用できる）
- アプリストアに配信できない。（ユーザとの接触面が減り、ホーム画面などに追加してもらいにくい）
- Web App Manifestは、Androidでは想定通り動作するが、iOS 11.3現在ではサポートされていない。 https://webkit.org/status/#specification-web-app-manifest
- 比較的新しい技術のため、実装・運用経験のあるエンジニアを集めるのは難しい。
- アプリストアの決済の仕組みを利用できない。

2018/04現在としては、PWAにしておいてアプリのような操作感を提供するのは良いことですが、「アプリの代替」とするのはまだ早いのでは？という印象です。（これはこれで、対応していく必要がありそうですが）
Safariのアップデート、ブラウザ動作の更なる高速化などにより、状況は変わってくる可能性がありそうです。 [^2]
[^2]: App Storeの収益を考えると、どこまでAppleが本気になってるのかわからないですが。

### WebView（ガワネイティブ）

アプリ内にWebViewを表示しておき、サーバの提供するURLを読み込み、特定のリンクのみアプリ側で反応する形。

**メリット**

- アプリストアに配信できる。
- サーバのリソースを随時見に行くため、UIの更新は容易。（ストアのアップデートを待つ必要が無い）
- 既存のWebを、"基本的"にそのまま利用できる。
    - UIの実装については、Webフロントエンジニアのみで行える。
- 特定のURLをフックする形でのネイティブの機能呼び出し可能。

**デメリット**

- 長いリスト表示、shadowやradius系のUIヘビーなstyleなどを利用した際に、ネイティブに比べて動作速度が劣る。（要実測・検討）
- iOS/Androidの両方に同じHTMLを配信することになるので、アプリらしいUIを構築するのが難しい（サーバ側でUserAgentによる判断・切り替えは可能だが、処理が複雑になる）
- Webそのままでは利用できない場合が多い。（フッタを非表示化したり、window.openを使わないように変更したり）
    - WebがSPA的になっていない場合、毎回レイアウト情報が通信路に乗るので、画面表示まで時間がかかりやすい。
- ネイティブ改修（Webからネイティブの利用方法の追加・変更なども）の場合は、アプリ更新が必要。
    - Webは最新がユーザに提供され続けるが、アプリはユーザの判断によって古い可能性がある。下位互換を保ったり、強制バージョンアップの仕組みを実装する必要がある。
- ネイティブの機能を実装する必要があるので、結局チーム内にはネイティブ実装が出来るエンジニアが必要。

### ハイブリッド（Cordovaなど）

Cordovaなどによる実装。
Webフロントのリソース（HTML/JavaScript/CSS）をアプリ内に埋め込み、XHRなどを利用してサーバとの通信を行う。
（ただし、Cordovaで上記の「ガワネイティブ」的に実装することも可能な模様。要確認。）

**メリット**

- UIの実装はWebフロントの技術で行える。
- アプリ内にHTMLなどを埋め込むことで、いくつかの利点がある。
    - アプリの更新時にUIも更新できるため、ガワネイティブであったようなバージョンの不一致が起こらない。
    - UI情報を毎回通信路に乗せないので、画面遷移にかかるネットワークコストが比較的低い。（アプリと同等）
- Cordovaなどのフレームワークの機能で、ネイティブ利用のインターフェース実装を削減できる。
- 手法としてある程度歴史があり、実装可能なエンジニアが一定数存在する。（はず）

**デメリット**

- ユーザに更新してもらわないと、新しい機能を提供できない。（CodePushが使える？要確認。）
- アプリ内にHTMLなどを埋め込むことになるので、Webサイトが存在する場合にコードの2重管理になりやすい。

### クロスプラットフォーム（Xamarin, React Native, Flutter）

Webフロントでもネイティブでもない言語を利用して、iOS/Android(/その他)の環境用のアプリを出力できるもの。
WebViewの上で動作するのと異なり、ネイティブに近い（or同等）の動作スピードを実現できている。（らしい）

**メリット**

- ネイティブとほぼ遜色ない動作速度
- 共通のコードを利用して、iOS/Androidのアプリを出力できる。（UIは別々に実装する場合もあり）
- XamarinであればWindows関連の技術者、React Nativeはフロントエンドエンジニアがコンバートしやすい。

**デメリット**

- まだ比較的情報が少なく、APIなども比較的不安定。
- 問題が起こったり、ネイティブに深く依存した機能を実装する場合は、結局各ネイティブの知識が必要になる。
- Webサイトとの共通化は諦めることになる。

### それぞれのネイティブ開発（Android - Kotlin, iOS - Swift）

普通にアプリをそれぞれ実装する。

**メリット**

- 情報が豊富、エンジニアも比較的集めやすい。
- OSの新バージョンが出た場合にも、そのまま利用できる。（他の手段の場合、ブリッジを実装したり、フレームワーク側の対応を待つ必要がある）
- 外部のSDK（Facebookログインや決済など）についても、サポートされている場合が多い。
- iOSらしい、AndroidらしいUIを構築しやすい。

**デメリット**

- iOS/Androidでそれぞれアプリを作成するため、工数・人員についてはそれぞれ必要。
- Webサイトとの共通化は諦めることになる。

## 比較表

雑で個人的感想も含まれていますが、簡単な比較表です。

|                | Web                               | ガワネイティブ                               | ハイブリッド                        | クロスプラットフォーム                                               | ネイティブ                      |
|----------------|-----------------------------------|----------------------------------------------|-------------------------------------|----------------------------------------------------------------------|---------------------------------|
| 動作速度       | x                                 | x                                            | x                                   | o                                                                    | o                               |
| ストア公開     | x                                 | o                                            | o                                   | o                                                                    | o                               |
| アップデート   | 随時                              | Web側は随時 アプリ側はストア更新             | ストア更新 （CodePushにより緩和？） | ストア更新 （CodePushにより緩和？）                                  | ストア更新                      |
| 実装           | Web front                         | Web front + ネイティブ                       | cordova(Web front)                  | C# or JavaScript or Dart                                             | Kotlin and Swift                |
| UI実装         | Web front                         | サーバサイドからのWeb frontレスポンス        | アプリ内でWeb frontの技術           | フレームワーク独自の実装方法 （iOS/Android共通・別実装は選択できる） | ネイティブでの実装              |
| オフライン対応 | ServiceWorkerを利用したキャッシュ | ServiceWorkerを利用 orネイティブでの独自実装 | XHRのエラーハンドリング             | APIアクセスのエラーハンドリング                                      | APIアクセスのエラーハンドリング |

## 感想

流行的には、
ガワネイティブ -> Cordova -> ネイティブ -> React Native/Xamarin -> ...
という流れがあるような気がしています。

まとめてみて思いましたが、どれも一定のメリット・デメリットがあり、ネイティブ側のエンジニアとしては概要ぐらいは押さえておきたいなーと思いました。（できれば、Getting Startedぐらいしておきたい）

ただ、やっぱりそれぞれのネイティブ（Kotlin/Swift）で実装することを推したいと思います。