Chucker для Kotlin: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Chucker для Kotlin: полное руководство с примерами

1. Что это и зачем нужна

Chucker — это мощная библиотека для отладки HTTP-запросов в Android-приложениях, написанная на Kotlin. Она позволяет разработчикам перехватывать, логировать и инспектировать весь сетевой трафик, проходящий через OkHttp клиент, прямо на устройстве. В отличие от стандартного логирования в Logcat, Chucker предоставляет удобный графический интерфейс в виде отдельного экрана (Activity), где можно просматривать заголовки, тела запросов и ответов, статус коды, время выполнения и размеры данных.

Основная цель Chucker — упростить процесс отладки сетевого взаимодействия. Вместо того чтобы подключать устройство к компьютеру и фильтровать логи, разработчик может открыть приложение и сразу увидеть все HTTP-транзакции. Это особенно полезно при тестировании на реальных устройствах, когда доступ к ADB ограничен, или при работе с командами QA, которые могут самостоятельно предоставлять скриншоты ошибок с подробной информацией о запросе.

Chucker также поддерживает фильтрацию по типу контента (JSON, XML, изображения), поиск по URL, просмотр ошибок и исключений, а также экспорт логов в файл. Библиотека автоматически собирает информацию об ошибках SSL, таймаутах и других сетевых проблемах, что делает её незаменимым инструментом для любого Android-разработчика, работающего с REST API.

2. Установка

Chucker распространяется через Maven Central. Для установки необходимо добавить зависимости в файл build.gradle.kts (или build.gradle) вашего модуля приложения.

Важно: Библиотека не предназначена для установки через pip, npm или cargo. Она является Android-библиотекой и подключается через систему сборки Gradle.

Команда для добавления в build.gradle.kts (Module: app):

// build.gradle.kts (Module: app)
dependencies {
    // Основная библиотека Chucker (только для debug сборок)
    debugImplementation("com.github.chuckerteam.chucker:library:4.0.0")

    // Библиотека для No-Op (пустышка) для release сборок
    releaseImplementation("com.github.chuckerteam.chucker:library-no-op:4.0.0")
}

Для Groovy (build.gradle):

// build.gradle (Module: app)
dependencies {
    debugImplementation 'com.github.chuckerteam.chucker:library:4.0.0'
    releaseImplementation 'com.github.chuckerteam.chucker:library-no-op:4.0.0'
}

Пояснение: Использование debugImplementation гарантирует, что Chucker будет доступен только в отладочных сборках. releaseImplementation с версией library-no-op заменяет все вызовы Chucker на пустые функции, что исключает утечку данных в продакшене и не увеличивает размер APK.

3. Быстрый старт — минимальный рабочий пример

После установки библиотеки необходимо создать OkHttpClient и добавить в него перехватчик Chucker. Затем этот клиент используется для создания Retrofit или любого другого HTTP-клиента.

// MainActivity.kt
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.chuckerteam.chucker.api.ChuckerCollector
import com.chuckerteam.chucker.api.ChuckerInterceptor
import okhttp3.OkHttpClient
import okhttp3.Request

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 1. Создаем коллектор для хранения логов
        val collector = ChuckerCollector(this)

        // 2. Создаем перехватчик
        val chuckerInterceptor = ChuckerInterceptor.Builder(this)
            .collector(collector)
            .maxContentLength(250_000L) // Лимит на размер тела запроса (250 КБ)
            .build()

        // 3. Создаем OkHttpClient с перехватчиком
        val client = OkHttpClient.Builder()
            .addInterceptor(chuckerInterceptor)
            .build()

        // 4. Выполняем тестовый GET-запрос
        Thread {
            try {
                val request = Request.Builder()
                    .url("https://jsonplaceholder.typicode.com/posts/1")
                    .build()
                val response = client.newCall(request).execute()
                println("Response: ${response.body?.string()}")
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }.start()
    }
}

После запуска приложения и выполнения запроса, в панели уведомлений появится иконка Chucker. Нажав на неё, вы попадёте в интерфейс инспектора, где сможете увидеть детали запроса.

4. Основные методы/функции/классы

Ниже приведены ключевые классы и методы библиотеки Chucker с примерами использования.

4.1. ChuckerCollector

Сигнатура: class ChuckerCollector(context: Context, showNotification: Boolean = true, retentionPeriod: RetentionManager.Period = RetentionManager.Period.ONE_HOUR)

Что делает: Управляет хранением и жизненным циклом перехваченных HTTP-транзакций. Определяет, как долго хранить логи и показывать ли уведомление.

// Пример: хранение логов в течение 24 часов, без уведомления
val collector = ChuckerCollector(
    context = this,
    showNotification = false,
    retentionPeriod = RetentionManager.Period.TWENTY_FOUR_HOURS
)

4.2. ChuckerInterceptor

Сигнатура: class ChuckerInterceptor(context: Context, collector: ChuckerCollector? = null, maxContentLength: Long = 250_000L, headersToRedact: Set<String> = emptySet())

Что делает: Основной перехватчик OkHttp. Перехватывает запросы и ответы, передавая их в коллектор для отображения.

// Пример: перехватчик с маскировкой заголовка Authorization
val interceptor = ChuckerInterceptor.Builder(this)
    .collector(collector)
    .maxContentLength(500_000L)
    .redactHeaders("Authorization", "Cookie") // Скрываем значения этих заголовков
    .build()

4.3. Chucker.isOpened()

Сигнатура: fun isOpened(): Boolean

Что делает: Проверяет, открыт ли в данный момент интерфейс Chucker (Activity). Полезно для предотвращения повторного открытия.

// Пример: проверка перед открытием
if (!Chucker.isOpened()) {
    startActivity(Intent(this, ChuckerActivity::class.java))
}

4.4. Chucker.getLaunchIntent()

Сигнатура: fun getLaunchIntent(context: Context): Intent

Что делает: Возвращает Intent для запуска главного экрана Chucker. Позволяет программно открыть инспектор.

// Пример: открытие Chucker по нажатию кнопки
button.setOnClickListener {
    val intent = Chucker.getLaunchIntent(this)
    startActivity(intent)
}

4.5. Chucker.getTransactionsCount()

Сигнатура: fun getTransactionsCount(): Int

Что делает: Возвращает общее количество перехваченных HTTP-транзакций с момента запуска приложения (или последней очистки).

// Пример: отображение счетчика запросов в UI
val count = Chucker.getTransactionsCount()
textView.text = "Перехвачено запросов: $count"

4.6. Chucker.clearTransactions()

Сигнатура: fun clearTransactions()

Что делает: Очищает все сохраненные логи HTTP-транзакций. Полезно для сброса состояния перед новым тестом.

// Пример: очистка логов
buttonClear.setOnClickListener {
    Chucker.clearTransactions()
    Toast.makeText(this, "Логи очищены", Toast.LENGTH_SHORT).show()
}

4.7. RetentionManager.Period

Сигнатура: enum class Period { ONE_HOUR, TWENTY_FOUR_HOURS, ONE_WEEK, FOREVER }

Что делает: Определяет политику хранения логов. FOREVER хранит логи до ручной очистки или перезапуска приложения.

// Пример: хранение логов навсегда
val collector = ChuckerCollector(
    context = this,
    retentionPeriod = RetentionManager.Period.FOREVER
)

4.8. ChuckerInterceptor.Builder.redactHeaders()

Сигнатура: fun redactHeaders(vararg headers: String): Builder

Что делает: Указывает, какие заголовки необходимо маскировать (заменять значение на "***") при отображении в интерфейсе Chucker. Критически важно для безопасности (токены, пароли).

// Пример: маскировка нескольких заголовков
val interceptor = ChuckerInterceptor.Builder(this)
    .redactHeaders("Authorization", "X-Api-Key", "Set-Cookie")
    .build()

5. Реальный практический пример (100-200 строк кода)

В этом примере мы создадим простое приложение, которое загружает список пользователей с публичного API и отображает их в RecyclerView. Chucker будет перехватывать все запросы. Мы также добавим кнопку для очистки логов и отображения счетчика запросов.

// MainActivity.kt
import android.content.Intent
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.chuckerteam.chucker.api.Chucker
import com.chuckerteam.chucker.api.ChuckerCollector
import com.chuckerteam.chucker.api.ChuckerInterceptor
import com.chuckerteam.chucker.api.RetentionManager
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import java.util.concurrent.TimeUnit

// API интерфейс
interface UserApi {
    @GET("users")
    suspend fun getUsers(): List
}

// Модель данных
data class User(
    val id: Int,
    val name: String,
    val email: String,
    val username: String
)

class MainActivity : AppCompatActivity() {

    private lateinit var recyclerView: RecyclerView
    private lateinit var adapter: UserAdapter
    private lateinit var countTextView: TextView
    private lateinit var api: UserApi

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Инициализация UI
        recyclerView = findViewById(R.id.recyclerView)
        countTextView = findViewById(R.id.countTextView)
        val buttonOpenChucker: Button = findViewById(R.id.buttonOpenChucker)
        val buttonClear: Button = findViewById(R.id.buttonClear)
        val buttonLoad: Button = findViewById(R.id.buttonLoad)

        // Настройка RecyclerView
        adapter = UserAdapter()
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = adapter

        // 1. Настройка Chucker
        val collector = ChuckerCollector(
            context = this,
            showNotification = true,
            retentionPeriod = RetentionManager.Period.ONE_HOUR
        )

        val chuckerInterceptor = ChuckerInterceptor.Builder(this)
            .collector(collector)
            .maxContentLength(500_000L)
            .redactHeaders("Authorization") // На случай, если добавим авторизацию
            .build()

        // 2. Настройка OkHttp с логированием и Chucker
        val loggingInterceptor = HttpLoggingInterceptor().apply {
            level = HttpLoggingInterceptor.Level.BODY
        }

        val client = OkHttpClient.Builder()
            .addInterceptor(chuckerInterceptor) // Chucker должен быть первым
            .addInterceptor(loggingInterceptor) // Логирование в Logcat
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()

        // 3. Настройка Retrofit
        val retrofit = Retrofit.Builder()
            .baseUrl("https://jsonplaceholder.typicode.com/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()

        api = retrofit.create(UserApi::class.java)

        // 4. Обработчики кнопок
        buttonLoad.setOnClickListener {
            loadUsers()
        }

        buttonOpenChucker.setOnClickListener {
            val intent = Chucker.getLaunchIntent(this)
            startActivity(intent)
        }

        buttonClear.setOnClickListener {
            Chucker.clearTransactions()
            updateTransactionCount()
            Toast.makeText(this, "Логи очищены", Toast.LENGTH_SHORT).show()
        }

        // Обновляем счетчик при старте
        updateTransactionCount()
    }

    private fun loadUsers() {
        // Запускаем корутину для асинхронного запроса
        kotlinx.coroutines.MainScope().launch {
            try {
                val users = api.getUsers()
                adapter.submitList(users)
                updateTransactionCount()
                Toast.makeText(this@MainActivity, "Загружено ${users.size} пользователей", Toast.LENGTH_SHORT).show()
            } catch (e: Exception) {
                Toast.makeText(this@MainActivity, "Ошибка: ${e.message}", Toast.LENGTH_LONG).show()
                e.printStackTrace()
            }
        }
    }

    private fun updateTransactionCount() {
        val count = Chucker.getTransactionsCount()
        countTextView.text = "Запросов: $count"
    }
}

// UserAdapter.kt (простой адаптер для RecyclerView)
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class UserAdapter                    

Рекомендаций