Androidアプリにおけるエラー時のユーザーフィードバックについて

こんにちは、フロントエンドエンジニアの権守です。

プログラミングをしていると頭を悩まされるものの1つにエラーハンドリングがあると思います。シンプルにできた実装に手を入れる必要が生じるなど、正直目を逸らしたくなることもあります。ですが、Androidアプリ開発を通して改めて考える機会があったので、そこで得られた知見を紹介しようと思います。 本記事では特に、エラー時にユーザーへどのようなフィードバックを返すかという点に注目して、それについての考えと取り入れている仕組みを紹介します。

f:id:vasilyjp:20180222174852j:plain

Androidにおけるフィードバックのデザイン

まず、エラー時のフィードバックにおいて、どのようなコンポーネントを使い分けているかについて説明します。 VASILYではAndroidアプリを開発する際にはMaterial Design Guidelinesにできるだけ準拠するように心がけています。エラー時のフィードバックについても例外ではありません。ガイドラインでは、簡潔なフィードバックを表示する際にはSnackbarを使うように書かれています。そのため、エラーメッセージは基本的にSnackbarを用いて表示しています。一方で、システムからのメッセージはToastを使うように書かれているので、カメラやストレージへのアクセス権限がないときのエラーはToastを用いて表示するようにしています。

f:id:vasilyjp:20180222174814p:plain:w300 f:id:vasilyjp:20180222174839p:plain:w300

また、Activityの初期化時にエラーが起こった場合には、エラー表示用のレイアウトに切り替えて再読込を促すようにしています。

f:id:vasilyjp:20180222174843p:plain:w300

APIリクエスト時におけるエラーのフィードバック

表示するデータの多くをWeb APIを利用して取得するアプリでは、APIリクエスト時のエラーをどのように扱うかが特に重要です。そのため、ここではAPIリクエスト時のエラーに着目して、どのような問題があるかとそれを解決するために導入した仕組みについて説明します。

エラーメッセージの管理

同じサービスをiOSとAndroidなど複数のプラットフォームで開発する際に、エラーメッセージをどのように管理するかは悩ましい問題の1つです。よくある解決法としてはAPI側とアプリ側で共通のエラーコードを持ち、それを元にアプリ側でエラーメッセージの出し分けをするものがあります。 一方、VASILYではAPIに起因するエラーメッセージはAPI側で管理するようにしています。具体的には、更新リクエストやエラー時のレスポンスのJSONには、フィードバックに利用するメッセージを載せるようにしています。

{
  "message":"プロフィール画像を保存しました",
  "code":200
}
{
  "message":"プロフィール画像の保存に失敗しました",
  "code":400
}

これによりAPI側に起因するエラー時にはプラットフォームをまたいで同じエラーメッセージを表示することができます。

アプリ実装時の問題点

しかし、このアプローチが有効なのは、あくまでAPIのアプリケーションサーバー(Rails等)でのエラー発生時に限ります。なぜなら、アプリからAPIへリクエストを行った場合、アプリケーションサーバーへ到達する間に様々なエラーが起こり得るからです。そして、それらはもちろん上記のJSONフォーマットに沿ったものではありません。 例えば、Webサーバーの不調により、アプリケーションサーバーまで到達せずにエラーステータスのみが返ってくることが考えられます。他にも、端末がそもそもネットワークに接続されていない場合には、OS側からのExceptionとして返ってきます。 これらの様なケースを考慮せずに実装してしまうと、ライブラリやミドルウェアなどが返したエラーメッセージをそのままユーザーに表示してしまうといった事態に陥ります。その結果、ユーザに不信感を与えるだけでなくセキュリティ的に問題を起こす可能性もあります。

ErrorFeedbackクラスの導入

そこで、ErrorFeedbackという以下に示すようなクラスを実装し、エラーメッセージを扱いやすくしました。

*サンプルプロジェクト全体はこちらから見れます。

実装はシンプルで、受け取ったThrowableを元に対応するErrorFeedbackを継承したクラスのオブジェクトを返すというものです。 サンプルでは対応するExceptionを少ししか書いていませんが、必要に応じて追加していただければ様々なライブラリに対応することもそれほど難しくないと思います。また、パースするJSONのフォーマットを別のクラスに変えることで、他のAPIに対応させることもできます。

Snackbarを表示するためのExtensionの導入

引数として直接文字列やリソースIDを渡すのではなく、ErrorFeedbackオブジェクトを渡すことでSnackbarを表示できるExtensionを実装しました。これにより、アプリケーション全体で一貫してユーザーフレンドリーなエラーメッセージを表示できるようになりました。

fun Activity.snackbar(errorFeedback: ErrorFeedback, duration: Int = Snackbar.LENGTH_LONG): Snackbar =
        Snackbar.make(findViewById(android.R.id.content), errorFeedback.getMessage(this), duration)

まとめ

Androidアプリ開発におけるエラー時のフィードバックをどのように扱っているかを紹介しました。普段、エラー時の表示まであまり気を配れていない方もこれを機に改めて考えてみてください。

最後に

VASILYでは、細部までこだわりを持って実装できるエンジニアを募集しています。少しでも興味がある方は以下のリンクからお申し込みください。