# 【Android】Hyperion-Crashのようなクラッシュ時に立ち上がるアプリを作ってみた
# 今回やったこと
↓ このようなアプリを作りました。
ボタンを押すと意図的にアプリをクラッシュさせ、そのタイミングでForegroundServiceを起動させて、ログをストレージに書き込むといったことをしています。
この記事と似たような内容は GitHub の README.md にも書いてあります。
そっちを見てもらってもいいかも。
なお、タイトルにもありますが、このアプリは Hyperion-Crash を参考にしています。
マジリスペクト!
# アプリクラッシュの検出方法
アプリがクラッシュしたタイミングを知るには独自の Thread.UncaughtExceptionHandler
をセットしてやればいいみたいです。
↓ こんな感じのコードを Application#onCreate()
で呼んでやっています。
internal object CrashReporter {
fun setup(context: Context) {
val newHandler = when (val existingHandler = Thread.getDefaultUncaughtExceptionHandler()) {
null -> Handler(context)
else -> Wrapper(existingHandler, Handler(context))
}
Thread.setDefaultUncaughtExceptionHandler(newHandler)
}
private class Handler(private val context: Context) : Thread.UncaughtExceptionHandler {
override fun uncaughtException(t: Thread, e: Throwable) {
CrashReporterService.start(this.context, e)
}
}
private class Wrapper(
private val existing: Thread.UncaughtExceptionHandler,
private val handler: Handler
) : Thread.UncaughtExceptionHandler {
override fun uncaughtException(t: Thread, e: Throwable) {
this.handler.uncaughtException(t, e)
this.existing.uncaughtException(t, e)
}
}
}
Hyperion-Crashでは onApplicationCreated()
で同じようなコードを呼んでいるのがわかります。
参考: https://github.com/willowtreeapps/Hyperion-Android/blob/develop/hyperion-crash/src/main/java/com/willowtreeapps/hyperion/crash/CrashPlugin.java
私のSuicideReporterでは CrashReporterService
を起動させていますが、Hyperion-Crashでは CrashActivity
を起動させています。 ↓
@Override
public void uncaughtException(Thread t, Throwable e) {
CrashActivity.start(context, reportFactory.createReport(e));
}
# process属性について
ここで起動させるActivity・Serviceなんですが、AndroidManifestに android:process=":crash"
が記述されています。
このようなコロン始まりのプロセス名を指定してやった場合、別のプロセスとして立ち上がるみたいです。
試しにこのManifestのServiceの android:process
を
<service
android:name=".reporter.CrashReporterService"
android:process=":crash" />
↓ のように指定せずに実行してみると、
<service android:name=".reporter.CrashReporterService" />
クラッシュさせてもServiceが立ち上がってきませんでした。
# アプリ内で使えるストレージのディレクトリについて
ログの保存場所は ↓ のように取得しています。
File(context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS), fileName)
Context#getExternalFilesDir()
で取得できるディレクトリ下に保存する場合はパーミッションがいらないみたいですね。
(知らなかったよ 😿)
外部ストレージにファイルを保存する | Android デベロッパー | Android Developers
私の環境では ↓ のようなパスが取得できました。
/storage/emulated/0/Android/data/net.aridai.suicidereporter/files/Documents/
このディレクトリの中身をPCにコピーするにはターミナルで以下を実行します。
adb pull /storage/emulated/0/Android/data/net.aridai.suicidereporter/files/Documents/ ~/Documents/作業フォルダ/
すると作業フォルダに中身がコピーされます。
(ただし、これはDebugビルドされているときしかできないかも...?)
眠たいので寝ます。
おやすも。