| @登山/ランニング

Apple Watch でトレイルランニングするためのアプリ

Apple Watch トレラン のようなキーワードで検索すると、「 Apple Watch はトレランでは使えない」、「ランニングウォッチとしては微妙」というようなレビューが見つかる。自分もそうだと思ってたんだけど、それらのレビューは純正のワークアウトアプリか Strava アプリ、 NIKE のアプリくらいしか試してないようだった。果たして本当に Apple Watch はトレイルランニングで使えないのだろうか?

※この記事で紹介しているアプリよりももっと良いアプリを見つけたので以下の記事も是非読んでみて下さい。

Garmin などランニング特化の時計でできること

Twitter を見てると Garmin の時計を付けてランニングをしてる人たちがその日のトレーニングの様子とか体調をキャプチャで載せてる様子が観測できる。

どうも Garmin だと心拍数と睡眠時間などから「今日は体調良くないですよ」(トレーニングレディネス)とか、今日の運動メニュー(おすすめワークアウト)とか、フルマラソンなどのレースの予想タイム(レースウィジェット)を教えてくれるっぽい。

Apple Watch にも Apple 純正のアクティビティトラッカー(ワークアウトアプリ)あるし、心拍数を計測する機能も睡眠トラッキング機能もあるけど、その日のトレーニングがどうだったのか、体調がどうなのか(その数字が何を意味するのか)は自分で解釈・判断しないといけない。

加えて Garmin の上位機種( Forerunner 955 など)では地図とルート表示およびナビゲーションが可能で、山の中でスマートフォンや紙地図を取り出すことなく予定のルートと地図を確認できるようだ。つまり

  1. オフライン地図表示&ナビゲーション
  2. 運動回復支援機能

↑の二つが Apple Watch にはない機能で、 Garmin 勢うらやましいなぁと思っていたが、いろいろ調べてみると以下の二つのアプリを入れることで Apple Watch を Garmin 相当にすることができるようだった。

  1. WorkOutDoors
  2. Athlytic

オフライン地図表示&ナビゲーションアプリ WorkOutDoors

WorkOutDoors

Apple Watch には Apple 純正のワークアウトアプリがあって、普段走るときはこれを使っているが、メトリクスを計測するのみで地図でのナビゲーション機能はない。レースコースという、過去の自分のルート・記録と比較しつつ走れる機能はあるが、同じルートを何回か走ってからでないとレースコースとしてワークアウトに表示されない。

しかしルートを表示する機能は初めて行く山域や知らない場所を走るときにこそ必要で、 WorkOutDoors はそれを実現するアプリだ。ワークアウトアプリにはできない、任意の GPX ファイルを読み込ませてルート表示することができ、特定の範囲の地図をダウンロードしてオフライン表示することも可能だ。

しかも純正のワークアプリと同等のアクティビティログの取得も可能で、きちんとランニングのデータが保存される。 GPS ログや心拍数に加え、 watchOS 9 から取得できるようになったランニングパワーや上下動もちゃんと記録される。

実を言うと最初自分はこのアプリを iPhone で GPX ファイルを閲覧するためにインストールしていたが、あまり便利ではなく(使い方が難しかった)すぐ使わなくなっていた。しかし改めて Apple Watch でアクティビティトラッカー件ルートナビゲーションアプリとして使えることを知ってまさにこういうのが欲しかったということに気が付いた。ルートを外れたときの警告機能もあるし、心拍数などのメトリクスを Apple Watch で計測しながら道がわからないところを走るならこれ一択という感じがする(土地勘があるところなら Apple のワークアウトアプリの方がシンプルで使いやすい)。

WorkOutDoors はハチャメチャふにカスタマイズ可能

さらにこのアプリがすごいのがめちゃくちゃ細かくカスタマイズできるところで、画面表示やレイアウトだけでなく、画面を複数回タップしたときの挙動までカスタムできる。自分はソフトウェア開発者なのでこういう複雑な UI には強い方だと思うけど、これは普通の人には使いこなせない複雑さだと思う。しかしランニング意欲と IT リテラシーの両方が高い人からするとめっちゃうれしい使い勝手の良さを備えている。

watchOS 9 でワークアウトアプリがだいぶ進化して、ランニング中に表示するメトリクスの内容を自分でカスタマイズできるようになったが、いまにして思うとこのような機能は WorkOutDoors アプリでは以前から搭載されていたようで、ワークアウトアプリは WorkOutDoors の後追いをしているとも言える。純正ワークアウトアプリの方がデザインが洗練されていて使いやすいが、少々込み入った作業が必要でも自分に本当に必要なデータ(ペース、心拍数、累積獲得標高などなど)を厳選したい人にはうってつけだ。

WorkOutDoors は有料ソフトだがサブスクリプションではなく一回だけの買い切りで値段も安く良心的( 1100 円)。トレランでも Apple Watch を使いたい人にはおすすめです。

運動回復支援アプリ Athlytic

Athlytic

Garmin の時計でいうところのトレーニングレディネスとおすすめワークアウト機能のようなものを提供してくれるのが Athlytic だ。

Apple 純正のヘルスケアアプリで睡眠時間や安静時心拍数などを知ることができるが、どう理解すれば良いかがわからない。昨日の睡眠時間は 6 時間で、そのうちレム睡眠が〇時間です、なんて言われてもそれが良いのか悪いのかがわからない。

Athlytic は睡眠の状況と心拍数からその日の体調をはじき出し、今日は休んだ方がよいとか、激しいトレーニングしてもオッケーとか教えてくれる。

Athlytic Athlytic Athlytic

このブログでたびたび話題にしている HealthFit というアプリでも回復具合を表示してくれるが、睡眠時間や安静時心拍数からではなく、トレーニングをしているかしていないかで判定している。元の TSB モデルというもの自体がそういうものなので仕方がないが、トレーニングしてないから体調が良いかというとそうでもなくて、あまりよく眠れてなくて体が重いこともあるので、 Athlytic のようなアプリが欲しいと思っていた。本当はあんまり体調良くないときに張りきって高負荷のトレーニングをして怪我したら最悪だ。 Athlytic を使うことで客観的に自分の体調を把握できるようになる。

なお買い切りの WorkOutDoors と異なり Athlytic は年間 3400 円のサブスクリプションだ。調べたところ同種のアプリはほかにもあって、値段が安いものや無料のもののあるが、 iPhone 側にはほとんど UI がなくて Apple Watch で情報を見なければならなかったり( Training Today )、体調の判定だけでおすすめのワークアウトを教えてくれる機能はなかったり( CHIPR )するので、少々出費は必要だが Athlytic を使うのが良さそうだ。

でも Apple Watch はバッテリーもたないですよね?

バッテリーに関してはやっぱり Garmin に負けてしまう。自分の 2 年半使った Apple Watch Series 6 はワークアウトを動かすと 6 時間くらいで電池が切れてしまうので、登山やトレランで Apple Watch を使う場合は Ultra を買うしかないだろう。また Apple Watch Ultra であったとしても二日に一回は充電が必要なのは避けられない。

しかしトレランの 100 マイルレースで Apple Watch Ultra を使って完走したという情報もあるので、 Apple Watch Ultra で節電モードをうまく使えばウルトラマラソンや 100 マイルレースでも Apple Watch Ultra は使えそうだ。

これまで泊まりの登山や 100km 、 100 マイルのトレランレースでは Apple Watch は候補に入ってこなかったと思うが、 Ultra によって 20 時間以上のワークアウトを記録できるようになったので、ランニングのときのためだけに Garmin を使う必要がなくなったとも言える。 WorkOutDoors や Athlytics のようなアプリが本領発揮できるような環境が Apple Watch Ultra によって整ったということだ。

おとなしく Garmin 使えばよくない? 何で Apple Watch にこだわるの?

この動画見てください。

Garmin は長時間のアクティビティには確かに向いてるかもだけど、日常生活が厳しい…。アメリカですら Garmin Pay は使い勝手が良くないと言われているのに日本だったらもっと使えないですよ。音楽を聞くのだって Amazon Music と Spotify しか対応してなくて事前に楽曲をダウンロードしておく必要があって不便。

一方で Apple Watch は日常の使い勝手はとてもよく、 Apple Pay でコンビニやスーパーで買い物できるのはもちろんのこと、 Mac のスクリーンロックを解除したり、 Siri で Apple TV を操作したり、運転中には Apple マップのナビゲーション通知を受け取ったりできる。最近の車だと Apple Watch が車の鍵になったりもするようだ。

運動好きだけどデジタルガジェットも好きで、 Apple エコシステムの提案する快適な生活を捨てがたいという人は Apple Watch を使うしかないでしょう。金持ちだったらランニング用に Garmin を買うこともできるだろうけど、トレーニングレディネス(睡眠や日常の心拍数変動から算出)のことを考えるとトレーニング中もそうじゃないときも同じ時計を使っていることに意味があるので、日常は Apple Watch 、走るときは Garmin という使い分けはあんまり意味がない。同じものをずっと身に付けていた方がよい。

まとめ

WorkOutDoors と Athlytic というアプリを使うことで Garmin のような機能が手に入る。これまで日常生活での快適さを諦めて Garmin 使ってた人も Apple Watch Ultra に乗り換えて WorkOutDoors と Athlytic をインストールすれば Garmin を使ってた頃と近しい感じでトレーニングできる。

様々なアプリが App Store にあって自分好みのアプリを探してインストールすることができるのが iOS / watchOS の強みなので、純正のワークアウトアプリだけ使って「 Apple Watch はトレランでは使えない」という評価を下すのは早計だと思う。適したアプリを探して入れてやれば Apple Watch はトレランでも使えます。 40km くらいまでの短いレースであれば普通の Apple Watch でもバッテリー切れにはならないはず。活動時間が 6 時間を超えてくるような距離( 50km 以上?)のレースでは Apple Watch Ultra が無難でしょう。

なお、このゴールデンウィーク期間中、 Amazon で Apple Watch Ultra がタイムセール対象になっているようだ(人気のないバンドカラー、サイズのみ)。自分も正直買おうか悩んでいてここ 4 日くらいカートに入れたり出したりを繰り返している。よろしければご検討ください。

| @Mac/iPhone

ossan.fm playing in Castro, a CarPlay podcast client

(※タイトルは ChatGPT に考えてもらいました)

Apple CarPlay はとてもよくできたサービスだと思うけど、ネットであまり使っている情報を見かけない。自分の観測範囲が狭いだけかもしれないが、デジタルガジェット好きな人が大抵東京近辺に住んでて車を運転する習慣がないからではないかと思っている。なので今日は CarPlay の便利さについて書いてみたい。

自分は 3 年前のハワイ旅行でレンタカーで使った CarPlay に衝撃を受けて車を買い換えることにした。

いまも車の純正カーナビは使っておらず、車を運転するときは CarPlay で Apple マップか Google マップを使っている。ナビゲーションはもちろんのこと、届いたメッセージを読み上げてくれたり、音声入力で返信したり、 Hey Siri できたり、電話をかけたり受けたりできる。もちろん音楽や Podcast も聴ける。運転中に iPhone でしたいようなことが大抵できるようになってる。車に純正で付いてるカーナビだと精々 Bluetooth で iPhone につながってハンズフリー通話したり音楽を再生したりくらいしかできないが、 CarPlay を使うと車が iPhone の外付けデバイス的な感じになる。

CarPlay のなかでも Apple マップがめちゃくちゃよくできてて、例えば休みの日に 11 時からショッピングセンターで予定があったとして(カレンダーに予定と場所の情報が入れてある)、 10 時半に車に乗って iPhone を車につなぐと iPhone にプッシュ通知が来て「ショッピングセンターへのナビゲーションを開始しますか?」と表示される。ようわかっとるやんけと思いながら通知をタップするとナビゲーションが始まる。

運転をしていると交差点が近づいてきたときに Apple Watch が震えて右折しなければならないことを教えてくれる。カーナビで音声ナビゲーションさせることもできるし、音声は出さずに Apple Watch 経由でナビゲーションしてもらうこともできる。 Podcast を聞き入っていたのにナビの音声に邪魔されるということがない。

目的地に着いて駐車場に車を止めると駐車位置が Apple マップ上に反映される。ショッピングセンターの広大な駐車場で自分の車の駐車位置がわからなくなり延々さまようということがなくなる。

うっかりガソリンを入れ忘れていて燃料警告灯が付いてしまった。すると iPhone にプッシュ通知が届いて「ガソリンスタンドを探しますか?」と表示される。通知をタップすると地図上で最寄りのガソリンスタンドが表示される。

このように Apple マップは車とつながることでハチャメチャにユーザーの状況に適した提案をしてくる。めちゃくちゃかゆいところに手が届く感じ。ガソリン切れそうになったときに通知が来たときは便利すぎて正直引いた。

フツーの車が近未来デバイスみたいになったみたいな感じになるので、 CarPlay に対応しているカーナビを搭載している車を持ってる人は今すぐ純正カーナビ使うのやめて CarPlay で Apple マップ使い始めた方がよいし、これから車を買おうとしている人はナビが CarPlay 対応しているかどうかはチェックした方がよい。車がデジタルガジェットの一部になる感覚を味わって欲しい。

| @ブログ

Mac の定番ランチャー、 Alfred のような検索 UI が好きだ。こういう UI で検索できるソフトウェアやウェブサイトがあると気持ちいい。自分のブログにモーダルウィンドウの検索を追加したときも Alfred みたいにしたいと思いながら作った。

見た目は Alfred っぽくできたが、キーボードで操作できない点が気になっていた。いちいち画面右上の🔍マークを押さないと検索 UI を呼び出せないし、検索しようと思って気が変わったときにはカーソルを動かしてモーダルウィンドウの外の領域をクリックしないとモーダルを閉じられない。これが地味にストレスだった。

見た目だけでなく使い勝手も Alfred のようにしようと思ってガチャガチャやってみた。 Access Key を割り当てて Alt + Control + s で検索窓を開き、おもむろに検索文字列を入力すると結果が出てきて、矢印キー上下で候補を移動でき、 Return で選択(その記事に遷移)できる。検索をやめたいと思えば Esc でモーダルウィンドウを閉じることができる。トラックパッドやマウスに持ち替えることなく、キーボードだけで検索できるようになった。めっちゃ便利。

| @ブログ

普段は Vim などのテキストエディターで文章を書いていて、ブログの投稿画面にはできあがった内容をコピペするだけだったので、投稿画面の使いやすさやは気にしたことがなかった。画像のドラッグ・アンド・ドロップ・アップロードや、オン・ザ・フライでプレビューをできるようにしたが、テキスト自体の書きやすさを改善しようとはしてこなかった。

大筋はテキストエディターで書いたとしても、最後に推敲したり、推敲していて気が付いたおかしなところの修正は投稿画面で行うことが多い。やっぱり投稿画面の書きやすさは重要だ。特に長大な内容を編集しているときにテキストエリアが狭いととても使いづらい。ある程度大きさがあり、画面内に大量の文字が表示されるテキストエリアが好みだ。

Lokka が開発されていた 10 年以上前は解像度の小さいディスプレイが主流で、 Lokka の管理画面は小さいサイズのウィンドウで閲覧することを想定したテキストエリアのサイズになっている。今日の高解像度ディスプレイで見ると不便なので画面一杯にテキストエリアが広がるようにした。

投稿画面のレイアウトを改善

iPad からも投稿しやすいように投稿画面のレイアウトも修正した。本文のテキストエリアが広がったためスクロールしないと「スラッグ」以降の入力欄にアクセスできなくなったので、ある程度横幅のあるウィンドウのときにはこれらを右側に配置するようにした。

加えて、フォームを書きかけで保存したかどうかがはっきりせず、未保存の内容があるのに保存せずページから離脱してしまうことがあったので、変更点があるときは背景色を変えてわかるようにした。これにより記入内容を保存せずページを離脱してしまい、内容が失われるという悲劇を回避できるようになった。やり方は適当に検索して出てきた Stack Overflow を参考に、ページを読み込んだ時点で JavaScript でフィールド内の要素を JSON.stringify して data attribute に格納し、その後各フィールドの input イベントを監視して変更があるかどうかをチェックしている。

class FormObserver {
  constructor() {
    this.initializeFields();
    this.observeFieldsChange();
  }

  initializeFields() {
    const fields = Array.from(document.querySelectorAll('div.field'));
    for (const field of fields) {
      const inputElement = field.querySelector('input[type="text"], textarea, input[type="datetime-local"], select option:checked');
      if (inputElement === null) {
        continue;
      }
      field.dataset.serialize = JSON.stringify(inputElement.value);
    }
  }

  observeFieldsChange() {
    const fields = Array.from(document.querySelectorAll('div.field'));
    for (const field of fields) {
      const inputElement = field.querySelector('input[type="text"], textarea, input[type="datetime-local"], select');
      if (inputElement === null) {
        continue;
      }
      inputElement.addEventListener('input', () => {
        if (field.dataset.serialize != JSON.stringify(inputElement.value)) {
          inputElement.dataset.changed = 'true';
          field.classList.add('edited');
        } else {
          inputElement.dataset.changed = 'false';
          field.classList.remove('edited');
        }
      })
    }
  }
}

input イベントを監視すると動作がもっさりするのではないかと心配したが、そんなことはないようだ。普通に使えている。

いまのところ管理画面の HTML レンダリングはサーバーサイドで Ruby で行っているが、これ以上凝ったことをやるなら React などを使って JavaScript で HTML を組み立てる方式にしていく方が効率が良さそうだ。

| @技術/プログラミング

偶発的に puma のバージョンを上げたところ Encoding::CompatibilityError: incompatible character encodings: UTF-8 and ISO-8859-1 が多発して厳しい感じになった。

このブログでは puma は v4 系を使っていたが、調べると最近 v6 もリリースされたようで v5 系に上げてみることにした。すると忘れていたのだが puma は v5 系から daemonize する機能が削除され、デーモン化は systemd を使うべしということになっていた。プロセスのデーモン化は puma にやってもらわないと capistrano で deploy するときに面倒なので以前は v5 に上げるのを諦めて v4 を維持していたのだった。

capistrano3-puma が systemd に対応していたのでえいやっと puma を v5 に上げて deploy してみたところ、冒頭の Encoding::CompatibilityError: incompatible character encodings: UTF-8 and ISO-8859-1 が多発してページが全く表示されなくなってしまった。

一方で管理画面やアーカイブページは表示に問題がなかった。どうもファイルの読み込みが発生するページ(このブログではキャッシュを多用していて、ファイルに書き出したキャッシュを読み込んでいる)でエラーが発生しているようだった。

自分で fork した sinatra-cache.gem でファイル読み込みする部分で encoding オプションを指定してみたりしたが問題が直らない。 Haml や Sinatra のバージョンも古いのでこれらも上げてみようかと試みたが、そうするとより盛大にエラーが出てしまう( Haml を v6 にすると html_safe している出力もさらにエスケープされて HTML がぶっ壊れる)。

気になるのはローカル環境( Mac )ではこのエラーが発生しないこと。「これは環境起因では?」と思い至ってガチャガチャやってみたところ修正することができた。

Lokka では Encoding.default_external を参照しつつ String#force_encoding しているところがある。「ひょっとして Encoding.default_external の値がローカルとサーバーで異なるのでは?」試してみたところ、ローカルでは #<Encoding:UTF-8> となる Encoding.default_external の結果が、サーバーでは #<Encoding:ISO-8859-1> となっていた。

以下のブログを参考に、環境変数 RUBYOPT でエンコーディングを指定して puma を動かすことでエラーを回避できた。

systemd 経由で puma を動かすときに環境変数を設定するのは結構難しい。最初は puma が RACK_ENV=production で動かず困ったが、 systemd 用の設定ファイルで EnvironmentFile のパスを指定し、環境変数用のファイルの中で各種環境変数を定義してやる必要があった。こんな感じ。

systemd の設定ファイル

[Unit]
Description=Puma HTTP Server for portalshit (production)
After=network.target

[Service]
Type=simple

WorkingDirectory=/var/www/deploys/portalshit/current
# Support older bundler versions where file descriptors weren't kept
# See https://github.com/rubygems/rubygems/issues/3254
EnvironmentFile=/var/www/app/.config/systemd/user/portalshit_env
ExecStart=/var/www/app/.rbenv/bin/rbenv exec bundle exec --keep-file-descriptors puma -C /var/www/app/portalshit/config/puma.rb
ExecReload=/bin/kill -USR1 $MAINPID
StandardOutput=append:/var/www/deploys/portalshit/shared/log/puma_access.log
StandardError=append:/var/www/deploys/portalshit/shared/log/puma_error.log

Restart=always
RestartSec=1

SyslogIdentifier=puma

[Install]
WantedBy=default.target

環境変数の定義ファイル

RACK_ENV=production
RUBYOPT=-EUTF-8

puma v5 に移行しようとしている方の参考になれば幸いです。

| @Mac/iPhone

プログラミングをほとんどやらなくなったので iPad Air でよいだろうと思って買ってみたところ、結構使いづらい。

普段 US キーボードを使っているので何の気なしに US 配列の Smart Keyboard Folio ( MU8G2LL/A )を選んだが、日本語と英語の切り替えがハチャメチャにやりづらい。 macOS 標準の日本語入力も ATOK も Ctrl + Shift + j で日本語に、 Ctrl + Shift + ' で英語に切り替えるデフォルトショートカットキーが割り当てられているので、このショートカットで日本語・英語を切り替えていた。 iPad でもこのショートカットで切り替えたいが残念ながら使えない。 JIS キーボードであればおなじみの 英数かな キーがあるのでより簡単に日本語・英語を切り替えられる。

Smart Keyboard Folio のキーピッチの狭さも厳しい。 Apple キーボードぐらいの使い心地を想像していたが、各種キーが小さくなっておりブラインドタッチできない。ふむーという感じ。

Apple のサイトを見ると iPad Pro の 12.9 インチ版はフルキーピッチになってるようなので、プログラミングをしない場合であってもキーボードを使ってそれなりに文章を書くつもりなのであれば iPad Pro 大を選ぶべきであった。

しかし iPad Pro 大と Magic Keyboard の組み合わせとなると ¥172,800 + ¥53,800 = ¥226,600 となり、軽く MacBook Air くらい買えてしまう値段になる。重さ的にも MacBook Air の方が有利そうだ。

iPad Air であれば、コンテンツの消費をメインにしつつ、ある程度はブログ書きもこなせて自分のニーズにマッチするかと期待していたが、正直なところ微妙なようだった。

| @Mac/iPhone

iPad Air (第 5 世代)を買った。

10 年くらい前に第 3 世代の iPad を持っていたが、当時はあまりしっくりこなくてほどなくして使わなくなってしまった。当時の自分のなかの結論としては iPad は様々なアプリからピロピロ通知が来て気になるし、プログラミングできないし、キーボードがないからブログ書きにも使えないし自分にはノートパソコンの方が向いているというのものだった。

しかしプログラミングは卒業してしまったし、今は Apple からカバーと一体となったキーボードも発売されていて、ブログ書きにも使えそうな雰囲気になってきた。 Apple Pencil にも興味がある。そして何より一番気になっている点は iPad 版 Kindle アプリの出来だ。

iOS の Kindle アプリは比較的よくできているのに Mac の Kindle アプリは本当に出来が良くない。クラッシュしまくるし、線を引こうとすると余計なところに引かれてしまうし、使っていてストレスしか感じない。 App Store でのレビューを見ると iPad OS 版の Kindle アプリの評価は悪くないようなので、リストカット感覚で iPad Air を買って iPad 版の Kindle アプリを試してみることにした。

この記事は早速 iPad Air から書いているが、変換に慣れている ATOK を使えないこと以外は特に問題がない。キーボードは一世代前の Smart Keyboard Folio の US 配列( MU8G2LL/A )をフリマサイトで安く購入した。 iPad Air はカメラが一つしかないので現行の iPad Pro 向けに作られた穴が大きい Smart Keyboard Folio よりも一世代前のバージョンの方が向いている。ちゃんと使えるかは reddit で調べて確認した。

これで寝床でゴロゴロしながらブログを書けるようになったので、これまで以上に駄文を濫造していけそうだ。