Save 37% off PRO during our Black Friday Sale! »

"It's an Inside Job" - Building Debug Features

"It's an Inside Job" - Building Debug Features

Droidcon Boston - April 11, 2017

DC Android - March 15, 2017

5701f31a8433a22ae736282de8d08cd6?s=128

Sam Edwards

April 11, 2017
Tweet

Transcript

  1. #droidconbos @HandstandSam “It’s an Inside Job” BUILDING DEBUG FEATURES Sam

    Edwards @HandstandSam
  2. #droidconbos @HandstandSam 1. WHAT IS A DEBUG FEATURE? 2. GRADLE

    BUILD VARIANTS 3. EXAMPLE SCENARIOS 4. OPEN SOURCE INSPIRATION 5. DON’T SHIP TO PROD OUTLINE
  3. #droidconbos @HandstandSam WHAT IS A DEBUG FEATURE?

  4. #droidconbos @HandstandSam DEBUG FEATURES • HELP YOU TEST AND DEBUG

    • DON’T SHIP TO PRODUCTION
  5. #droidconbos @HandstandSam AS DEVELOPERS, WE HAVE INSIDER ACCESS TO BUILD

    THEM
  6. #droidconbos @HandstandSam DEBUG FEATURES IN YOUR APP ENABLE YOUR TEAM

    TO EFFECTIVELY PERFORM TASKS THAT CAN’T BE AUTOMATED.
  7. #droidconbos @HandstandSam DEBUG FEATURE POSSIBILITY MATRIX

  8. #droidconbos @HandstandSam Modify Mock Monitor Capture Inspect Configurations Persistent Data

    Networking Resources Views Notifications Sensors … and more.
  9. #droidconbos @HandstandSam GRADLE BUILD VARIANTS

  10. #droidconbos @HandstandSam “main” SOURCE FOLDER

  11. #droidconbos @HandstandSam BuildConfig.java

  12. #droidconbos @HandstandSam DEFAULTS = = RELEASE.APK DEBUG.APK “main”

  13. #droidconbos @HandstandSam “debug” and “release” SOURCE FOLDERS

  14. #droidconbos @HandstandSam “debug” & “release” SOURCE FOLDERS = = RELEASE.APK

    DEBUG.APK “main” “debug” “release” +
  15. #droidconbos @HandstandSam SOURCE STRUCTURE

  16. #droidconbos @HandstandSam “debug”

  17. #droidconbos @HandstandSam “release”

  18. #droidconbos @HandstandSam GRADLE COMPILE DEPENDENCIES

  19. #droidconbos @HandstandSam GRADLE DEPENDENCIES

  20. #droidconbos @HandstandSam GRADLE DEPENDENCIES = = RELEASE.APK DEBUG.APK “compile” “debugCompile”

    “releaseCompile” +
  21. #droidconbos @HandstandSam GENERATED APKS

  22. #droidconbos @HandstandSam EXAMPLE SCENARIO

  23. #droidconbos @HandstandSam SAMPLE APP https://github.com/handstandsam/BuildingDebugFeatures

  24. #droidconbos @HandstandSam ANDROID DEV

  25. #droidconbos @HandstandSam ANDROID DEV DESIGN

  26. #droidconbos @HandstandSam ANDROID DEV DESIGN BACKEND

  27. #droidconbos @HandstandSam ANDROID DEV PRODUCT DESIGN BACKEND

  28. #droidconbos @HandstandSam ANDROID DEV TESTING PRODUCT DESIGN BACKEND

  29. #droidconbos @HandstandSam JOE: “CAN I HAVE A SPECIAL BUILD TO

    TEST A NEW SERVER ENDPOINT?” BACKEND
  30. #droidconbos @HandstandSam SURE, BUT IT’LL TAKE A FEW MINUTES.

  31. #droidconbos @HandstandSam @Provides Retrofit.Builder retrofitBuilder(OkHttpClient.Builder okHttpClientBuilder) { Retrofit.Builder builder =

    new Retrofit.Builder() .baseUrl("https://server") .addConverterFactory(MoshiConverterFactory.create(new Moshi.Builder().build())) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(okHttpClientBuilder.build()); return builder; }
  32. #droidconbos @HandstandSam @Provides Retrofit.Builder retrofitBuilder(OkHttpClient.Builder okHttpClientBuilder) { Retrofit.Builder builder =

    new Retrofit.Builder() .baseUrl("https://temp-server") .addConverterFactory(MoshiConverterFactory.create(new Moshi.Builder().build())) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(okHttpClientBuilder.build()); return builder; }
  33. #droidconbos @HandstandSam WAIT FOR GRADLE...

  34. #droidconbos @HandstandSam How many times have you hit ______ In

    and then waited for
  35. #droidconbos @HandstandSam This ISN’T the first time you’ve been asked

    for this. BACKEND BACKEND BACKEND BACKEND BACKEND TESTING TESTING TESTING TESTING ANDROID DEV
  36. #droidconbos @HandstandSam NOR THE LAST BACKEND BACKEND BACKEND BACKEND BACKEND

    TESTING TESTING TESTING TESTING ANDROID DEV BACKEND BACKEND BACKEND BACKEND BACKEND TESTING TESTING TESTING TESTING ANDROID DEV BACKEND BACKEND BACKEND BACKEND BACKEND TESTING TESTING TESTING TESTING ANDROID DEV BACKEND BACKEND BACKEND BACKEND BACKEND TESTING TESTING TESTING TESTING ANDROID DEV
  37. #droidconbos @HandstandSam YOU CAN ENABLE OTHERS

  38. #droidconbos @HandstandSam CUSTOM DEBUG FEATURE “CHANGE ENDPOINT”

  39. #droidconbos @HandstandSam WHAT WILL THIS UI LOOK LIKE?

  40. #droidconbos @HandstandSam DEBUG DRAWER https://github.com/JakeWharton/u2020 • Requires changes to existing

    UI hierarchy. • Could interfere with actions that use side-to-side swiping.
  41. #droidconbos @HandstandSam HOVERING MENU https://github.com/google/hover • REQUIRES NO CODE CHANGES

    • LOOKS COOL • REQUIRES LEARNING A NEW PARADIGM OF USING THE WINDOW MANAGER
  42. #droidconbos @HandstandSam NEW ACTIVITY • REQUIRES NO CHANGES TO EXISTING

    UI CODE • STRAIGHT FORWARD
  43. #droidconbos @HandstandSam BUT… HOW WILL THEY ACCESS THE NEW ACTIVITY?

  44. #droidconbos @HandstandSam OPTION 1: MULTIPLE LAUNCHER ICONS FOR A SINGLE

    APP
  45. #droidconbos @HandstandSam <activity android:name=".MainActivity" android:launchMode="singleTask"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category

    android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> MAIN ACTIVITY (src/main)
  46. #droidconbos @HandstandSam <activity android:name=".DebugActivity" android:icon="@drawable/magnifying_glass" android:label="BDF - DEBUG" android:launchMode="singleTask"> <intent-filter>

    <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> DEBUG FEATURE ACTIVITY (src/debug)
  47. #droidconbos @HandstandSam <activity android:name=".DebugFeatureActivity" android:launchMode="singleTask"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category

    android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> DEBUG FEATURE ACTIVITY (src/debug)
  48. #droidconbos @HandstandSam

  49. #droidconbos @HandstandSam OPTION 2: PERSISTENT NOTIFICATION

  50. #droidconbos @HandstandSam HOW WILL WE SAVE AND USE THE NEW

    ENDPOINT?
  51. #droidconbos @HandstandSam ALLOW USER TO EDIT ENDPOINT

  52. #droidconbos @HandstandSam public class DebugPreferences { public static final String

    BASE_URL = "base_url"; private final SharedPreferences sharedPreferences; public DebugPreferences(Context context) { sharedPreferences = PreferenceManager .getDefaultSharedPreferences(context.getApplicationContext()); } public void setBaseUrl(String baseUrl) { sharedPreferences.edit().putString(BASE_URL, baseUrl).apply(); } public String getBaseUrl() { return sharedPreferences.getString(BASE_URL, "https://server"); } } SAVE IN A PREFERENCE
  53. #droidconbos @HandstandSam FORCE KILL AND RESTART APP Process Phoenix https://github.com/JakeWharton/ProcessPhoenix

  54. #droidconbos @HandstandSam @Provides Retrofit.Builder retrofitBuilder(DebugPreferences debugPreferences, OkHttpClient.Builder okHttpClientBuilder) { Retrofit.Builder

    builder = new Retrofit.Builder() .baseUrl(debugPreferences.getBaseUrl()) .addConverterFactory(MoshiConverterFactory.create(new Moshi.Builder().build())) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .client(okHttpClientBuilder.build()); return builder; } APPLY UPON APP INITIALIZATION
  55. #droidconbos @HandstandSam CONFIG CHANGE TOAST

  56. #droidconbos @HandstandSam WICKED AWESOME

  57. #droidconbos @HandstandSam ANDROID DEV TESTING PRODUCT DESIGN BACKEND

  58. #droidconbos @HandstandSam PRODUCT JEFF: “I NEED AN EASY WAY TO

    DEMO NOTIFICATIONS.”
  59. #droidconbos @HandstandSam CUSTOM DEBUG FEATURE “NOTIFICATION TESTING”

  60. #droidconbos @HandstandSam TRIGGER A NOTIFICATION WITHOUT GOING THROUGH GCM?

  61. #droidconbos @HandstandSam Broadcast Receivers via ADB

  62. #droidconbos @HandstandSam <receiver android:name=".DebugBroadcastReceiver"> <intent-filter> <action android:name="PR_NOTIFICATION" /> </intent-filter> </receiver>

    BROADCAST RECEIVER (src/debug/AndroidManifest.xml)
  63. #droidconbos @HandstandSam public class DebugBroadcastReceiver extends BroadcastReceiver { private static

    final String PR_NOTIFICATION = "PR_NOTIFICATION"; @Override public void onReceive(Context context, Intent intent) { String intentAction = intent.getAction(); if (intentAction == null || !PR_NOTIFICATION.equals(intentAction)) { return; } Timber.d("processing " + PR_NOTIFICATION); Bundle extras = intent.getExtras(); if (extras == null) { return; } final String username = extras.getString("username"); Timber.d("username " + username); IntentUtils.triggerPRNotification(context, username); } } BROADCAST RECEIVER
  64. #droidconbos @HandstandSam

  65. #droidconbos @HandstandSam DYNAMIC HOME SCREEN SHORTCUTS

  66. #droidconbos @HandstandSam

  67. #droidconbos @HandstandSam Intent addShortcutIntent = new Intent(); addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, deepLinkIntent); addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME,

    "My Shortcut"); addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(applicationContext, R.drawable.shortcut)); addShortcutIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); applicationContext.sendBroadcast(addShortcutIntent); DYNAMIC HOME SCREEN SHORTCUTS
  68. #droidconbos @HandstandSam Intent addShortcutIntent = new Intent(); addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, deepLinkIntent); addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME,

    "My Shortcut"); addShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(applicationContext, R.drawable.shortcut)); addShortcutIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); applicationContext.sendBroadcast(addShortcutIntent); DYNAMIC HOME SCREEN SHORTCUTS
  69. #droidconbos @HandstandSam WICKED AWESOME

  70. #droidconbos @HandstandSam ANDROID DEV TESTING PRODUCT DESIGN BACKEND

  71. #droidconbos @HandstandSam I WANT TO VALIDATE NETWORKING TRAFFIC IN A

    VISUAL WAY. TESTING
  72. #droidconbos @HandstandSam OPTION 1: STETHO • CHROME DEVELOPER TOOLS •

    NETWORK INSPECTION • PREFERENCE INSPECTION & MODIFICATION • DB INSPECTION & MODIFICATION • VIEW HIERARCHY • JAVASCRIPT CONSOLE • DUMP APP
  73. #droidconbos @HandstandSam

  74. #droidconbos @HandstandSam

  75. #droidconbos @HandstandSam

  76. #droidconbos @HandstandSam <INSERT SCREENSHOT>

  77. #droidconbos @HandstandSam “I’M NOT GOING TO BE CONNECTED TO A

    COMPUTER.”
  78. #droidconbos @HandstandSam OPTION 2: CHUCK https://github.com/jgilfelt/chuck

  79. #droidconbos @HandstandSam SURE, GIVE ME A FEW MINUTES, I’LL ADD

    IT TO ALL FUTURE DEBUG BUILDS.
  80. #droidconbos @HandstandSam WICKED AWESOME

  81. #droidconbos @HandstandSam OPEN SOURCE INSPIRATION

  82. #droidconbos @HandstandSam DON’T RE-INVENT THE WHEEL LEVERAGE EXISTING OPEN SOURCE

    LIBRARIES
  83. #droidconbos @HandstandSam UI DESIGN & VIEW INSPECTION

  84. #droidconbos @HandstandSam Keyline Pushing https://play.google.com/store/apps/details?id=com.faizmalkani.keylines • Overlays Material Design Keylines

  85. #droidconbos @HandstandSam Scalpel https://github.com/JakeWharton/scalpel • A surgical debugging tool to

    uncover the layers under your app.
  86. #droidconbos @HandstandSam Madge https://github.com/JakeWharton/madge • Overlays for debugging whether assets

    are drawing at their native resolution.
  87. #droidconbos @HandstandSam Logging

  88. #droidconbos @HandstandSam Logcat

  89. #droidconbos @HandstandSam Timber https://github.com/JakeWharton/timber • Abstraction on top of Android

    Log ◦ Log.d(TAG, message); • More concise syntax ◦ Timber.d(message); ◦ d(message); - Static Import • Ability to toggle logging on/off. • Ability to keep logs in memory.
  90. #droidconbos @HandstandSam Hugo https://github.com/JakeWharton/hugo • Annotation-triggered method call logging for

    your debug builds.
  91. #droidconbos @HandstandSam Bug Reporting

  92. #droidconbos @HandstandSam Telescope https://github.com/mattprecious/telescope • A simple tool to allow

    easy bug report capturing within your app.
  93. #droidconbos @HandstandSam Memory Leaks

  94. #droidconbos @HandstandSam Leak Canary https://github.com/square/leakcanary • A memory leak detection

    library for Android and Java.
  95. #droidconbos @HandstandSam Network Inspection

  96. #droidconbos @HandstandSam Network Debugging • Stetho • Chuck

  97. #droidconbos @HandstandSam DON’T SHIP TO PROD

  98. #droidconbos @HandstandSam APK ANALYZER

  99. #droidconbos @HandstandSam APK ANALYZER - DEBUG BUILD

  100. #droidconbos @HandstandSam APK ANALYZER - RELEASE BUILD

  101. #droidconbos @HandstandSam CLASSY SHARK https://github.com/google/android-classyshark

  102. #droidconbos @HandstandSam CLASSY SHARK - DEBUG BUILD

  103. #droidconbos @HandstandSam CLASSY SHARK - RELEASE BUILD

  104. #droidconbos @HandstandSam CLASSY SHARK - DEBUG BUILD

  105. #droidconbos @HandstandSam CLASSY SHARK - RELEASE BUILD

  106. #droidconbos @HandstandSam RECAP • USE GRADLE BUILD VARIANTS • USE

    EXISTING LIBRARIES IF THEY WORK • START SIMPLE & BE PRAGMATIC
  107. #droidconbos @HandstandSam IN MY OPINION: DEBUG FEATURES THAT ENABLE YOUR

    TEAM IS JUST AS VALUABLE AS WHAT GETS SHIPPED TO PROD.
  108. #droidconbos @HandstandSam THINK OUTSIDE THE BOX

  109. #droidconbos @HandstandSam THE END