asken テックブログ

askenエンジニアが日々どんなことに取り組み、どんな「学び」を得ているか、よもやま話も織り交ぜつつ綴っていきます。 皆さまにも一緒に学びを楽しんでいただけたら幸いです!

Androidアプリのデバッグメニューを改善した話

こんにちは。システム部の大澤です。 普段は北米版あすけんのアプリを開発しています。

今回は北米版あすけんアプリのAndroidで活用しているデバッグメニューの話です。

解決したかった課題

開発している中でアプリの動作確認の作業はとても大変です。かつ、開発者以外の人にも動作確認をしてもらうのも同様です。 その問題を解決するためにデバッグメニューを導入しています。 私がアサインされてから、より効率的に動作確認をするために改善し、工夫した点をまとめました。

重要視した視点

  • 非エンジニアでも簡単に動作可能
    • デバッグメニューなので非エンジニアが動作確認するケースも念頭に置いて実装をする。
  • 長期的に費用対効果が高い
    • 導入コストは高いが長期的にコストを改修できるものを採用。
  • メンテナンスが楽
    • あくまでデバッグ用なので改修のコストが上がるのは目的と逆行してしまう。

主な機能

  • A/B Testの割り当ての切り替え
  • Feature Flagの切り替え
  • Firebase Analyticsのイベントの履歴の表示
  • APIのレスポンスの履歴
  • SharedPreferencesの削除
  • アプリやアカウントの状態確認
  • UIコンポーネントカタログ ...

などさまざまな機能があります。その中でとくに効果的だった機能を紹介します。

デバッグメニューは端末シェイクで簡単に表示

特定の画面に依存すると操作ステップが増え、余計に大変になってしまうと考えました。 シェイクジェスチャーであれば、画面に依存せず、いつでも簡単に表示できます。

willowtreeapps/Hyperion-Androidの実装を参考にしました。

アプリ起動時にActivityLifecycleCallbacksを使い、遷移したActivityにシェイクジェスチャーを監視する処理を入れます。 シェイクされたら、デバッグメニューへ遷移するようにしました。

実装コードはこのような感じです。

open class DebugMenuLifecycleDelegate : ActivityLifecycleCallbacks() {
    private var shakeDetectors = mutableMapOf<String, ShakeDetector>()
    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
        val shakeDetector = ShakeDetector()
        shakeDetector.setOnShakeListener(object : ShakeDetector.OnShakeListener {
            override fun onShake() {
                // ここでデバッグメニューへの遷移処理を呼び出す
            }
        })

        shakeDetectors[activity.localClassName] = shakeDetector
    }

    override fun onActivityResumed(activity: Activity) {
        registerListener(activity)
    }

    override fun onActivityPaused(activity: Activity) {
        unregisterListener(activity)
    }

    override fun onActivityDestroyed(activity: Activity) {
        shakeDetectors.remove(activity.localClassName)
    }

    private fun registerListener(activity: Activity) {
        val sensorManager = activity.applicationContext.getSystemService(Context.SENSOR_SERVICE) as? SensorManager ?: return
        val accelerometer = sensorManager?.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        val shakeDetector = shakeDetectors[activity.localClassName]
        sensorManager?.registerListener(shakeDetector, accelerometer, SensorManager.SENSOR_DELAY_UI)
    }

    private fun unregisterListener(activity: Activity) {
        val sensorManager = activity.applicationContext.getSystemService(Context.SENSOR_SERVICE) as? SensorManager ?: return
        sensorManager.unregisterListener(shakeDetectors[activity.localClassName])
    }
}

シェイクの実装はこのファイルを参考にしました。 ShakeDetector.java

A/B Testの切り替え

本プロダクトではA/B TestのUI切り替えにFirebase Remote Configを使っています。 本番環境やリリース前の動作検証の際に切り替えの時間がかかり非効率でした。 そこでFirebaseのRemote configの機能を使い、特定条件のユーザーに対して、指定したパターンが割り振られるようにしています。

Firebase Remote Config -> パラメータ作成 -> 新たな条件の追加で追加します。 ユーザープロパティを組み合わせることで割り振りをコントロールできます。 この機能を活用するメリットとして、アプリに条件分岐を増やすことなくFirebaseでコントロール可能になります。

また、デバッグメニューから切り替えを行えるようにして、効率的に業務ができる様になりました。

よく使うUIコンポーネントをカタログ化

特定条件で表示するダイアログやよく使うUIコンポーネントを簡単に動作確認できる機能です。 通常のアプリでは再現が難しい状態をMock化してデータを渡すことで状態を再現し、動作確認のコストを下げます。 Mockを活用することでAPIなどに依存せず、UIを構築できるので開発効率アップに貢献しています。 デバッグメニューから任意の画面を開けるようになっているので動作確認は楽です。

今後やりたいこと

  • UIコンポーネントカタログの活用した自動テスト
    • 自動化することで動作確認コストをさらに下げられます。
  • 移植可能にする
    • SDKにして、他のプロジェクトにも簡単に導入可能にしていきたいです。

お知らせ

askenでは、開発効率化に興味あるエンジニアを募集しています。

www.wantedly.com

www.wantedly.com

www.wantedly.com