EDIT MODE

モバイルアプリ開発に関することを書いています

一人開発でつまづいたときの処方せん for DroidKaigi 2020

はじめに

この記事は、やむなく中止となってしまったDroidKaigi 2020で発表予定だった、「一人開発でつまづいたときの処方箋」の内容をブログ用に書き下ろしたものになります。コロナ禍のこの半年、公私でいろいろなことがありすぎて全然気持ちが前を向かず、記事を書くのにめちゃくちゃ時間が掛かってしまいました。なんとか書き終えて良かったです。

droidkaigi.jp

なおDroidKaigiでは40分で発表する内容のため少し長文となりますが、もし興味を持っていただけたら最後まで読んでいただけると嬉しいです。 サッと眺めてみたい方は、以下のSpeaker Deckにアップしてあるスライドを見ていただく方がいいかもしれません。

一人開発でつまづいたときの処方箋 - Speaker Deck

目次

  • 自己紹介
  • 発表内容
    1. ビルドが通らないときの処方せん
    2. アプリがクラッシュするときの処方せん
    3. アプリの評価が上がらないときの処方せん
  • まとめ

自己紹介

株式会社ストライプデパートメントという会社で、smarbyというAndroidアプリの開発を担当しています。ただし8月のサービス終了に伴い退職予定です。今後は業務委託で関わっていたYper株式会社さんに正式にジョインし、OKIPPAというサービスのReactNativeアプリの開発に携わる予定です。

発表内容

Speaker Deckにアップしている資料および本記事の内容は、以下の環境で確認した内容になります。

  • Android Studio 3.6.1
  • Play Console(2020年7月時点)

1. ビルドが通らないときの処方せん

f:id:androhi:20200603141336j:plain

ビルドが通らないと一口に言っても様々な理由があることは、少しでもプログラミングを経験したことがある人なら周知の事実かと思います。 ここでは、書いたコードを正しく(=ビルドが通るように)書くことが出来ているはずにも関わらず、ビルドが通らない場合にフォーカスしてみました。 また、特にAndroidアプリ開発という枠の中でビルドエラーに遭遇したときに、ぜひこれを試してみて欲しいと筆者が思ったものに絞って、紹介していきたいと思います。

Import文を正しく記述する

基本的にJavaおよびKotlinでクラスを呼び出す際には、import文を記述します。(完全修飾名で呼べば必要ありませんが、長くて可読性が悪いので滅多にやりませんよね。) このimport文が正しくないと、未定義のクラスとなってしまいビルドに失敗します。

コードを書いている最中は、正しくimport文が記述されていることがほとんどだと思いますが、クラス名を変更したりファイルのマージ作業等で、意図せず正しくなくなってしまうケースもあります。

Android Studioには、import文の記述を自動で行うようにしてくれる設定があります。これを設定することで、前述のような意図しないimport文の変更を防ぎつつ、普段のコーディングも快適にすることが出来るようになります。

f:id:androhi:20200603150419j:plain

Auto Importの項目で行える設定には2種類あります。「Add unambiguous imports on the fly」と「Optimize imports on the fly」です。これらを有効にすることで、何が出来るようになるか見てみましょう。

Add unambiguous imports on the fly

この設定を有効にすることで、次のような挙動の変化があります。

新しいクラス等を入力した際に、最適なimport文を自動で追加してくれます。ただし複数の同名クラスが存在する場合は、候補のリストが表示されるのでimportしたいものを指定する必要があります。

Optimize imports on the fly

この設定を有効にすることで、ファイル内全体のimport文を最適化してくれます。

具体的には2つの挙動があります。1つ目は不要なimport文の削除です。ファイル内で使用されていないクラス等のimport文があった場合に、自動で削除してくれるようになります。2つ目はimport文の記述位置の整理です。この整理を行うことで、import文をパッケージ名とクラス名でアルファベット順に並び替えてくれます。普段はあまりimport文を見ることは少ないかもしれませんが、「なんかコードのサジェストがおかしいなと思ったら、全然違うパッケージのクラスを使ってた」などが起きたときに、整理されたimport文だと該当箇所を発見しやすかったりします。

また、この設定は手動で行うことも可能で、メニューから『Code > Optimize Imports』を選択するか、ショートカット『Cntl+Opt+O』で実行することが出来ます。

こちらの設定はファイル内のimport文全てを一括で最適化してくれるため、とても便利な反面望まない変更が発生する可能性もあります。例えば、ちょっとコードを読むために開いたファイルで、import文がアルファベット順になっていなかった場合に自動で整理されてしまい、本来の修正と直接関係の無い差分が発生してしまうことになります。もしこのようなケースが多い場合は手動で行うようにするなど、設定のON/OFFをうまく使い分ける必要があります。

ProjectのCleanとBuild

新機能の開発などをgitのブランチを切って作業している場合など、ブランチ間の差分がとても大きくなってしまうケースがあるかと思います。 そのような状況で、ブランチを切り替えてからビルドしようとすると、大量のビルドエラーが出てしまうことがあります。 その場合いくつか考えられる原因の1つに、ライブラリによって自動生成されるソースコードが関係している可能性もあります。

例えばメジャーなものだと、GlideやDaggerなどといったライブラリは、Annotation Processingによってビルド時にソースコードを生成します。 @Component とかアットマーク付きで書く部分ですね。

f:id:androhi:20200702143228j:plain

Androidアプリのプロジェクトでは、プロジェクト直下の『build/generated/source』フォルダに自動生成されたソースコードが格納されます。(Javaだとaptフォルダ、kotlinだとkaptフォルダです。)

プロジェクトをGitで管理している場合、このbuildフォルダは管理対象外とするのが一般的です。APKファイルなどと同様に、ビルド成果物なので差分を管理する必要がないためです。そのためブランチを切り替えたとき、このbuildフォルダは切り替え前のものがそのまま残ることになります。この状態のままビルドを行い、自分で書いたコードと自動生成されたコードとで不整合が起きてしまった場合に、シンボルエラー等が発生してしまう可能性があります。

解決方法としては、これらのビルド実行によって生成されるファイル達を、一度全て削除してあげることで解決出来ます。メニューから『Build > Clean Project』を行うか『Build > Rebuild Project』を行い再ビルドすることで、現状のソースコードに合致した自動生成コードにすることが出来ます。

f:id:androhi:20200702152835j:plain

キャッシュクリア

まれに何をどうやっても解決出来ないビルドエラーが、発生してしまうこともあります。そんな時は、一度ビルドキャッシュのクリアを試してみるといいかもしれません。

f:id:androhi:20200702160557j:plain

例えばAndroid Gradle Pluginは、上図のようなキャッシュファイルを生成しています。こういったビルドキャッシュを、一括でクリアするには以下のコマンドを実行します。

./gradlew cleanBuildCache

前述のビルドキャッシュ・クリアでも解決出来ないときに試したいのが、Android Studio全体のキャッシュクリアです。メニューから『File > Invalidate Caches/Restart...』を選択し、表示されるダイアログから『Invalidate and Restart』をクリックすると実行出来ます。(他にも再起動だけやキャッシュクリアだけも行えます。)

ただし下図のように、キャッシュクリアしてしまうことによる弊害も多いので、あまり頻繁にはやらない方が良い機能でもあります。

f:id:androhi:20200702162257j:plain

2. アプリがクラッシュするときの処方せん

f:id:androhi:20200703161056j:plain

ビルドが無事に通り、アプリを動かすことに成功したといっても安心出来ないですよね。意図した通りに動かないならまだしも、突然アプリがクラッシュして強制終了してしまうのは本当に悲しいことですし、リリース後に起きたとしたらアプリの評価にもダメージがあります。

Stack Traceを分解して読み解く

クラッシュの原因を探るために最も信頼出来る情報は、Stack Traceと呼ばれるエラーログです。なぜならStack Traceには、プログラムのどこでどのようなエラーが発生したかの詳細情報が載っているためです。

f:id:androhi:20200703171338j:plain

ところがStack Traceって慣れないうちは、ちょっと抵抗感あるというか何を見るべきなのか分かりづらいですよね。赤字でいかにもって感じですし...。ただ落ち着いて少しずつ見ていけば、そんなに難しいものでは無いよというのをここではお伝えしていければと思います。

f:id:androhi:20200703172112j:plain

Androidアプリがクラッシュする際には、多くのケースで例外処理(予期できなかった処理)が発生しています。上図だと java.lang.RuntimeException の部分です。 ここに大まかな事象が書かれているので、まず始めに読むべき箇所かと思います。

試しに上図の場合を読んでみると、「RegisterActivityというActivityがスタート出来ない。nullオブジェクトの参照でString.lentgh()メソッドを呼び出そうとしました。」と書かれていそうですね。

f:id:androhi:20200703173505j:plain

今回の例では既に分かってしまいましたが、例外が発生した原因は何かというのは「Caused by:(〜のせいで)」で始まるログに書かれています。つまり「nullを参照しているオブジェクトが、String.length()メソッドを呼んでいる」ことが、今回の原因ということみたいですね。

f:id:androhi:20200703174005j:plain

原因が分かったので、次はどこでその例外が発生してしまっているか、場所を突き止めないといけません。そのため上図にあるように、ログのパッケージ名に着目します。自分が開発しているアプリのパッケージ名を探しましょう。

f:id:androhi:20200707114206j:plain

上図の箇所に注目すると、「RegisterActivity.javaの105行目でStringクラスのlengthメソッドを呼んでいるコードでクラッシュしている」ことが、分かりました。以上のことから、Stack Traceにクラッシュの原因と発生場所が記録されていることが確認出来たかと思います。

もちろん例外の種類はたくさんありますし、Stack Traceが示すメッセージだけでは解決出来ないケースもありますが、まずはStack Traceをしっかりと読むことがクラッシュ対応の第一歩になるはずです。

類似ケースのIssueを探す

Stack Traceから自分なりにコードを修正してみたが、どうにもクラッシュが直らなかったりするケースもあります。そんな時はエラーメッセージで検索すると、いろいろな記事やQAサイトなどが見つかると思います。それらに書かれている対応で問題が解決すれば良いのですが、それでもなお解決出来ないことも多々あります。

なぜなら、その問題の原因が自分で書いたコードではなく、プラットフォームや使用しているライブラリ側にあるケースもあるためです。

f:id:androhi:20200707163645j:plain

Androidアプリ開発を行っていく中で、そのようなプラットフォームやライブラリの問題に遭遇することがあれば、類似の問題が報告されていないかを上図のような場所で探してみると、修正版がリリースされていることや暫定の対処方法が提案されていたりすることが分かり、解決への道筋が見えるかもしれません。

基本的に英語でやり取りされているので敬遠しちゃう人もいるかと思いますが、問題の解決だけでなくOSSへの関わり方の雰囲気も分かって一石二鳥ですので、Google翻訳や今だとDeepL等を使って頑張って触れてみる方がいいと思います。

3. アプリの評価が上がらないときの処方せん

f:id:androhi:20200707171448j:plain

一生懸命に不具合を直し機能を追加しても、アプリの評価が上がらなくて悩むこともあると思います。Play Store上には、それこそ星の数ほどアプリがありますから、あなたのアプリは他のたくさんのアプリと比べられながら評価されているため、どうすれば評価が上がるのかの答えも様々です。

公開アプリを管理するPlay Consoleでは、そういった他のアプリと比べてあなたのアプリにどのような課題があるかを、視覚化してくれる機能が充実しています。それらの指標を元にアプリを改善していけば、アプリ評価の向上に繋がっていくはずです。

Android Vitalsでアプリのクオリティをチェック

パフォーマンスと安定性は、Google Play での良好な評価に直結します。問題を修正し、動作不良を防止すると、ユーザー エクスペリエンスの向上や評価のアップ、アプリをインストールしたユーザーの定着率の増加につながります。

Google Play  |  Android Developers より引用

Developersサイトでは、上記のようにアプリの評価をアップするためには、パフォーマンスと安定性を何より重視すべきと示しています。つまり サクサク動いて落ちないアプリ が良いアプリの条件というわけです。PlayConsoleには、こうしたアプリのパフォーマンスや安定性に関する指標を細かく表示してくれる、Android Vitalsという機能が備わっています。

f:id:androhi:20200709151554j:plain

Android端末のプライバシー設定の中には、上図のような「使用状況と診断情報」という項目が存在します。この設定が有効になっていると、アプリの安定性やUIのレンダリング時間などのデータを収集し、Googleへ自動送信してくれるようになります。(厳密にはアプリだけでなく、システムや端末自体のデータも収集しているようです。)

様々なデータがAndroid Vitals上で確認出来ますが、特にANR発生率とクラッシュ発生率は常に注視するべき指標かと思います。ANRはApplication Not Responding(=アプリの反応が無い状態)の略ですので、クラッシュと同様にアプリの安定性に非常にマイナスです。 この2点がどの程度のクオリティなのかを、このAndroid Vitailsで確認するべきです。

f:id:androhi:20200709153711j:plain

アプリのパフォーマンスを計測するには、Firebase Crashlytics / Performance Monitoringや他のツールを使っても可能ですが、Android Vitalsには上図のように他の類似アプリとの相対値を示してくれる、というメリットがあります。例えばこの相対値を参考に、ANR発生率とクラッシュ発生率のどちらを優先的に対処するか、といった判断の一助になると思います。

これはAndroid Vitalsが、前述した端末から自動収集しているデータを元にしているためで、他のツールに比べて強みなのではないかなと思います。

ユーザーの日常の体験をチェック

アプリの評価を上げユーザー数を増やすには、競合となるアプリやユーザーからのレビューを定期的にチェックすることで、ユーザーの動向の変化にアンテナを張っておくことも重要ではないでしょうか。

f:id:androhi:20200709163006j:plain

Android Vitalsの説明で出てきた類似アプリは、いくつかのアプリのグループになっており、上図のようにカスタマイズすることが可能です。特にパフォーマンスの比較に用いるグループと、評価の比較に用いるグループとを別で設定出来るのは便利です。

Android Vitals用は『Android Vitals -> 概要(もしくはANR発生率/クラッシュ発生率の詳細を表示) -> 類似アプリのグループを編集』から、評価用は『ユーザーフィードバック -> 評価 -> 類似アプリのグループを編集』から、それぞれ設定出来ます。

f:id:androhi:20200709164652j:plain

ユーザーフィードバックのメニューには、レビュー解析という項目があります。文字通り集まったアプリのレビューを元に、どのような内容が評価に影響を与えているのかを分析してくれた内容を、表示してくれる機能です。

上図のように、レビュー中の頻出キーワードをトピックとして集計し、トピックごとにいろいろな指標を示してくれています。これを見ると自分でレビューの集計などしてなくても、レビューの傾向を掴むことに役立てることが出来そうです。

実はここでも前述の類似アプリのグループを活用した「ベンチマーク」という、レビュー解析機能が存在するのですが、2020年7月時点では英語でのレビューしか対応していません。これが見られるようになると、レビューの傾向も競合アプリと比較することが出来るようになるので、評価改善の施策を練る助けになりそうな気がしています。

まとめ

今回紹介した内容は、Androidアプリ開発を行う上でのTipsのごく一部ですが、ここからさらに枝葉を広げていけるようにいろいろな観点で紹介出来るよう心がけました。 もし今まで敬遠していたり触っていなかった部分がありましたら、ぜひ手を動かしてみて頂けると幸いです。

以下、この記事で触れた内容のまとめです。

ビルドが通らないときの処方せん

  • Auto Importの設定を活用するし、参照エラー等を起きにくくする
  • ProjectのClean & Buildで、自動生成されるコード等を再生成する
  • 解決が難しいビルドエラーでは、いろいろなキャッシュのクリアを試す

アプリがクラッシュするときの処方せん

  • Stack Traceの読み方に慣れ、エラーメッセージから手がかりを得る
  • 類似ケースのIssueを探し、解決の糸口を探る

アプリの評価が上がらないときの処方せん

  • Android Vitalsを活用して、アプリの改善点を探す
  • 類似アプリのグループを活用して、競合アプリと比較する

最後まで読んでくださって、ありがとうございます!来年は無事にDroidKaigiが開催され、またたくさんのAndroidアプリ開発者の方に会えることを願っています!!!