ストロボライトで働くエンジニアの徒然日記

株式会社ストロボライトのエンジニア開発ブログです。LOVEGREEN、botapii、MIDOLASを支えるエンジニアの日々の生活を綴っていきます

ストロボライトで働くエンジニアの徒然日記

株式会社ストロボライトのエンジニア開発ブログです。LOVEGREEN、botapii、MIDOLASを支えるエンジニアの日々の生活を綴っていきます

Monaca開発でハマったこと6選

Cordova, Monaca を使った開発の図

ストロボライトのエンジニア 武田です。

トップ画は私が育てている亀甲竜(冬型)です。
寒い日が続いていますが、ここ最近もぐんぐん蔓を伸ばしてます!
私達も寒さに負けずに成長していかなければですね!

先日も Monaca を使ってアプリ開発をしましたが、やはり色々とハマりました。
そのなかでもこれは辛かった!と思ったものを共有致します。

目次

1. input要素へのタップが無視される(iOS)

事象
input要素のtype=“text”へのタップ時にフォーカスがあたらず、
キーボードが表示されない、という現象が起きました。
若干長押しするとキーボードが表示されるのですが、
普通のタップでは全く反応せず、使い物になりませんでした。

解決方法
有識者に聞いたところ、iOSのWebビューコンポーネントであるUIWebViewのバグでした。
UIWebViewはApple社としては既に非推奨になっているようですが、
Cordovaでは未だデフォルトでUIWebViewが使われています。
そこで下記のプラグインを導入し、WKWebViewにすることで解決されました!

iPhoneXからのノッチ対応もWKWebViewのほうが楽なので、
Cordova開発する時にはWKWebViewプラグインは必須と考えてよいと思います。
ただし、下方の 3. 及び 4. の問題に注意が必要です。

2. Cordovaプラグインが読み込まれない

事象
Monaca cloud IDEでビルドしたアプリを動かした際、
Cordovaプラグインが全く読み込まれない、という現象が起きました。
アプリは起動するがプラグインAPIはまったく呼び出せない、という状況です。

解決方法
問題は、monacaが生成するwebpack設定ファイル(webpack.config.js)に対して変更した箇所でした。

monacaが生成するwebpack設定ファイルにはproductionモードとdevelopmentモードがあります。
productionモードでは、ソースファイルのminifyやconcatといった
一般的に製品版で必要となる処理が行われるように設定されています。
一方でdevelopmentモードではこれらの処理は行われません。

実装中はデバッグ効率化のために、
developmentモードでビルドするように設定ファイルを変更してました。
ですが実は、monacaのwebpack設定ファイルでは、
developmentモードにするとプラグインを読み込まないようになっていました。

結論として、monaca cloud IDEでビルドする際は常にproductionモードでビルドすることで
プラグインが使用出来るようになりました。

3. 自社APIサーバとXHR通信出来ない

事象
それまでは通信出来ていたのに、ある日突然XHR通信出来なくなりました。
iOSのATS対応のためのWhitelistプラグイン設定のミスや
2.のプラグインが読み込まれない問題と同時期に発生しため、切り分けに苦労しました。。

解決方法
この問題は1.でWKWebViewを導入したことに起因する問題でした。

Cordovaではローカルのソースコードを動かすためfile://プロトコルとして動作します。
そのため、APIサーバとのHTTPS通信はクロスドメイン通信となります。
UIWebViewでは問題が生じませんが、WKWebViewではサーバ側でCORSを有効化しないと通信してくれません。

よって、APIサーバ側でCORSを有効化してもらうことで解決しました。

4. Firestoreからデータが取得できない

事象
FirebaseのCloud Firestoreからデータを取得しようとしたところ、
下記のエラーが出力されて取得失敗しました。

[Error] [2018-10-18T07:01:04.315Z]  @firebase/firestore:
[Error] Firestore (5.5.0): Could not reach Cloud Firestore backend. Backend didn't respond within 10 seconds.
This typically indicates that your device does not have a healthy Internet connection at the moment. The client will operate in offline mode until it is able to successfully connect to the backend.

解決方法
config.xmlへ下記を入れることで、取得出来るようになりました。

<preference name=“InterceptRemoteRequests” value=“none” />

原因としては、WKWebView導入時に入れた cordova-plugin-wkwebview-file-xhr が
通信をインタラプトした際に、どうやらFirestoreとの通信を阻害しているようです。

今振り返ると、cordova-plugin-wkwebview-file-xhr でなく、 cordova-plugin-wkwebview-engine を使うべきだったかもしれません。

ちなみに上記は https://teratail.com/questions/152802 でアシアルの方に解析して頂きました!
本当に感謝です。

5. FacebookのCordovaプラグインを入れるとビルド出来ない。

検索すると phonegap-facebook-plugin と cordova-plugin-facebook4 の2つがあって迷いますが、 ここは cordova-plugin-facebook4 が正解です。

また、package.jsonへ以下を追記します。

{
    ... 中略
    "cordova": {
        "plugins": {
            ... 中略
            "cordova-plugin-facebook4": {
                "APP_ID":   Facebookの管理画面から抜き出す,
                "APP_NAME": Facebookの管理画面から抜き出す
            }
        }
    },
    ... 中略
}

6. phonegap-push-pluginがビルドできない

事象
phonegap-plugin-push を導入してmonacaでビルドすると、ビルドに失敗します。

解決方法
monaca が対応している Cordova Android プラットフォームはバージョン「6.4.0」なのですが、 phonegap-plugin-pushの最新2.2.x系では「7.1.0」が必須となっています。
これによりビルド出来ません。

そこで、phonegap-plugin-pushの2.1.x系までversionを落とす必要がありました。
詳細は https://github.com/phonegap/phonegap-plugin-push/blob/master/docs/INSTALLATION.md#installation-requirements を確認してください。

最後に

Cordovaアプリ開発では有志によるプラグインの力をお借りすることで、ネイティブと同じ機能を実現出来ます。 その一方で、有志が提供するものであるがゆえにバージョンや相性問題が起きやすいです。
こういった情報もみんなで共有、解決することで盛り上げて行きたいですね!

あと、monacaのビルドサーバも問題が生じていることがあります。 なにかおかしいなぁと思ったら以下を見ると良いです。 ja.monaca.io

以上です。

Firebaseカスタム認証の実装

f:id:strobolight-developers:20181105142247j:plain

ストロボライト のエンジニア、小河原です。

今回は既に動いているアプリケーションに後からFirebaseを導入する、という業務で多々ある、しかしWebにはあまり詳しく情報がない「カスタム認証」について書きたいと思います。

同じように実装する人の少しでもお役に立てればいいなと。ハイ。

Firebaseアプリケーションは作成済み前提で、
How to カスタム認証 Let'sスタートです!!

やったこと

カスタム認証とは

FirebaseはGoogleが提供するBaaSです。Firebase AuthenticationというSNSやSMS認証機能も提供されているため、サーバーレスで新規アプリケーションを作る際にはとても便利です。

提供されている認証方法のうち、既にユーザー認証機能は自社システムで持っていて後からFirebaseの認証のみを追加するケースのために、提供されているのがカスタム認証です。

証明書の取得

f:id:strobolight-developers:20181102110400p:plain

  1. 歯車アイコンからプロジェクトの設定へ移動
  2. グローバルナビのサービスアカウントへ移動
  3. 新しい秘密鍵の生成から秘密鍵をダウンロード
  4. すべてのサービスアカウントを管理へ移動

IAMロールの設定

f:id:strobolight-developers:20181102111207p:plain

admin-sdkアカウントのIAMロールにサービスアカウントトークン作成者権限を付与します。

カスタムトークン(IDトークン)発行処理

private-key.pemファイルの作成

ダウンロードした秘密鍵からprivate-key.pemを作成します。秘密鍵テキストエディタで開くとprivate-keyやpublic-key等pemファイル作成に必要な情報が記載されています。

pemファイルはpemファイルとして読み込まれるためのフォーマットがありますので、フォーマットに沿って作成しましょう。そして作成が終わったら、既存の認証サーバーに配置しましょう。

参考記事
qiita.com

カスタムトークンの作成

こちらはPHPのLaravelフレームワークを使用して書いたサンプルコードです。
FirebaseのカスタムトークンはJWTフォーマットなので、JWT変換するためにライブラリを使用しています。

<?php
# 説明①
use Firebase\JWT\JWT;

class FirebaseHelper
{
    static function issueFirebaseCustomToken($uid, $is_premium_account) {
        // Get your service account's email address and private key from the JSON key file
        $service_account_email = env('SERVICE_EMAIL');
        # 説明②
        $private_key = Storage::get('/firebase/private-key.pem');

        $now_seconds = time();
        $payload = array(
             "iss" => $service_account_email,
             "sub" => $service_account_email,
             "aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
             "iat" => $now_seconds,
             "exp" => $now_seconds+(60*60),  // Maximum expiration time is one hour
             "uid" => $uid,
             "claims" => array(
                 "premium_account" => $is_premium_account
                 )
             );
             return JWT::encode($payload, $private_key, "RS256");
      }
}

ユーザー認証後に、ここで作成したカスタムトークンも付与して、フロントに返却します。
フロントはこのカスタムトークンを使用し、FirebaseのsignInWithCustomToken(token)を呼び出す事で認証が行えます。

まとめ

カスタム認証便利!!そして新規のモバイルアプリケーションを作成する際はユーザー認証もFIrebaseに寄せてmBaaSとして最大限活用できれば開発スピードが上がる事は間違いないと思います。
既に認証機能あるし、、でもFirebaseの機能も使いたい、、って思ってる人は是非カスタム認証を使って始めてみてください!

技術の話に限らず今後も投稿していきますので、よろしくお願いします!

nginxでWordPress高速化

f:id:strobolight-developers:20180831201708p:plain
どうも、ストロボライトでエンジニアをやっている荒木です。

いよいよ弊社でもエンジニアブログを始める、ということで、初めてのエントリを拝命しました。

まず、色々話す前に、弊社のサービスのざっくりとした説明を…

ストロボライトでは、

LOVEGREEN」というメディアサイ
lovegreen.net

Botapii」というフリーペーパー
botapii.jp

MIDOLAS」という造園事業
midolas.jp

と、Green領域において多岐に事業を展開しております。

基本、開発事業部では、全ての事業を見ておりネタとしても色々とあるのですが、今回は「LOVEGREEN」にて実施した「nginx+WordPressでサイト高速化」について触れてみようかと思います。

本日のお品書き

WordPressのみのチューニングの限界

この辺りは昔から色々と誰もが試行錯誤して情報は世の中に沢山溢れていますが、高トラフィックなサイトでのチューニングとなると、WordPress単体でのチューニングには限界が出てきます。

そもそも、トラフィックが多いのでサーバーも含めた総合的な高速化を行わないと限界があるということです。

nginxでのキャッシュを導入を検討

元々、CloudFlare + apache + php-fpm + WordPressという構成で、さくらクラウドで稼働させていたものを、AWSへ移行し、CloudFlare + nginx + php-fpm + WordPressという構成に変更しました(この辺りのお話しは、また別の機会に)

で、そこからnginxのキャッシュを使って、そもそもWordPressに処理をさせないようにします。

いわゆる、FastCGI Cache」の導入です。

この辺りは、沢山ドキュメントが出ていますので、特に迷うこともないかと思います。

FastCGI Cacheの設定

nginx.conf(もしくはvhostのconf)」に必要な設定を追加していきます。

# 説明①
fastcgi_cache_path  {キャッシュファイルを保存するパス} levels=1:2 keys_zone={キャッシュゾーン名}:100m inactive=1d max_size=10g;

## 中略 ##

# 説明②
set $fixed_scheme 'https';

# 説明③
set $cache_enable 0;
set $keys_zone {キャッシュゾーン名};
#    set $cache_enable 1;
#    set $keys_zone '';

# 説明④
if ($request_method != GET) {
    set $cache_enable 1;
}

# 説明⑤
if ($request_uri ~* "({キャッシュしたくないURLを|でつなぐ})") {
      set $cache_enable 1;
}

# 説明⑥
if ($http_cookie ~* "{キャッシュしたくないCookie名を|でつなぐ}") {
    set $do_not_cache 1;
}


set $is_sp '';

# 説明⑦
if ($http_user_agent ~* '({スマホと判定されるUAを|でつなぐ(例えばPhone|iPod|Androidなど)})') {
        set $is_sp 'sp.';
}

location ~ \.php$ {

## 中略 ##

    # 説明⑧
    fastcgi_no_cache      $cache_enable;
    fastcgi_cache_bypass  $cache_enable;
    fastcgi_cache         $keys_zone;
    fastcgi_cache_key     $is_sp$fixed_scheme://$host$request_uri;
    fastcgi_cache_valid   200 30m;
    fastcgi_cache_valid   301 302 30m;
    fastcgi_cache_valid   404 1m;
    fastcgi_cache_valid   500 10s;
    fastcgi_cache_valid   any 1m;

}

大分端折りましたが、ざっとFastCGI Cacheの設定周りだけ記載してみました。
そんなに特殊なことはしていません。

以下ざっと説明です。

FastCGI Cacheの各項目の説明

説明① 「fastcgi_cache_pathの設定」

ここは基本マニュアル通りに設定します。
現状ではinactiveを1日にして、全くアクセスされなかったページは1日で削除されるように設定しています。
maz_sizeは10Gにして多めにキャッシュできるようにしています。

説明② 「HTTPスキーマの設定」

基本、LOVEGREENではSSL Onlyにしているのでキャッシュ時のkey(fastcgi_cache_key)に含めるHTTPスキーマも「https」固定にしてあります。

説明③ 「変数定義」

この辺りは動的に設定する変数の定義です。
$cache_enableという変数を定義して、動的にキャッシュする、しないを切り替えられるようにしています。($cache_enable=1でキャッシュON、$cache_enable=0でキャッシュOFF)

説明④ 「リクエストメソッドでのキャッシュON/OFF」

ここではGETメソッド以外はキャッシュしないように制御しています。

説明⑤ 「リクエストURLでのキャッシュON/OFF」

キャッシュしたくないページのURLを列挙していきます。
WordPressの場合、管理画面のURL、sitemapのURL、WordPressのフォーム画面などのURLになります。

説明⑥ 「CookieでのキャッシュON/OFF」

特定のCookieを持っている場合、キャッシュしない設定をここで定義します。
WordPressの場合だと

ぐらいですね。コメント機能があるのであれば、comment_authorも入れておけばよいかと思います。

説明⑦ 「UA判定でキャッシュKeyをPC/SPで分ける」

PCとSPでURLが同じ場合、キャッシュのKey(fastcgi_cache_key)を同じにしてしまうと、PCの時にSPの画面が表示されたり、SPの時にPCの画面が表示されたりしてしまいます。
レスポンシブサイトであれば問題なさそうですが、LOVEGREENはそうではないので、キャッシュKeyをデバイスごとに判定して、PC/SPそれぞれデバイスにあったキャッシュを作成、保持して上げる必要があるので、このようにUA判定を入れています。

説明⑧ 「fastcgi_cacheの設定」

ここでfastcgi_cacheの設定を定義しています。
主な項目について説明していきます。

fastcgi_no_cache
キャッシュする、しないを$cache_enableによって設定しています。

fastcgi_cache_bypass
キャッシュでの応答有無をを$cache_enableによって設定しています。
(キャッシュが存在してもWordPressからレスポンスを返却するかどうか)

fastcgi_cache_key
ここで、実際のキャッシュする際のキャッシュKeyを生成しています。
基本、ページURL+デバイスでユニークになるように、プレフィックスで$is_spを設定するようにしています。

ざっとこんな感じです。

で、結果は?

PageSpeed Insightsで計測すると、キャッシュ導入前、導入後で以下のような結果となりました。

キャッシュ導入前 キャッシュ導入後
FCP 3.2s 2.1s
DCL 5.3s 3.3s

まぁ、元々が遅かったので、キャッシュの恩恵は出ているのかな?と思います。

何より、Frontの描画処理でのCPU利用率が下がったので、管理画面側のレスポンスが異常に良くなりました。
(これまでは更新に3分待つとか、地獄のような状態だったので)
これによって、編集部メンバーから称賛されるという、予期しない効果も出ています。


とりあえず、あまり濃い内容ではないですが、これから開発事業部のメンバーが定期的に技術的なエントリ、たまに趣味の話など、色々綴っていきますので、よろしくお願い致します。