Upgrade to Pro — share decks privately, control downloads, hide ads and more …

(続) Debug Menuはじめました。

operandoOS
October 27, 2017

(続) Debug Menuはじめました。

(続) Debug Menuはじめました。

shibuya.apk #19
https://shibuya-apk.connpass.com/event/68094/

Sample Project
https://github.com/operando/android-debug-menu-sample

operandoOS

October 27, 2017
Tweet

More Decks by operandoOS

Other Decks in Technology

Transcript

  1. (ଓ) Debug Menu

    ͸͡Ί·ͨ͠ɻ
    shibuya.apk #19

    View Slide

  2. About Me
    Shinobu Okano
    @operandoOS
    Mercari, Inc.
    Souzoh, Inc.

    View Slide

  3. ٕज़ॻయͰຊॻ͖·ͨ͠ʂ

    View Slide

  4. ୈ4ষ Debug Menu͸͡Ί·ͨ͠ɻ

    View Slide

  5. Debug Menu??
    • ։ൃ࣌ͷ࡞ۀͳͲΛศརʹ͢Δ΍ʔͭʔ
    • AndroidͳΒ։ൃऀ޲͚Φϓγϣϯ͕͋ΔΑͶ

    View Slide

  6. Debug MenuΛ࡞Δ͜ͱͰ

    ಘΒΕΔϝϦοτ
    • ΞϓϦ։ൃ࣌ʹߦ͏࡞ۀͷख͕ؒল͚Δ
    • ઃఆ߲໨͕มߋͰ͖ɺΞϓϦΛϏϧυ͠௚͢

    ख͕ؒল͚Δ
    • ΤϯδχΞҎ֎΋ଟ༷ͳ؀ڥ΍ঢ়ଶ

    ઃఆͰΞϓϦͷಈ࡞Λ֬ೝͰ͖Δ

    View Slide

  7. ϝϧΧϦ Χ΢ϧͷ

    Debug Menu

    View Slide

  8. ϝϧΧϦ Χ΢ϧͷDebug Menu

    View Slide

  9. ϝϧΧϦ Χ΢ϧͷDebug Menu
    • Debug Menuͷը໘͸ৗઃ௨஌͔Β؆୯ʹ

    ։͚ΔΑ͏ʹͳͬͯΔ

    View Slide

  10. ϝϧΧϦ Χ΢ϧͷDebug Menu

    View Slide

  11. ϝϧΧϦ Χ΢ϧͷDebug Menu
    • ೔ʑࢥ͍͖ͭͰͲΜͲΜͱػೳΛ௥Ճ͓ͯ͠Γ

    ݱࡏ10ݸҎ্ͷػೳ͕͋Δ
    • ௥Ճ͢Δػೳ͕Ϋʔϧʢศརʣ͔Ͳ͏͔͕ܾΊख
    • iOS൛ͷ։ൃΞϓϦʹ΋ࣅͨΑ͏ͳDebug Menu
    Λ౥ࡌ͍ͯ͠·͢ɻ

    View Slide

  12. Debug MenuΛ࡞Δίπ
    • ݟͨ໨͸ؾʹͤͣͱʹ͔͘ػೳ໘Λॏࢹͯ͠࡞Δ
    • ͍͍ػೳΛࢥ͍͍ͭͨΒͱʹ͔࣮͘૷ͯ͠ΈΔ
    • γϯϓϧʹ࣮૷͢Δ
    • ແବͳ΋ͷ͸࡞Βͳ͍
    • ͲΜͳػೳ͕͋Δͱศར͔νʔϜϝϯόʔʹώΞϦϯάͯ͠ΈΔ

    View Slide

  13. Debug Menu࣮ફೖ໳

    View Slide

  14. DemoΞϓϦ͸Githubʹ͋Γ·͢ʂʂ
    https://github.com/operando/
    android-debug-menu-sample
    Android debug menu sample

    View Slide

  15. ϦϦʔε൛ΞϓϦʹDebug MenuΛؚΊͳ͍
    • Build TypeΛ׆༻͢Δ
    • ྫ͑͹ɺdebug build typeʹDebug Menuͷ
    ίʔυΛ࣮૷͢Δ

    View Slide

  16. ϦϦʔε൛ΞϓϦʹDebug MenuΛؚΊͳ͍

    View Slide

  17. ৗઃ௨஌͔ΒDebug Menuͷը໘Λ։͘
    • NotificationManager࢖ͬͯʹ௨஌Λઃఆ͢Δ
    • NotificationCompat.BuilderͷsetOngoingϝιου
    ʹtrueΛࢦఆ͢Δ͜ͱͰɺΫϦΞͰ͖ͳ͍

    ৗઃ௨஌ͱͯ͠දࣔͰ͖Δ
    • ௨஌Λؒҧͬͯফ͞ͳ͍ͨΊͷରࡦ

    View Slide

  18. private static final String NOTIFICATION_TAG = "DebugMenuNotificationManager";
    private static final int NOTIFICATION_ID = Integer.MAX_VALUE;
    private static final String CHANNEL_ID = "debug";
    public static void showDebugMenuNotification(Context c) {
    Intent i = new Intent(c, DebugMenuActivity.class);
    PendingIntent pi =
    PendingIntent.getActivity(c, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
    Notification n = buildNotification(c, pi);
    NotificationManager nm = getNotificationManager(c);
    nm.notify(NOTIFICATION_TAG, NOTIFICATION_ID, n);
    }
    private static Notification buildNotification(Context c, PendingIntent pi) {
    PackageManager pm = c.getPackageManager();
    String applicationName =
    c.getApplicationInfo().loadLabel(pm).toString();
    NotificationCompat.Builder builder =
    new NotificationCompat.Builder(c, CHANNEL_ID);
    builder.setTicker("debug menu");
    builder.setOngoing(true);
    builder.setContentTitle(applicationName);
    builder.setContentText("λοϓ͢ΔͱDebug Menu͕։͖·͢");
    builder.setSmallIcon(R.drawable.ic_notification_small);
    builder.setContentIntent(pi);
    builder.setAutoCancel(false);
    return builder.build();
    }
    private static NotificationManager getNotificationManager(Context c) {
    return (NotificationManager)
    c.getSystemService(Context.NOTIFICATION_SERVICE);
    }

    View Slide

  19. private static final String CHANNEL_ID = "debug";
    private static Notification buildNotification(Context c, PendingIntent pi) {
    PackageManager pm = c.getPackageManager();
    String applicationName =
    c.getApplicationInfo().loadLabel(pm).toString();
    NotificationCompat.Builder builder =
    new NotificationCompat.Builder(c, CHANNEL_ID);
    builder.setTicker("debug menu");
    builder.setOngoing(true);
    builder.setContentTitle(applicationName);
    builder.setContentText("λοϓ͢ΔͱDebug Menu͕։͖·͢");
    builder.setSmallIcon(R.drawable.ic_notification_small);
    builder.setContentIntent(pi);
    builder.setAutoCancel(false);
    return builder.build();
    }

    View Slide

  20. private static final String NOTIFICATION_TAG
    = "DebugMenuNotificationManager";
    private static final int NOTIFICATION_ID = Integer.MAX_VALUE;
    public static void showDebugMenuNotification(Context c) {
    Intent i = new Intent(c, DebugMenuActivity.class);
    PendingIntent pi =
    PendingIntent.getActivity(c, 0, i, PendingIntent.FLAG_CANCEL_CURRENT);
    Notification n = buildNotification(c, pi);
    NotificationManager nm = getNotificationManager(c);
    nm.notify(NOTIFICATION_TAG, NOTIFICATION_ID, n);
    }
    private static NotificationManager getNotificationManager(Context c) {
    return (NotificationManager)
    c.getSystemService(Context.NOTIFICATION_SERVICE);
    }

    View Slide

  21. ৗઃ௨஌͔ΒDebug Menuͷը໘Λ։͘
    • ϝϧΧϦ Χ΢ϧͰ͸௨஌ͷදࣔɾΫϦΞͷ੍ޚʹ
    Application.ActivityLifecycleCallbacksΛ࢖ͬͯΔ
    • ΞϓϦ͕ىಈͨ࣌͠ʹ௨஌Λදࣔ͢Δ
    • Activityͷback stack্Ͱ࠷ޙͷActivity͕Destroy͢Δ࣌ʹ
    ௨஌ΛΫϦΞ͢Δ
    • ࣮૷ͨ͠Application.ActivityLifecycleCallbacks͸
    ApplicationͷonCreateͱ͔Ͱొ࿥͢Δ

    View Slide

  22. public class DebugMenuActivityLifecycleCallbacks
    implements Application.ActivityLifecycleCallbacks {
    private boolean isShowDebugMenuNotification;
    @Override
    public void onActivityCreated(Activity activity, Bundle bundle) {
    if (!isShowDebugMenuNotification) {
    DebugMenuNotificationManager.showDebugMenuNotification(activity);
    isShowDebugMenuNotification = true;
    }
    }
    @Override
    public void onActivityDestroyed(Activity activity) {
    if (activity instanceof MainActivity) {
    DebugMenuNotificationManager.cancelDebugMenuNotification(activity);
    isShowDebugMenuNotification = false;
    }
    }
    }

    View Slide

  23. Demo

    View Slide

  24. γεςϜͷઃఆΞϓϦͰ

    ΞϓϦৄࡉը໘Λ։͘

    View Slide

  25. γεςϜͷઃఆΞϓϦͰ

    ΞϓϦৄࡉը໘Λ։͘
    • ϓϦΠϯετʔϧ͞Ε͍ͯΔγεςϜͷ

    ઃఆΞϓϦ͸୺຤ϝʔΧʔʹΑͬͯ

    ݟͨ໨͕શવҧ͏ʂ
    • ݕূػछ͕ଟ͍ͱγεςϜͷઃఆΞϓϦ͔Β
    ΞϓϦৄࡉը໘Λ։͘͜ͱ΋Ұۤ࿑

    View Slide

  26. ͜Μͳ͜ͱͰϘΫ͸

    ೰Έͨ͘ͳ͍ʂʂ

    View Slide

  27. ͦΜͳ೰ΈΛղܾ͢Δ

    ૉఢͳػೳ͕؆୯ʹ࡞Ε·͢ʂ

    View Slide

  28. γεςϜͷઃఆΞϓϦͰ

    ΞϓϦৄࡉը໘Λ։͘
    • γεςϜͷઃఆΞϓϦͰࣗ਎ͷΞϓϦৄࡉ

    ը໘Λ։͘IntentΛ࡞Δͷ͸؆୯
    • ޙ͸ద౰ʹViewΛλοϓͨ͠ΒɺͦͷIntentΛ
    start͢Ε͹Α͍
    • ͪΐͬͱ࣮ͨ͠૷ͰϝʔΧʔ͝ͱͷγεςϜͷઃఆ
    ΞϓϦʹ೰·͞ΕΔ͜ͱ͕ͳ͘ͳΓ·͢ʂ

    View Slide

  29. public class DebugMenuActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityDebugMenuBinding binding
    = DataBindingUtil.setContentView(this, R.layout…);
    binding.openApplicationSettings.setOnClickListener(v -> {
    Intent i = new Intent();
    i.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    i.setData(Uri.fromParts("package", getPackageName(), null));
    startActivity(i);
    });
    }
    }

    View Slide

  30. Demo

    View Slide

  31. ͗͢ΐ͍

    View Slide

  32. APIͷURLΛมߋ͢Δ

    View Slide

  33. APIͷURLΛมߋ͢Δ
    • ϝϧΧϦ Χ΢ϧͷ։ൃͰ͸αʔόʔαΠυͰ৽͍͠ػೳΛ

    ௥Ճ͢Δ৔߹ɺػೳ͝ͱʹAPIͷURL͕ҟͳΔ
    • ΞϓϦ͔Βࢀর͢ΔAPIͷURLΛมߋ͍ͨ͠৔߹ʹ

    URLΛมߋͯ͠ΞϓϦΛϏϧυ͠௚ͯ͠Δͱ͕͔͔࣌ؒΔ
    • ։ൃ൛ͷΞϓϦ͸ΤϯδχΞ͚ͩͰͳ͘

    σβΠφʔ΍QAͳͲ΋৮Δ
    • ୭Ͱ΋؆୯ʹAPIͷURLΛมߋͰ͖Δඞཁ͕͋Δ

    View Slide

  34. APIͷURLΛมߋ͢Δ
    • Debug Menu͔ΒAPIͷURLΛมߋͰ͖ΔΑ͏ʹͯ͠Δ
    • SharedPreferencesΛ࢖͑͹؆୯ʹ࣮૷Ͱ͖Δ

    View Slide

  35. APIͷURLΛมߋ͢Δ
    • APIͷURL͸ΫϥεΛհͯ͠औಘ͢ΔΑ͏ʹ͢Δ
    • SharedPreferencesʹมߋޙͷAPIͷURL͕

    ͋Ε͹มߋޙͷAPIͷURLΛฦ͢
    • ͦ͏Ͱͳ͍৔߹͸ΞϓϦ಺Ͱݩʑఆٛͯ͋͠Δ
    APIͷURLΛฦ͢

    View Slide

  36. public class UrlManager {
    public static final String API_URL = "https://tech-book-fest-debug.com";
    private static DebugInformationPrefs debugInformationPrefs;
    public static void setDebugInformationPrefs(DebugInformationPrefs prefs) {
    UrlManager.debugInformationPrefs = prefs;
    }
    public static String getApiUrl() {
    // APIͷURLʹมߋ͕ͳ͍৔߹ɺఆٛࡁΈͷAPIͷURLΛฦ͢
    if (debugInformationPrefs == null || !debugInformationPrefs.hasApiUrl()) {
    return API_URL;
    }
    return debugInformationPrefs.getApiUrl();
    }
    }

    View Slide

  37. APIͷURLΛมߋ͢Δ
    • Debug MenuʹAPIͷURLΛมߋ͢Δ

    ػೳΛ௥Ճ͢Δ
    • EditTextͷaddTextChangedListenerͰ

    ؆୯ʹ࣮૷Ͱ͖Δ

    View Slide

  38. public class DebugMenuActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityDebugMenuBinding binding
    = DataBindingUtil.setContentView(this, R.layout…);
    binding.apiUrl.setText(UrlManager.getApiUrl());
    binding.apiUrl.setSelection(binding.apiUrl.getText().toString().length());
    binding.apiUrl.addTextChangedListener(new TextWatcher() {
    @Override
    public void afterTextChanged(Editable s) {
    DebugInformationPrefs.get(DebugMenuActivity.this)
    .setApiUrl(s.toString());
    }
    });
    }
    }

    View Slide

  39. Demo

    View Slide

  40. APIͷURLΛมߋ͢Δ ؾ͔͍ͮ
    • ΞϓϦ಺ʹݩʑఆ͍ٛͯ͠ΔAPIͷURLʹ

    ໭͢ૢ࡞΋සൟʹߦ͏ͨΊɺΫϦΞϘλϯ

    ΋༻ҙ͓ͯ͘͠ͱศརʂ

    View Slide

  41. Picassoͷσόοάϩάදࣔ΍
    Πϯδέʔλදࣔͷ

    ༗ޮɾແޮΛ੾Γସ͑Δ

    View Slide

  42. Picassoͷσόοάϩάදࣔ΍Πϯδ
    έʔλදࣔͷ༗ޮɾແޮΛ੾Γସ͑Δ
    • ϝϧΧϦ Χ΢ϧͰ͸ը૾μ΢ϯϩʔυʹPicassoΛ࢖ͬͯΔ
    • Picassoʹ͸ɺ։ൃ࣌ʹ໾ཱͭػೳ͕͍͔ͭ͋͘Δ
    • σόοάϩάͷදࣔ
    • ಡΈࠐ·Εͨը૾͕ωοτϫʔΫɺσΟεΫɺϝϞϦ

    Ͳ͔͜Βདྷͨͷ͔൑ผͰ͖ΔΠϯδέʔλΛը૾্ʹදࣔ͢Δ

    View Slide

  43. Picassoͷσόοάϩάදࣔ΍Πϯδ
    έʔλදࣔͷ༗ޮɾແޮΛ੾Γସ͑Δ
    • ศར͚ͩͲৗʹग़ͯ͠Δͱ͏͍ͬͨ͟
    • ඞཁͳ࣌ʹDebug Menu͔Β༗ޮɾແޮΛ

    ੾Γସ͑Δ͍ͧʂ
    • SharedPreferencesΛ࢖͑͹؆୯ʹ࣮૷Ͱ͖Δ

    View Slide

  44. Picassoͷσόοάϩάදࣔ΍Πϯδ
    έʔλදࣔͷ༗ޮɾແޮΛ੾Γସ͑Δ
    • SwitchΛ࢖ͬͯ༗ޮɾແޮͷ੾Γସ͑Λ

    ϋϯυϦϯάͯ͠ɺSharedPreferencesʹอଘ͢Δ
    • ༗ޮɾແޮͷ੾Γସ͑ΛPicassoʹઃఆ͢Δ

    View Slide

  45. public class DebugMenuActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ActivityDebugMenuBinding binding
    = DataBindingUtil.setContentView(this, R.layout…);
    binding.picassoEnableDebugLog.setChecked(
    Picasso.with(this).isLoggingEnabled());
    binding.picassoEnableDebugLog.setOnCheckedChangeListener((__, ic) -> {
    DebugInformationPrefs.get(this).setPicassoLoggingEnabled(ic);
    Picasso.with(this).setLoggingEnabled(ic);
    });
    binding.picassoEnabledIndicators.setChecked(
    Picasso.with(this).areIndicatorsEnabled());
    binding.picassoEnabledIndicators.setOnCheckedChangeListener((__, ic) -> {
    DebugInformationPrefs.get(this).setPicassoAreIndicatorsEnabled(ic);
    Picasso.with(this).setIndicatorsEnabled(ic);
    });
    }
    }

    View Slide

  46. Picassoͷσόοάϩάදࣔ΍Πϯδ
    έʔλදࣔͷ༗ޮɾແޮΛ੾Γସ͑Δ
    • ApplicationͷonCreateͱ͔Ͱ༗ޮɾແޮͷ

    ੾Γସ͑Λอ࣋ͯ͠ΔSharedPreferences

    ͔Β஋ΛऔΓग़ͯ͠Picassoʹઃఆ͢Δ
    • ࠶౓ΞϓϦΛ։͍ͨࡍʹ΋ઃఆ஋Λ൓өͰ͖Δ

    View Slide

  47. public class DebugApplication extends Application {
    @Override
    public void onCreate() {
    super.onCreate();
    DebugInformationPrefs prefs = DebugInformationPrefs.get(this);
    Picasso picasso = Picasso.with(this);
    picasso.setLoggingEnabled(prefs.getPicassoLoggingEnabled());
    picasso.setIndicatorsEnabled(prefs.getPicassoAreIndicatorsEnabled());
    }
    }

    View Slide

  48. Demo

    View Slide

  49. Picassoͷσόοάϩάදࣔ΍Πϯδ
    έʔλදࣔͷ༗ޮɾແޮΛ੾Γସ͑Δ
    • ͜ͷON/OFF੾Γସ͑ͷΞϓϩʔν͸

    ଞͷ੾Γସ͑Ͱ΋༗ޮ
    • Ұ౓࡞Ε͹ಉ͡Α͏ͳ࣮૷ͰON/OFF੾Γସ͑ܥ
    ͷDebug Menu͕௥ՃͰ͖Δ
    • ϝϧΧϦ Χ΢ϧͰ͸LeakCanaryͷON/OFFʹ

    ಉ͡Α͏ͳ࣮૷Λ࢖ͬͯΔ

    View Slide

  50. ͜͜·Ͱ͸ຊʹॻ͍ͨ͜ͱͰ͢ʂ

    View Slide

  51. σβΠϯνΣοΫΛ

    ͬ͘͞ͱ΍Δ

    View Slide

  52. σβΠϯνΣοΫΛͬ͘͞ͱ΍Δ
    • ΞϓϦͰڞ௨Ͱ࢖ͬͯΔStyleΛద༻ͨ͠View
    Λͬ͘͞ͱνΣοΫͰ͖Ε͹ָͦ͏ʂ
    • ಛʹΞϓϦΛ࡞Γ࢝Ίͨࠒ͸σβΠφʔͱͷ
    ΍ΓऔΓͰ࢖ͬͯͨ
    • มߋ͢Δ࣌΋ؔ࿈ͯ͠Δ΋ͷ͕·ͱΊͯ

    มΘΔ͔Ͳ͏͔΋Θ͔Γ΍͘͢ͳΔ

    View Slide

  53. σβΠϯνΣοΫΛͬ͘͞ͱ΍Δ
    • ࡞Δͷ͸ΊͬͪΌ؆୯
    • StyleΛద༻ͨ͠ViewΛฒ΂ͨΓ

    ී௨ʹViewฒ΂ͯϦ͢Ε͹͍͍͚ͩʂ

    View Slide


  54. ...>
    style="@style/Button.A"
    android:text="Button A" />
    style="@style/Button.B"
    android:text="Button B" />
    style="@style/Button.C"
    android:text="Button C" />

    View Slide

  55. Demo

    View Slide

  56. APIͷURLΛ΋ͬͱ؆୯ʹ

    มߋ͢Δ

    View Slide

  57. APIͷURLΛ΋ͬͱ؆୯ʹมߋ͢Δ
    • มߋ͢ΔͷʹҰʑURLଧͬͯΒΕΔ͔ʂʂ
    • ͦΕҎ֎ͷؾ͕༙͍࣋ͪͯ͜ͳ͍...

    View Slide

  58. APIͷURLΛ΋ͬͱ؆୯ʹมߋ͢Δ
    • APIͷURL͕ҰཡʹͳͬͯͨΒ੾Γସָ͑͡ΌͶʁ
    • Ϧετબ୒ͨ͠ΒURLมߋͨ͠Βָ͡ΌͶʁ

    View Slide

  59. APIͷURLΛ΋ͬͱ؆୯ʹมߋ͢Δ
    • RecyclerViewͱ͔ListView࢖͑͹؆୯ʹͰ͖Δʂ
    • બ୒͞Εͨ಺༰ΛIntentʹ٧Ίͯ

    setResult͢Ε͹؆୯ʹͰ͖Δʂ

    View Slide

  60. Demo

    View Slide

  61. ͗͢ΐ͍

    View Slide

  62. APIͷURLΛ΋ͬͱ؆୯ʹมߋ͢Δ
    • ࠷ߴʹͳͬͨʂ
    • QRΛಡΈࠐΜͰURLΛม͑Δͬͯ

    ࣮૷ͯ͠Δͷ΋ݟͨ͜ͱ͋Δͧʂ

    View Slide

  63. ·ͱΊ
    • Debug Menu͸γϯϓϧͳ࣮૷ͰศརͳػೳΛఏڙͰ͖Δ
    • ڵຯΛ࣋ͬͨํ͸ɺڞʹ։ൃ͢ΔਓͨͪʹͲΜͳ

    Debug Menu͕͋Ε͹ศར͔ώΞϦϯάͯ͠

    ࣮૷ͯ͠ΈΔͱΑ͛͞
    • ࢲୡͷΞϓϦͷDebug Menuʹ͸͜Μͳػೳ͕͋Δͥʂʯ

    తͳͷฉ͖͍ͨͷͰΈΜͳڞ༗͠Α͏ͥʂʂ

    View Slide

  64. Debug Menu

    ΍͍͖ͬͯ·͠ΐʂ

    View Slide

  65. Thanksʂʂ

    View Slide