istornz / flutter_live_activities

A Flutter plugin to use iOS 16.1+ Live Activities ⛹ī¸ & iPhone Dynamic Island 🏝ī¸ features
https://dimitridessus.fr/
MIT License
175 stars 54 forks source link

Fix: never intercept the applinks from 3rd plugins. #41

Closed etlevent closed 1 year ago

istornz commented 1 year ago

Ho @etlevent, can you elaborate why this is actually not working ? I just want to understand your fix before merging 👍

Thanks !

ggirotto commented 1 year ago

I think the issue here is that, according to FlutterApplicationLifeCycleDelegate docs, the function application:openURL:options: should return true only if the plugin handled the URL request. I read sometime ago in a Flutter thread (that I don't remember exactly which was) that if the application return true in these lifecycle functions, the Flutter engine doesn't trigger other possible plugins that may be using it as well (it stops the chaining call).

In this plugin context, I think the problem exists but the owner solution is not the correct one. The correct solution here is to check if url is targeted to this plugin specifically, and if yes, handles it and return true. If the url doesn't belong to this plugin, the function should return false so the Flutter engine can send it to be handled by other plugin that implementing this function.

The key question here is How to know ifurlis targeted to the current plugin? I'm assuming that these URLs are handled to allow this communication. In this case I suggest to force a specific URL scheme in the plugin implementation, so we would know for sure that this URL belong to the plugin by doing:

let components = URLComponents(url: url, resolvingAgainstBaseURL: false)

    if components?.scheme == nil || components?.scheme != "la" { return false } // UPDATE HERE

    var queryResult: Dictionary<String, Any> = Dictionary()

    queryResult["queryItems"] = components?.queryItems?.map({ (item) -> Dictionary<String, String> in
      var queryItemResult: Dictionary<String, String> = Dictionary()
      queryItemResult["name"] = item.name
      queryItemResult["value"] = item.value
      return queryItemResult
    })
    queryResult["scheme"] = components?.scheme
    queryResult["host"] = components?.host
    queryResult["path"] = components?.path
    queryResult["url"] = components?.url?.absoluteString

    urlSchemeSink?.self(queryResult)
    return true

This is just a suggestion, but the issue is also explained. If you follow this suggestion, the docs would need to be updated as well to indicate that this schema needs to be used from now on.

istornz commented 1 year ago

Thanks for the explanation @ggirotto, this is very clear. Your solution seems to be good to me. I'm just worry about breaking any app for apps using live_activities.

Example: If two apps are using this plugin, both will use la scheme...

Maybe let the user define the scheme is an option. What do you think about it?

ggirotto commented 1 year ago

Good callout. Yes, I think letting the user define its custom URL scheme is the best option here. This could be enforced just like the group id is used to initialize the plugin. The difference is that this initialization should be optional, because not everyone use this communication feature.

istornz commented 1 year ago

@ggirotto Perfect, I will try to implement this feature asap 👍

istornz commented 1 year ago

@ggirotto If you want to review the new PR you are welcome 👍

istornz commented 1 year ago

Closing this PR in favor of #50