[Firebase][iOS] Firebase Hosting でキャンペーンページを作ってみよう
はじめに
モバイルアプリサービス部の中安です。
「Firebase
を触ってみるシリーズ」の続きになります。
ここまでは
というお題で書かせていただきましたが、
今回はFirebase
の静的ウェブホスティングサービスであるFirebase Hosting
を触ってみようと思います。
またもウダウダと書きますが、何かのお役に立てば幸いです。
Firebase Hosting
Firebase Hosting
は、ホスティングされたWebページやWebアプリを簡単な操作でデプロイできちゃうサービスです。
アプリではWebページ(しかも簡易的な)で済ませたい機能はよくあります。 たとえば、利用規約やプライバシーポリシーなどといった約款系であったり、FAQのような静的でありながら運用上更新がかかるような画面、 そして今回のお題のような何かをお知らせするようなキャンペーンページなどでしょうか。
Webページであれば、iOSのみならずAndroidアプリにも流用が簡単です。
簡単な上に高速性、安心性があるならば、 アプリ開発者としてはわざわざサーバを立てたり借りたりするよりもサクッと良い感じに作れるので 選択肢のひとつに十分なりうると思います。
以下は公式ドキュメントから引用したFirebase Hosting
の特長です。
- 安全な接続を介して配信する: 最新のウェブは優れたセキュリティを備えています。
Firebase Hosting
には構成が不要のSSL
が組み込まれているため、コンテンツを常に安全に配信できます。 - コンテンツを高速に配信する: アップロードしたファイルは世界中の
CDN
エッジにあるSSD
にキャッシュされます。ユーザーがどこにいても、コンテンツを高速に配信できます。 - 高速なデプロイ:
Firebase CLI
を使用して、わずか数秒でアプリを稼働させることができます。コマンドラインツールにより、デプロイターゲットを簡単にビルドプロセスに追加できます。 - ワンクリックのロールバック: 迅速なデプロイは大いに有用ですが、間違いを元に戻せることはさらに優れた利点です。
Firebase Hosting
はワンクリックでロールバックできる完全なバージョン管理とリリース管理を提供しています。
うん、素敵。
準備
Xcodeプロジェクト側
基本的にWebページを扱うので、SDKなどの準備は不要かと思います。
https
でのやりとりになりますが、もしもApp Transport Security(ATS)
に何らかの制限をかけている場合は、そのあたりをご注意くださいませ。
Firebase CLI
Firebase Hosting
へのデプロイは前述にちらっと出てきましたが、Firebase CLI (Command-Line Interface)
というコマンドベースのツールを使って行います。
Firebase Hosting
以外のサービスにも使用するツールではありますが、この記事シリーズでは初出なのでその準備方法を書いておきます。
申し訳ないのですが、当記事ではMacのターミナルで作業する前提で進めていきます。 Windows等については他の諸記事や公式ドキュメントなどを参照ください。
node.jsとnpmは入っていますか?
Firebase CLI
自体は、Node.js
のモジュールパッケージ管理ツールである「npm (Node Package Manager)
」を使用してインストールします。
もし、未インストールの場合は先にそちらをインストールしておいてください。
インストール済みかどうかはバージョンを確認することで分かると思います。
Node.js
の確認 (2019年2月現在 Node.js
は5.10.0以降が必要)
$ node -v
npm
の確認
$ npm -v
CLIのインストール
下のコマンド一発ポンっです。そのまましばし待たれよ
$ npm install -g firebase-tools
終わったら念の為確認します
$ firebase --version
バージョン番号が出てきたら大丈夫と思います。
ウェブページコンテンツ
今回の主役はWebページです。 サンプルなので簡易的なものを用意します。
秋葉原に誕生した架空のカフェ「でででっぱーかふぇ」のお知らせページです。 (実際のカフェとは関係ありません)
<!doctype html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>でででっぱーかふぇオープンのお知らせ</title> </head> <body> <header> <h1>でででっぱーかふぇオープンのお知らせ</h1> </header> <section> <article> <p> 11月1日に「でででっぱーかふぇオープン」が秋葉原にオープンしました </p> </article> </section> <footer> <address>Copyright(C) でででっぱーかふぇ All right reserved.</address> </footer> </body> </html>
<!doctype html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>コーヒー価格値下げのお知らせ</title> </head> <body> <header> <h1>コーヒー価格値下げのお知らせ</h1> </header> <section> <article> <p> 12月1日よりコーヒーの価格を300円から270円に値下げいたします。この機会にぜひお越しください。 </p> </article> </section> <footer> <address>Copyright(C) でででっぱーかふぇ All right reserved.</address> </footer> </body> </html>
デプロイしてみる
では、用意したHTMLファイルを実際にデプロイしてみたいと思います。
Firebase CLI
を使うためにターミナルを開きます。
Firebaseにログイン
まず、Firebase CLI
からFirebase
にログインします。
$ firebase login
すでにブラウザでGoogleアカウントにログインしていると、
Already logged in as (アカウントのメールアドレス)
と返ってくるかもしれません。
その場合は次のイニシャライズの項に進んでください。
では、初回ログイン時の話をします。
まず、Allow Firebase to collect anonymous CLI usage and error reporting information? (Y/n)
と質問されると思いますが、
こちらは「Firebaseの使用状況やエラーを匿名で収集していい?」とのことなので、「まぁいいでしょう」とY
を選択するでいいと思います。
すると、次にブラウザが立ち上がってGoogleのログイン画面が自動的にローディングされると思います。
ログインするとFirebase CLI
に対するスコープの許可を下図のように聞かれます。
確認しつつ許可しましょう。
このように成功したらターミナルに戻ります。
Success! Logged in as (アカウントのメールアドレス)
と表示されているはずです。
イニシャライズ
次に、Firebase CLI
を使ってFirebase Hosting
のための初期化処理をしてあげる必要があります。
ホスティングするファイルの置き場のルートにしたい新規フォルダを適当なところに作り、 ターミナルからそのフォルダへと移動します。
$ cd (作ったフォルダのパス)
イニシャライズのコマンドを実行します。
$ firebase init
すると下記のようなFirebase CLI
との対話が始まります。
######## #### ######## ######## ######## ### ###### ######## ## ## ## ## ## ## ## ## ## ## ## ###### ## ######## ###### ######## ######### ###### ###### ## ## ## ## ## ## ## ## ## ## ## ## #### ## ## ######## ######## ## ## ###### ######## You're about to initialize a Firebase project in this directory: /Users/(ディレクトリパス) ? Which Firebase CLI features do you want to setup for this folder? Press Space to select features, then Enter to confirm your c hoices. (Press <space> to select) ❯◯ Database: Deploy Firebase Realtime Database Rules ◯ Firestore: Deploy rules and create indexes for Firestore ◯ Functions: Configure and deploy Cloud Functions ◯ Hosting: Configure and deploy Firebase Hosting sites ◯ Storage: Deploy Cloud Storage security rules
「このフォルダでセットアップするのはどの機能であるか?」と聞かれているので、
矢印をHosting:
に合わせ、スペースキー押下で選択状態にしてエンターキーをタァーンします。
色々と何かが行われた後にまた質問がきます。
? Select a default Firebase project for this directory: (Use arrow keys) ❯ [don't setup a default project] project-name-a (ProjectA) project-name-b (ProjectB) project-name-c (ProjectC) [create a new project]
「このディレクトリでデフォルトで使うプロジェクトは何かね?」と聞かれるので、 対象のFirebaseプロジェクトを選びます。
? What do you want to use as your public directory? (public)
「Firebase Hosting
で公開されるコンテンツのディレクトリ」を聞かれます。
好みで変えてもいいですが、今回はデフォルトのpublic
のままにしようと思うので、このままエンターキーをタァーンします。
? Configure as a single-page app (rewrite all urls to /index.html)? (y/N)
「よかったらSPA
に適した設定してあげるけど、どう?」と聞かれるので、今回はパスするのでN
をタァーンします。
そうすると、Firebase CLI
は準備を終えて終了します。
中身を見てみます。
$ ls -la
drwxr-xr-x 6 hoge staff 192 2 21 15:21 . drwxr-xr-x 13 hoge staff 416 2 21 15:08 .. -rw-r--r-- 1 hoge 55 2 21 15:21 .firebaserc -rw-r--r-- 1 hoge 1144 2 21 15:21 .gitignore -rw-r--r-- 1 hoge 134 2 21 15:21 firebase.json drwxr-xr-x 4 hoge 128 2 21 15:21 public
このように、firebase.json
を含む色々なファイルと、public
ディレクトリが自動的に配置されました。
public
ディレクトリの中にはindex.html
などが置かれていると思います。
デプロイ
先ほど作った2つのHTMLファイルをpublic
のディレクトリに移動させて、ディレクトリは移動せずに下記のコマンドを打ちます。
$ firebase deploy
たったこれだけ。あら簡単。デプロイが始まります。
=== Deploying to '(プロジェクト)'... i deploying hosting i hosting[(プロジェクト)]: beginning deploy... i hosting[(プロジェクト)]: found 4 files in public ✔ hosting[(プロジェクト)]: file upload complete i hosting[(プロジェクト)]: finalizing version... ✔ hosting[(プロジェクト)]: version finalized i hosting[(プロジェクト)]: releasing new version... ✔ hosting[(プロジェクト)]: release complete ✔ Deploy complete! Project Console: https://console.firebase.google.com/project/(プロジェクト)/overview Hosting URL: https://(プロジェクト).firebaseapp.com
Deploy complete!
と出ましたね。
最後にホスティングのURLとしてhttps://(プロジェクト).firebaseapp.com
と書かれているので、試しに開いてみます。
$ open https://(プロジェクト).firebaseapp.com/shop_open.html
ブラウザで確認できました。おめでとうございます
キャンペーン画面を作る
ここまでできたら「Firebase Hosting
の基本的な使い方はできましたね」という感じですが、
今回のお題は「キャンペーンページを作ってみる」なので、もう少しアプリを絡めた実務的な使い方を書いていきたいと思います。
Firestore
にキャンペーンを作る
ここでいうキャンペーンとは「運用者がアプリユーザにお知らせしたいコンテンツ」とします。
「運用者がキャンペーンを登録して、それをユーザがアプリで見る」という流れにするために、
Cloud Firestore
にキャンペーン情報を貯めておくことにします。
Cloud Firestore
については、こちらに書いています。
データを作る
図のようにcampaigns
というコレクションを作り、その中に手入力で情報を書いていきます。
ドキュメントIDは自動採番で、タイトルと先ほどホスティングしたURLを入れてみました。
2つページを用意したので、同構造のデータをもう1つ作っておきます。
ルール設定
ルールはとりあえずは誰でも見れるという設定にしておきます。
service cloud.firestore { match /databases/{database}/documents { match /campaigns/{document=**} { allow read } } }
アプリ側でキャンペーン一覧画面を作る。
iOSアプリ側を作っていきたいと思います。
サンプルなので、デザインは画面一杯にテーブルビューが置かれているだけのUIにします。
ビューコントローラ
キャンペーン一覧画面としてCampaignViewController
を用意しました。
空っぽの実装ですが、テーブルビューの処理は事前にこのようにしておきます。
import UIKit class CampaignViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet private weak var tableView: UITableView! func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 0 // あとで実装 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) // あとで実装 return cell } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) // あとで実装 } }
インポート
キャンペーンの詳細は、Firestoreで先ほど設定したurl
の値を取得し、Safariビューコントローラで表示することにします。
import UIKit import Firebase import SafariServices
このようにインポートさせてやります。
データ取得
今回はviewDidLoad()
のタイミングでFirestore
へのデータ取得をしにきます。
private var data = [[String : Any]]() override func viewDidLoad() { super.viewDidLoad() let db = Firestore.firestore() db.collection("campaigns").getDocuments() { [weak self] querySnapshot, error in guard let self = self else { return } if let error = error { // エラー処理 self.data = [] self.tableView.reloadData() return } if let querySnapshot = querySnapshot { self.data = querySnapshot.documents.map { snapshot in return snapshot.data() } self.tableView.reloadData() } } }
コレクション参照オブジェクトの getDocuments()
で複数のドキュメントを参照しに行っています。
コールバックではクエリスナップショットが返され、その中に取得できたドキュメントのデータが入っているので、
それを保持しつつテーブルビューをリロードします。
データ表示
Firestore
ドキュメントのデータはディクショナリで渡されてきます。
Campaign
クラスといったデータオブジェクトのクラスでラッピングしてあげるほうがベターと思いますが、
今回はそのまま使います。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return data.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) let datum = data[indexPath.row] cell.textLabel?.text = datum["title"] as? String return cell }
詳細を表示
テーブルビューのセルが選ばれたら詳細を表示するようにします。
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let datum = data[indexPath.row] let urlString = datum["url"] as! String let url = URL(string: urlString)! let view = SFSafariViewController(url: url) present(view, animated: true, completion: nil) }
SFSafariViewController
にFirestore
で設定されたURLを渡して開きます。
動作確認
このようにFirestore
に登録したデータが一覧に表示されます。
セルをタップでHosting
にデプロイしたWebページが表示されます。
このようにキャンペーン一覧からキャンペーン詳細を見ることのできるアプリとなりました。
最後に
簡素なサンプルでしたが、Webページを簡単に公開することができました。
多くのリソースをホスティングしたり、同時にたくさんのユーザが訪れるようなWebページを考えている場合は、 無料枠だと制限があることに注意してください。
詳しくは Firebase Hosting のリファレンスを参照ください