WatchTower, Observe API Calls in browser

도입

adibfara/WatchTower(https://github.com/adibfara/WatchTower)는 브라우저 내 에서 OKHttp으로 인한 통신에 대한 요청 / 결과 데이터 및 헤더 등을 볼 수 있는 라이브러리로, 2019년 5월 24일에 첫 버전이 릴리즈된 라이브러리이다.

지금까지 OKHttp으로 인한 통신을 앱에서 검출하려면 주로 facebook/stetho(https://facebook.github.io/stetho/) 를 사용했으나, stetho의 기반은 Chrome developer tools에 작동한다는 점에서 이 WatchTower는 그러한 제약을 가지지 않고, 앱 내에서 NanoHTTPd를 사용하여 웹 서버를 열고 자료를 볼 수 있게 하는 것에 큰 차이점을 가진다.

또한 차후 확장하여 액티비티 내에서 볼 수 있게 하는 점도 가능하니, 기능은 Stetho에 비해 매우 빈약하지만 (Stetho가 네트워크 인터셉터 외에도 뷰 구조나 덤프 등을 제공하기 때문에) 네트워크 인터셉트 기능으로 한정하면 WatchTower가 더 이점을 가진다고 볼 수 있다.

당연하게도 Retrofit 또한 OKHttp가 기반이므로 Retrofit를 사용해도 위 기능을 전부 활용할 수 있다.

따라서 이 글에서는 기본적인 WatchTower의 사용법을 소개한다.

사용법

모듈의 gradle에 아래 종속성을 추가한다.

implementation 'com.snakyapps.watchtower:core:1.0.0'
debugImplementation 'com.snakyapps.watchtower:interceptor-okhttp:1.0.0'
releaseImplementation 'com.snakyapps.watchtower:interceptor-okhttp-no-op:1.0.0'

debugImplementation, releaseImplementation으로 나눠지는데 이는 디버그 빌드에서만 해당 행동을 할 수 있게 종속성 분야에서 강제하는 것이다. 따라서 별도로 BuildConfig.DEBUG로 판단할 필요가 없어진다.

1.0.0 문서에 따르면, 안드로이드 환경에서는 Service에서 WatchTower를 시작하는 것이 권장된다고 되어있어, Service 객체를 생성한다.

class WatchTowerService : Service() {

   override fun onBind(intent: Intent?): IBinder? {
       return null
  }

   override fun onCreate() {
       super.onCreate()
       val port = Config.confg.watchTowerPort
       WatchTower.start(WebWatchTowerObserver(port = port))

       Timber.d("WatchTower is started. URL: http://localhost:$port")
  }

   override fun onDestroy() {
       super.onDestroy()
       WatchTower.shutDown()
  }
}
<service
           android:name=".module.watch.WatchTowerService"
           android:enabled="true" />

위와 같이 작성하고 Manifest에 작성하였으면, 그 다음에는 OKHttp를 설정할 때에 Interceptor를 추가하면 된다.

현재 구축된 기반의 경우 Dagger의 Multibinding 기능을 이용하여 Set<Interceptor>LoggingInterceptor 순서로 추가하게 되어 있으므로, LoggingInterceptor 뒤에 WatchTower 자체의 Interceptor를 추가한다.

@Provides
fun provideClient(interceptors: Set<@JvmSuppressWildcards Interceptor>,
                     @Named("loginterceptor") logsInterceptor: Interceptor): OkHttpClient {
   val builder = OkHttpClient().newBuilder()
   builder.readTimeout(Config.config.timeout.toLong(), TimeUnit.MILLISECONDS)
   builder.connectTimeout(Config.config.connectTimeout.toLong(), TimeUnit.MILLISECONDS)
   builder.retryOnConnectionFailure(Config.config.retryOnConnectionFailure)
   if (interceptors.isNotEmpty()) {
       interceptors.forEach {
           builder.addInterceptor(it)
      }
  }

   if (!Config.config.notUseLogInterceptor) {
       builder.addInterceptor(logsInterceptor)
  }

   if (Config.config.useWatchTower) {
       builder.addInterceptor(WatchTowerInterceptor())
  }

       return builder.build()
}

마지막으로 Activity 에서 서비스를 시작하거나 중지하면 작동하게 된다.

이제, 앱을 빌드하게 되면 기기의 브라우저에서는 http://localhost:8085 를, PC에서는 http://기기의 로컬 주소:8085 를 입력하면 접속이 되고, OKHttp로 통해 통신이 진행될 경우 맨 위의 사진처럼 로그가 나오게 된다. 기기의 로컬 주소는 기기에서 https://www.whatismybrowser.com/detect/what-is-my-local-ip-address 에 접속하면 나온다.

마무리

간단한 사용법을 가지면서도, 편리한 사용법을 가져서 누구나 쉽게 적용할 수 있다는 포인트가 제일 강점이다. 구현하는 데에도 큰 시간이 들어가지 않으므로 적용해서 사용하면 큰 편리함을 얻을 수 있을 것 같다.