【iOS】iOSアプリの「もっさり感」を追いかける！MetricKitの活用法

この記事は[レコチョク Advent Calendar 2024](https://qiita.com/advent-calendar/2024/recochoku)の23日目の記事となります。

## はじめに

こんにちは、後藤です。
株式会社レコチョクでiOSアプリの開発をしています。

毎年スキマスイッチの武道館のライブに参戦しており、今年も参加してきました。
最新アルバム「A museMentally」に収録されている「ごめんねベイビー」は、まるで消しゴム三部作のような雰囲気があり、とても気に入っています。
 
突然ですが、アプリを使用していて「もっさり感」を感じたことはありますか？
私が担当しているアプリでも、「アプリがもっさりする」という問い合わせをいただいたことがあり、この問題を解決する方法を模索しました。

「もっさり感」は抽象的で捉えにくい問題ですが、定量的に測定することで、具体的な改善施策を立てやすくなります。また、改善後の効果検証も行いやすくなります。
そこで、ユーザーごとのパフォーマンスデータを取得し、詳細な分析をするためにMetricKitを導入しました。
 
本記事では、以下のポイントについて詳しく解説します。
- 「もっさり感」を定量化するために実施した取り組み
- MetricKitを活用して取得したパフォーマンスデータについて
- パフォーマンスデータをどのように分析・活用したか

なお、MetricKitの導入手順や具体的なパフォーマンス改善施策については、本記事の範囲外としています。

## 実行環境
- Xcode 16.1
- iOS 18.1

## MetricKitとは？
[MetricKit](https://developer.apple.com/documentation/metrickit)は、iOSやmacOSなどのデバイス上でアプリの診断情報やパフォーマンス、消費電力に関するメトリクスを集約・分析するフレームワークです。
iOS 13以降で利用可能で、以下のような特徴があります。

- 過去24時間のメトリクスを1日に最大1回配信（iOS 15以降では診断データを即時配信）
- クラッシュやハングの原因分析、パフォーマンス改善に活用
- データをヒストグラムやスタックトレースなどで詳細に表現可能

## なぜMetricKitを導入したのか？

「はじめに」でも述べた通り、私が担当するアプリでは「アプリがもっさりする」というお問い合わせをいただいていました。
しかし、「もっさりする」という表現は定性的な指標です。
「もっさりする」原因を特定し、改善に繋げることは容易ではありません。

そこで、お問い合わせいただいたユーザー情報を分析した結果、アプリ独自の楽曲登録機能の利用率が高いユーザー（楽曲登録件数が多いユーザー）から、「もっさりする」という声が多く寄せられていることが判明しました。
この結果を踏まえ、楽曲登録件数とパフォーマンスの関係を調査し、相関を見つけることで「もっさり感」の正体を明らかにできるのではないかという仮説を立てました。

MetricKit以外にもパフォーマンスを測定する手段として、[Xcode Organizer](https://developer.apple.com/documentation/xcode/viewing-app-store-connect-reports-in-xcode)を使う方法もあります。
Xcode Organizerは、App Storeから収集されたクラッシュレポートやパフォーマンスデータを確認でき、アプリ全体の傾向を把握するのに便利です。
しかし、データは全ユーザーの集計値であるため、特定のユーザーやシナリオに基づいた詳細な分析はできません。

一方、MetricKitは特定のユーザーごとのパフォーマンスデータを収集できます。
そのため、「もっさり感」のような個別のユーザー体験を分析するには、MetricKitが適していると判断しました。

## 収集したMetricKitのデータ

「もっさり感」を定量化するために、以下のデータを収集しました。

| **データ項目**                             | **説明**                                                                                  | **MetricKitのドキュメント**                             |
|--------------------------------------------|------------------------------------------------------------------------------------------|--------------------------------------|
| **アプリの初期描画までの時間**             | アプリが起動してから最初の描画が完了するまでの時間のヒストグラムデータ                    | [histogrammedTimeToFirstDraw](https://developer.apple.com/documentation/metrickit/mxapplaunchmetric/histogrammedtimetofirstdraw) |
| **アプリの合計ハング時間**                 | アプリが応答しなくなった時間（ハング時間）のヒストグラムデータ                            | [histogrammedApplicationHangTime](https://developer.apple.com/documentation/metrickit/mxappresponsivenessmetric/histogrammedapplicationhangtime) |
| **スクロールヒッチ比率**                   | スクロール中に発生する引っ掛かり（ヒッチ）の割合のヒストグラムデータ（iOS 14以降で利用可能） | [scrollHitchTimeRatio](https://developer.apple.com/documentation/metrickit/mxanimationmetric/scrollhitchtimeratio) |
| **ピークメモリ使用量**                     | アプリの動作中に使用された最大メモリ量                                                   | [peakMemoryUsage](https://developer.apple.com/documentation/metrickit/mxmemorymetric/peakmemoryusage) |
| **ディスク書き込みデータ量**               | アプリがディスクに書き込んだデータの累積量                                               | [cumulativeLogicalWrites](https://developer.apple.com/documentation/metrickit/mxsignpostintervaldata/cumulativelogicalwrites) |
| **アプリ再開時間**                         | バックグラウンドからフォアグラウンドに戻るまでの時間のヒストグラムデータ                 | [histogrammedApplicationResumeTime](https://developer.apple.com/documentation/metrickit/mxapplaunchmetric/histogrammedapplicationresumetime) |
| **最適化された初期描画時間**               | 最適化された初期描画時間のヒストグラムデータ（iOS 15.2以降で利用可能）                   | [histogrammedOptimizedTimeToFirstDraw](https://developer.apple.com/documentation/metrickit/mxapplaunchmetric/histogrammedoptimizedtimetofirstdraw) |
| **停止状態中の平均メモリ使用量**           | バックグラウンドで停止中のアプリが使用している平均メモリ量                               | [averageSuspendedMemory](https://developer.apple.com/documentation/metrickit/mxmemorymetric/averagesuspendedmemory) |

さらに、楽曲登録件数などのアプリ特有のデータも収集し、それらをMetricKitのパフォーマンスデータと組み合わせて分析しました。
収集したデータはアプリ内で整形し、Firebaseを通じてGoogle Analyticsにイベントとして送信しています。
その後、Google Analyticsで収集したイベントデータをBigQueryに連携し、集計・分析を実施しました。

また、MetricKitで提供されるデータはヒストグラム形式の場合があるため、中央値を計算して分析に活用しています。たとえば、「アプリの初期描画までの時間」や「ハング時間」などの項目では、ヒストグラムから中央値を抽出し、それを代表値として利用しました。

なお、MetricKitのログ送信はバックグラウンドスレッドで行われます。そのため、送信タイミングにメインスレッドで処理を行っていると、予期せぬクラッシュが発生する可能性があります。この問題を避けるため、ログ送信に関連する処理はバックグラウンドで安全に実行できる処理にしましょう。

## パフォーマンスの計測結果
今回の分析は、5046人分のデータを対象に実施しました。

以下の散布図は、ハング時間（ms）と楽曲登録件数（件）の関係を示しています。

### 線形スケールのグラフ

![MetricKit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279002/b3d4a956-ca19-359e-a944-d1f99cc51afc.png)


楽曲登録件数とパフォーマンスの関係を分析した結果、仮説通り「楽曲登録件数が多いユーザーほどハング時間が長い」という傾向が確認されました。相関係数は0.34と弱い相関ではありますが、登録件数の多いユーザーでハング時間が増加しています。
たとえば、あるユーザーでは1日に約20秒のハング時間を経験していることが判明しました。

また、この傾向を踏まえて調査を進めた結果、楽曲取得処理の一部がハング時間の増加に関与していることが明らかになりました。次回以降のリリースでは、この処理の最適化を実施し、全体のハング時間削減を目指します。

一方で、その他のパフォーマンスデータと楽曲登録件数には関連性が見られないことが明らかになりました。
たとえば、楽曲登録件数とピークメモリ使用量の関係についても検証したところ、相関係数は0.08と非常に小さく、楽曲登録件数とピークメモリ使用量の間にはほとんど関連性がないことが確認されました。

なお、楽曲登録件数が少ないユーザーのデータについては、スケールの影響で詳細が分かりにくいため、次に示す対数スケールのグラフを用いてさらに詳しく分析します。

### 対数スケールのグラフ

![MetricKitLog.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279002/23d6da27-27ba-4bf7-9d91-1380010f006b.png)


対数スケールを使用することで、データの密集している低い範囲の詳細が観察できるようになります。このグラフから以下のことが追加で読み取れます。

- 楽曲登録件数が0件の場合でもハング時間が発生し、ばらつきが見られる（緑色部分）
- 登録件数が500件を超えるあたりから、ハング時間の増加傾向が2つのトレンド（赤色とオレンジ色）に分かれている可能性がある

![MetricKitLogColor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279002/8682bfc1-c688-cf75-90fe-fff203395a98.png)

とくに、楽曲登録件数が0件の場合にもハング時間がばらついている点については、楽曲登録件数ではない別の要因が関与している可能性を示唆しています。
そこで、楽曲登録件数が0件のユーザー（138人分）のデータを分析し、OSバージョンや端末による違いを調査しました。

なお、データの偏りを防ぐために、サンプル数が4件以上のデータのみを可視化し、全体の傾向を分析しました。

### OSのバージョンによるハング時間の傾向

![MetricKitOS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279002/29718f22-5e4e-0b52-1b84-d398434aed98.png)


このグラフは、OSバージョンごとにハング時間の平均値と中央値を可視化したものです。
OSバージョンによる平均値のばらつきは見られるものの、中央値はほぼ同じ500ms前後であることから、OSの違いによるハング時間の影響は少ない可能性が高いと分かりました。

### iPhoneの機種によるハング時間の傾向


![MetricKitOSMobile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279002/f8b3bde6-c12a-89fe-4413-bda450555fa8.png)


このグラフは、iPhoneの機種ごとのハング時間の平均値と中央値を可視化したものです。
OSバージョンの場合と同様、平均値にはばらつきが見られるものの、中央値はほぼ同じ500ms前後であり、機種によるハング時間への影響も少ない可能性が高いと分かりました。

### 楽曲登録件数が0件のユーザーの分析の結論

楽曲登録件数が0件のユーザーを分析した結果、OSバージョンや端末の違いによる影響はほとんどないことが確認されました。
このことから、アプリの実装に問題がある可能性が高いと考えています。
とくに、楽曲登録がない場合でもハング時間が発生することから、初回起動時や毎回の起動時に特定の処理負荷が発生している可能性が高いと考えています。

### 今後の課題

今後の課題として、まずはアプリの初回起動時や起動時に発生していると考えられる処理負荷を特定し、それを改善する必要があります。
また、楽曲登録件数が500件を超えたユーザーに見られる2つの異なるトレンド（赤色とオレンジ色）が発生する原因を明らかにするために、データサンプルをさらに増やして詳細な分析を進める予定です。

## まとめ

本記事では、MetricKitを活用してアプリの「もっさり感」を定量化する方法と、そのデータを分析した結果について紹介しました。
とくに、楽曲登録件数とハング時間の相関を明らかにし、楽曲登録取得処理に原因があることを特定できた点は、パフォーマンス改善の第一歩となりました。

今後は、特定した改善点を元にプロダクトコードを修正し、全体のハング時間を削減することを目指します。さらに、他のパフォーマンス指標についても継続的に分析を進め、より快適なユーザー体験を提供できるアプリを目指します。

最後までお読みいただきありがとうございました！  
明日の [レコチョク Advent Calendar 2024](https://qiita.com/advent-calendar/2024/recochoku) は24日目「設計はメリット・デメリットを分析して考えよう」です。お楽しみに！

## 参考資料
- [Apple Developer Documentation - MetricKit](https://developer.apple.com/documentation/metrickit)
- [WWDC Videos about MetricKit](https://developer.apple.com/videos/play/wwdc2019/417/)
- [Measurements with MetricKit](https://dev.to/mtmorozov/measurements-with-metrickit-4239)
- [健康第一！MetricKitで始めるアプリの健康診断 / App Health Checkups Starting with MetricKit](https://speakerdeck.com/nekowen/app-health-checkups-starting-with-metrickit)

---

この記事はレコチョクのエンジニアブログの記事を転載したものとなります。 
 
https://techblog.recochoku.jp/11610