Slide 1

Slide 1 text

Hand-made CrashReport of Android Library potatotips #22 @petitviolet

Slide 2

Slide 2 text

About me • @petitviolet • Fringe81 Co., Ltd. • ޿ࠂSDKͷAndroid/iOS։ൃ • ࠷ۙ͸Scalaॻ͍ͯ·͢

Slide 3

Slide 3 text

ΫϥογϡϨϙʔτ

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

CrashReport • ΞϓϦέʔγϣϯ͕Ϋϥογϡͨ࣌͠ͷঢ়گ ΛϨϙʔτͱͯ͠ૹ৴ • ୺຤ͷछྨ • OS • ελοΫτϨʔε • etc.

Slide 6

Slide 6 text

crashlytics https://try.crashlytics.com/

Slide 7

Slide 7 text

ACRA https://github.com/ACRA/acra

Slide 8

Slide 8 text

Desire • ϥΠϒϥϦىҼͷΫϥογϡϩά΋ऩू͍ͨ͠ • ΞϓϦͷΫϥογϡϩά͸ऩू͠ͳ͍ • ͦΕ͸Crashlytics౳ʹ͓೚ͤ • ಠࣗͷσʔλ͕ཉ͍͠

Slide 9

Slide 9 text

UncaughtException • (جຊతʹ)Ϋϥογϡ͢Δͱ͖ʹඈͿྫ֎ • catch͞Εͳ͔ͬͨͷͰuncaught • ErrorͰ͸ͳ͘Exception

Slide 10

Slide 10 text

UncaughtExceptionHandler • UncaughtExceptionΛͲ͏ѻ͏͔ • σϑΥϧτͷಈ࡞͸ getDefaultUncaughtExceptionHandler • Defaultͷಈ࡞Λյ͞ͳ͍ͨΊʹอଘ

Slide 11

Slide 11 text

جຊ෦෼ 
 class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
 private static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID;
 
 private final Thread.UncaughtExceptionHandler mDefaultHandler;
 private WeakReference mContext;
 volatile private static boolean sCrashing = false;
 
 public MyUncaughtExceptionHandler(Context context) {
 mContext = new WeakReference<>(context.getApplicationContext());
 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
 }
 }

Slide 12

Slide 12 text

جຊ෦෼ 
 class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
 private static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID;
 
 private final Thread.UncaughtExceptionHandler mDefaultHandler;
 private WeakReference mContext;
 volatile private static boolean sCrashing = false;
 
 public MyUncaughtExceptionHandler(Context context) {
 mContext = new WeakReference<>(context.getApplicationContext());
 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
 }
 } UncaughtExceptionHandlerΛܧঝ

Slide 13

Slide 13 text

جຊ෦෼ 
 class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
 private static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID;
 
 private final Thread.UncaughtExceptionHandler mDefaultHandler;
 private WeakReference mContext;
 volatile private static boolean sCrashing = false;
 
 public MyUncaughtExceptionHandler(Context context) {
 mContext = new WeakReference<>(context.getApplicationContext());
 mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
 }
 } DefaultͷUncaughtExceptionHandlerΛอଘ UncaughtExceptionHandlerΛܧঝ

Slide 14

Slide 14 text

جຊ෦෼ @Override
 public void uncaughtException(final Thread thread, final Throwable ex) {
 if (sCrashing) {
 mDefaultHandler.uncaughtException(thread, ex);
 return;
 }
 sCrashing = true;
 StackTraceElement[] stackTraceElements = ex.getStackTrace();
 
 boolean inLibraryException = false;
 for (StackTraceElement stackTraceElement : stackTraceElements) {
 if (stackTraceElement.getClassName().contains(PACKAGE_NAME)) {
 inLibraryException = true;
 break;
 }
 }
 
 // ϥΠϒϥϦ಺ͰͷΫϥογϡͩͬͨ৔߹͸ϩάΛૹΔ
 if (inLibraryException) {
 try {
 sendCrashReport(ex);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 
 // ϝΠϯεϨουͩͬͨ৔߹͸ࢮ͵͔͠ແ͍
 if (thread.getId() == Looper.getMainLooper().getThread().getId() || !inLibraryException) {
 mDefaultHandler.uncaughtException(thread, ex);
 }
 }

Slide 15

Slide 15 text

@Override
 public void uncaughtException(final Thread thread, final Throwable ex) {
 if (sCrashing) {
 mDefaultHandler.uncaughtException(thread, ex);
 return;
 }
 sCrashing = true;
 StackTraceElement[] stackTraceElements = ex.getStackTrace();
 
 boolean inLibraryException = false;
 for (StackTraceElement stackTraceElement : stackTraceElements) {
 if (stackTraceElement.getClassName().contains(PACKAGE_NAME)) {
 inLibraryException = true;
 break;
 }
 } ͢ͰʹΫϥογϡͨ͠ޙͳΒࢮ͵

Slide 16

Slide 16 text

@Override
 public void uncaughtException(final Thread thread, final Throwable ex) {
 if (sCrashing) {
 mDefaultHandler.uncaughtException(thread, ex);
 return;
 }
 sCrashing = true;
 StackTraceElement[] stackTraceElements = ex.getStackTrace();
 
 boolean inLibraryException = false;
 for (StackTraceElement stackTraceElement : stackTraceElements) {
 if (stackTraceElement.getClassName().contains(PACKAGE_NAME)) {
 inLibraryException = true;
 break;
 }
 } ͢ͰʹΫϥογϡͨ͠ޙͳΒࢮ͵ Library಺ͷΫϥογϡ͔Ͳ͏͔൑ఆ

Slide 17

Slide 17 text

// ϥΠϒϥϦ಺ͰͷΫϥογϡͩͬͨ৔߹͸ϩάΛૹΔ
 if (inLibraryException) {
 try {
 sendCrashReport(ex);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 
 // ϝΠϯεϨουͩͬͨ৔߹͸ࢮ͵͔͠ແ͍
 if (thread.getId() == Looper.getMainLooper().getThread().getId() || !inLibraryException) {
 mDefaultHandler.uncaughtException(thread, ex);
 }
 }

Slide 18

Slide 18 text

// ϥΠϒϥϦ಺ͰͷΫϥογϡͩͬͨ৔߹͸ϩάΛૹΔ
 if (inLibraryException) {
 try {
 sendCrashReport(ex);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 
 // ϝΠϯεϨουͩͬͨ৔߹͸ࢮ͵͔͠ແ͍
 if (thread.getId() == Looper.getMainLooper().getThread().getId() || !inLibraryException) {
 mDefaultHandler.uncaughtException(thread, ex);
 }
 } Library಺ͷΫϥογϡͳΒϩάૹ৴

Slide 19

Slide 19 text

// ϥΠϒϥϦ಺ͰͷΫϥογϡͩͬͨ৔߹͸ϩάΛૹΔ
 if (inLibraryException) {
 try {
 sendCrashReport(ex);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 
 // ϝΠϯεϨουͩͬͨ৔߹͸ࢮ͵͔͠ແ͍
 if (thread.getId() == Looper.getMainLooper().getThread().getId() || !inLibraryException) {
 mDefaultHandler.uncaughtException(thread, ex);
 }
 } Library֎ͷΫϥογϡ͔UIεϨουͳΒࢮ͵ Library಺ͷΫϥογϡͳΒϩάૹ৴

Slide 20

Slide 20 text

جຊ෦෼ @Override
 public void uncaughtException(final Thread thread, final Throwable ex) {
 if (sCrashing) {
 mDefaultHandler.uncaughtException(thread, ex);
 return;
 }
 sCrashing = true;
 StackTraceElement[] stackTraceElements = ex.getStackTrace();
 
 boolean inLibraryException = false;
 for (StackTraceElement stackTraceElement : stackTraceElements) {
 if (stackTraceElement.getClassName().contains(PACKAGE_NAME)) {
 inLibraryException = true;
 break;
 }
 }
 
 // ϥΠϒϥϦ಺ͰͷΫϥογϡͩͬͨ৔߹͸ϩάΛૹΔ
 if (inLibraryException) {
 try {
 sendCrashReport(ex);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }
 
 // ϝΠϯεϨουͩͬͨ৔߹͸ࢮ͵͔͠ແ͍
 if (thread.getId() == Looper.getMainLooper().getThread().getId() || !inLibraryException) {
 mDefaultHandler.uncaughtException(thread, ex);
 }
 } Library಺ͷΫϥογϡ͔Ͳ͏͔൑ఆ Library಺ͷΫϥογϡͳΒϩάૹ৴ Library֎ͷΫϥογϡ͔UIεϨουͳΒࢮ͵ ͢ͰʹΫϥογϡͨ͠ޙͳΒࢮ͵

Slide 21

Slide 21 text

େࣄͳ͜ͱ • ϥΠϒϥϦ΋ΫϥογϡϩάΈͯվળ • ΞϓϦͷअຐΛ͠ͳ͍ • σϑΥϧτͷಈ࡞Λࡴ͞ͳ͍ • ϑϦʔζͤ͞ͳ͍Α͏ʹ • ແݶΫϥογϡ͠ͳ͍Α͏ʹ؅ཧ • ໘౗Ͱ΋ϑϥά؅ཧ