Apache CordovaでWeb(PC、スマホ)、アプリのコード共通化について

#はじめに
2018年4月に[家事代行サービス Casy](https://casy.co.jp/)のシステムをリニューアルし、静的ページ以外のページ(ログイン後のページ)はSPAで作成しました。
iOSやAndroidアプリの作成には[Apache Cordova](https://cordova.apache.org/)を使うことで、Web(PC スマホ),iOSアプリ,Androidアプリがまったく同じコードで動作しています。

# よかった点
プラットフォームごとに開発する必要もなくなり、1つの機能に対して大幅に工数が削減できるようになりました。コードを修正をしても審査が必要ないので、気軽にリリースができます。Cordovaの場合はNativeの機能もコミュニティに豊富にpluginが用意されていて、javascriptでメソッドを呼び出すだけで使え、Webの知識だけで開発できます。

# Cordovaの現状について
良いことづくめのようですが、Cordovaは古くからあり(2012年ぐらい)、React、Vue、AngularとSPAが広まってきているにも関わらず、この手法で開発されているサービスはそれほど多くないようです。
逆にアプリだけでいいと割り切ってReact Nativeが使われるケースも増えてきました。

Google Trendを見ると2015年をピークに下がりつづけています
<img width="363" alt="スクリーンショット 2018-05-20 14.08.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/10645/1009fa0f-7a3b-044e-d131-e3ef418f6abd.png">

人気がない原因として、UIWebViewがひと昔前のJavaScriptエンジンのせいもあり、もっさりしていたり、Safariと挙動が違うことがあったり、CSSでアプリっぽく作るのが大変だったり、Swiftが登場して、iOSアプリが作りやすくなったことが要因としてあると思います。

ただCordovaでWkWebViewが使えるようになり(要plugin)、JavaScriptエンジンも刷新され速くなりました。
PC対応を気にしなければ、CordovaベースですでにネイティブっぽいUI部品もそろったフレームワークに[Onsen UI](https://ja.onsen.io/)や[ionic](https://ionicframework.com/)があり、CSSの知識すらほとんどなしに開発できる環境ができています。

# CordovaのSPA開発で困ったこと

## cookieが使えない
### 問題点
corsの設定で、Cordovaの場合はhostがないので、Access-Control-Allow-Originを'*'にせざるを得ず、そうするとAccess-Control-Allow-Credentialsがtrueにできない決まりなので、cookieが使えない。そのため、Webサーバによるセッション管理が使えない。
### 対応
ログイン確認ができたら、トークンを発行して送信し、Ajax呼び出しの際にトークンをセットしてもらうことで認証。なりすましを防ぐため、時々トークンを更新する。

## Geolocation APIが動かない
### 問題点
現在地を取得するGeolocation APIがブラウザだと動くのに、Cordovaだと動かない
### 対応
[cordova-plugin-geolocation](https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-geolocation/index.html)のプラグインを入れる。
iOS10以上だと位置情報取得にユーザの許可のダイアログが必須になり、ブラウザだと勝手に出してくれるのに、デフォルトのCordovaだとダイアログを出す設定がされていないので、機能自体が使えない。
ついブラウザで動くならCordovaでも動くはずと思ってしまうが、動かないこともあるので特殊なAPIは確認したほうがいい。

## WebView(アプリ内ブラウザ)の扱いが難しい
### 問題点
外部API呼び出し等でCordova内から呼び出すとアクセス元URLをチェックされる等でエラーになってしまう場合に、WebViewを立ち上げるもののgetのURLでしか立ち上げられなく、URLにトークンをのせるのは好ましくないが、再度ログインしてもらうのもつらい。
また一連の動作終了後、Webviewの閉じるボタンを見つけて閉じてもらうのもつらい。
### 対応
WebViewを立ち上げる前に、1回だけ短時間有効なトークンを取得し、それをWebViewのgetに含めることで自動ログインできるようにする。CordovaでWebviewのURLを監視できるので、完了用に予め決めたURLになったら、Webviewを閉じる

## history.back()を実行すると画面がずれる
### 問題点
history.back()を呼び出すと、画面上部にあるstatusbarの下にあったwkWebViewの画面がせりあがってstatusbarに被り、その分画面下にスペースができる。
iOSの設定で予めstatusbarにoverlayするようにし、最初からwkWebViewをstatusbarに被らせる。statusbarにあった時計が見えなくなってしまうので、自前で時計を出力。

## iPhoneXの画面の表示幅が小さい
### 問題点
iPhoneXで上下に黒い帯があって画面の表示域がせまい。
### 対応
iPhoneX用のスプラッシュ画像(1125px × 2436px)がアプリにないと、iPhoneXの画面幅が使われない。(要申請)
また、viewportのcontentに viewport-fit=coverの指定が必要。

## 複数人開発の際にgitの管理が大変
### 問題点
自動生成されたiOSやAndroidのコードは個人ごとの環境により内容が異なるので、git pullした後ビルドすると大量のdiffができてしまう。
### 対応
cordova platform rm ios && cordova platform rm androidして自動生成したコードを消した後のコードを管理する。
各platformごとに必要なresourceファイル(画像や画像の設定ファイル等)は、platform以下以外のところに置くようにして、git pullした後にcordova platform add iosやcordova platform add androidした後にそのresourceファイルをplatforms以下にコピーする。
もしくはCorodovaをビルドする端末は1台に制限する

# まとめ
Service WorkerがSafariに搭載されることになり、Webでもアプリと同じようにオフラインで動かせたり、Push通知ができるようになると、アプリの場合に必要だった、更新の際の審査やApp内課金による手数料がなくせるため、モバイルの中心がアプリからWebになる可能性があると思います。
ただ、まだService Workerが行き渡っている訳ではないため、その間はCordovaでアプリを作成するのはいい選択だと思います。