package com.example;
import android.app.Application;
import android.os.Build;
import android.os.StrictMode;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.core.CrashlyticsCore;
import com.example.tools.dagger.components.ApplicationComponent;
import com.example.tools.dagger.components.DaggerApplicationComponent;
import com.example.tools.dagger.modules.ApplicationModule;
import com.example.tools.stetho.StethoTool;
import com.example.tools.timber.CrashlyticsTree;
import com.example.util.TestUtil;
import io.fabric.sdk.android.Fabric;
import rx.plugins.RxJavaHooks;
import timber.log.Timber;
import javax.inject.Inject;
public class App extends Application {
private static ApplicationComponent applicationComponent;
@Inject StethoTool stethoTool;
@Override
public void onCreate() {
super.onCreate();
initDagger();
initTimber();
initFabric();
initStetho();
initStrictMode();
enableBetterStackTracesForRx();
}
private void initDagger() {
applicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
applicationComponent.inject(this);
}
/**
* Setup Timber. We only enable the timber logcat tree in debug builds. Release builds tend to not have have logs:
* a) As logs are not accessible to developers.
* b) For security reasons.
* c) For performance reasons.
*
* Having said that, we plant a second tree that takes {@link Timber#wtf} calls and posts them to crashlytics (but not logcat).
*/
private void initTimber() {
if (BuildConfig.DEBUG) {
Timber.plant(new Timber.DebugTree());
} else {
Timber.plant(new CrashlyticsTree());
}
}
/**
* Setup Fabric. We also set the build time and sha key so that we can easily reproduce bug reports.
*
* Note 1: To send an exception to crashlytics use {@link Crashlytics#logException(Throwable)}. It will send a non-fatal exception.
* This is reported separately in the crashlytics dashboard. See
* https://docs.fabric.io/android/crashlytics/caught-exceptions.html?caught%20exceptions#caught-exceptions for more details.
*
* Note 2: To log a statement in Crashlytics use {@link Crashlytics#log(String)}. This log statement will appear when clicking on a
* specific crash report. For example if you have a crash that occurred 10 times, one would need to click through all 10 instances of
* that crash to see the individual log statements for every instance of this crash.
* See https://docs.fabric.io/android/crashlytics/enhanced-reports.html for more info.
*
* Note 3: To log a key-value pair in Crashlytics use {@link Crashlytics#setString(String, String)}. Same concept as logging a
* statement described in Note 2.
*/
private void initFabric() {
CrashlyticsCore crashlyticsCore = new CrashlyticsCore.Builder()
.disabled("debug".equals(BuildConfig.BUILD_TYPE)) // 'debug' builds not using fabric, 'qa' and 'release' do.
.build();
Crashlytics crashlytics = new Crashlytics.Builder()
.core(crashlyticsCore)
.build();
Answers answers = new Answers();
final Fabric fabric = new Fabric.Builder(getApplicationContext())
.kits(crashlytics, answers)
.debuggable(BuildConfig.DEBUG) // 'debug' and 'qa' build types have extra log statements, 'release' build type doesn't.
.build();
Fabric.with(fabric);
Crashlytics.setString("GIT_SHA_KEY", BuildConfig.GIT_SHA);
Crashlytics.setString("BUILD_TIME", BuildConfig.BUILD_TIME);
}
private void initStetho() {
stethoTool.init();
}
private void initStrictMode() {
if (BuildConfig.DEBUG && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && !TestUtil.areEspressoTestsRunning()) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectResourceMismatches()
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectActivityLeaks()
.detectCleartextNetwork()
.detectFileUriExposure()
.detectLeakedClosableObjects()
.detectLeakedRegistrationObjects()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeathOnCleartextNetwork()
.penaltyDeathOnFileUriExposure()
.build());
}
}
/**
* From https://github.com/ReactiveX/RxJava/wiki/Plugins :
* In addition, the RxJavaHooks offers the so-called assembly tracking feature. This shims a custom Observable, Single and Completable
* into their chains which captures the current stacktrace when those operators were instantiated (assembly-time). Whenever an error is
* signalled via onError, these middle components attach this assembly-time stacktraces as last causes of that exception. This may help
* locating the problematic sequence in a codebase where there are too many similar flows and the plain exception itself doesn't tell
* which one failed in your codebase.
*/
private void enableBetterStackTracesForRx() {
if (BuildConfig.DEBUG) {
RxJavaHooks.enableAssemblyTracking();
}
}
public static ApplicationComponent getApplicationComponent() {
return applicationComponent;
}
}