Flutter SDK: соединение Dart и Native
Tracelet уникален, поскольку переносит почти всю логику в собственные SDK для iOS и Android. Почему? Потому что изолирующие устройства Dart тяжелые, а запуск движка Flutter в фоновом режиме каждый раз, когда пользователь делает шаг, сокращает срок службы батареи.
На этой странице объясняется, как слой Flutter взаимодействует с собственным движком в реальных сценариях.
Сценарий 1: Подписка пользовательского интерфейса
Изученные концепции: потоки событий, автоматическое выполнение.
Проблема
Вы создаете фитнес-приложение. Когда пользователь смотрит на экран, вы хотите, чтобы маленькая синяя точка перемещалась по карте Google в режиме реального времени. Когда пользователь блокирует экран, вы все равно хотите записать запуск в базу данных, но вам не нужно обновлять пользовательский интерфейс, на который никто не смотрит.
Как Tracelet решает эту проблему
Tracelet отделяет Встроенную систему отслеживания от Потоков пользовательского интерфейса Dart.
Когда вы вызываете Tracelet.start(), включается собственный движок iOS/Android. Он полностью обрабатывает обнаружение движения, фильтрацию GPS, сохранение SQLite и синхронизацию HTTP в Swift/Kotlin.
В пользовательском интерфейсе Flutter вы просто подписываетесь на поток:
import 'package:tracelet/tracelet.dart' as tl;
void initializeTracking() async {
// 1. Listen to events in the UI
tl.Tracelet.onLocation((tl.Location location) {
print('Update UI map marker: ${location.coords.latitude}, ${location.coords.longitude}');
});
tl.Tracelet.onMotionChange((tl.Location location) {
print('User started/stopped moving: ${location.isMoving}');
});
// 2. Start the native engine
await tl.Tracelet.ready(tl.Config.balanced());
await tl.Tracelet.start();
}Магия: если пользователь принудительно закрывает ваше приложение, поток onLocation Dart прекращает работу. Но встроенный механизм отслеживания продолжает работать. Он продолжает сохранять местоположения в SQLite. Когда пользователь позже снова откроет приложение, вы можете запросить базу данных SQLite, используя адаптер базы данных, чтобы отобразить его маршрут.
Сценарий 2: Процесс адаптации
Изученные понятия: Обработка разрешений, отказы
Проблема
Вы создаете приложение для пожилых пациентов, позволяющее отслеживать блуждание. Вам необходимо разрешение «Всегда» для фонового определения местоположения. Если вы просто бросите им диалог системных разрешений, они запутаются, нажмите «Запретить», и приложение станет бесполезным.
Как Tracelet решает эту проблему
Tracelet никогда автоматически запрашивает разрешения. Он полностью оставляет поток пользовательского интерфейса на усмотрение вашего кода Flutter, позволяя вам показывать обучающие пользовательские диалоги перед запуском пугающих подсказок ОС.
import 'package:tracelet/tracelet.dart' as tl;
// 1. Check current status
final status = await tl.Tracelet.requestLocationAuthorization();
// 2. The user permanently denied permission in the past
if (status == tl.AuthorizationStatus.deniedForever) {
// Show a beautifully designed Flutter dialog explaining WHY you need it.
// Add a button that calls:
await tl.Tracelet.openAppSettings();
return;
}
// 3. We haven't asked yet, or they selected "Ask Next Time"
if (status == tl.AuthorizationStatus.notDetermined || status == tl.AuthorizationStatus.denied) {
// Ask for foreground permission first
final result = await tl.Tracelet.requestLocationAuthorization();
if (result == tl.AuthorizationStatus.whenInUse) { // They granted "When In Use"
// Show a second Flutter dialog explaining why "Always" is needed.
// Then upgrade the permission:
await tl.Tracelet.requestLocationAuthorization();
}
} Location Status
Tracelet.requestLocationAuthorization() возвращает перечисление AuthorizationStatus:
notDetermined: Вы еще не спросили.denied: пользователю отказано (можно спросить еще раз на Android).whenInUse: разрешен только передний план.always: предоставлен фоновый доступ.deniedForever: пользователь отметил флажок «Больше не спрашивать», или iOS навсегда отклонила запрос. Вы ДОЛЖНЫ отправить их в настройки.