Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CarPlay app required Flutter App open first? #12

Open
ankiimation opened this issue Apr 1, 2022 · 15 comments · May be fixed by #25
Open

CarPlay app required Flutter App open first? #12

ankiimation opened this issue Apr 1, 2022 · 15 comments · May be fixed by #25
Labels
let's discuss Let's discuss this issue question Further information is requested

Comments

@ankiimation
Copy link

I think CarPlay app can start itself with out starting Flutter App first

@oguzhnatly
Copy link
Owner

oguzhnatly commented Apr 1, 2022

Hello @ankiimation,

That method you mentioned is not recommended because we set the root template of the CarPlay App in the Flutter App's initial state. As a result, if the flutter app is never opened after installation, you may see a black screen or crash directly. The CarPlay app may be displayed successfully after the first opening of the flutter app, but it may not function properly. That is why it is recommended to use the app. Currently, the Flutter App must be opened first to see the CarPlay app screens/templates.

I also highly recommend creating a graphic art for the carplay app when it is not open, as this will notify the user of the need to open the app first.

@oguzhnatly oguzhnatly added question Further information is requested let's discuss Let's discuss this issue labels Apr 1, 2022
@ankiimation
Copy link
Author

Hello @ankiimation,

That method you mentioned is not recommended because we set the root template of the CarPlay App in the Flutter App's initial state. As a result, if the flutter app is never opened after installation, you may see a black screen or crash directly. The CarPlay app may be displayed successfully after the first opening of the flutter app, but it may not function properly. That is why it is recommended to use the app.

I also highly recommend creating a graphic art for the carplay app when it is not open, as this will notify the user of the need to open the app first.

ok bro, love it

@snipd-mikel
Copy link

Hi @ankiimation,

I have found a way to launch the Flutter app when starting the app through the CarPlay interface when the app is not running on the foreground. The solution is based on this blog post: https://adapptor.com.au/blog/enhance-existing-apps-with-carplay where they solve it for ReactNative.

The main idea is to move the FlutterEngine creation to the AppDelegate, which will be run when the app is launched from anywhere (CarPlay or device). We can run the FlutterEngine in headless mode, so the dart code can run before the engine is attached to any actual view (which happens when launching the app first on the CarPlay). Then, on the SceneDelegate we reuse the engine and attach it to the actual view.

So the AppDelegate.swift will be like this:

import UIKit
import Flutter

let flutterEngine = FlutterEngine(name: "SharedEngine", project: nil, allowHeadlessExecution: true)

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application( _ application: UIApplication,
                             didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    
    flutterEngine.run()
    GeneratedPluginRegistrant.register(with: flutterEngine)

    return super.application(application, didFinishLaunchingWithOptions: launchOptions);
    
  }
}

and the SceneDelegate.swift like this:

@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        guard let windowScene = scene as? UIWindowScene else { return }

        window = UIWindow(windowScene: windowScene)
        let controller = FlutterViewController.init(engine: flutterEngine, nibName: nil, bundle: nil)
        window?.rootViewController = controller
        window?.makeKeyAndVisible()
    }
}

With this we have the dart code running when the user launches the app from the CarPlay interface. However, some changes are needed on this plugin as well, as it will fail to update the rootInterface if it was null when launching the CarPlayScene. The solution here is to modify the FlutterCarplayPluginSceneDelegate so it doesn't set the interfaceController to nil if the rootTemplate is not set at startup. You have to replace the templateApplicationScene with the following snippet:

func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene,
                                didConnect interfaceController: CPInterfaceController) {
    FlutterCarPlaySceneDelegate.interfaceController = interfaceController
    
    SwiftFlutterCarplayPlugin.onCarplayConnectionChange(status: FCPConnectionTypes.connected)
    let rootTemplate = SwiftFlutterCarplayPlugin.rootTemplate
    
    if rootTemplate != nil {
      FlutterCarPlaySceneDelegate.interfaceController?.setRootTemplate(rootTemplate!, animated: SwiftFlutterCarplayPlugin.animated, completion: nil)
    }
  }

Then on your dart code, after setting the root template using FlutterCarplay.setRootTemplate you have to force the plugin to update the displayed template using: _flutterCarplay.forceUpdateRootTemplate();

With this you should be able to run the app when the user opens it on the CarPlay.

I have a branch with this changes here: snipd-mikel@a4a201c

@oguzhnatly Would it be possible to merge the changes onto the main repository? Only the ones on this file FlutterCarplayPluginSceneDelegate are actually needed to be included on the plugin. The rest of the changes could be part of the README. If you are interested I can work on a PR to have this ready.

@ankiimation
Copy link
Author

@snipd-mikel
Love your work bro. I already have made my flutter navigation app run on CarPlay without open it on the device first. The same as you, I created a static FlutterEngine in AppDelegate.

@ankiimation
Copy link
Author

ankiimation commented Jun 8, 2022

But there some issues when we run Flutter app on CarPlay without open it on the device first:

  • dart:ui: I can't turn into ui.Image and draw images(assets, network) on canvas
  • navigator: I'm using AutoRouter and cant push to other screens
  • ...
    But luckily, all other functions are still OK haha

@snipd-mikel
Copy link

Thanks for the info. I haven't yet run into many issues, as most of what I need on the CarPlay is not related to Flutter UI components. However, I encountered some issue where after some async event the UI was not being updated (I needed that to start the authentication flow) . I had to manually call WidgetsBinding.instance.scheduleForcedFrame(); to force it to update.

@vanlooverenkoen
Copy link

I don't think this issue should be closed. At least it should be documented. On what the recommended way should be to implement this.

vanlooverenkoen added a commit to icapps/flutter_carplay that referenced this issue Sep 16, 2022
@ghost
Copy link

ghost commented Nov 16, 2022

I don't think this should be closed either. Have any of you encountered a bug, where there is a black screen after a splash? I think that's because initializing Flutter renderer overrides the splash, but I don't know how could I solve that

@ankiimation ankiimation reopened this Nov 20, 2022
@RedC4ke
Copy link

RedC4ke commented Nov 22, 2022

TO ANYONE WHO STRUGGLES WITH SPLASHSCREENS ON IOS

I've found out that the only thing needed here is to add
controller.loadDefaultSplashScreenView()
in @snipd-mikel solution after controller initialization. Now it works like a charm :)

@RedC4ke
Copy link

RedC4ke commented Nov 22, 2022

Also I don't think that this is an ideal solution, won't it create two engines sometimes? Bc I keep getting some old view for a split second before the splashscreen

daniel-naegele added a commit to daniel-naegele/flutter_carplay that referenced this issue Jan 12, 2023
…ackground

oguzhnatly#12: Added support for flutter to start in the background. Even when …
igmt added a commit to igmt/flutter_carplay that referenced this issue Jul 24, 2023
oguzhnatly#12: Added support for flutter to start in the background. Even when …
@harryandroiddev
Copy link

After these changes i cannot login with facebook when i have the fb app installed .

@zhushenwudi
Copy link

Thanks for the info. I haven't yet run into many issues, as most of what I need on the CarPlay is not related to Flutter UI components. However, I encountered some issue where after some async event the UI was not being updated (I needed that to start the authentication flow) . I had to manually call WidgetsBinding.instance.scheduleForcedFrame(); to force it to update.

I use GetX for status management, but when I try to open CarPlay first and then start the mobile app, I find that GetX is invalid. Have you ever experienced a similar situation?

@marcolettieri
Copy link

marcolettieri commented Feb 2, 2024

@harryandroiddev i've solved just with this in SceneDelegate:

 if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
      appDelegate.window = window
  }

@derrik-fleming
Copy link

derrik-fleming commented Oct 28, 2024

It doesn't seem like this works anymore. After attempting to use the solution mentioned in this comment in my app and having no success, I pulled down the linked repo and found I got the same results. App will open on CarPlay, it appears main is executed, but none of the CarPlay methods function as intended. The result is a blank screen until the app is closed on CarPlay, opened on mobile, and then re-opened on CarPlay.

Am I missing something?

@richanshah
Copy link

it is not working for me

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
let's discuss Let's discuss this issue question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants