Как Flutter адаптируется под Android?

«Как Flutter адаптируется под Android?» — вопрос из категории Платформенное взаимодействие, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Flutter обеспечивает глубокую, но гибкую интеграцию с Android, сохраняя при этом высокую производительность и единую кодовую базу.

Ключевые механизмы адаптации:

  1. Нативный рендеринг через Skia: Flutter самостоятельно отрисовывает каждый пиксель на экране, используя графический движок Skia. Это даёт полный контроль над UI и гарантирует идентичный внешний вид и поведение на всех версиях Android, минуя фрагментацию нативных компонентов.

  2. Material Design из коробки: Виджеты MaterialApp, Scaffold, AppBar, FloatingActionButton и сотни других реализуют актуальные гайдлайны Material Design, что сразу делает приложение привычным для пользователей Android.

  3. Доступ к платформенным API:

    • Готовые плагины: Для типовых задач (камера, геолокация, сенсоры) используются плагины из pub.dev (например, camera, geolocator).
    • Platform Channels: Для уникальной логики или доступа к специфичным API используется прямой двусторонний канал связи между Dart-кодом и нативным Kotlin/Java-кодом.
  4. Адаптация к системе: Flutter автоматически обрабатывает системные темы (тёмная/светлая), жесты навигации (например, "свайп назад"), плотность пикселей (pixel ratio) и интенты (intents).

Пример использования MethodChannel для вызова нативного кода:

// Dart-сторона (Flutter)
import 'package:flutter/services.dart';

class BatteryService {
  static const platform = MethodChannel('com.example.app/battery');

  static Future<int> getBatteryLevel() async {
    try {
      final int result = await platform.invokeMethod('getBatteryLevel');
      return result;
    } on PlatformException catch (e) {
      // Обработка ошибки канала
      return -1;
    }
  }
}
// Android-сторона (Kotlin, в MainActivity.kt)
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.BatteryManager
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES

class MainActivity: FlutterActivity() {
    private val CHANNEL = "com.example.app/battery"

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
            call, result ->
            if (call.method == "getBatteryLevel") {
                val batteryLevel = getBatteryLevel()
                if (batteryLevel != -1) {
                    result.success(batteryLevel)
                } else {
                    result.error("UNAVAILABLE", "Battery level not available.", null)
                }
            } else {
                result.notImplemented()
            }
        }
    }

    private fun getBatteryLevel(): Int {
        val batteryLevel: Int
        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
            val batteryManager = getSystemService(Context.BATTERY_SERVICE) as BatteryManager
            batteryLevel = batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
        } else {
            val intent = ContextWrapper(applicationContext).registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
            batteryLevel = intent!!.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) * 100 / intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1)
        }
        return batteryLevel
    }
}
  1. Кастомизация нативного слоя: Папка android/ в проекте Flutter — это полноценный Android-проект (Gradle). Я могу редактировать AndroidManifest.xml, настраивать build.gradle, добавлять ресурсы или изменять MainActivity.kt для реализации специфичной для платформы логики.