Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

iOS14 勉強会参加レポート

こんにちは。Twitter に流れてくる PS5 当選Tweet を見て嫉妬にかられている iOS チームの髙橋佑一朗です。 今回は 11/06 の金曜に行われた「アプリ開発に強みを持つ3社がiOS14の開発事情を語る」 に参加してきましたので、その内容をレポートにまとめてみました!

アプリ開発に強みを持つ3社がiOS14の開発事情を語る について

今回の勉強会はつい最近リリースされた iOS14 へのアプリ対応の取り組みについて 株式会社Mobility Technologies、株式会社ゆめみ、Sansan株式会社の3社の iOS エンジニアが登壇し、どのような開発を行っているか、どんな部分に苦労したかお話ししていただきました!

イベントの概要

LT

JapanTaxi x MOV = Goの開発体制と iOS14 対応 (株式会社Mobility Technologies 日浅貴啓 氏)

トップバッターは今年4月に会社統合をした Mobility Technologies の日浅さんから、会社統合後のチームビルディングやその中での iOS 14 対応についてお話いただきました!

speakerdeck.com

会社統合について

今年の4月に会社統合が行われ、 JapanTaxi と MOV のエンジニアが一緒になったことで合計8名になり 、開発も爆速でできる!と喜んでいたのも束の間、統合直後の課題として次のようなものを挙げられていました。

  • 新しいアプリの仕様が FIX していないため、開発が進められない
  • 人数が増えたが、既存アプリの改修、問い合わせ対応でリソースが持っていかれてしまう
  • コロナ渦でリモートワークだったため、新メンバーとのコミュニケーションが取りづらい

4月といえばコロナが日本でも猛威をふるい始めた時期でとても混乱していた時期に思います。そんな時期に新しいメンバー、新しい環境で仕事をするということは自分が考える以上に大変なのかなと感じました。

爆速で開発を進めるために

開発を円滑に行うためには多くの課題がありましたが、アプリの仕様が固まった際に爆速で開発できるように準備を進めていたようです。

リソース増強へ向けて

既存アプリの対応を減らしていくため、JapanTaxi アプリの開発、運用を委託したそうです。 委託に関して、 JapanTaxi は Library アップデート、コードフリーズやリリース作業の自動化などをしており、コミュニケーションパスの整理だけで開発の移譲が終わったということでした。 開発を移譲したことで 80% ほどプロパーエンジニアの対応工数を削減できており、既存アプリの対応工数の問題は解決したそうです。 自動化やリリースの自動化に関しては同じくMobility Technologies の今入さんがこちらの勉強会で以前発表されていた資料に載っているそうなので興味がある方はこちらも合わせてご覧ください!

buildersbox.corp-sansan.com

コロナ渦のコミュニケーション

コロナ渦で新しいチームとしてやっていくために、課題を洗い出し、どう解消しつつチームビルディングをしたかというお話をされていました。 コミュニケーションの課題を解消するためにやったことはざっくりと次のようなものでした。

  • ブレーンストーミングのように不安に思っていることを書き出す
  • 書き出したものを組織化、技術品質、製品品質の三つのグループにわける
  • 対応の優先順位づけを行い、二つのチームに分けて役割分担をした
  • チーム腹斜筋: 組織化、製品品質を担当
  • チームライザップ: 組織化、技術品質を担当

自分が不安に思っていることを書き出す については不安に思っていることをそのまま書き出すとマイナスの方向に議論が進んでしまうということもあり、代わりにどういう状態になっていたいかを書き出していたというのが印象的でした。 マイナスな言い方をプラスな言い方に変えるというのはどこでも応用が効きそうで自分も意識していきたいなと感じました。

技術品質と製品品質についても一般的には製品品質の中に技術品質が内包されていると勘違いされているが、実際は技術品質に製品品質に内包されていると言われていて、缶ジュースの話がとてもわかりやすかったです。 缶ジュースの 安全性 という部分が技術品質に相当するものであり、意識していないけど、一番重要なはず。安全性という技術品質が安定しているからこそ、味や香りといった製品品質で付加価値を付けていけると。

f:id:chaaaaanu:20201116015937p:plain
製品品質が技術品質に内包されているのが正確

ちなみにチーム名の由来は

  • 腹斜筋: 一番かっこいい筋肉であり、mobility を技術で支える会社として腹斜筋のように一番かっこよくありたいと思うから
  • ライザップ: 結果にコミットしていきたいという意思から

ということで背景を知るとそれぞれ渋いチーム名に思えてきて、名前以上にかっこいいなと感じました。

Go アプリの開発

Go アプリの開発についても開発を進めながら、技術品質を担保するということで iOS14 対応もしつつ、さらに技術品質は iOS14 対応だけではないとアーキテクチャの変更も同時に行っていたようでかなり驚きました。 開発、iOS14対応、アーキテクチャの改善と三つのことを並行して行うのはかなりハードなことだと思うので、Go 開発チームのレベルの高さが垣間見えました。 いろいろ聞いてみたいところですが、今回は iOS 14 対応の部分のことをお話ししていただきました。 Go アプリの開発については Mobility Technologies の monoqlo さんが既に iOSDC で発表されているとのことだったので、興味がおありの方はそちらも合わせてご覧ください!

note.com

Go の iOS14 対応

Go アプリの iOS14対応では大きく以下の二つの対応があったようです。

  • 位置情報 (正確な位置情報をオフ)
  • 文字間隔調整の係数 (Tracking) の変更

位置情報 (正確な位置情報をオフ)

iOS14 から、設定アプリ内で個別のアプリに対して正確な位置情報を提供するか否かという設定を行えるようになりました。 Go アプリでは配車のため位置情報を利用していますが、乗り降りのいちをユーザが指定するため大きな問題にはなっていないようでした。 ただ、降車位置については住所での指定も可能なため Accuracy については考慮しておく必要があり、実際に電車に乗ってアプリの検証を行われていたようです。

文字間隔調整の係数 (Tracking) の変更

まず前提として、iOS では文字サイズによって使われているフォントが少し異なり、例えば 文字サイズが 20 pt 未満の場合は SF Text を、20pt 以上の場合は SF Display を利用するようになっていました。 iOS13 まではこのフォントが切り替わるタイミングで大きく Tracking も代わり、急激に文字間隔が開くようになっていましたが、 iOS14 からは 17pt ~ 28pt の間で緩やかに変化するようになり、ラベルが省略されるなどレイアウト崩れが起きてしまっていました。 対応策として、カーニングで文字と文字の間を逐一調整するのではなく、Tight Tracking を利用して文字の美しさを保てるように修正をしたそうです。 実際のコードとしては UILabel.allowsDefaultTighteningForTruncationtrue にするだけのようです。

まとめ

iOS14 対応だけでなく、会社統合後のチームビルディングの話まで聞けて非常に濃密な内容のセッションだったなと感じました。 技術品質の部分で行われていた、アーキテクチャの改善についても今後お話しいただけるとのことだったのでそちらにもぜひ期待したいところです!

こんなにあった!ゆめみでの iOS 14 対応 (株式会社ゆめみ 林 大地 氏)

二人目はユニークな制度が多いことで有名な株式会社ゆめみの林さんから、ゆめみであったiOS14へのアプリ対応のお話をしていただきました!今年の iOSDC と同じく事前録画形式で発表をされており、ご自身もTwitter 等で視聴者の方とお話しながら一緒に発表を見ているのが印象的でした!

speakerdeck.com

また、プロダクションコードは出せないということで今回はサンプルアプリを使っての発表となっていました(すごい)ので、こちらも合わせて、手元で動かしてお試しください! github.com

今回はUIを中心に大まかに以下の4つについて対応をされていたということで順番に見ていきたいと思います。

  • UIPageControl の仕様が変わった
  • デフォルトブラウザを変えるとエラー
  • UIStackView の背景色が突然現れた
  • backButton 長押しメニューの対応

UIPageControlの仕様変更

起こったこと

iOS14から UIPageControl の見た目が変わってコンパクトになってしまった!

やりたいこと

iOS13 と同じ見た目に揃えたい!

解決方法

今のところiOS13と同じ見た目に戻すことはできなさそう! 😇

最初はホーム画面などでおなじみの UIPageControl について。ドットの並びで現在位置と総ページ数を表現できるため、ページングのある UI などでよく用いられていますね。 このドットですが、 iOS13 までは有限で、画面幅によって最大で 20 ドットほど表示ができ、常に全てのドットが画面内に表示されている形になっていました。

f:id:chaaaaanu:20201116021232p:plain
iOS13 では全部表示されていた

さて、iOS14 ではこの UIPageControlのドットが20個ある状態にすると一部のドットが省略され、全ては見えなくなり、コンパクトな見た目になります。 また、端に行くほど小さくなっており、まだ先に見えないドットがあることを示すような見た目に変わっていました。

f:id:chaaaaanu:20201116021401p:plain
iOS14 では部分的に表示されるようになり、ドットも端が小さい

これは iOS14 からの変更の一つである UnlimitedPages が原因で UIPageControl は iOS14 以降では無制限にドットが表示できるようになりました。 そんなにたくさんのページをスワイプとタッチだけで移動するのは大変では?と思いましたが、インタラクションにも変更が入っており、 UIPageControl を擦る(スクラブ)ことでページ間を高速で移動できるようになるためその辺のケアはされているようです。詳しくはこちらの WWDC のセッションで詳しく説明されていますので興味がある方は合わせてご覧ください。

これを iOS13 のような見た目に戻す方法は今のところ見つかっていないようで解決案としては

  • iOS 14 の仕様変更を受け入れる
  • あまりにページ数が多い場合は UIPageControl を別のグリッドに置き換えることを検討する

の二つが挙げられており、前者を採用したようでした。 後者は HIG に書かれている

10ドットを超えるとページをひと目で数えるのが難しくなり、20ドットを超えると任意のページに辿り着くのが困難になる。総ページ数が20を超える場合には別の非順次Viewの使用を検討するべき。

の内容を根拠としており、確かにコストを考えなければ解決案としては一番綺麗だと感じました。(ではなぜ UnlimitedPages の変更を入れたのか・・・)

デフォルトブラウザを変えるとエラー

起こったこと

デフォルトのブラウザを Safari から別のブラウザに変えるとアプリから URL を開けない!(canOpenURL が常に false になる)

やりたいこと

デフォルトブラウザが Safari 以外での場合でもアプリから URL を開きたい!

解決方法

Info.plist の LSApplicationQueriesSchemes に開きたい URL スキームを追加する (http, https 含む)

続いては iOS14から可能になったデフォルトブラウザの変更に関連するお話です。 iOS 13までは基本的にアプリから URL を UIApplication.open(_:) で開く場合は Safari 一択でしたが、iOS 14 からどのブラウザで開くか、設定アプリ内で対応ブラウザを自由に設定できるようになりました。 愛用しているブラウザをデフォルトブラウザとして登録できるようになったことで自分としては QOL が上がったな(当社比)という印象でした。 さて、UIApplication.open を使って URL を開く場合は大抵の場合 UIApplication.canOpenURL(_:) で URL が開けるかどうか事前にチェックすることが多いかと思うのですが、これがデフォルトブラウザを変更した場合に常に false になってしまうということでした。 僕も canOpenURL のドキュメントをしっかり読んだことがなく、知らなかったですがドキュメントにきちんと

If your app is linked on or after iOS 9.0, you must declare the URL schemes you pass to this method by adding the LSApplicationQueriesSchemes key to your app's Info.plist file. This method always returns false for undeclared schemes, whether or not an appropriate app is installed.
(作ってるアプリが iOS9.0 以降に動作するなら、このメソッドに渡したい URL schemes を Info.plist のLSApplicationQueriesSchemes key と一緒に追加しておかないと、常に false を返しちゃうよ(意訳))

と書いてあったようで、ドキュメント通り Info.plist に LSApplicationQueriesSchemes と渡したい URL scheme を追加することで無事動くようになるとのことでした。

UIStackView の背景色が突然現れた

起こったこと

UIStackView の backgroundColor に誤って設定されていた色が画面に反映されるようになった

やりたいこと

UIStackView の背景色を無くしたい

解決方法

UIStackView の backgroundColor の設定がされていないかチェックして無くしていく

これまで UIStackView の backgroundColor はただあるだけで、設定しても何もしない子でしたが、 iOS14からはしっかりと設定された色を反映させる子になったようです。 UiStackView の主な仕事は自分の配下の view をレイアウトすることであり、UIStackView 自体が画面上にレンダリングされることはありませんでした。 iOS 14 から UIStackView がレンダリングされるようになり、その影響で見えていなかった背景色が見えるようになったということでした。 具体的な変更としては UIStackView の layerClass が CATransfromLayer から CALayer に置き換えられたということでした。 間違えて別の場所に背景色指定しちゃったけど、どうせ見えないしいいでしょ!と放置することがちょこちょこあったのできちんと不要なものはそのままにしておかないように綺麗にしておくべきだと反省する良い機会になりました。

backButton 長押しメニューの対応

起こったこと

NavigationBar の戻るボタンのタイトルを空にしていると、backButton長押しメニューがおかしなことになってしまう

やりたいこと

戻るボタンのタイトルを空にしつつ、 backButton 長押しメニューの表示を綺麗にしたい

解決方法

navigaitonItem.backButtonDisplayMode に .minimal を設定する

最後は iOS 14 から追加された BackButtonHistoryMenu (?) についてですね。 iOS14 から BackButton を長押しすることでどこに戻るかを表示されたメニューから選べるようになりました。 基本的にこのメニューに表示される 各画面のタイトルはスライドの表のようになっています。

f:id:chaaaaanu:20201116021541p:plain
長押しメニューのタイトルの取得元一覧

今回のケースでは navigationItem.backBarButtonItem にタイトルが空の BarButtonItem を入れていたため、タイトルが表示されずにどこに戻るのかわからない状態になってしまっていました。 解決策として iOS14 と iOS13 で分岐を入れて、 iOS14 では新しく追加された navigaitonItem.backButtonDisplayModeminimal を設定することで NavigationBar の戻るボタンのタイトルを空にしつつ、メニューにタイトルを表示させることができていました!

まとめ

ゆめみさんの発表ではUI周りを中心に、iOS14をアプリに対応させる方法を聞くことができました。 なんとなく変わったことは知っていたけど変更後の細かい挙動まで把握していないUI変更もあったので今後 UI を作っていく上でとても参考になった発表でした!

iOS 14 での MetricKit の新機能について (Sansan株式会社 多鹿 豊)

最後は弊社 Sansan の多鹿から MetricKit での変更点や実装についてのお話をしました! MetricKit 自体は iOS13 から存在しますが、今回はiOS14でどう変わったかという観点で iOS13 で取得できる内容を振り返りつつ話をしていました!

speakerdeck.com

MetricKit について

MetricKit は iOS13 から追加されたフレームワークでアプリのバッテリー負荷やパフォーマンスに関わる情報を取得することができます。 アプリのパフォーマンスの計測方法についていくつか方法がありますが、MetricKit は実機で動いてるアプリの情報を取得して貯めておけるのが嬉しいですね。 WWDC では開発プロセスが以下のスライドの通り三つに分けられており、そのうち、 Beta, PublicRelease の段階のアプリの情報がとれるようです。 つまり MetricKit では TestFlight などを利用してベータ版として配布されているアプリや AppStore に上がっている製品としてのアプリのパフォーマンス状況が見れるということですね。

f:id:chaaaaanu:20201116021643p:plain
MetricKit では Beta, Public Release のフェーズでのデータが取れる

またデータの取得のタイミングは 1日に1回で、24時間分のデータが取れるようです。

f:id:chaaaaanu:20201116021813p:plain
データの取得は1日に1回

実装について

ここからはおさらいという形でまずは実装方法とデータの受け取り方についてお話していました。 実装方法はそこまで難しくなく以下のように実装していきます。

import MetricKit // 1. まずはフレームワークをインポート

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // 3. MXMetricManager に MXMetricManagerSubscriber をセット(今回は self)
        MXMetricManager.shared.add(self)
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // 4. アプリが kill された時に MXMetricManagerSubscriber を削除する
        MXMetricManager.shared.remove(self)        
    }
}

// 2. AppDelegate などで MXMetricManagerSubscriber を採用し、didReceive(_:) メソッドを実装
extesnion AppDelegate: MXMetricManagerSubscriber {
    func didReceive(_ payloads: [MXMetricPayload]) {
         // payloads のデータを受け取ってどこかに投げる
    }
}

これでデータを受け取る準備は完了です。基本的な実装はこの程度で非常にさっくり実装できてしまうような印象でした。 didReceive の実装内容についてもある程度スライドで言及されており、自社サーバなどにデータを送信することでより細かく計測ができるということ、整形したデータを送る際には MXMetric, MXMetricPayload に生えている jsonRepresentation メソッドを利用すると Data 型への変換が簡単ということについて触れられていました。

f:id:chaaaaanu:20201116022046p:plain
実装イメージ

f:id:chaaaaanu:20201116022058p:plain
Debug もお手軽

どんなデータを取れるのか? (iOS13 では)

iOS13 では MetricKit の情報として次のようなものが取れるようです。

Battery

  • ネットワークの接続状況
    • シグナルバーの本数
  • ディスプレイの輝度
  • CPU, GPU の使用状況
  • 位置情報追跡の使用状況
  • ネットワーク転送
    • セルラー、wifi でのアップロード、ダウンロード量

Performance

  • ハングが起こった時間
  • ディスクの書き込み総量
  • アプリの起動
    • 起動、復帰
  • メモリ使用量

この時点でもかなりいろいろなものが取れるようですね。
もう少し詳しくみたい方は以下の MXMetricPayload のドキュメントも合わせてご覧ください!
Apple Developer Documentation

iOS 14 での新機能

iOS 14 での変更点としては以下の 2点が紹介されていました

  • 新しいメトリクスの追加
  • 新しい診断 API

新しいメトリクスの追加

iOS 14 から新たに以下の メトリクスが追加されたようです

  • CPU 命令数
  • スクロールヒッチ率
  • アプリケーションの終了、強制終了の回数

この中で特に良いなと思ったのはスクロールヒッチ率で、スクロールヒッチはスクロールの引っ掛かりのことのようです。 滑らかなスクロールは iOS アプリの大きな特徴だと思うのでそこのデータが取れるのは非常に嬉しいです。 スクロールヒッチ率は 1秒あたりのスクロールヒッチ時間のことでパフォーマンス改善のための目安として以下のようにWWDC で説明されていたようです。

f:id:chaaaaanu:20201116022020p:plain
この辺の可視化はさすが Apple といったところ

新しい診断 API (MetricKit Diagnostic)

新しい診断 API を使って次のような診断データを取集できるようです。

  • ハング
    • ハングが発生した回数
  • クラッシュ
  • ディスク書き込み例外処理
    • 書き込み量
  • CPU 例外処理
    • CPU 時間
  • 高い CPU 使用率がサンプリングされた合計時間

またデータそれぞれに backtrace が CallStackTree の状態で渡ってくるため、atos コマンドなどを利用することで細かい追跡が可能になるようです。

データの受け取り方については実装の時に出てきた MXMetricManagerSubscriber に追加されたメソッドを実装すれば受け取れるようです。

extension AppDelegate: MXMetricManagerSubscriber {
    func didReceive(_ payloads: [MXMetricPayload]) {
        // ...
    }

    func didReceive(_ payloads: [MXDiagnosticPayload]) {
        // ここで診断データを受け取る
    }
}

まとめ

MetricKit を使って実際にユーザが使っているデバイスの情報を取得する方法についてでした! スライドにもあるとおり、残念ながら弊社 Sansan でもまだ導入はできていないですが、ここでの情報を元にMetricKit の採用も考えてパフォーマンス改善を行っていきたいと思います!

総まとめ

ということでここまで内容をざっくりまとめてまいりましたがいかがでしたでしょうか? 今回もオンライン開催ということで参加者や、登壇者の方と直接お話することはできませんでしたが、 Twitter で盛り上がっていたり、トークの際に登壇者がそれぞれ声を掛け合ってつないでいくなど、オフラインとは一味違った良さや雰囲気があり、イベントとしてもとても楽しかったなと感じました。 このまとめの記事を書きながら、発表内容も情報の密度にも改めて驚かされました。 最後に、素晴らしい知見を共有してくださった登壇者の皆様に感謝の意でまとめを終わりたいと思います。お疲れ様でした!


buildersbox.corp-sansan.com buildersbox.corp-sansan.com buildersbox.corp-sansan.com

© Sansan, Inc.