Cordova で Android の Adaptive Icon を設定する方法。
colors.xml
を作成config.xml
の <platform name="android">
内にアイコン設定を追記1 | <icon |
1 | $ sw_vers |
1 | Android Studio 4.1.1 |
Cordova のドキュメント(Customize app icons)に config.xml
の設定方法は記載されているが、「そもそもどうやってそのアイコン作るの?」とかが全然見つからなかったので手順を整理した。(※あくまで「自分はこうやった」なので他に適切なやり方あるかも)
各自で適宜用意。今回はサンプルアイコンとして 無料の暴れ牛のフラットアイコン素材 | FLAT ICON DESIGN -フラットアイコンデザイン- を利用。
Android Studio で /path-to-your-project/platforms/android
を開く。
res
を右クリックして、 New
→ Image Asset
を選択。
Foreground Layer
タブでアイコン画像を選択し、 Resize
で良い感じに調整。
Background Layer
タブは必要に応じて変更。(たぶん触らなくても良いはず)
Options
タブも必要に応じて変更。(自分の環境では Legacy Icon
, Round Icon
は不要なので No
を選択)
Next
→ Finish
で出力。 Res Directory
は main
で OK。
/path-to-your-project/platforms/android/app/src/main/res/
に mipmap-xxxx
が出力されているので /path-to-your-project/res/icon/android/
配下にコピー。
自分の環境では以下にコピーした。
/path-to-your-project/res/icon/android/mipmap-hdpi/ic_launcher_foreground.png
/path-to-your-project/res/icon/android/mipmap-mdpi/ic_launcher_foreground.png
/path-to-your-project/res/icon/android/mipmap-xhdpi/ic_launcher_foreground.png
/path-to-your-project/res/icon/android/mipmap-xxhdpi/ic_launcher_foreground.png
/path-to-your-project/res/icon/android/mipmap-xxxhdpi/ic_launcher_foreground.png
colors.xml
作成/path-to-your-project/res/icon/android/values/colors.xml
を作成。
1 |
|
config.xml
変更config.xml
の <platform name="android">
内に追記。(※見やすいように改行してます)
1 |
|
あとはいつも通りにビルドすれば OK。デバイス/OS 次第では、1度アンインストールしないと Adaptive Icon に切り替わらないかもなので注意。
colors.xml
を作成config.xml
の <platform name="android">
内にアイコン設定を追記1 | <icon |
Android aab ファイルから versionName
, versionCode
を 抽出/確認 する方法。
bundletool
を使うbundletool dump manifest --bundle /path/to/aab/example_app.aab
1 | $ sw_vers |
bundletool
をインストールして bundletool dump manifest
コマンドを実行。
1 | $ bundletool dump manifest --bundle /path/to/aab/example_app.aab | grep -i -e versioncode -e versionname |
出力結果抜粋(※見やすいように整形済み)
1 | <manifest |
bundletool
を使うbundletool dump manifest --bundle /path/to/aab/example_app.aab
位置情報 API と逆ジオコーディングAPIを使ってブラウザで住所を取得する方法
navigator.geolocation.getCurrentPosition
で取得latitude
), 経度(longitude
), 精度(accuracy
)などが取得可能https://mreversegeocoder.gsi.go.jp/reverse-geocoder/LonLatToAddress?lat=<緯度>&lon=<経度>
lv01Nm
), 住所コード(muniCd
) が取得可能https://maps.gsi.go.jp/js/muni.js
GSI.MUNI_ARRAY[<muniCd>]
で取得可能すごく雑に書いたサンプル、 <head>
などは割愛。
1 | <body> |
CodePen、直接開いた方が良いかも: https://codepen.io/17num/pen/XWaYgLo
See the Pen Untitled by 17num (@17num) on CodePen.
コード中にコメントも書いてるので参考リンクと合わせて見れば OK。
navigator.geolocation.getCurrentPosition
で取得latitude
), 経度(longitude
), 精度(accuracy
)などが取得可能https://mreversegeocoder.gsi.go.jp/reverse-geocoder/LonLatToAddress?lat=<緯度>&lon=<経度>
lv01Nm
), 住所コード(muniCd
) が取得可能https://maps.gsi.go.jp/js/muni.js
GSI.MUNI_ARRAY[<muniCd>]
で取得可能逆ジオコーディング API に関する公式ドキュメントを小一時間探したけど見つからず。
もう少し精度の良い住所情報が欲しい場合は他にも API がある。試してないし、有料のものもあるので参考レベル。
Cordova で iOS, Android で異なる ID を使う方法。(特殊な事情がない限りは iOS, Android で同じ ID を使うと思う)
config.xml
の widget
に以下を設定ios-CFBundleIdentifier
android-packageName
1 | $ sw_vers |
参考:
config.xml
の widget
で id
の代わりに ios-CFBundleIdentifier
, android-packageName
を使う。
変更前
1 | <widget |
変更後
1 | <widget |
※id
と併用できるか(id
を残したままでも問題ないか)は未確認
config.xml
の widget
に以下を設定ios-CFBundleIdentifier
android-packageName
プラグイン追加などでなんかの問題が起きるかも。
Cloud Functions for Firebase を色々と触った際の メモ/Tips。ドキュメントを読んだだけで試せてない(後で試したい)ものもあり。
1 | $ sw_vers |
公式ドキュメントに大体書かれている。
参考: HTTP リクエスト経由で関数を呼び出す | Firebase
参考: req.get(field)
- Express 4.x - API Reference
onRequest
の第一引数 request
は Express の Request なので、request.get
で Request Headers の情報を取得可能。
1 | const functions = require("firebase-functions"); |
参考: req.query
- Express 4.x - API Reference
1 | const functions = require("firebase-functions"); |
参考:
region('region-name')
でデプロイ先のリージョンを指定可能。デフォルトは us-central1
(アイオワ)。
以下は asia-northeast1
(東京)を指定する例。
1 | const functions = require("firebase-functions"); |
functions.region()
でカンマ区切りの複数のリージョン文字列を渡すことで、複数のリージョンを指定できます。
カンマ区切りで指定すると、複数リージョンを指定できるとのこと、たぶん以下のような感じ(未検証)
1 | exports.someFunction = functions |
ざっくり以下の方法でファイル分割できる
index.js
から require
する1 | // index.js |
参考:
res.set(field [, value])
- Express 4.x - API Referenceresponse.set
で 'Access-Control-Allow-Origin
を設定する。あるいは cors
を噛ませる。
1 | const functions = require("firebase-functions"); |
1 | const functions = require("firebase-functions"); |
firebase emulators:start [--only functions]
コマンドでローカルサーバが起動。
1 | $ firebase emulators:start |
あとは Functions を実行(ブラウザでアクセスするなり、Node.js REPL から API 叩くなり)して挙動を確認できる。
ローカル実行でも firebase-admin
を使って Firestore などにもアクセス可能。
1 | const functions = require("firebase-functions"); |
ちなみに http://localhost:4000
にアクセスすると以下のような GUI で情報を確認できる。
参考:
new Agent
http.request
毎回コネクション確立するとオーバーヘッドがあるので、コネクションを維持できるっぽい。(未検証。試したら追記する)
http
ではなく axios を使いたい場合は、以下を参考にすればたぶんいけそう。
?.
)を使いたい参考:
Node.js 14 を使えば Optional Chaining(?.
)がデフォルトで使えるようになる。ただし、2021/05/08 時点では Node.js 14 はβ版なので注意。
Node.js のバージョンを指定したい場合は functions/package.json
の engines
で指定可能。
1 | { |
もしくは Webpack や Babel を使って index.js
を出力する感じでもいけそう。以下はChrome 拡張の話だけど、多少は参考にはなるはず。
Rails で Devise と論理削除を両立する方法。
active_for_authentication?
をオーバーライドvalidatable
と同等のバリデーションを自分で設定1 | $ cat /etc/os-release |
1 | mysql> status; |
参考: Railsで論理削除(soft delete)を実装する(discard gem利用) - Qiita
いくつか Gem があるが jhawthorn/discard を採用した。
destroy
などがオーバーライドされるので同様の理由で非推奨(という認識)README に従ってセットアップすれば OK。
Gemfile
に gem 'discard', '~> 1.2'
を追記。
1 | gem 'discard', '~> 1.2' |
bundle install
でインストール。
1 | $ bundle install |
論理削除用のカラムを追加。
1 | $ rails g migration add_discarded_at_to_users discarded_at:datetime:index |
モデルに include Discard::Model
を追加
1 | class User < Activerecord::Base |
user.discard
で論理削除したりが可能になる、以下は主要なもの。その他は Usage を参照。
1 | user.discard # 論理削除(discarded_at に現在日時が設定される) |
論理削除されたレコードをデフォルトで除外したい場合は、デフォルトスコープを設定する。
1 | class User < Activerecord::Base |
デフォルトスコープを設定した場合は、対象の抽出時に注意。
1 | User.all # 論理削除されていないレコード |
active_for_authentication?
をオーバーライドして、論理削除されていないユーザーのみがログイン可能に変更。(公式では super && !discarded?
だけど、 !discarded?
が二重否定みたいな感じがするので kept?
に変更した。)
1 | class User < Activerecord::Base |
MySQL 前提
参考:
email
に対してユニーク制約が設定されているので、Generated Column を追加して再設定する。MySQL と Generated Column については MySQL でユニーク制約と論理削除を同時に実現する方法 を参照。
1 | $ rails g migration reset_unique_constraint_to_users |
Qiita 記事では up
の中で execute "ALTER TABLE ...
としていたが、as
でも設定できる。
(Rails のバージョンによっては使えないかも)
1 | class ResetUniqueConstraintToUsers < ActiveRecord::Migration[6.0] |
Devise の設定とかソースコードを見た限りでは、validatable
の挙動変更はできないようなので、自前で定義する。
active_email
はレコード保存後に有効になるので on: :update
に制限email_required?
を定義email
のユニーク検証は scoe: :discarded_at
を追加active_email_required?
を追加password_required?
を定義1 | class User < Activerecord::Base |
lynndylanhurley/devise_token_auth を使う場合は、DeviseTokenAuth::Concerns::UserOmniauthCallbacks
相当も実装する必要がある
config/initializers/devise_token_auth.rb
を変更、コールバックを無効化。
1 | # By default we will use callbacks for single omniauth. |
バリデーションや関連メソッドを定義。
1 | class User < Activerecord::Base |
active_for_authentication?
をオーバーライドvalidatable
と同等のバリデーションを自分で設定後半(特に バリデーション定義)は書くのに力尽きて、なにかミスとかあるかもしれないので注意。
MySQL でユニーク制約と論理削除を同時に実現する方法。
status = 1
なら 'hoge'
, status = 2
なら 'fuga'
みたいにできる1 | mysql> status; |
参考:
MySQL 5.7 以降で使用可能な Generated Column を使う。
Generated Column を使うと status = 1
なら 'hoge'
, status = 2
なら 'fuga'
みたいに、他カラムを参照して動的に値を設定することが可能。かつ、Generated Column に対してユニーク制約を設定することもできる。
email
: メールアドレスdiscarded_at
: 論理削除日時active_email
: 有効なメールアドレス(Generated Column)1 | mysql> CREATE TABLE `my_users` ( |
email
はすでに存在する前提で、discarded_at
と active_email
, およびユニーク制約を追加する。
1 | mysql> ALTER TABLE `my_users` |
hoge@fuga.com
のユーザーを登録。論理削除されてないので active_email
にそのまま反映される。
1 | mysql> INSERT INTO `my_users` (`email`) VALUES ('hoge@fuga.com'); |
もう一度 hoge@fuga.com
のユーザーを登録しようとするとユニーク制約でエラー。
1 | mysql> INSERT INTO `my_users` (`email`) VALUES ('hoge@fuga.com'); |
論理削除(discarded_at
を設定)すると、active_email
が NULL
になる。
1 | mysql> UPDATE `my_users` SET `discarded_at` = NOW() WHERE `id` = 1; |
この状態であれば hoge@fuga.com
のユーザーを登録できる。
1 | mysql> INSERT INTO `my_users` (`email`) VALUES ('hoge@fuga.com'); |
status = 1
なら 'hoge'
, status = 2
なら 'fuga'
みたいにできるCordova で QR コードスキャナのプラグイン(bitpay/cordova-plugin-qrscanner)を追加すると、iOS, Android のビルドがエラーになる問題の対応方法。
platforms/android/app/src/main/java/com/bitpay/cordova/qrscanner/QRScanner.java
を修正1 | $ sw_vers |
読み飛ばしてもOK
bitpay/cordova-plugin-qrscanner をインストール後、cordova build ios
でビルドすると以下エラー。
1 | $ cordova plugin add cordova-plugin-qrscanner |
上記リンク(とエラー内容)を見ると、メソッドが変わっていてエラーになっているとのこと。
Fork したリポジトリ(danielzen/cordova-plugin-qrscanner)を使うと大丈夫とのことで、リポジトリを指定してプラグインを入れ直す。ちなみに android - Adding plugins from specific revision Github project to the Cordova project - Stack Overflow によると cordova plugin add https://github.com/phonegap-build/PushPlugin#2345fd8fe48572eae3df631cf8fb262ef2804779
のようにインストールできる。
1 | $ cordova plugin rm cordova-plugin-qrscanner |
プラグイン再追加後 iOS をビルドすると正常に完了した。
1 | $ cordova build ios |
読み飛ばしてもOK
iOS が解決したと思ったら、cordova build android
を実行するとエラーになった。
1 | $ cordova build android |
参考: cannot find symbol / ActivityCompat · Issue #335 · bitpay/cordova-plugin-qrscanner
上記によるとライブラリのパスが変わっているとのこと。danielzen/cordova-plugin-qrscannerも修正されていないので、(やりたくはないが)プラグインを直接修正する。
platforms/android/app/src/main/java/com/bitpay/cordova/qrscanner/QRScanner.java
の27行目あたりを修正。
1 | import android.provider.Settings; |
これで cordova build android
も問題なく成功するようになる。
platforms/android/app/src/main/java/com/bitpay/cordova/qrscanner/QRScanner.java
を修正Cordova もメンテされなくなっている感あるし、Flutter v2 で Web 対応とかも発表されたし Flutter 触ってみるかな。
Vue.js を kazupon/vue-i18n が動作しない問題の修正方法。
vue add i18n
でプラグイン追加src/i18n.js
を修正messages[locale] = locales(key).default
-> messages[locale] = locales(key)
1 | $ sw_vers |
リポジトリ: 17number/vue-i18n-test
Vue CLI の vue create
でプロジェクト作成。
1 | $ vue create vue-i18n-test |
vue add i18n
で kazupon/vue-i18n を追加。
1 | $ vue add i18n |
これで $t('message')
とすると、locales/xx.json
にかかれている内容が参照される。
…はずなんだけど、どうもバージョンの組合せ問題(?)なのか上手くうごかなかった。
プラグイン追加すると src/i18n.js
が作成されるのだが、どうも loadLocaleMessages
が上手く機能してないっぽい。
1 | import Vue from 'vue' |
挙動を追ったところ、 messages[locale] = locales(key).default
が undefined
になっているのが原因なので、以下のように修正する。
1 | function loadLocaleMessages () { |
これで $t('message')
や $t('hello.world', { world: '世界' })
などが動作するようになった。
vue add i18n
でプラグイン追加src/i18n.js
を修正messages[locale] = locales(key).default
-> messages[locale] = locales(key)
npm や yarn インストールした typicode/husky のフックが動かない問題の対応方法。
package.json
の変更で OKnpm i -D husky@^4
, yarn add -D husky@^4
でインストール.git/hooks
配下に色々と作られるpackage.json
に "husky"
セクションを追記すれば OK.git/hooks
下には何も作られない)npx husky install
or yarn husky install
npx husky add .husky/pre-commit "echo 'pre-commit'"
or yarn husky ...
1 | $ sw_vers |
参考: What’s new in husky 5 - DEV Community
v5 系へのメジャーアップデートで、セットアップ手順が変わっている。
公式リポジトリ(typicode/husky)にも、以下のように書かれている。
Note: husky 5 is a major version with breaking changes. Upgrading from v4 to v5 requires additional steps, please see the docs.
読まなくても OK
以下はダメな例。先に書いておくと 「v5 系がインストールされるのに、v4 系の設定をしている」 ので NG
1 | $ npm i -D husky # もしくは yarn add -D husky |
package.json
に以下を追記。
1 | { |
コミットしてみると husky による pre-commit フックは動作しない。
1 | $ git add package.json && git commit -m "husky test" |
husky インストール後、husky init
, husky install
, husky add
でセットアップすれば OK。
1 | $ npm i -D husky |
なお .husky
配下にコンフィグなどが追加されており、.husky/pre-commit
はこんな感じ。
1 |
|
ちなみに npx husky
で出てくるヘルプに例が載っている。
1 | $ npx husky |
v4 系を使いたい場合は、インストール時にバージョン指定。
1 | $ npm i -D husky@^4 |
あとは package.json
に以下を追記。
1 | { |
package.json
の変更で OKnpm i -D husky@^4
, yarn add -D husky@^4
でインストール.git/hooks
配下に色々と作られるpackage.json
に "husky"
セクションを追記すれば OK.git/hooks
下には何も作られない)npx husky install
or yarn husky install
npx husky add .husky/pre-commit "echo 'pre-commit'"
or yarn husky ...
以下を参考にして .git/hooks
を削除して再インストールしたりとか、yarn
のバージョン確認してみたりしたけど、結局はメジャーアップデートによる影響というもの。
ついつい日本語でググってしまうけど、これまでの環境との違い(今回は husky のバージョン)や、一次情報を真っ先に確認する癖をつけたい。
guyromb/cordova-open-native-settings を使って、Cordova アプリから OS の設定アプリを開く方法。
README には「iOS 8/9/10」と記載されているが、iOS 14.4 でも問題なく動作した。
cordova plugin add cordova-open-native-settings
でプラグイン追加cordova.plugins.settings.open
で設定アプリを開くことができる1 | $ sw_vers |
cordova plugin add
でプラグイン追加
1 | $ cordova plugin add cordova-open-native-settings |
cordova.plugins.settings.open(setting_constant, success_callback, failure_callback)
で設定アプリを開くことができる。
setting_constant
は Settings Options (Android), Settings Options (iOS) を参照。
例えば通知設定を開きたい場合は iOS, Android ともに notification_id
を指定する。
1 | if (typeof cordova === 'undefined' || !cordova?.plugins?.settings) { |
Android のデフォルト動作だと、同じアプリ内で開く挙動になる。別アプリとして開きたい場合は、第一引数を ['notification_id', true]
のような配列(2要素目を true
)にすると良い。iOS と Android で処理分岐させる必要はなく、iOS も以下コードで問題なく動作する。
1 | if (typeof cordova === 'undefined' || !cordova?.plugins?.settings) { |
以下の端末で動作確認、2021/03 時点の新しめの OS でも問題ないっぽい。
デバイス | OS | 区分 |
---|---|---|
iPhone 11 Pro | iOS 14.4 | 実機 |
iPhone 8 Plus | iOS 14.4 | シミュレータ |
iPhone 8 Plus | iOS 13.5 | シミュレータ |
iPhone 8 Plus | iOS 12.4 | シミュレータ |
iPhone 8 Plus | iOS 11.4 | シミュレータ |
Huawei nova lite2 | Android 9 | 実機 |
Pixel 4 | Android 11 | エミュレータ |
Pixel 3a | Android 10 | エミュレータ |
Pixel 3a | Android 9 | エミュレータ |
※iOS シミュレータだと、設定アプリの機能が制限されているので注意。(例: 「通知」の設定画面がない、など)
cordova plugin add cordova-open-native-settings
でプラグイン追加cordova.plugins.settings.open
で設定アプリを開くことができるCordova で Repro とカスタム URL スキームを使ってディープリンクを扱う方法。
config.xml
変更(allow-intent
, config-file
追加)window.handleOpenURL
を定義1 | $ sw_vers |
Repro のプッシュ通知でディープリンクを使う方法はドキュメント通りなので、カスタム URL スキーム の設定がほぼすべて。
EddyVerbruggen/Custom-URL-scheme を使う。
EddyVerbruggen/Custom-URL-scheme インストール。
インストール時に --variable URL_SCHEME=<YOUR_SCHEME>
でカスタム URL スキームを指定する。なお、ハイフン(-
)、大文字、2単語以上、既に使われているものなどは指定不可。
1 | # ハイフン(-) は使えない: my-scheme -> NG, myscheme -> OK |
index.html
修正参考: javascript - Using handleOpenURL with Custom URL scheme in Cordova - Stack Overflow
index.html
を修正。
Content-Security-Policy にカスタム URL スキームを追加、今回は mycoolapp:
の記述を追加。
1 | <meta |
config.xml
修正参考:
allow-intent
, platform name="android"
配下に config-file
(intent-filter
を追加する設定)を追加。
1 |
|
参考:
If you want to alert the URL for testing the plugin, at least on iOS you need to wrap it in a timeout like this:
[Google翻訳] プラグインをテストするためにURLにアラートを送信する場合は、少なくともiOSでは、次のようなタイムアウトでプラグインをラップする必要があります。
README にも書かれている通り、iOS で alert
を出す場合は setTimeout
を使う必要がある。
自分は Cordova + Vue を使っており src/main.js
を修正した。以下は alert
を表示する例だが、「指定のページを表示させたい」とか「特定の処理を行いたい」とかを url
(ディープリンク) の内容をもとに実装すれば OK。
1 | import Vue from 'vue'; |
以下を参考に行う。本記事では省略。
/dashboard/campaign/push-notification.html
) — Repro ドキュメント/dev/sdk/push-notification/index.html
) — Repro ドキュメント参考:
Web から設定する場合は以下のように設定する。
API を使う場合は「スタンダード形式でdeeplink_url
を設定」すれば良い。
1 | { |
画像など省略。
ここまでの設定で iOS/Android ともに「Repro でプッシュ通知を受信して、
参考:
上記 Issue にもある通り cordova-android v7 以降だと上手く動かないっぽい、自分は cordova-android v9.0.0 でダメだった。(「簡単になおせるよ」と言われてなぜかずっと取り込まれていない。。。)
フォーク先ではプラグインに手を入れている(当たり前)が、プラグインは修正したくないので前述の通り config.xml
を修正した。
1 |
|
config.xml
変更(allow-intent
, config-file
追加)window.handleOpenURL
を定義/dashboard/campaign/push-notification.html
) — Repro ドキュメント/dev/sdk/push-notification/index.html
) — Repro ドキュメントfirebase/firebaseui-web による Firebase Authentication の認証 UI でパスワードの強度チェック(文字数や文字種のルール設定)を行う方法。
CDN の v3.5.2, v4.7.3 で動作確認済み
1 | <!-- v3.5.2 --> |
パスワード入力欄に、入力規則(バリデーションルール)を追加表示。
制限を満たしてなければメッセージ表示
以下の JS を実行する、実装は適当なので注意。
1 | function isValidPassword(password) { |
CSS
1 | .new-password-description { |
firebase/firebaseui-web の挙動を確認して以下のような処理を追加。
name
は異なるpassword
newPassword
input
イベントで newPassword
だったら正規表現による検証を行うdisabled=false
disabled=true
.firebaseui-id-page-password-sign-up
が新規登録時のコンテナクラスdisabled=true
雑な実装なのでイケてない点が多々あるが「とりあえずカジュアルに脆弱なパスワードを防ぎたい」とかであればありかなと。
以下も参考になるかも
firebase/firebaseui-web による Firebase Authentication の認証 UI をローカライズ(日本語化)する方法。
script
に __{LANGUAGE_CODE}
を付けるLANGUAGE_CODE
は LANGUAGES.md
参照1 | -<script src="https://www.gstatic.com/firebasejs/ui/4.7.3/firebase-ui-auth.js"></script> |
以下 CDN を使っている前提の話。
README に書かれている通り、読み込む script
を https://www.gstatic.com/firebasejs/ui/4.7.3/firebase-ui-auth.js
から https://www.gstatic.com/firebasejs/ui/4.7.3/firebase-ui-auth__{LANGUAGE_CODE}.js
にすれば良い。
サポートしている言語は LANGUAGES.md
に書かれている。日本語 UI にする場合は以下の用に変更する。
1 | -<script src="https://www.gstatic.com/firebasejs/ui/4.7.3/firebase-ui-auth.js"></script> |
ちなみに、Stripe & Firebase によるサブスクリプションのメモ で使った stripe-firebase-extensions/firestore-stripe-subscriptions - GitHub だと、script
は以下のようになっていた。
1 | <script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script> |
これも同様に https://www.gstatic.com/firebasejs/ui/4.7.3/firebase-ui-auth__{LANGUAGE_CODE}.js
に変更で日本語化できた。
1 | // OK |
自分は試してないが、以下が参考になりそう。
script
に __{LANGUAGE_CODE}
を付けるLANGUAGE_CODE
は LANGUAGES.md
参照1 | -<script src="https://www.gstatic.com/firebasejs/ui/4.7.3/firebase-ui-auth.js"></script> |
なし
Chrome 拡張機能で Firebase Authentication を使って認証する方法。
signInWithEmailAndPassword
で実施1 | $ sw_vers |
拡張機能のベースは webpack & Babel を使って Chrome 拡張機能を開発するためのテンプレート(Hot Reload 付き) を使用。
あらかじめ Firebase Auth へのユーザー登録は済ませている前提。
リポジトリ: 17number/chrome-extension-with-firebase-auth-email-password-example
アイコンクリックで Email/Password の入力エリアを表示、ログインできたら Firebase UID を表示する。
次回以降ログインできる用(= 毎回入力しなくて良い用)に Email, Password を Sync ストレージに保存しておく。(※)
ログイン前
ログインできたら、Firebase UID を表示
options.html
1 |
|
options.js
1 | import './assets/stylesheets/options.scss'; |
initializeApp
で Firebase SDK の初期化email
, password
が保存されていたら signInWithEmailAndPassword
でログイン試行email
, password
を Sync ストレージ に保存chrome.storage.sync
の代わりに mozilla/webextension-polyfill の browser.storage.sync
を使用uid
を表示実装はシンプルでわかりやすいが Email, Password を Storage に保存しておく必要がある(= セキュリティ的に良くない)ので注意。
最低限生データではなく暗号化して保存した方が良いと思われる。(本質的な解決にはならないし、暗号化/復号化 に使う secret
も同梱するので微妙ではあるが。。。)
以下、brix/crypto-js を使う場合の一例。
1 | const CryptoJS = require('crypto-js'); |
Storage に認証情報そのものではなくトークンを保存する方法。
以下あたりを参考にすればいけると思うが、試せてない(ので、できないかも)。試したら追記する。
試せてない。以下あたりが参考になると思う。試したら追記する。
signInWithEmailAndPassword
で実施Stripe & Firebase によるサブスクリプションを試した際のメモ。
status
と current_period_end
を使えば OK1 | $ sw_vers |
Stripe が公式提供している Firebase Extension があるのでそれを使う。
上記 Extension 中にも手順が書かれているが、以下の Qiita 記事をベースに作業するのがおすすめ。
Qiita 記事と似たような内容になるが、ざっくりやったこと概要。
git clone git@github.com:stripe-samples/firebase-subscription-payments.git
)public/javascript/app.js
を変更STRIPE_PUBLISHABLE_KEY
taxRates
firebaseConfig
functionLocation
firebase serve --project <your-project-id>
firebase use --add
してから firebase deploy
ここからは Firebase ExtensionsのRun Subscription Payments with Stripeを使ってサブスク課金をコードを書かずに実装する - Qiita に出てこない話を中心に記述。
何らかのプロダクトに Stripe & Firebase によるサブスクを導入したとして、ユーザーが現在サブスク購読中かどうかを確認したい場合の話。
(購読停止したユーザーには機能制限するなど)
Firebase ExtensionsのRun Subscription Payments with Stripeを使ってサブスク課金をコードを書かずに実装する - Qiita にも書かれている通り、購読状況は Firestore に格納される。
具体的には customers/xxxx/subscriptions/sub_yyyy
に格納される。
基本的には current_period_end
と status
だけ見れば良い(はず)。
1 | status === 'active' && |
上記をクエリできるように複合インデックスを作成しておく。(インデックス作成してないとエラーになる)
なお オレンジ枠内に書いてある通り、インデックスが必要なクエリを実行すると「このリンクでインデックス作ってね」と言われるので、そこから作る感じでも良いと思う。
1 | app.firestore() |
Node.js のコンソールで簡単に確認した。
参考: Firebase を JavaScript プロジェクトに追加する
まずは Firebase client SDK をインストール。
1 | $ npm i firebase |
以下、サンプルコード。
1 | const firebase = require("firebase/app"); |
個人的には Firebase の API Reference 分かりづらい(探しづらい)と思うので、リンク貼りつつ概要解説。
initializeApp
で初期化signInWithEmailAndPassword
で認証Promise<UserCredential>
(非同期) なので注意currentUser
で認証済みユーザー取得uid
を Firestore のパス指定に使う/customers/xxxx/subscriptions/
以下に格納されているので、collection
でパスを指定し、where
で条件を指定し、get
で QuerySnapshot
を取得し、size
や empty
を見れば購読状況を判断できるdocs
を使うAuth での認証
Firestore のクエリ周り
参考: Integrating the customer portal
Stripe のデフォルト設定のまま試すと、利用者(サブスク購読者)側からサブスクのキャンセルができない(はず)。
Stripe のダッシュボードで「設定」→「Billing」→「カスタマーポータル」にアクセスし、
「定期支払いをキャンセル」を有効にすると、カスタマーポータルからキャンセルできるようになる。
有効化後はカスタマーポータル上に「プランをキャンセル」ボタンが出てくる。
キャンセルすると Firestore の cancel_at
, canceled_at
などに反映される。
キャンセル後、カスタマーポータルには「プランを更新」ボタンが出てくる。
「プランを更新」すると、Firestore の cancel_at
, canceled_at
などがクリアされる。(画像略)
他にも色々と細かい設定ができるので、詳細は公式ドキュメント参照。(英語だけど)
status
と current_period_end
を使えば OK別記事で試した。
以下も合わせて要確認
Firebase 公式ドキュメント Firebase による支払い処理 を試した際のメモ。
1 | $ sw_vers |
基本的に Firebase による支払い処理 の手順で進める。
試した際のリポジトリ: 17number/stripe-payment-with-firebase-example
https://dashboard.stripe.com/register でアカウントを作成。
作成後、ダッシュボードでテスト用の API キー/シークレット をメモしておく。
Firebase Console でプロジェクト作成。
サイドバーの一番下から Blaze プランにアップグレードする。Google アカウントでクレカ未設定だと設定画面が挟まるかも。
予算アラートは必要に応じて設定する。(試してみる程度なら不要、本番環境だとあった方が良さげ)
Authentication で Google, メールを有効化
Firestore を有効化。ロケーションは asia-northeast1
(東京) を選択した(※1)
サンプルリポジトリからソースコードをダウンロードする。(DL用 直リンク)
自分はダウンロード後 src
配下に展開した。(が、正直プロジェクトルートで良さげ)
展開したディレクトリに移動して、firebase use --add
コマンドを実行し、プロジェクトを選択
1 | $ cd src |
src/public/javascript/app.js
内の Stripe の公開鍵を設定
1 | -const STRIPE_PUBLISHABLE_KEY = '<YOUR STRIPE PUBLISHABLE KEY>'; |
Stripe のシークレットキーを firebase functions:config:set
コマンドで設定
1 | $ firebase functions:config:set stripe.secret=<YOUR STRIPE SECRET KEY> |
Functions(Cloud Functions for Firebase) で利用するパッケージをインストール
1 | $ cd functions && npm i && cd - |
参考:
firebase deploy
コマンドでデプロイ。
1 | $ firebase deploy |
デプロイ成功したら Hosting URL が表示される、基本的には https://<project id>.web.app
のはず。
Hosting URL にアクセスすると、公式デモサイト と同じ画面が表示される。
適当にメールアドレスでユーザー登録する。なお、デモアプリではメールアドレス確認は行われない。
登録後はこんな画面に遷移する。
Authentication にユーザー登録されており、
Firestore にもデータが作成される。
カード登録を実行する。
Firestore に payment_methods
サブコレクションが作られる。
支払いを実行すると、画面下の Payments 部分に履歴が表示される。
Firestore には payments
サブコレクションが作られる。
なぐり書きなので間違っているかもしれないことに留意。
public/
配下が Firebase Hosting によってホストされているpublic/index.html
や public/javascript/app.js
を編集して再デプロイpublic/javascript/app.js
と functions/index.js
を編集して再デプロイfunctions/index.js
内)onCreate
, onUpdate
, onDelete
などの Cloud Firestore トリガー を利用公式 Extension を試した。
以下も合わせて要確認
Cordova Android アプリで HTTP(≠ HTTPS) 通信をした際に出る net::ERR_CLEARTEXT_NOT_PERMITTED
エラーの解決方法
cleartextTrafficPermitted="false"
がデフォルトになったAndroidManifest.xml
に android:usesCleartextTraffic="true"
を追加すれば HTTP 通信を許可できるplatforms/android/app/src/main/AndroidManifest.xml
config.xml
に edit-config
を追加すれば OK1 | $ sw_vers |
Android 検証機: Huawei nova lite 2 (Android 9) (公式)
参考:
基本的に参考サイトに書かれている通り、以下 抜粋/補足追加/整理 した概要。
cleartextTrafficPermitted="false"
がデフォルトになったAndroidManifest.xml
に android:usesCleartextTraffic="true"
を追加すれば HTTP 通信を許可できるplatforms/android/app/src/main/AndroidManifest.xml
config.xml
に edit-config
を追加すれば OKということで、(Cordova 9.0 環境でない限りは) config.xml
に edit-config
を追加すれば解決する(はず)。
1 |
|
cleartextTrafficPermitted="false"
がデフォルトになったAndroidManifest.xml
に android:usesCleartextTraffic="true"
を追加すれば HTTP 通信を許可できるplatforms/android/app/src/main/AndroidManifest.xml
config.xml
に edit-config
を追加すれば OKCordova Android で iframe 内のリンクをシステムデフォルトブラウザで開く方法。
前置きなどは 親 Window で iframe からのデータ受信、イベント検出する方法 の「前置き」と同じ。
以下はとあるプロジェクトの要件など。
- Cordova で iOS/Android まとめて開発
- コンテンツ内部は先方が作成
- コンテンツ内に先方管理外のサイトへのリンクがある
- ガワはこちらで作成して、コンテンツを
iframe
で読み込むiframe
内のリンクをシステムデフォルトブラウザで開きたいiOS は問題なかった(意図通りに動作した)が、Android だけ上手く動かなかった。具体的には、リンクをタップすると
iframe
内で開こうとするが、X-Frame-Options の設定によりnet::ERR_BLOCKED_BY_RESPONSE
となる、というもの。
iframe
側: postMessage
でリンク先 URL を送信preventDefault
で元イベント(リンク先を iframe
内で開こうとするアクション)を抑止created
, beforeDestroy
フックでイベントリスナを 追加/削除1 | $ sw_vers |
Android 検証機: Huawei nova lite 2 (Android 9) (公式)
apache/cordova-plugin-inappbrowser をインストール
1 | $ cordova plugin add cordova-plugin-inappbrowser |
基本的な仕組み自体は前回(親 Window で iframe からのデータ受信、イベント検出する方法)とほぼ同じ。
postMessage
でリンク先 URL を送って、アプリ(Cordova App)側で apache/cordova-plugin-inappbrowser を経由してシステムデフォルトのブラウザを呼び出す。
iframe
側iframe
で読み込まれていたら(= window.parent
が存在していたら) postMessage
でリンク先を送信して、preventDefault
で元イベント(リンク先を iframe
内で開こうとするアクション)を抑止する。
iframe.html
1 | <a href="https://google.co.jp"> |
Vue + Vue Router + Cordova でいつも実装しているので、サンプルコードも Vue で書く。
iframe.html
を https://example.com
から読み込む場合、メッセージハンドラ(messageHandlerFromIframe
)内で event.origin
が https://example.com
かどうかをチェック(前回と同じ)。
他ページで余計な動作をしないように、created
, beforeDestroy
フックでイベントリスナの 追加/削除 を実施。
Cordova 環境の場合のみ apache/cordova-plugin-inappbrowser を利用。
parent.vue
1 | <template> |
iframe
側: postMessage
でリンク先 URL を送信preventDefault
で元イベント(リンク先を iframe
内で開こうとするアクション)を抑止created
, beforeDestroy
フックでイベントリスナを 追加/削除以下記事で「config.xml
(apache/cordova-plugin-whitelist)の設定で解決した」みたいなことが書かれていたので試したが、回答時から時間が経って環境(バージョン)が変わっているせいか自分の方では上手くいかなかった。
親 Window で iframe
から送られてきたデータを受信したり、iframe
内のイベントを検出する方法。
※イベント検出もデータ送受信機能で実現しているので、厳密にはイベント検出(addEventListener
相当)ではない。
iframe
側から window.postMessage
でデータ送信targetOrigin
を適切に指定(可能なら)addEventListener('message', handler)
で受信ハンドラ設定event.origin
で送信元をチェックiframe
で読み込むサイトが管理外の場合は実現不可(のはず)1 | $ sw_vers |
以下はとあるプロジェクトの要件など。
iframe
で読み込むiframe
内のリンクをシステムデフォルトブラウザで開きたいiOS は問題なかった(意図通りに動作した)が、Android だけ上手く動かなかった。具体的には、リンクをタップすると iframe
内で開こうとするが、X-Frame-Options の設定により net::ERR_BLOCKED_BY_RESPONSE
となる、というもの。
この記事でまとめる方法と、apache/cordova-plugin-inappbrowser とを組み合わせることで解決できたので、その話は別記事にまとめた。
この記事では、その前段階として、iframe
と親 Window との間での通信方法について整理。
ざっくり書くと以下。
iframe
側から window.postMessage
でデータ送信addEventListener('message', handler)
でデータ受信(ハンドラ設定)iframe
側(child.html
)
1 | <div id="send-message"> |
親 Window 側(parent.html
)
1 | <iframe id="parent" src="child.html"></iframe> |
(特別な理由がなく、origin が分かるのであれば) origin の 指定/判定 を行うべき。
postMessage
の第2引数(targetOrigin
) で対象 origin の指定が可能event.origin
で判別が可能送られてきたデータを元に条件分岐など、複雑な処理を実現したい場合は JSON.stringify
, JSON.parse
で相応のデータを送受信すれば良い。
1 | // 子側 |
iframe
側から window.postMessage
でデータ送信targetOrigin
を適切に指定(可能なら)addEventListener('message', handler)
で受信ハンドラ設定event.origin
で送信元をチェックiframe
で読み込むサイトが管理外の場合は実現不可(のはず)以下などで「iframe
内の要素に対しても addEventListener
でイベントハンドラ設定できる」みたいな記述があったが、(自分が試した限りでは)実現できなかった。(ちなみに自分は jQuery でのやり方は試していない)
ただ、自分が間違っていた可能性もありそうなので、また気が向いた時に試すかも。