Androidアプリのデバッグには、クラッシュ、ANR、一貫性のないログなど、独特な課題が豊富にあります。
しかし、問題を素早く特定して解決し、より良いパフォーマンスとユーザー体験を実現する簡単な方法がいくつかあります。
今回は、Android のデバッグを効率化する基本的なツールとテクニックを紹介し、ANR について説明します!
Androidデバッグにおける「3つ」の基本
- Android StudioのLogcat
Logcatはリアルタイムにログを出力し、手動でエラーを見つけるのに役立ちます。このツールでは、以下のようなカスタムタグを使用することで特定の問題を切り分けることが簡単にできます。
Logcatで 「MyAppTag 」でフィルタリングすると、無関係なログを選別することなく、NullPointerExceptionのような特定の問題に焦点を当てることができます。
- Android Studioのブレークポイント ブレークポイントは、実行時の動作を検査するために不可欠です。コードの重要な行にブレークポイントを設定します。
ブレークポイントがトリガーされると、Android Studioは実行を一時停止し、変数(結果)を検査したり、コードの実行をステップ実行してロジックの展開を確認したりすることができます。
この方法は、フロー制御や計算の微妙なバグをキャッチするために非常に有効です!
ブレークポイントがトリガーされると、Android Studioは実行を一時停止し、変数(結果)を検査したり、コードの実行をステップ実行してロジックの展開を確認したりすることができます。
この方法は、フロー制御や計算の微妙なバグをキャッチするために非常に有効です!
- Sentry によるリアルタイムのエラー追跡 ローカルでの開発デバッグや手動ログだけに頼るのではなく、Sentry は本番環境でのエラー追跡を自動化します。例えば、APIリクエストが失敗した場合を追跡する場合、以下のように記述します。
Sentryはエラーをキャプチャし、スタックトレース、ブレッドクラム(エラーに至るまでのイベント)、環境の詳細を含む詳細なレポートを生成します。このコンテキストは、アプリが稼動した後に問題を診断し解決するために非常に貴重です。Sentryはまた、スタックトレースやパンくずのような追加コンテキストでLogcatログからエラーレポートをキャプチャし、強化することによって、Logcatと統合することができます。
さて、基本をカバーしたところで、Androidアプリケーションで非常に頻繁かつ一般的な問題であるANRに取り組む方法など、Androidをデバッグするための他の戦略について、さらに深く掘り下げてみましょう。
AndroidでANRを検出する
ANR(Application Not Responding)は、アプリのメインスレッドが長時間ブロックされ、システムがエラーダイアログを表示することで発生します。
最も一般的なものは、Input Dispatching Timeoutで、ユーザーが操作した後アプリのメインスレッドが5秒以上応答しない場合に発生します。これはユーザー体験に大きく悪影響を与え、Google Playストアでアプリのダウングレードにつながる可能性があります。
AndroidでANRを検出する方法はいくつかあり、それぞれに長所と短所があります。トレードオフの関係性にあります。以下で確認していきましょう。
- ウォッチドッグスレッド: メインスレッドに定期的にタスクを送信します。スレッドが設定した時間(通常は5秒)以内に応答しなかった場合、ANRが発生したと見なされます。この方法はリアルタイムで検出できますが、ユーザーとの対話がない場合は誤検出してしまうリスクがあります。
- ネイティブシグナルハンドラ: ネイティブレベルでシグナルハンドラをインストールすることで、システムによって発生したANRをリッスンすることができます。この方法はネイティブのシグナルを捕捉できますが、バックグラウンドのANRをカバーできず、提供されるスレッド情報も限られてしまいます。
- アプリケーション終了情報API(Android 11以上): この新しいAndroid APIは、完全なスタックトレース、スレッド情報、デッドロック検出など、ANRの最も正確な検出を提供します。フォアグラウンドANRとバックグラウンドANRを区別しますが、Android 11以上でのみ利用可能です。
ANRの検出方法はまだ半分に過ぎません。
AndroidのANRのデバッグについて、Sentryを使用して説明しましょう。
SentryによるANRのデバッグ
ANR が発生すると、Sentry は自動的に発生時のアプリの状態、デバイスのパフォーマンス(メモリやバッテリー容量など)、および完全なスレッドダンプを含む重要な詳細を瞬時にキャプチャします。
実際のシナリオを挙げて、確認していきましょう。
スレッドロッキングの問題でアプリが「Input Dispatching Timeout」を出力したとします。Sentryを使えば、ブロックを引き起こしている正確なスレッドを示す詳細なレポートを受け取ることができます。同期化の問題なのか、何か他のものがメインスレッドをロックしているのかを突き止めることができます。
パフォーマンスプロファイリングを使ってANRを解決する
Sentryのプロファイリングツールは、アプリの実行の定期的なスナップショットを取ることで、デバッグ機能の別のレイヤーを追加します。
これらのスナップショットはフレームグラフで可視化され、実行に最も時間がかかっている関数をハイライトします。UIスレッドの関数が長く実行されている場合、これがANRの根本的な原因であると考えられます。このデータを使って、集中的なタスクをメインスレッドから移動するようにコードを迅速にリファクタリングすることが可能になります。
Sentryのリアルタイムエラー追跡と高度なプロファイリングを統合することで、より簡単にANRを検出し、デバッグし、防止することができます。このトピックについては、こちらのワークショップで詳しく説明しています。ぜひご覧ください。
Sentry for Androidのセットアップと最大限の活用方法
Senty for Androidを立ち上げて実行するのは、JavaでコーディングしていてもKotlinのような言語でコーディングしていても、信じられないほど簡単です!
ProGuardを使うか、ウェイン・ザリンスキー(詳しくはディズニーをご覧ください)の縮小光線でアプリのサイズを小さくしたとしても、これはかなり無視できるものです。
この標準的な実装は、エラーが発生したときに瞬時に記録し、発生した場所のスタックトレースを表示し、バッテリー残量、使用しているAndroidのバージョン、ハードウェア、電話の向き、利用可能なディスク容量、デバイスがroot化されているかどうかなど、その時点でのデバイスに関する状態を出力します。エラー監視はたったこれだけ。完了です。
しかしSentryには、エラーレポートを強化し、チームが混乱するかもしれない問題を解析しやすくするための機能が他にもいくつかあります。これらの機能は、利用するのに少し手間がかかりますが、その努力をする価値は十分にあります。
パンくずの追加
エラーが発生するまでにユーザーが何をしていたのか、詳細な情報が手元にあればあるほど、エラーの解析と修正するまでの時間を短縮できます。
パンくずを使うことで、いつ、どのように問題が発生したかについて、ユーザーの(通常は不完全な)説明に頼る必要がなくなります。
ちなみに、アプリケーションのライフサイクルのどの時点でも、パンくずを記録することができます。最新の100個のパンくずがメモリに保存され、発生したエラーと一緒にSentryに送信されます。
あなたが開発しているアプリが『ソーシャル写真共有アプリ』だとします。写真のアップロード、フィルターの選択、フィルターの変更、各種編集ツールの選択、編集の完了、場所の追加、タグ付け、写真の共有、プロセスのバックアウト、下書きの保存など、ユーザーが行う主要なアクションごとにパンくずを記録したいとします。
パンくずの記録は、以下の簡単なコードで実装可能です。
エラーにユーザーを関連付ける
誰がエラーに遭遇したかを Sentry に伝えるための機能です。
これは、アプリのユーザー名、メールアドレス、IPなど、エラーとユーザーを一意に結びつけるためのものです。
パンくずと同様に、これはローカルにメモリに保存され、発生したエラーと共に送信されます。
これには2つの価値があります。
- 開発者側からは、そのユーザーが遭遇したバグの数や、バグが影響を与えたユニークユーザーの数を正確に把握することができます。VIPユーザがいる場合は、そのユーザが遭遇した問題に特別な注意を払うことで、一般的なエラーの場合よりも迅速に対処することができます。
- 顧客体験の面では、ユーザーが問題について連絡してきた場合、そのユーザーを見つけ、彼らが話していることをすぐに確認することができるため、ユーザーに説明させる必要がなくなります。Sentryのコミュニティが作成したZendesk統合のようなツールを使えば、サポートシステム内でこの情報にアクセスすることも可能です。
あなたがユーザー名をどのように管理しているか、私たちが正しく推測することはまずないので、これはあなたのアプリに自動的に追加できるものではありません。しかし、これも簡単に実装できます。その方法は以下の通りです。
ユーザーは、id、username、email、ipのうちの1つによってのみ記述される必要があります。
タグとデータ・フィールドを増やしてカスタム・コンテキストを追加する
この記事の冒頭で述べたように、クラッシュやエラーが発生するたびに、基本的なデバイス情報(バッテリー残量やAndroidのバージョンなど)を取得します。
しかし、問題を引き起こしている原因を突き止めるのに役立つ、あなたのアプリ特有の情報が他にもあるかもしれません。
もしかしたら、スマートフォンの動作速度が時速88マイルに達するとエラーが発生することに気づくかもしれません。
この場合、問題はユーザーのフラックスキャパシターによる干渉かもしれません。
あなたのアプリのユーザーはどの契約プランを利用していますか?
もしかしたら、特定のエラーが発生するのは、超高額のエンタープライズプランに加入している人だけかもしれません。
エラーが全員に影響するような状況でも、このデータを使って、どのユーザーに最初に謝罪や手動での修正を連絡すべきかを判断できる可能性があります。
コンテキストやタグを追加するのは、以下のコードだけで実現可能です。
Androidにプロファイリングを追加する
SentryをAndroidアプリに統合するには、Sentry Gradleプラグインをプロジェクトに追加することから始めます。次のコマンドを使用して、Sentry の CLI ウィザードをインストールします。
ウィザードは、プロジェクトにSentryを自動的にセットアップし、高度なデバッグのためのパフォーマンス・モニタリングを含みます。プロファイリングを有効にするには、アプリで SentryOptions を設定してプロファイリング データを取得します。
options.profilesSampleRate = 1.0 // 全てのセッションでプロファイリングを有効にする }.
プロファイリングを有効にすると、Sentryはパフォーマンスの詳細なインサイトを取得し、ボトルネックの特定に役立つフレームグラフで可視化します。遅い関数やUIフレームの問題を監視し、アプリのパフォーマンスを効果的に最適化します。
Androidのセッション・リプレイの追加
SentryでAndroidセッション・リプレイをセットアップするには、まずSentry SDKの最新バージョンを使用していることを確認してください。
次に、Sentryオプションを設定して、プロジェクトでセッション・リプレイを有効にします。初期化するには以下のコードを追加します。
options.enableSessionTracking = true options.sessionTrackingIntervalMillis = 30000 // 必要に応じて調整 options.replaysSessionSampleRate = 1.0 // リプレイ用にセッションの100%をキャプチャする }.
これにより、ユーザーインタラクションとセッションデータが自動的にキャプチャされ、実際のユーザーセッションからの問題の再生とデバッグが容易になります。
SentryによるAndroidデバッグの改善
Android でのクラッシュやエラーのデバッグの最大の課題の 1 つは、アプリが置かれる状況や、デバイスの様々な状況下によって引き起こされます。
ANRの検出と防止に加えて、いくつかの基本的なことをうまく活用すれば、成功への準備が整います。
Sentryのパンくず、タグ、プロファイリング、セッションリプレイをさらに活用することで、リアルタイムでデータを集約し、以前よりも早くバグを修正できるだけでなく、最も大切なユーザーに喜ばれる機能を構築する方法について、積極的で幅広い視野を得ることができます。ぜひSentryを最大限、ご活用ください。
IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談はこちらのフォームからお気軽にお問い合わせください。