プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

avd 保存先を変更

android のエミュレータ (avd, android virtual device) をいくつか作成するようになると、結構ディスク容量がとられることに気づきます。で、案の定、システムディスクの容量が足りなくなってきたので、avdの保存先を移動できないか調べたら、できそうなので早速やってみました。

今回の元ネタは下記の記事になります。ありがとうございます。

www.javadrive.jp

ちなみに、現在のディスク容量はこんな感じです。

f:id:junichim:20201120084628p:plain

Dドライブのほうが空いているので、こちらに avd を移動させます。 なお、Dドライブへは C:\Users\ユーザー名\home に junction を張ってるので、Cドライブ以下のパス(C:\Users\ユーザー名\home )でアクセスできるようにしています。

環境変数の設定

まずは、avdを保存しているフォルダを環境変数に設定します。

『コントロールパネル』 -> 『システム』 -> 『システムの詳細設定』 -> 『環境変数』 を開いて、ユーザーの環境変数 または システム環境変数 のどちらかに ANDROID_AVD_HOME を追加します。

f:id:junichim:20201120085513p:plain

今回はユーザー用環境変数に追加しました。

avdファイルの移動

次に、既存のavdファイル(デフォルトだと、 C:\Users\ユーザー名\.android\avd になると思います)をすべて、新しいフォルダに移動させます。

f:id:junichim:20201120092217p:plain

f:id:junichim:20201120092335p:plain

に移動させます。

移動が完了したら、avd名.ini ファイルをエディタで開いて、

avd.ini.encoding=UTF-8
path=C:\Users\mor\.android\avd\Pixel_3a_XL_API_29.avd
path.rel=avd\Pixel_3a_XL_API_29.avd
target=android-29

の部分にある path= で示された絶対パスを、下記のように新しいavdフォルダに合わせて編集します。

avd.ini.encoding=UTF-8
path=C:\Users\mor\home\avd\Pixel_3a_XL_API_29.avd
path.rel=avd\Pixel_3a_XL_API_29.avd
target=android-29

これを移動させたすべての avd 分行います。

確認

最後に、Android Studio を起動して AVD Manager を立ち上げて、既存のエミュレータが問題なく表示されることを確認します。

f:id:junichim:20201120093012p:plain

OKですね。

なお、エミュレータを起動してみると、起動はするけど操作を受け付けない、という状態になっていました。多分、前回起動時の状態(変更前のavdフォルダのパスで起動した状態)が何か残っていて。これが悪さをしているのではないかと推測されます。

今回は、一旦、エミュレータを終了させ、AVD Manager から Cold Boot Now を選択して、 Cold Boot すると問題なく起動・操作ができるようになりました。

ちなみに、おおよそ 68GB 程度空いたようです。

f:id:junichim:20201120092753p:plain

参考

環境変数についての公式の説明

環境変数  |  Android デベロッパー  |  Android Developers

その他の参考記事

AVDの場所を変える - HONDAのAndroid アプリ, Web アプリ開発備忘録

Formspree のお問い合わせフォームで reCAPTCHA を有効にする

先日、こちらの記事で書いたように、 Hugo で作っている自分のサイトのテーマをアップデートし、Formspree を使ったお問い合わせフォームもちゃんと動くようにしました。

で、作業後土日を挟んで、問い合わせフォーム経由のメールを見ると、スパムとか機械的な営業メールと思しきものが結構たくさん来てました(ロシア語のメールなんてわかるわけありません)。無料でのフォームからの送信可能枠が50通なんで、このままでは無料範囲からはみ出す恐れがあります。

ということで、少しでもスパムを抑えるために、 Formspree が reCAPTCHA に対応しているので、その機能を使うことにしました。本記事はこの設定時のメモ書きになります。

reCaptcha 機能の有効化

Formspree の reCaptcha 機能を使うのは非常に簡単でした。

まず、 Formspree にログインします。次に、対象のフォームの Settings を表示します。

f:id:junichim:20201102223200p:plain

『reCAPTCHA』が無効になっている場合、有効にします。これで完了です。

実際に試してみます。

f:id:junichim:20201102112638p:plain

問い合わせフォームを開いて、必要事項を入力して、『送信』を押します。

f:id:junichim:20201102112739p:plain

Formspree のページにリダイレクトされ、 reCAPTCHA が表示されます。ここで、チェックをつけて問題がなければ、

f:id:junichim:20201102112840p:plain

と、送信完了を通知するページが表示されます(本当はこのページをなくしたいのですが、有料プランじゃないとなくせないので当面諦めます)。

Formspree の reCAPTCHA ページを利用しない方法

さて、 reCAPTCHA を使うだけならこれでいいのですが、 Formspree の reCAPTCHA ページにリダイレクトされるのが、いまひとつな感じです。

なので、これを回避して、フォームと同じ場所に reCAPTCHA のボタンを出したいと思います。

このためには、先ほど Formspree で reCAPTCHA を有効にすると、その下に表示される 『Custom reCAPTCHA Key』 を利用すれば良いようです。

f:id:junichim:20201102113345p:plain

以下では、Formspree 公式の説明を参考に設定した内容をまとめておきます。

Google 側の設定

まず、最初に、下記のリンク先から Google で reCaptcha を使うための設定を行います。

https://www.google.com/recaptcha/admin

設定には、 Google アカウント が必要になります。

新たにサイトを登録する際は、reCAPTCHA タイプとして Formspree が対応している v2 を選択してください。 今回はv2の『チェックボックス』を選択しました。

あとは、この reCAPTCHA を利用するサイトのドメイン名を登録すればOKです。

日本語の説明も簡単に見つかるので、下記などを参考にしてください。

Google reCAPTCHA の使い方(v2/v3) / Web Design Leaves

Formspree 側の設定

次は、 Formspree 側の設定です。といっても先ほどの設定画面の『Custom reCAPTCHA Key』にシークレットキーを入力すればOKです。

Google の reCAPTCHA の設定画面を開いて、『reCAPTCHA のキー』をクリックすると

f:id:junichim:20201102114850p:plain

このように、サイトキーとシークレットキーが表示されます。 Formspree 側に入力するのは、シークレットキーになりますので、間違えないようにしてください。

Hugo の テーマでの設定

最後はクライアント側の設定です。今回は Hugo の Universal テーマを使っているので、カスタマイズしてこれに組み込む形になります。

universal テーマのバージョンは v1.1.1 を使っています。

config.toml に reCAPTCHA のサイトキーを設定します。

    googleRecaptchaKey = "your recaptcha site key"

次に、このキーがある場合に、 reCAPTCHA のウィジェットを表示するようにします。 themes/hugo-universal-theme/layouts/partials/contact.html を layouts/partials/contact.html にコピーして、 Form タグの内側に

                        {{ if .Site.Params.googleRecaptchaKey }}
                        <div class="col-sm-12">
                            <div class="g-recaptcha" data-sitekey="{{ .Site.Params.googleRecaptchaKey }}"></div>
                            <br/>
                        </div>
                        {{ end }}

                        <div class="col-sm-12 text-center">
                          <button type="submit" class="btn btn-template-main"><i class="far fa-envelope"><;/i>{{ i18n "contactSend" }}</button>

                        </div>

のような感じでタグを追加します。

最後に、reCAPTCHA の js ファイルを読み込むように設定します。

themes/hugo-universal-theme/layouts/partials/scripts.html を layouts/partials/scripts.html にコピーして

{{ if .Site.Params.googleRecaptchaKey }}
<script src="//www.google.com/recaptcha/api.js" async defer></script>
{{ end }}

を追記します。

なお、クライアント側の設定は、下記の Google の公式サイトを見るとより詳しく載っています。

reCAPTCHA v2  |  Google Developers

動作確認

ここまで出来たら、動作確認します。

まずはローカルサイトで動かしてみます。

mor@DESKTOP-H6IEJF9:/mnt/d/work/own_app/mywebsite$ hugo server

この場合、 reCAPTCHA のウィジェットは表示されますが、Google の reCAPTCHA で設定したドメインと違う(localhost)ということで、警告が出ています。

f:id:junichim:20201102120518p:plain

とはいえ、reCAPTCHA のウィジェットが出ているので、本番サーバーにアップして試してみます(クリティカルなサーバーならステージングサーバーで試してください)。

f:id:junichim:20201102120758p:plain

ちゃんと出てますね。

実際に送信テストを行うと、きちんと届いていました。

これで、もうしばらく無料で運用できそうです。

ご参考までに。

Hugo のテーマをアップデート

森ソフトの Webサイト は Hugo を使っています。この Hugo で使っているテーマをアップデートしたので、その際の作業をメモっておきます。

なお、作業は WSL (v1) 上の Ubuntu 18.04 で行っています。

テーマを更新

Web サイト自体は Netlify でホスティングしています。Netlify で使う場合はテーマ部分を git の submodule にしています。 なので、まずは、 submodule である Hugo のテーマ(現在は universal を利用)を最新に更新します。作業ディレクトリで確認すると、

mor@DESKTOP-H6IEJF9:/mnt/d/work/own_app/mywebsite/themes/hugo-universal-theme$ git tag
1.0.0
1.0.1
1.0.2
1.1.0
1.1.1
mor@DESKTOP-H6IEJF9:/mnt/d/work/own_app/mywebsite/themes/hugo-universal-theme$ 

とあるので、一番新しいリリースである 1.1.1 を利用します。

mor@DESKTOP-H6IEJF9:/mnt/d/work/own_app/mywebsite/themes/hugo-universal-theme$ git checkout tags/1.1.1
Previous HEAD position was f2f2c4f Https (#135)
HEAD is now at e45210f Avoid markify footer. (#251)
mor@DESKTOP-H6IEJF9:/mnt/d/work/own_app/mywebsite/themes/hugo-universal-theme$ 

これで、切替OKです。

新テーマに対応

Hugo で気に入っているところは、ディレクトリ構成がかっちりしてて、サイトのディレクトリ構成とテーマのディレクトリ構成が同じであるため、テーマ部分のあるファイルを変更したければ、対応するサイトのディレクトリ構成に同じ名前でファイルをコピーして変更することで、オーバーライドのようにカスタマイズできるところです。

このサイトも、いくつかのファイルについてカスタマイズしています。

なので、少し面倒ですが、新旧のファイルを比較して、新しいテーマの内容とカスタマイズの内容をマージする必要があります。

今回は次のようにしました。

  1. カスタマイズ済みのサイト側のファイルに、新しいテーマフォルダにある当該ファイルを上書きコピー
  2. カスタマイズ済みのサイト側のファイルはリポジトリに登録済みのため、テーマのバージョンアップに伴う差分を簡単に確認
  3. 差分がテーマのアップデート由来のものであれば、最新の記述を採用し、カスタマイズに由来するものであれば最新のスタイルに合わせて反映する

カスタマイズ用の変更前に、対応するファイルをテーマ側のディレクトリよりコピーした状態でリポジトリに登録しておけば、カスタマイズ部分を反映するのも簡単だったと思われます(まあ、いずれにしても一度は修正内容を確認しないといけませんが)。

作業が終わったら、 hugo server を実行してローカルで確認します。一応これで当初のサイトを復元することができました。

Formspree の新しいフォームスタイルへ対応

さて、これで問題ないかと思いきや、いろいろとテストしていると、この universal テーマのコンタクトフォームが正しく動作していないことがわかりました。つい先日までは動いていたんですけどね。

コンタクトフォームからの問い合わせ先のメールを見ると、 Formspree から 『PLEASE UPDATE YOUR LEGACY FORMS』というタイトルのメールが届いていました。 どういうことだろうかと思い、メール内のリンクを開いてみると、

Phasing out legacy forms (email URLs) – Formspree Help

とあります。

表示された記事を読んでみると、今までは、フォームのactionでメールアドレスを直接した形だったんですが、これをセキュリティ他の理由により Formspree の発行したエンドポイントを利用する形式に変更になったようです(直接的には今回のテーマのアップデートとは無関係だったようですね)。

なので、これに対応する必要があります。

対応方法

とはいえ、対応方法は難しいわけではなく、上記のリンク先の通り作業をすればOKです。一応手順を書いておきます。

まずは、 Formspree 側の作業です。

  1. Formspree に登録
  2. 確認用リンクが登録時のメールアドレスに送られてくるので、認証
  3. Formspree にログイン f:id:junichim:20201031155945p:plain
  4. 『+ New Project』ボタンを押してプロジェクトを作成(プロジェクトが1つもない場合)
  5. 『+New Form』ボタンを押す
  6. フォームを定義し、連絡先となるメールアドレスを指定する
  7. フォーム作成後、エンドポイントが表示されるので、それを控えておく f:id:junichim:20201031160334p:plain

今までは登録せずとも使えていたので、最初の登録に抵抗があるかもしれませんね。

次は、 Universal テーマ側の作業です。

config.toml を開いて、 email の部分をエンドポイントに変更します。なお、指定するエンドポイントは https://formspree.io/ を除いたものになります。

    email = "xxx/yyyyyyyyyyy"
    contact_form_ajax = false

これで、

hugo server

を実行して、コンタクトフォームを試すとちゃんとメールを受け取ることができました。

あとは、変更をリポジトリにアップして、本番環境へ反映して完了です。

一件落着。

(参考)

Hugo によるエラーの解消

実は、universal のテーマのアップデートの際に若干トラブルがあったので、下記に載せておきます。

最初、上記の作業の前に、テスト用サイトを作って、新しいバージョンのテーマでどうなるか確認してみました。すると、

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/test$ hugo new site sample
Congratulations! Your new Hugo site is created in /mnt/c/Users/mor/home/work/own_app/test/sample.
(略)
Visit https://gohugo.io/ for quickstart guide and full documentation.
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/test$
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/test$ cd sample/themes/
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/test/sample/themes$ git clone https://github.com/devcows/hugo-universal-theme
(略)
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/test/sample/themes$ cd hugo-universal-theme/exampleSite/
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/test/sample/themes/hugo-universal-theme/exampleSite$ hugo server -D

Building sites … ERROR 2020/10/30 21:56:26 Failed to add template "theme/partials/head.html" in path "/mnt/c/Users/mor/home/work/own_app/test/sample/themes/hugo-universal-theme/layouts/partials/head.html": template: theme/partials/head.html:10: unexpected "=" in operand
ERROR 2020/10/30 21:56:26 Failed to add template "theme/partials/recent_posts.html" in path "/mnt/c/Users/mor/home/work/own_app/test/sample/themes/hugo-universal-theme/layouts/partials/recent_posts.html": template: theme/partials/recent_posts.html:18: function "site" not defined
ERROR 2020/10/30 21:56:26 theme/partials/head.html : template: theme/partials/head.html:10: unexpected "=" in operand
ERROR 2020/10/30 21:56:26 theme/partials/recent_posts.html : template: theme/partials/recent_posts.html:18: function "site" not defined
ERROR 2020/10/30 21:56:26 Error while rendering "page" in "blog/": template: theme/_default/single.html:4:5: executing "theme/_default/single.html" at <partial "head.html" ...>: error calling partial: template: "theme/partials/head.html" is an incomplete or empty template
ERROR 2020/10/30 21:56:26 Error while rendering "page" in "": template: theme/page/single.html:4:5: executing "theme/page/single.html" at <partial "head.html" ...>: error calling partial: template: "theme/partials/head.html" is an incomplete or empty template
ERROR 2020/10/30 21:56:26 Error while rendering "section" in "": template: theme/_default/list.html:4:5: executing "theme/_default/list.html" at <partial "head.html" ...>: error calling partial: template: "theme/partials/head.html" is an incomplete or empty template
ERROR 2020/10/30 21:56:26 Error while rendering "taxonomyTerm" in "": template: theme/_default/list.html:4:5: executing "theme/_default/list.html" at <partial "head.html" ...>: error calling partial: template: "theme/partials/head.html" is an incomplete or empty template
ERROR 2020/10/30 21:56:26 Error while rendering "taxonomy" in "": template: theme/_default/list.html:4:5: executing "theme/_default/list.html" at <partial "head.html" ...>: error calling partial: template: "theme/partials/head.html" is an incomplete or empty template
ERROR 2020/10/30 21:56:26 Error while rendering "home" in "": template: theme/index.html:4:5: executing "theme/index.html" at <partial "head.html" ...>: error calling partial: template: "theme/partials/head.html" is an incomplete or empty template
ERROR 2020/10/30 21:56:26 Error while rendering "404" in "": template: theme/404.html:4:5: executing "theme/404.html" at <partial "head.html" ...>: error calling partial: template: "theme/partials/head.html" is an incomplete or empty template
Total in 326 ms
Error: Error building site: logged 4 error(s)
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/test/sample/themes/hugo-universal-theme/exampleSite$

こんな感じでエラーが大量にでてきました。

何が悪いのか全然わからないのですが、エラーメッセージでググると、全然別のプロジェクトで、Hugo が 0.40.x の時に似たようなエラーが出てるディスカッションがありました。

Severe: Failed to add template · Issue #703 · wowchemy/wowchemy-hugo-modules · GitHub

手元の hugo のバージョンを調べてみると、

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/test/sample/themes/hugo-universal-theme/exampleSite$ hugo version
Hugo Static Site Generator v0.40.1 linux/amd64 BuildDate: 2018-04-25T17:16:11Z
mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/test/sample/themes/hugo-universal-theme/exampleSite$

どうもこれの可能性があるかもしれませんね。

今の Hugo は、確か、aptでインストールしたものを使っていたはずです。 apt だとバージョンが古いので、 snap を使えばもうちょっと新しいのが入るようですが、残念ながら WSL (v1) は snap が使えないようです。

なので、こちらの記事を参考に最新版を入れてみます。

まず、既存の Hugo をアンインストールします。

mor@DESKTOP-H6IEJF9:~$ sudo apt purge hugo
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  gyp javascript-common libc-ares2 libhttp-parser2.7.1 libjs-async libjs-inherits libjs-jquery libjs-node-uuid libjs-underscore libpython-stdlib libpython2.7-minimal libpython2.7-stdlib libssl1.0-dev
  libuv1-dev nodejs-doc python python-minimal python-pkg-resources python2.7 python2.7-minimal
これを削除するには 'sudo apt autoremove' を利用してください。
以下のパッケージは「削除」されます:
  hugo*
アップグレード: 0 個、新規インストール: 0 個、削除: 1 個、保留: 305 個。
この操作後に 17.7 MB のディスク容量が解放されます。
続行しますか? [Y/n] y
(データベースを読み込んでいます ... 現在 42157 個のファイルとディレクトリがインストールされています。)
hugo (0.40.1-1) を削除しています ...
man-db (2.8.3-2ubuntu0.1) のトリガを処理しています ...
mor@DESKTOP-H6IEJF9:~$

次にリリースされている deb パッケージをダウンロードしてインストールします。

mor@DESKTOP-H6IEJF9:~$ wget https://github.com/gohugoio/hugo/releases/download/v0.77.0/hugo_0.77.0_Linux-64bit.deb
mor@DESKTOP-H6IEJF9:~$ sudo apt install ./hugo_0.77.0_Linux-64bit.deb
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
注意、'./hugo_0.77.0_Linux-64bit.deb' の代わりに 'hugo' を選択します
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  gyp javascript-common libc-ares2 libhttp-parser2.7.1 libjs-async libjs-inherits libjs-jquery libjs-node-uuid libjs-underscore libpython-stdlib libpython2.7-minimal libpython2.7-stdlib libssl1.0-dev
  libuv1-dev nodejs-doc python python-minimal python-pkg-resources python2.7 python2.7-minimal
これを削除するには 'sudo apt autoremove' を利用してください。
以下のパッケージが新たにインストールされます:
  hugo
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 305 個。
14.0 MB 中 0 B のアーカイブを取得する必要があります。
この操作後に追加で 46.1 MB のディスク容量が消費されます。
取得:1 /home/mor/hugo_0.77.0_Linux-64bit.deb hugo amd64 0.77.0 [14.0 MB]
以前に未選択のパッケージ hugo を選択しています。
(データベースを読み込んでいます ... 現在 42128 個のファイルとディレクトリがインストールされています。)
.../hugo_0.77.0_Linux-64bit.deb を展開する準備をしています ...
hugo (0.77.0) を展開しています...
hugo (0.77.0) を設定しています ...
mor@DESKTOP-H6IEJF9:~$

無事にインストール出来たようです。

新しい Hugo のバージョンは 0.77.0 になりました。

mor@DESKTOP-H6IEJF9:~$ hugo version
Hugo Static Site Generator v0.77.0-EF290125 linux/amd64 BuildDate: 2020-10-30T10:14:31Z

再度試します。

mor@DESKTOP-H6IEJF9:/mnt/c/Users/mor/home/work/own_app/test/sample/themes/hugo-universal-theme/exampleSite$ hugo server -D
Start building sites …

                   | EN
-------------------+------
  Pages            |  36
  Paginator pages  |   0
  Non-page files   |   0
  Static files     | 103
  Processed images |   0
  Aliases          |  14
  Sitemaps         |   1
  Cleaned          |   0

Built in 439 ms
Watching for changes in /mnt/c/Users/mor/home/work/own_app/test/sample/themes/hugo-universal-theme/{archetypes,exampleSite,i18n,layouts,package.json,static}
Watching for config changes in /mnt/c/Users/mor/home/work/own_app/test/sample/themes/hugo-universal-theme/exampleSite/config.toml
Environment: "development"
Serving pages from memory
Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
Press Ctrl+C to stop

ちゃんと動きましたね。

疑問点

上記のように、 Hugo のバージョンを新しくしたことで解決したのはいいのですが、ただ、 universal もアップデート前のものを使っていた時は、 0.40.1 の Hugo でも問題なく動作していました。テーマとの兼ね合いもあるのかもしれませんね。

ま、何かのご参考までに。