Перейти к основному содержимому

Навигация и маршрутизация

Переходы между экранами — и внятный ответ на вопрос «где я сейчас», который переживает deep link, системную кнопку «Назад», адресную строку браузера и приложение, восстановленное из фона.

Почему это важно. Навигация кажется мелочью ровно до того момента, когда приложению нужно открыться на конкретном экране по уведомлению, восстановить состояние после того, как система его выгрузила, или работать в вебе со ссылкой, которой можно поделиться. Вкрутить настоящую модель маршрутизации в приложение, собранное на разрозненных push, — один из самых дорогих рефакторингов, какие бывают.

Что нужно понимать

  • Что такое текущее местоположение, если выразить его данными, а не стеком вызовов
  • Что должно происходить по «Назад» с каждого экрана, включая первый
  • Какие экраны обязаны открываться по ссылке или по уведомлению
  • Где место проверкам доступа — пользователь не вошёл, не прошёл onboarding, не имеет прав
  • Что передаётся между экранами, а что правильнее загрузить на месте

Основные темы

Модели

  • Императивный Navigator.push и предел, за которым он перестаёт масштабироваться
  • Декларативная маршрутизация: местоположение — это состояние, стек выводится из него
  • Именованные маршруты, типизированные маршруты и почему строки со временем становятся обузой
  • Вложенные навигаторы и отдельный стек на каждую вкладку

Настоящие требования

  • Deep links и app links, включая верификацию на каждой платформе
  • URL в вебе и честный ответ на вопрос, что в них обязано быть
  • Восстановление после того, как процесс убили
  • Проверки и редиректы, которые нельзя обойти прямой ссылкой

Передача данных

  • Параметры пути и query-параметры против объектов в памяти
  • Передать id и загрузить, а не передавать модель целиком
  • Возврат результата с экрана
  • Маршрут, который можно описать, — чтобы воссоздать его с нуля

Мелочи, на которых обжигаются

  • Кнопка «Назад» в Android против свайпа в iOS и predictive back
  • Двойное нажатие, открывающее экран дважды
  • Диалоги, шторки — и место ли им в стеке
  • Анимации переходов и то, где они описаны

Уровни

УровеньКак это выглядит
JuniorОткрывает и закрывает экраны, передаёт аргументы, обрабатывает кнопку «Назад».
MiddleРаботает с декларативным роутером и типизированными маршрутами, делает deep links и проверки доступа, справляется с вложенными стеками.
SeniorПроектирует маршрутизацию так, что у любого состояния есть адрес и его можно восстановить; понимает поведение стека на разных платформах и при холодном старте.

Практика

Для начала

  • Открыть по ссылке Сделайте так, чтобы deep link открывал экран конкретного элемента, а стек «Назад» при этом оставался осмысленным.

  • Закрыть маршрут Уведите неавторизованного пользователя с защищённого экрана — в том числе при прямом входе по ссылке.

  • Убрать двойной переход Найдите кнопку, которая может открыть экран дважды, и почините это как следует.

Дальше

  • Дать адрес каждому состоянию Придумайте каждому экрану URL, который воссоздаёт его с холодного старта.

  • Вложить стек Сделайте вкладки, где каждая хранит свою историю, и добейтесь правильного поведения «Назад».

  • Вернуть результат Напишите экран выбора, который возвращает типизированное значение и корректно обрабатывает отмену.

Проверьте себя

  • На каждый ли экран вашего приложения можно попасть по ссылке — и нужно ли это?
  • Что происходит по «Назад» с первого экрана, если пользователь пришёл по deep link?
  • Что вы передаёте между экранами — идентификаторы или объекты, и почему?
  • Где у вас проверки доступа при навигации и можно ли обойти их прямой ссылкой?
  • Что делает приложение, когда его восстанавливают после выгрузки?
  • Какая часть навигационного кода сломается, если завтра добавить поддержку веба?

Материалы

  • Navigation and routing — официальный обзор: в том числе о том, когда императивного API достаточно, а когда уже нет.
  • go_router — пакет для декларативной маршрутизации, который поддерживает команда Flutter. Документация подробно разбирает редиректы, вложенность и deep links.
  • Router class reference — декларативная модель маршрутизации, лежащая в основе любого пакета-роутера. Читается плотно, но прочитать стоит до того, как выберете пакет: становится понятно, что именно все они оборачивают.
  • Deep linking — настройка на стороне платформ, где и делается большая часть настоящей работы.
  • Predictive back on Android — документация Android о поведении, которое приложениям на Flutter теперь приходится поддерживать.