Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
"It's an Inside Job" - Building Debug Features
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Sam Edwards
April 11, 2017
Programming
380
7
Share
"It's an Inside Job" - Building Debug Features
Droidcon Boston - April 11, 2017
DC Android - March 15, 2017
Sam Edwards
April 11, 2017
More Decks by Sam Edwards
See All by Sam Edwards
Trailblaze - Droidcon NYC 2025
handstandsam
1
69
KotlinConf 24 - Dynamic Exploration of Static Analysis with Compose
handstandsam
2
120
Interception - Droidcon NYC 2023
handstandsam
1
240
KMP4FREE in 2023 @ Droidcon NYC 2022
handstandsam
2
330
Embracing commonMain for Android Development - Droidcon SF 2022
handstandsam
4
620
Why I Left Java for Kotlin
handstandsam
1
480
Kotlin Actors - No Drama Concurrency
handstandsam
6
30k
SELECT * FROM Kotlin - Droidcon NYC 2019
handstandsam
1
390
Android Summit 2019: DIY Dependency Injection with Kotlin
handstandsam
7
1.8k
Other Decks in Programming
See All in Programming
Swift Concurrency Type System
inamiy
1
560
iOS機能開発のAI環境と起きた変化
ryunakayama
0
190
クラウドネイティブなエンジニアに向ける Raycastの魅力と実際の活用事例
nealle
2
220
検索設計から 推論設計への重心移動と Recall-First Retrieval
po3rin
4
1.3k
The Monolith Strikes Back: Why AI Agents ❤️ Rails Monoliths
serradura
0
360
Oxlintとeslint-plugin-react-hooks 明日から始められそう?
t6adev
0
300
AI-DLC Deep Dive
yuukiyo
9
4.9k
PHP で mp3 プレイヤーを実装しよう
m3m0r7
PRO
0
290
YJITとZJITにはイカなる違いがあるのか?
nakiym
0
260
AIと共に生きる技術選定 2026
sgash708
0
110
瑠璃の宝石に学ぶ技術の声の聴き方 / 【劇場版】アニメから得た学びを発表会2026 #エンジニアニメ
mazrean
0
300
Claude Code × Gemini × Ebitengine ゲーム制作素人WebエンジニアがGoでゲームを作った話
webzawa
0
170
Featured
See All Featured
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
11
900
Ethics towards AI in product and experience design
skipperchong
2
260
A designer walks into a library…
pauljervisheath
211
24k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
120
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
240
First, design no harm
axbom
PRO
2
1.2k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.9k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
22k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
500
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
64
54k
Designing for Performance
lara
611
70k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.6k
Transcript
#droidconbos @HandstandSam “It’s an Inside Job” BUILDING DEBUG FEATURES Sam
Edwards @HandstandSam
#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
#droidconbos @HandstandSam WHAT IS A DEBUG FEATURE?
#droidconbos @HandstandSam DEBUG FEATURES • HELP YOU TEST AND DEBUG
• DON’T SHIP TO PRODUCTION
#droidconbos @HandstandSam AS DEVELOPERS, WE HAVE INSIDER ACCESS TO BUILD
THEM
#droidconbos @HandstandSam DEBUG FEATURES IN YOUR APP ENABLE YOUR TEAM
TO EFFECTIVELY PERFORM TASKS THAT CAN’T BE AUTOMATED.
#droidconbos @HandstandSam DEBUG FEATURE POSSIBILITY MATRIX
#droidconbos @HandstandSam Modify Mock Monitor Capture Inspect Configurations Persistent Data
Networking Resources Views Notifications Sensors … and more.
#droidconbos @HandstandSam GRADLE BUILD VARIANTS
#droidconbos @HandstandSam “main” SOURCE FOLDER
#droidconbos @HandstandSam BuildConfig.java
#droidconbos @HandstandSam DEFAULTS = = RELEASE.APK DEBUG.APK “main”
#droidconbos @HandstandSam “debug” and “release” SOURCE FOLDERS
#droidconbos @HandstandSam “debug” & “release” SOURCE FOLDERS = = RELEASE.APK
DEBUG.APK “main” “debug” “release” +
#droidconbos @HandstandSam SOURCE STRUCTURE
#droidconbos @HandstandSam “debug”
#droidconbos @HandstandSam “release”
#droidconbos @HandstandSam GRADLE COMPILE DEPENDENCIES
#droidconbos @HandstandSam GRADLE DEPENDENCIES
#droidconbos @HandstandSam GRADLE DEPENDENCIES = = RELEASE.APK DEBUG.APK “compile” “debugCompile”
“releaseCompile” +
#droidconbos @HandstandSam GENERATED APKS
#droidconbos @HandstandSam EXAMPLE SCENARIO
#droidconbos @HandstandSam SAMPLE APP https://github.com/handstandsam/BuildingDebugFeatures
#droidconbos @HandstandSam ANDROID DEV
#droidconbos @HandstandSam ANDROID DEV DESIGN
#droidconbos @HandstandSam ANDROID DEV DESIGN BACKEND
#droidconbos @HandstandSam ANDROID DEV PRODUCT DESIGN BACKEND
#droidconbos @HandstandSam ANDROID DEV TESTING PRODUCT DESIGN BACKEND
#droidconbos @HandstandSam JOE: “CAN I HAVE A SPECIAL BUILD TO
TEST A NEW SERVER ENDPOINT?” BACKEND
#droidconbos @HandstandSam SURE, BUT IT’LL TAKE A FEW MINUTES.
#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; }
#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; }
#droidconbos @HandstandSam WAIT FOR GRADLE...
#droidconbos @HandstandSam How many times have you hit ______ In
and then waited for
#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
#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
#droidconbos @HandstandSam YOU CAN ENABLE OTHERS
#droidconbos @HandstandSam CUSTOM DEBUG FEATURE “CHANGE ENDPOINT”
#droidconbos @HandstandSam WHAT WILL THIS UI LOOK LIKE?
#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.
#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
#droidconbos @HandstandSam NEW ACTIVITY • REQUIRES NO CHANGES TO EXISTING
UI CODE • STRAIGHT FORWARD
#droidconbos @HandstandSam BUT… HOW WILL THEY ACCESS THE NEW ACTIVITY?
#droidconbos @HandstandSam OPTION 1: MULTIPLE LAUNCHER ICONS FOR A SINGLE
APP
#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)
#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)
#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)
#droidconbos @HandstandSam
#droidconbos @HandstandSam OPTION 2: PERSISTENT NOTIFICATION
#droidconbos @HandstandSam HOW WILL WE SAVE AND USE THE NEW
ENDPOINT?
#droidconbos @HandstandSam ALLOW USER TO EDIT ENDPOINT
#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
#droidconbos @HandstandSam FORCE KILL AND RESTART APP Process Phoenix https://github.com/JakeWharton/ProcessPhoenix
#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
#droidconbos @HandstandSam CONFIG CHANGE TOAST
#droidconbos @HandstandSam WICKED AWESOME
#droidconbos @HandstandSam ANDROID DEV TESTING PRODUCT DESIGN BACKEND
#droidconbos @HandstandSam PRODUCT JEFF: “I NEED AN EASY WAY TO
DEMO NOTIFICATIONS.”
#droidconbos @HandstandSam CUSTOM DEBUG FEATURE “NOTIFICATION TESTING”
#droidconbos @HandstandSam TRIGGER A NOTIFICATION WITHOUT GOING THROUGH GCM?
#droidconbos @HandstandSam Broadcast Receivers via ADB
#droidconbos @HandstandSam <receiver android:name=".DebugBroadcastReceiver"> <intent-filter> <action android:name="PR_NOTIFICATION" /> </intent-filter> </receiver>
BROADCAST RECEIVER (src/debug/AndroidManifest.xml)
#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
#droidconbos @HandstandSam
#droidconbos @HandstandSam DYNAMIC HOME SCREEN SHORTCUTS
#droidconbos @HandstandSam
#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
#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
#droidconbos @HandstandSam WICKED AWESOME
#droidconbos @HandstandSam ANDROID DEV TESTING PRODUCT DESIGN BACKEND
#droidconbos @HandstandSam I WANT TO VALIDATE NETWORKING TRAFFIC IN A
VISUAL WAY. TESTING
#droidconbos @HandstandSam OPTION 1: STETHO • CHROME DEVELOPER TOOLS •
NETWORK INSPECTION • PREFERENCE INSPECTION & MODIFICATION • DB INSPECTION & MODIFICATION • VIEW HIERARCHY • JAVASCRIPT CONSOLE • DUMP APP
#droidconbos @HandstandSam
#droidconbos @HandstandSam
#droidconbos @HandstandSam
#droidconbos @HandstandSam <INSERT SCREENSHOT>
#droidconbos @HandstandSam “I’M NOT GOING TO BE CONNECTED TO A
COMPUTER.”
#droidconbos @HandstandSam OPTION 2: CHUCK https://github.com/jgilfelt/chuck
#droidconbos @HandstandSam SURE, GIVE ME A FEW MINUTES, I’LL ADD
IT TO ALL FUTURE DEBUG BUILDS.
#droidconbos @HandstandSam WICKED AWESOME
#droidconbos @HandstandSam OPEN SOURCE INSPIRATION
#droidconbos @HandstandSam DON’T RE-INVENT THE WHEEL LEVERAGE EXISTING OPEN SOURCE
LIBRARIES
#droidconbos @HandstandSam UI DESIGN & VIEW INSPECTION
#droidconbos @HandstandSam Keyline Pushing https://play.google.com/store/apps/details?id=com.faizmalkani.keylines • Overlays Material Design Keylines
#droidconbos @HandstandSam Scalpel https://github.com/JakeWharton/scalpel • A surgical debugging tool to
uncover the layers under your app.
#droidconbos @HandstandSam Madge https://github.com/JakeWharton/madge • Overlays for debugging whether assets
are drawing at their native resolution.
#droidconbos @HandstandSam Logging
#droidconbos @HandstandSam Logcat
#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.
#droidconbos @HandstandSam Hugo https://github.com/JakeWharton/hugo • Annotation-triggered method call logging for
your debug builds.
#droidconbos @HandstandSam Bug Reporting
#droidconbos @HandstandSam Telescope https://github.com/mattprecious/telescope • A simple tool to allow
easy bug report capturing within your app.
#droidconbos @HandstandSam Memory Leaks
#droidconbos @HandstandSam Leak Canary https://github.com/square/leakcanary • A memory leak detection
library for Android and Java.
#droidconbos @HandstandSam Network Inspection
#droidconbos @HandstandSam Network Debugging • Stetho • Chuck
#droidconbos @HandstandSam DON’T SHIP TO PROD
#droidconbos @HandstandSam APK ANALYZER
#droidconbos @HandstandSam APK ANALYZER - DEBUG BUILD
#droidconbos @HandstandSam APK ANALYZER - RELEASE BUILD
#droidconbos @HandstandSam CLASSY SHARK https://github.com/google/android-classyshark
#droidconbos @HandstandSam CLASSY SHARK - DEBUG BUILD
#droidconbos @HandstandSam CLASSY SHARK - RELEASE BUILD
#droidconbos @HandstandSam CLASSY SHARK - DEBUG BUILD
#droidconbos @HandstandSam CLASSY SHARK - RELEASE BUILD
#droidconbos @HandstandSam RECAP • USE GRADLE BUILD VARIANTS • USE
EXISTING LIBRARIES IF THEY WORK • START SIMPLE & BE PRAGMATIC
#droidconbos @HandstandSam IN MY OPINION: DEBUG FEATURES THAT ENABLE YOUR
TEAM IS JUST AS VALUABLE AS WHAT GETS SHIPPED TO PROD.
#droidconbos @HandstandSam THINK OUTSIDE THE BOX
#droidconbos @HandstandSam THE END