OTOBANK Engineering Blog

オトバンクはコンテンツが大好きなエンジニアを募集しています!

audiobook.jp作品のサンプルコンテンツを埋め込める様になりました

こんにちは、普段サーバーサイドやWeb開発をやりつつフロントエンド入門中の岩Dです。
コロナも怖いですが、そろそろインフルエンザも怖くなってくる時期ですね。皆様インフルエンザの予防接種はお済みですか?私は午前に予防接種を受けてきて左腕が重い今日この頃です。

さて、今回のネタは「Embed (埋め込みコンテンツ)を作ってみた」です。

Embed って?


鈴村健一・堀江由衣共演!『君の膵臓をたべたい』

この様な感じで、ブログやWebページ内にYoutubeなどのコンテンツを埋め込んで表示ができるもので、埋め込んだページ内で動画や音声の再生などが出来たり、ページが華やかになったりと様々な良いことがあります。

参考 oEmbed

実装した Embed

今回実装したのがこの Embed です。この様にオーディオブックの書籍画像とサンプル音源の再生画面が表示され、audiobook.jp の商品ページへ行かずともサンプル音源が再生できる様になっています。
※サンプル音源が備わっていない作品につきましては、Embedを埋め込んでも再生画面が表示されません。

Embed 埋め込みサンプル

<iframe
  width="100%"
  height="253"
  src="https://audiobook.jp/embed/product/234391"
  frameborder="0"
  scrolling="no">
</iframe>

実装要件

この Embed は以下の様な要件で実装されております。

  • PC/SP で縦幅が同じになる様にする
  • 様々な端末で表示ができる様レスポンシブ対応にする
  • 社内デザイナーがデザインした様な見た目のサンプル音源再生を実現する
  • サンプル音源がない場合はサンプル音源再生部分に商品概要を表示させる
  • タイトル、著者などの表示について、PCでは1行で、SPでは2行で表示させて Embed の横幅を超える場合は省略表示させる
  • 販売されていないオーディオブックが埋め込まれた場合、コンテンツが表示できない事を表示させる

気を遣った点

縦幅について

PC/SP で表示が若干異なるものの、縦幅を同じにしなければいけない要件がありました。著者の情報がないもの、サンプル音源がないものなど表示内容に欠損があったとしても縦幅が変わる事なく表示できる様にするため、各項目の表示領域に対して親要素の幅から計算し height を適切な値で設定する事で Embed の高さが変わらない様にしています。また、SP表示の時はサンプル音源再生の部分が書籍画像の下に配置されますが、書籍画像のサイズをPC表示より少し小さくし、PC表示と同じ高さになる様に色々計算をしています。

PC表示
f:id:siwadate:20201106154752p:plain
SP表示
f:id:siwadate:20201106154843p:plain

サンプル音源の再生について

サンプル音源の再生について、今回は <audio> タグと MediaElement.js を使い、css で見た目の最終調整をして表示させています。

before
f:id:siwadate:20201106144817p:plain
after
f:id:siwadate:20201106144954p:plain

これは、audiobook.jp の商品ページ(君の膵臓をたべたい by audiobook.jp)などで表示しているサンプル音源再生の部分でもほぼ同じ仕組みが使われていますが、 css で見た目を調整するだけで随分と変わるものですね。

終わりに

PC/SPで Embed の縦幅が同じになる様にし、様々な端末で表示できる様レスポンシブ対応させつつ、サンプル音源再生を表示させるなど様々な苦労点がありました。一番こだわったサンプル音源再生の部分については、再生・停止ボタンを変更した以外は css で見た目の調整をしたのみで、さほど手間をかけずに良いものができたと思います。

今回の様な見た目として反映されるものを作るのが好きなので、今後もこの様な見た目を良くする仕事をしていきたいです。

また、この Embed について社内 note にも記載があるのでこちらも併せてどうぞ。 note.com

末筆になりますが、水樹奈々さん妊娠おめでとうございます。お子様にはぜひ「おやすみ、ロジャー」をお読み聞かせください。

FlatList の onViewableItemsChanged で起きたエラーを解決する

こんにちは、アプリ開発担当のエモトです。遊んでいたソシャゲが12月にサービス終了ということで、溜まった石やアイテムを使って、後先考えずに遊んでいます。アニメ作品のゲーム化なのでいつまで続くのか不安でしたが、2年弱も続いたので満足しております。なお、弊社本社近くのラーメン屋でガチャを回すと引きが良いです(個人調べ)。ガチャ好きな皆さまの入社をお待ちしております。

FlatList で今表示されている item の情報を取得するため、onViewableItemsChanged を利用したのですが、問題が起こり手間が取られてしまいました。今回はその問題と解決方法を共有したいと思います。なお、以降に提示するコード例は簡易的にしています。

問題

FlatList で表示されている item を取得しようと onViewableItemsChanged を利用しました。

const onViewableItemsChanged = ({viewableItems}) => { ... }
<FlatList onViewableItemsChanged={onViewableItemsChanged} />

すると、エラーが出てきました。しかも、このエラーは常にではなく、ホットリロード時に起こるなど、特殊なエラーでした。

Changing onViewableItemsChanged on the fly is not supported

調べると、

At least one of the viewAreaCoveragePercentThreshold or itemVisiblePercentThreshold is required.

とのことなので、viewabilityConfig に値を設定しました。

const onViewableItemsChanged = ({viewableItems}) => { ... }
const viewabilityConfig = {
  itemVisiblePercentThreshold: 50,
}
<FlatList
  onViewableItemsChanged={onViewableItemsChanged}
  viewabilityConfig={viewabilityConfig}
/>

しかしながら、エラーは治りませんでした。

解決

viewabilityConfig の公式ドキュメントを読むと、気になる一文がありました。

This needs to be done in the constructor to avoid following error

リンクされていた issue を読むと、render のタイミングで生成して渡すとダメな仕様でした。解決方法は分かったものの、私は関数コンポーネントで作成していたので、クラスコンポーネントの constructor に対応するものは何?と悩むことに。いろいろ調べ試すと今回は useRef() で良いと分かりました。

const onViewableItemsChanged = useRef(({viewableItems}) => { ... })
const viewabilityConfig = useRef({
  itemVisiblePercentThreshold: 50,
})
<FlatList
  onViewableItemsChanged={onViewableItemsChanged}
  viewabilityConfig={viewabilityConfig}
/>

やっと無事に動きました。私の中に useRef() に関数を入れる発想はなかったので、時間がかかってしまいました。

まとめ

FlatList の仕様と、クラスコンポーネントのメソッドを関数コンポーネントで書くにはどうすればいいんだという2つの問題を踏み抜いて、久々に沼ってしまいました。改めて、こういうシーンでは、

  • ドキュメントを漁る
  • 関数コンポーネントとクラスコンポーネントの比較

に立ち返るのが良いですね。この FlatList の仕様は他の方でもハマりそうな問題だと思うので、少しでも参考になれば幸いです。

iOSDC Japan 2020 に参加しました #iosdc

こんにちは、アプリ開発担当のエモトです。先日、突然の iOS 14 リリース発表で世界中の iOS アプリ開発エンジニアが混乱しました。私も漏れなく混乱して気を失い、キーボードを REALFORCE 91UBK から REALFORCE TKL for Mac (R2TL-JPVM-WH) に買い換えていました。前のキーボードに不満はなかったのですが、第2世代・for Macを使ってみたいと思っていたので楽しく使っています。Karabiner の Big Sur サポート版がリリースされたので、もう何も怖くない。

さて、9月19日から22日の3日間 iOSDC Japan 2020 に参加しました。5回目のiOSDC、今回5回目の参加です。昨今の事情から、今回はオンライン開催ということで、お家でゆっくりして参加しました。フルリモートで田舎に住んでアプリ開発をしているので、飛行機や宿泊の予約も必要ないし、オンライン開催は楽だなーっと。

オンラインのカンファレンス

今回は、ニコ生、Twitter そして Discord とメディアが多いので、2つのパソコンと1つの iPad を駆使して発表を見ていました。まず、ニコ生をテレビで見たいので、パソコン1台をテレビに有線で接続してブラウザをテレビに映しました。全トラックを映すという聖徳太子スタイルを試みようとしましたが、我が家のインターネットの回線状況が怪しくなったので断念しました(実現しても私自身の処理がおそらく追いつかない)。

もう1台のパソコンと iPad は手元において、Twitter と Discord を立ち上げて参加していました。のちに、ニコ生のコメント数がトーク賞に繋がるとのことだったので、手元にニコ生をおいてコメントをすればよかったなーとクロージング中に思いました。

今回の印象

今回の印象は SwiftUI を取り扱った発表が多かったなです。私自身は SwiftUI を日頃使うことはほとんどないのですが、React Native や Flutter でコードベースのインタフェース設計は行っています。それゆえ SwiftUI でアプリを書きたい欲はあるのですが、iOS 13 以上からというハードルが高すぎて手を付けていませんでした。個人的には最新バージョンのみをサポートすれば良いとおもうのですが、商用アプリだとそうもいかず。

そのなか、Kevin Wong さんの オープンソースのAltSwiftUIの発表 には驚かされました。SwiftUI の代替フレームワークを作るという発想は私にはありませんでした。UI周りはかなり複雑なうえに、SwiftUI と同等の機能を実装しているとは本当にすごいです。そして、やはり一番の関心は iOS 11 以上からサポートしているということですね。これは熱い。実際のアプリでも導入してみたいですね。

それ以外にも、Yoshimasa Niwa さんの iOS のキーボードと文字入力のすべて もとても面白かったです。キーボード関連の制御は誰もが序盤にやって、そこで終わりと印象でしたが、そんなことはなく、より深い話が聞けて参考になりました。やはり真実はソースコードの中にある・・・。

まとめ

ここ最近は React Native をメインを開発にしているので、iOS アプリをまるっと全部ネイティブで作ることが少なくなったので、iOS アプリ開発関連の話が聞けて、良い刺激になりました。React Native でも一部は Swift を使ってネイティブ開発しているので、今回得た知識を使って、より良いものを作ろうと思いました。今回のために、ニコニコ動画のプレミアム会員に復帰したので、タイムシフト視聴を利用して、気になる発表の見直しや、まだ見れていない発表をチェックしたいと思います。