Доступ к приложению Flutter с экрана CarPlay без предварительного открытия приложения

У меня есть приложение Flutter — простой онлайн-плеер, который использует flutter_carplay и audio_service. Я выпускаю это приложение только для iOS.

  1. Когда приложение запускается, оно загружает элементы, в которые можно играть. На мобильном устройстве это работает так, как и ожидалось.
  2. Если я запускаю приложение, а затем включаю его через CarPlay, на экране CarPlay все элементы отображаются правильно.
  3. Если приложение не запущено и я открываю его только через CarPlay, экран пуст. Мне кажется, приложение нужно сначала запустить, прежде чем оно сможет работать через CarPlay. Может ли кто-нибудь посоветовать, как добиться такого поведения (чтобы его можно было запускать напрямую из CarPlay)? Я считаю, что это может быть полезно для многих разработчиков, поскольку функциональность CarPlay во Flutter до сих пор недостаточно документирована.

Это точка входа приложения:

void main() async {
  await App.initApp(); // basic initialization (Firebase, ...)
  runApp(const App());
}

Это App виджет.

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        builder: (BuildContext context, Widget? child) {},
        home: HomePage()
    );
  }
}

Весь код, связанный с CarPlay, можно найти в HomePage:

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final FlutterCarplay _flutterCarplay = FlutterCarplay();

  @override
  void initState() {
    super.initState();
    initCarPlay();
  }

  @override
  Widget build(BuildContext context) {
    return ...;
  }

  void initCarPlay() {
    FlutterCarplay.setRootTemplate(
      rootTemplate: CPListTemplate(
        sections: [
          CPListSection(header: "Section 1", items: [
            CPListItem(text: "Item 1"),
            CPListItem(text: "Item 2"),
            CPListItem(text: "Item 3"),
          ]),
          CPListSection(header: "Section 2", items: [
            CPListItem(text: "Item 4"),
            CPListItem(text: "Item 5"),
            CPListItem(text: "Item 6"),
          ])
        ],
        showsTabBadge: false,
        systemIcon: "house.fill",
      ),
      animated: true,
    );

    _flutterCarplay.forceUpdateRootTemplate();
    _flutterCarplay.addListenerOnConnectionChange(_onCarplayConnectionChange);
  }

  void _onCarplayConnectionChange(CPConnectionStatusTypes status) {
    //
  }

  @override
  void dispose() {
    _flutterCarplay.removeListenerOnConnectionChange();
    super.dispose();
  }
}

Я пытался напрямую вызвать initCarPlay() в main(), но результат был тот же.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
128
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Во-первых, вам необходимо убедиться, что ваш метод initCarPlay вызывается даже тогда, когда приложение запускается из CarPlay. Кроме того, обрабатывайте события жизненного цикла CarPlay-specific, чтобы правильно инициализировать интерфейс CarPlay и гарантировать, что необходимые данные и службы инициализируются в фоновом режиме, чтобы приложение было готово к запуску из CarPlay.

Измененная функция main

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await App.initApp(); 
  runApp(const App());
}

App Виджет

class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      builder: (BuildContext context, Widget? child) {
       return MediaQuery(
         data: MediaQuery.of(context).copyWith(textScaleFactor: 1.0),
         child: child!,
       );
      },
      home: const HomePage(),
   );
  }
}

Изменён HomePage Экран

Убедитесь, что initCarPlay вызывается независимо от того, как запускается приложение.

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  final FlutterCarplay _flutterCarplay = FlutterCarplay();

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance?.addPostFrameCallback((_) => initApp());
    _flutterCarplay.addListenerOnConnectionChange(_onCarplayConnectionChange);
  }

  Future<void> initApp() async {
    initCarPlay();
  }

  void initCarPlay() {
    FlutterCarplay.setRootTemplate(
      rootTemplate: CPListTemplate(
        sections: [
          CPListSection(header: "Section 1", items: [
            CPListItem(text: "Item 1"),
            CPListItem(text: "Item 2"),
            CPListItem(text: "Item 3"),
          ]),
          CPListSection(header: "Section 2", items: [
            CPListItem(text: "Item 4"),
            CPListItem(text: "Item 5"),
            CPListItem(text: "Item 6"),
          ])
        ],
        showsTabBadge: false,
        systemIcon: "house.fill",
      ),
      animated: true,
    );

    _flutterCarplay.forceUpdateRootTemplate();
  }

  void _onCarplayConnectionChange(CPConnectionStatusTypes status) {
    if (status == CPConnectionStatusTypes.connected) {
      initCarPlay();
    }
  }

  @override
  void dispose() {
    _flutterCarplay.removeListenerOnConnectionChange();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('Home Page Content'),
      ),
    );
  }
}

Другие вопросы по теме