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

how to open flutter carplay with proper data without opening app? #56

Open
richanshah opened this issue Oct 17, 2024 · 34 comments
Open

Comments

@richanshah
Copy link

Steps to reproduce

Open app in carplay and mobile device both
Play any song from carplay
Kill the app from mobile and observe that carplay app also stopped
Now open the app in carplay only
Observe
You will see "Please wait while data fetching" on collections, playlists and songs screen when you kill the app and then open app in carplay
Also this happens when you close the app and go back into the app in carplay only then click music you just get spinning.

[✓] Flutter (Channel stable, 3.19.5, on macOS 14.2.1 23C71 darwin-arm64 (Rosetta), locale en-IN)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.0)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2023.1)

@viniciusoliverrs
Copy link

Hi, @richanshah. I managed to find the solution to this issue with the comment at this link #12 (comment) -1150229720

@richanshah
Copy link
Author

OK, Thanks I will give it a try.

@derrik-fleming
Copy link

@richanshah did you have any luck with the solution in the link provided? I was not able to get it working.

@viniciusoliverrs
Copy link

@derrik-fleming
"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();"

@richanshah
Copy link
Author

I tried above code but it is not working for me.

@derrik-fleming
Copy link

derrik-fleming commented Nov 5, 2024

@viniciusoliverrs I was able to get it working. But I have a question about something that doesn't seem to be working in the same way as it does when the app is launched from the mobile device.

Do you know how I could get an accurate value for FlutterCarplay.connectionStatus when launching the app from the CarPlay device? It is initialized with CPConnectionStatusTypes.unknown, and it doesn't seem like the connection changed events stream is getting initialized until after the event is generated. This results in an inaccurate status until another connection changed event occurs.

@richanshah
Copy link
Author

I'm trying to use FlutterCarplay.connectionStatus to retrieve the CarPlay connection status for fetching data when CarPlay opens without the app running. However, the status is not being returned consistently, which is causing some issues.

If you know of any workarounds or have suggestions on how to get a reliable connection status in this scenario, please let me know.

Thank you!

@harpreetslabs
Copy link

@richanshah did you manage to solve the issue when Carplay opens without opening app? i tried above solution but does not work, it shows blank screen when opens directly from carPlay.

@derrik-fleming
Copy link

derrik-fleming commented Nov 6, 2024

@richanshah did you manage to solve the issue when Carplay opens without opening app? i tried above solution but does not work, it shows blank screen when opens directly from carPlay.

@harpreetslabs Ensure the app is not still running on CarPlay in the background. Try uninstalling the app first before testing the above code if you have not already. Or open it on the mobile device first, then close (which will close the app on CarPlay), and then try opening it on the CarPlay device. It seems like if the app is running on CarPlay in the background you may continue to have a blank screen.

@harpreetslabs
Copy link

@richanshah did you manage to solve the issue when Carplay opens without opening app? i tried above solution but does not work, it shows blank screen when opens directly from carPlay.

@harpreetslabs Ensure the app is not still running on CarPlay in the background. Try uninstalling the app first before testing the above code if you have not already. Or open it on the mobile device first, then close (which will close the app on CarPlay), and then try opening it on the CarPlay device. It seems like if the app is running on CarPlay in the background you may continue to have a blank screen.

Yes, my question is how I can work by opening the app from carplay directly, instead of opening the flutter app first.

@harpreetslabs
Copy link

@derrik-fleming I noticed one thing, when we open directly from carplay it shows black screen, then on closing carplay and opening again works fine. (I have not opened the Flutter app yet).

@richanshah
Copy link
Author

no, I have still the same issue as yours.

@derrik-fleming I noticed one thing, when we open directly from carplay it shows black screen, then on closing carplay and opening again works fine. (I have not opened the Flutter app yet).

@harpreetslabs
Copy link

no, I have still the same issue as yours.

@derrik-fleming I noticed one thing, when we open directly from carplay it shows black screen, then on closing carplay and opening again works fine. (I have not opened the Flutter app yet).

Any workaround for this?

@derrik-fleming
Copy link

derrik-fleming commented Nov 7, 2024

@derrik-fleming I noticed one thing, when we open directly from carplay it shows black screen, then on closing carplay and opening again works fine. (I have not opened the Flutter app yet).

@harpreetslabs Are you using the connection events to determine if you should push templates on to CarPlay? The thing that I noticed with the solution in this thread is that when launching the app from CarPlay (without opening the mobile app) is that the connection status is never updated, so it remains in its initialized value (unknown) until another event occurs. The fact that it works for you on the second launch makes me think this might be part of your issue.

@richanshah
Copy link
Author

richanshah commented Nov 8, 2024 via email

@harpreetslabs
Copy link

@richanshah @derrik-fleming you can try this fork:
url: https://github.com/icapps/flutter_carplay.git # Where to find Repo
ref: combine-all # branch name
It works fine for me, it also have now playing, image from URL feature.
I have only one issue in this branch when the app is opened and the carplay is running, killing the app also kills the carplay.

@derrik-fleming
Copy link

@richanshah @derrik-fleming you can try this fork: url: https://github.com/icapps/flutter_carplay.git # Where to find Repo ref: combine-all # branch name It works fine for me, it also have now playing, image from URL feature. I have only one issue in this branch when the app is opened and the carplay is running, killing the app also kills the carplay.

That's neat. I think all of the apps included with iOS behave in that same manner. So, I'm not sure that I would consider that an issue, unless you want it to perform otherwise.

@richanshah
Copy link
Author

thanks but I don't want to kill carplay on killing the app.

@richanshah
Copy link
Author

apps included with iOS behave in that same manner. So, I'm not sure that I would consider that an issue, unless you want it to perform otherwise.

if you see Spotify or Youtube music it does not work that day.

@richanshah
Copy link
Author

https://stackoverflow.com/a/78546045/9248248

this works for me but the issue is I have lots of data for carplay so it takes more time in the app so it cause performance issue.

@Ella-Kim913
Copy link

I have a same issue, thanks @viniciusoliverrs this works on debug/release mode, but crash the app on testflight build. Any suggestions?

@viniciusoliverrs
Copy link

Eu tenho o mesmo problema, obrigado@viniciusoliverrsisso funciona no modo debug/release, mas trava o aplicativo na compilação testflight. Alguma sugestão?

Can you explain better?

@popeyelau
Copy link

popeyelau commented Nov 19, 2024

https://stackoverflow.com/a/78546045/9248248

this works for me but the issue is I have lots of data for carplay so it takes more time in the app so it cause performance issue.

//Firstly you can set an emtpy template for init
FlutterCarplay.setRootTemplate(
      rootTemplate: CPTabBarTemplate(
        templates: [
         TabPage1().get(),
         TabPage2().get(),
         TabPage3().get(),
        ],
      ),
      animated: true,
    );
carplay.forceUpdateRootTemplate();


// TabPage singleton
class  TabPage1 {
 static final TabPage1 _singleton = TabPage1._internal();
 CPListTemplate? template;
 List<CPListSection> sections = [];

  factory TabPage1() {
    return _singleton;
  }

  CPListTemplate get() {
    final template = CPListTemplate(
      sections: sections,
      title: "Title",
      emptyViewTitleVariants: [],
      systemIcon: "icon"
    );
    this.template = template;
    return template;
  }

  //call it when templateWillAppear 
  Future<void> refresh() async {
   if (sections.isNotEmpty) return;

   // fetch api data and setup list sections
   template?.udpate(sections);
  }
}

e.g:
FlutterCarPlaySceneDelegate templateWillAppear
https://github.com/popeyelau/flutter_carplay/blob/4265e31d5108f322e2cba497d41e09c5ea4d6b07/ios/Classes/FlutterCarplayPluginSceneDelegate.swift#L87

FCPListTemplate update
https://github.com/popeyelau/flutter_carplay/blob/4265e31d5108f322e2cba497d41e09c5ea4d6b07/ios/Classes/models/list/FCPListTemplate.swift#L79

@Ella-Kim913
Copy link

Eu tenho o mesmo problema, obrigado@viniciusoliverrsisso funciona no modo debug/release, mas trava o aplicativo na compilação testflight. Alguma sugestão?

Can you explain better?

I followed the necessary steps, and everything works fine in both debug and release modes. However, the app crashes only when building on TestFlight. The crash report points to CarPlay.

Updating CarPlay was the only change since the last successful TestFlight build.

Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Codes: 0x0000000000000001, 0x0000000000000000

static SwiftFlutterCarplayPlugin.register(with:) + 120 (SwiftFlutterCarplayPlugin.swift:31)

Has anyone experienced a similar issue or have any ideas about what could be causing this?

@harpreetslabs
Copy link

I'm trying to use FlutterCarplay.connectionStatus to retrieve the CarPlay connection status for fetching data when CarPlay opens without the app running. However, the status is not being returned consistently, which is causing some issues.

If you know of any workarounds or have suggestions on how to get a reliable connection status in this scenario, please let me know.

Thank you!

Have you solved this issue? I could not get the correct status if CarPlay was already open and then the app was opened.

@harpreetslabs
Copy link

@derrik-fleming @richanshah

I tried to check using native code and added method channels. It works for me, but can you please check if it works fine?

Here is the implementation:

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)
    
    let methodChannel = FlutterMethodChannel(
      name: "carplay_status_channel",
      binaryMessenger: flutterEngine.binaryMessenger 
    )
    
    methodChannel.setMethodCallHandler { (call, result) in
      if call.method == "isCarPlayConnected" {
        result(self.isCarPlayConnected())
      } else {
        result(FlutterMethodNotImplemented)
      }
    }
    
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  private func isCarPlayConnected() -> Bool {
    for screen in UIScreen.screens {
      if screen.traitCollection.userInterfaceIdiom == .carPlay {
        return true
      }
    }
    return false
  }
}

@richanshah
Copy link
Author

ok thanks @harpreetslabs will update u

@harpreetslabs
Copy link

@derrik-fleming @richanshah Does your app open correctly? I am experiencing an issue where, when I open the app, it first shows the previous state, then displays the splash screen, and finally starts the app.
Issue: #58

Screen.Recording.2024-11-25.at.1.04.15.PM.online-video-cutter.com.mp4

@richanshah
Copy link
Author

@harpreetslabs it works fine for me.

@richanshah
Copy link
Author

I'm trying to use FlutterCarplay.connectionStatus to retrieve the CarPlay connection status for fetching data when CarPlay opens without the app running. However, the status is not being returned consistently, which is causing some issues.
If you know of any workarounds or have suggestions on how to get a reliable connection status in this scenario, please let me know.
Thank you!

Have you solved this issue? I could not get the correct status if CarPlay was already open and then the app was opened.

no there is no direct way to get this. I am looking into this.

@harpreetslabs
Copy link

@harpreetslabs it works fine for me.

  1. Did you use the fork or this official project?
  2. Have u added support for background, if carplay opened without opening flutter app? I know this is due to adding flutter engine in app delegate. I am using this fork : https://github.com/icapps/flutter_carplay/tree/combine-all
    as this has done for background support, now playing features also.

@richanshah
Copy link
Author

official one.

@viniciusoliverrs
Copy link

viniciusoliverrs commented Nov 29, 2024

Try using the fork https://github.com/brasilflutter/flutter_carplay
I use this fork to solve my problem

@harpreetslabs
Copy link

Try using the fork https://github.com/brasilflutter/flutter_carplay I use this fork to solve my problem

Does this fork solve the issue when carplay opened without app opening?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants