OTOBANK Engineering Blog

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

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 を使ってネイティブ開発しているので、今回得た知識を使って、より良いものを作ろうと思いました。今回のために、ニコニコ動画のプレミアム会員に復帰したので、タイムシフト視聴を利用して、気になる発表の見直しや、まだ見れていない発表をチェックしたいと思います。

必要な PHP拡張/パッケージをCIで検出し、インストール漏れエラーを防ぐ。 GitHub Actions と composer-require-checker で

composer での require と require-dev キー

PHPで広く使われている依存性マネージャの composer には、昨今の他の言語で用いられているツール同様に、依存性を設定するキーとして requirerequire-dev が存在します。

このキー欄にはそれぞれプロジェクトが依存する、PHPのバージョン・個々のPHP拡張・ベンダーパッケージとそのバージョン が指定できます。 普段PHPを利用する開発者のみなさんは、以下の通り依存性の追加コマンドを追加されてるかと思います。

composer require monolog/monolog # ロガーとしてmonologが必要
composer require --dev phpunit/phpunit # 開発時にテイスティングツールとしてPHPUnitが必要

require-dev の特徴として、

  • composer install --no-dev にてプロジェクトでのインストール時に対象外となる。
  • 依存指定するパッケージの require 指定時に、そのパッケージ先の require-dev は対象外となる。

が挙げられます。

本番リリース時のデプロイケース

開発用パッケージについては、本番の実行環境については必要ありませんので、デプロイパイプラインでは本番のみ --no-dev と指定しているプロジェクトも多いかと思います。

例えば、Google App Engine flex の実行Dockerイメージを作成する php-docker は、composer.jsonがプロジェクトルートに含まれていれば、指定されたPHP拡張のインストールも含め行ってくれますが、デフォルトでは、

'COMPOSER_FLAGS' => '--no-dev --prefer-dist',

--no-dev でのインストールになります。

require-dev が依存するパッケージの問題

この 本番と開発環境でインストールされるパッケージが異なる点について問題となるのが、dev指定のパッケージが依存するパッケージをプロダクションコードにて利用している場合です。 例えば、friendsofphp/php-cs-fixer を利用している場合 symfony/process がdev依存性でありますが、それに気づかず、Symfony\Component\Process\Process クラスを用いる改修を行い、require 設定をsymfony/processに行っていない場合にクラスが見つからずエラーとなってしまいます。

composer-require-checker による検出

昨年のPHPカンファレンス 2019 でも紹介しましたが、maglnet/composer-require-checker を用いると、composer.jsonでrequire定義されていないシンボル(クラスやPHP拡張の関数) を検出することができます。

github.com

実行方法としては、インストール後プロジェクトのルートディレクトリにて、

composer-require-checker check composer.json

とすることで、以下のような出力を得ることができます。

ComposerRequireChecker 2.1.0@0c66698d487fcb5c66cf07108e2180c818fb2e72
The following unknown symbols were found:
+------------------------------------------------------------+--------------------+
| unknown symbol                                             | guessed dependency |
+------------------------------------------------------------+--------------------+
| Aura\Router\Router                                         |                    |
| Aura\SqlQuery\Common\InsertInterface                       |                    |
| Aura\SqlQuery\Common\SelectInterface                       |                    |
| Aura\Sql\ExtendedPdoInterface                              |                    |
| BEAR\AppMeta\AbstractAppMeta                               |                    |
| BEAR\AppMeta\AppMeta                                       |                    |
| BEAR\AppMeta\Meta                                          |                    |
| ctype_digit                                                | ext-ctype          |
| Doctrine\Common\Cache\Cache                                |                    |

それぞれのクラス名については、対応するパッケージを追加し、guessed dependency 欄にext-○○○ と記載されている場合はPHP拡張がrequireセクションに足りないので追加します。

CIでの検出

このcomposer-require-checker check コマンドでのunknown symbolsがなにも検出されなかった場合と検出時のexitコードは分かれてますので、CIに組み込むができます。 弊社では GitHub Actionに composer-require-checker のセットアップを行いました。

GitHub Actions での設定例

最近では shivammathur/setup-php@v2 にて、7月21日リリースの2.4.0でtoolsにcomposer-require-checker が追加されたのでそちらを使うと良いかと思います。 https://github.com/shivammathur/setup-php/releases/tag/2.4.0

設定例としては、.github/workflows/composer-require-checker.yml に以下の設定を行います。

name: "Composer Require Checker"

on:
    pull_request:
    push:
        branches:
            - "master"
jobs:
    composer-require-checker:
        name: composer-require-checker check
        runs-on: ubuntu-latest
        steps:
            - name: "Checkout"
              uses: actions/checkout@v2

            - name: "Install PHP"
              uses: shivammathur/setup-php@v2
              with:
                  tools: composer-require-checker

            - name: "Get composer cache directory"
              id: composercache
              run: echo "::set-output name=dir::$(composer config cache-files-dir)"

            - name: "Cache composer dependencies"
              uses: actions/cache@v2
              with:
                  path: ${{ steps.composercache.outputs.dir }}
                  key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
                  restore-keys: ${{ runner.os }}-composer-

            - name: "Install dependencies"
              run: |
                  composer install --no-progress --no-scripts --no-dev

            - name: "Run composer-require-checker check"
              run: composer-require-checker check composer.json

余談ですが、 GitHub Actionsの場合は、 「Create Status badge」から以下のようなステータスバッジのマークダウンがコピーできますので、

![Composer Require Checker](https://github.com/{ベンダー}/{リポジトリ}/workflows/Composer%20Require%20Checker/badge.svg)

f:id:sasezaki:20200911112310p:plain
Github Actions composer require checker badge setting

README.md に追加して確認できるようにすると、ちょっとだけ安心感が増えるかも知れません。

f:id:sasezaki:20200911112423p:plain
composer-require-check-badge

利用/導入しての感想

composer-require-checkerの利用目的としては、上述に上げました--no-dev な本番環境へのリリース事後防止が上げらえますが、それ以外にも

  • extの指定漏れがなくなるので、途中からの参画メンバには composer install で必要な開発環境を確認してもらうことができる。
  • 依存パッケージが大多数の場合での、個別のパッケージupdate作業にて依存の確認が分かりやすくなった。

という良かった点があります。

利用されてないパッケージの削除? ~ composer-unused

composer-require-checker の"逆"なツールとして、コードベースでは未使用なrequireパッケージを検出する composer-unused が存在します。

github.com

現状では class-string なクラス名指定箇所に(Foo::class指定ではなく) 文字スカラー値そのままでの指定の場合にもunusedと検出されてしまうので、 現在、弊社のメインプロジェクトではCIには取り組めてないのですが、将来的にはこの点も解消した上で過不足無いパッケージにしていきたいです。

FlatListとセーフエリアの表示を考える

こんにちは、アプリ開発担当のエモトです。田舎からリモートワークで働いているのですが、どうも家のインターネット回線が不安定。今年前半の緊急事態宣言でリモートワークが広まった時期から明白に不安定になりだし、騙し騙し使ってましたが、流石に支障が出るため、ネットワーク環境の更新を計画中です。これを機に、IPoEで本当のインターネットを始めたい。

私の React Native 開発あるあるの1つとして、実装が終わったと安堵して確認したら、セーフエリア対応が不十分だったことがしばしばあります。ネイティブ開発なら勝手に動いていたことを忘れてしまい、後で SafeAreaView タグで囲って修正します。

今回、FlatList でセーフエリア対応したときに気づいたこと、その対応方法を紹介したいと思います。なお、以降に提示するコード例は簡易的にしています。

単純に以下のコードのように FlatList のみで画面を構成した場合、セーフエリアは考慮されません。

<FlatList />

f:id:mitsuharu_e:20200829111340g:plain

表示したい内容はすべて表示されていますが、リスト底部がセーフエリア(ホームバー)と重なっており、よいインタフェースであるとは言えません。

React Native でセーフエリアを考慮する場合は、SafeAreaView タグを用いてば良いです。早速やってみましょう。

<SafeAreaView>
  <FlatList />
</SafeAreaView>

f:id:mitsuharu_e:20200829111419g:plain

セーフエリアに重ならずに表示できましたが、違うそうじゃない。ユーザーのホームバー操作の保護が目的なら十分ですが、セーフエリアでの表示が無くなっています。これもよいインタフェースではありません。

なら、どうすればいいのか。この解決は、SafeAreaViewFlatList ではなく、 FlatList を構成する要素、例えば renderItem で指定する item などに対して行えば、うまく表示されます。

// renderItem に渡す関数など
import { SafeAreaView } from 'react-navigation'

<SafeAreaView forceInset={{ bottom: 'always' }}>
  <View />
</SafeAreaView>

f:id:mitsuharu_e:20200829111439g:plain

セーフエリアでも表示され、リスト底部がセーフエリアに重なることなく十分な余白を持ったので、今回こそ良いインタフェースと呼べるでしょう。なお、forceInset を設定するために、react-navigation を使用してました。なお、item それぞれに行うと、item 間にセーフエリア分の余白が生まれてしまうので、最下部の item のみに行う、または ListFooterComponent を使用していればそれに対して行うなどの手間があります。

まとめ

ノッチありスマホが発売されたとき、なんてキワモノなと思ってたこともありますが、昨今はノッチありがスタンダードの1つになりました。また、ディスプレイの湾曲や角丸で、セーフエリア設定は必須になったと言えます。実装した後に「あっ、セーフエリアを忘れてた」とならないように、良いインタフェースを持つアプリを開発していきたいです。

最後に、オトバンクではエンジニアを募集中です。日々良いユーザーインタフェースとは何なのかと考えている方、オーディオブック・React Native 開発(Swift や Kotlinのネイティブコードも書いてます)にご興味があれば、是非どうぞ。

お待ちしております。