WebエンジニアがパパっとCordova + ガワネイティブでスマホアプリを構築する


タイトルの通り

ガワネイティブとはスマホアプリに近いUIの外部サイトをネイティブアプリ上のwebviewにて画面いっぱいに表示してアプリ化することでWebサイトをアプリストアに載せられるようにする技術のことを指します。

今回は正確にはネイティブアプリではなくjsやhtmlでハイブリッドアプリを構築するフレームワークであるCordovaを使うのでガワネイティブの正確な定義に当てはまるかは微妙ですが、まあ便宜的にガワネイティブという言葉を使います。

ちなみにPWAというブラウザから直接ホーム画面にWebサイトを登録してもらいアプリのように扱えるようになるPWAという技術はありますが一般的にはまだまだ知名度が低く、やはりアプリストアに載せることができるのは集客上結構なアドバンテージとなりそうです。

あとはWebエンジニアが1からスマホアプリ開発を習得するのは大変なのでまあなんとか楽したいという思想。

今回はAndroid+Windows10で開発行いました。
導入手順は下記URLなどを参考にしてます。
https://qiita.com/danishi/items/c7656d45bde73bf62feb

今回はとりあえずCordovaのwebviewで外部サイトを表示し、
その中でネイティブアプリのAPIで取得した情報などを外部サイトと双方向でデータ通信する方法を記述します。
スマホアプリ開発は今日始めて勉強したレベルなので間違ってるところはあるかもしれません。
iOSは持ってないのでまだ試してないですが多分大きくは変わらないと思います。

Cordova側

コマンドプロンプトでプロジェクトディレクトリに入りとりあえずInAppBrowserというプラグインを追加します。
これはCordova上でwebviewを表示するためのプラグインとなります。

cordova plugin add cordova-plugin-inappbrowser

Cordovaで記述するソース

index.js
document.addEventListener('deviceready', onDeviceReady, false);
function onDeviceReady() {
    function openInAppBrowser() {
        // ネイティブの機能を使いたい場合は_selfではなく_blankであることが必須
        var target = "_blank";
        // フルスクリーン指定することでアドレスバーとかを表示させなくする
        var options = "location=no,fullscreen=yes";

        // 外部サイトを開く
        var inAppBrowserRef = cordova.InAppBrowser.open('_外部サイトのURL_', target, options);
        inAppBrowserRef.addEventListener('message', messageCallBack);

        // target="_blank"のタブが閉じたら同時にアプリを終了させる
        inAppBrowserRef.addEventListener('exit', function () {
            navigator.app.exitApp();
        });

        // 親画面から外部サイト上で特定のスクリプトを実行する 今回は単純に10秒後にアラートを出す
        setTimeout(function (){
            inAppBrowserRef.executeScript({code: 'alert("test");'})
        }, 10000);
    }


    // 外部サイトのイベントで受け取ったデータを処理する
    function messageCallBack(data){
        alert(data.value);
    }

    openInAppBrowser();
}

inAppBrowserRef.executeScript にて例えばネイティブの機能で取得したデバイス情報などをコードに埋め込み実行させることで外部サイトにデータを送ることができる感じですね。

外部サイト側

app.js
    // Cordova側に外部サイト上のデータを送信する
    function postMessage() {
        var messageObj = {
            "value": 'hogehoge',
        };
        var stringifiedMessageObj = JSON.stringify(messageObj); 
        webkit.messageHandlers.cordova_iab.postMessage(stringifiedMessageObj);
    }

    postMessage();

たったこれだけでデバイス、外部サイトの双方向のデータの受け渡しができるようです。
外部サイトのJSから直接Cordovaのプラグイン機能を呼び出すことは無理ですが、このようにデータを経由しあえばどうにでも行けそうです。

ちなみに親タブがあって、その親タブとtarget="_blank"で開いた外部サイトタブがデータを双方向に通信しあってるイメージで、target="_self"にした場合は親タブそのもののURLが切り替わるようで上記の方法は使えなくなります。

外部サイト側だけで機能が完結していてネイティブの機能連携など一切必要ない場合はtarget="_self"でもできそうですがこの場合マジでコードが2行とかで完結しそうなのでこんなんで審査通るのか疑問です。。。

あ、あとクッキー、ローカルストレージの保存とかはこの段階だとまだ課題としてありそうですね。

メリット・デメリットとか所管

メリットとしてはレスポンシブでうまく実装すればPC(Web)、iOSとAndroidアプリ、タブレットなどマルチデバイス対応を本当に最小工数で完結させることができそうです。
大きな工数がとれない個人開発などにおいてはかなり有用なテクニックになりそうです。

Webエンジニアがスマホアプリの開発を初めて行うというような際の学習コストも普通にハイブリッドアプリを構築するよりも小さく済みそうです。

デメリットとしてはやはり審査ですね。
ガワネイティブ自体はよく使われる技術ですが、本当にWebサイトをそのまま表示するだけのようなアプリは審査に落ちることも多々あるらしいです。

あと何気に致命的だと思ったのはネイティブ/外部サイト間でデータの受け渡しができるとは言っても
例えばAdMob(Googleが提供するアプリ向けの高単価広告サービス)など用のplugin導入には障壁があって(っていうか普通に導入無理じゃね?)、もしかすると広告収入モデルで収益化を目指してる場合はあまり向いてない可能性はありそうです。
こういうところまで考慮するなら固定オーバレイ広告を載せる前提でFlutterやガワネイティブという文字通りネイティブアプリとして開発した方が自由度は上がりそうです。

簡単そうで面倒なガワネイティブ、今だとどう実装するのが一番なんですかねぇ。。。