URLNavigator icon indicating copy to clipboard operation
URLNavigator copied to clipboard

Remove `scheme` requirement

Open lozhuf opened this issue 8 years ago • 6 comments

My app supports routing with multiple schemes (eg. myapp://, othertarget:// & https://), and I would like for the same URLOpenHandler to be called, no matter the scheme. I'm trying to migrate from JLRoutes (which can handle this), and coming up against the roadblock of the "Either matcher or URL should have scheme: '\(url)'" assertion in URLMatcher.

The way I would have assumed, and hoped, it would work is that if no scheme is provided when building the map, it is assumed to be a universal route and is matched no-matter the input URL's scheme (but if a scheme is provided in the map pattern, or the scheme property is set on URLNavigator, it is only matched when that scheme is input).

I understand that this would change expected behaviour for people already using the framework, but think it'd be a great addition to the project.

In the meantime, or if you dont feel it fits the goals of your work, do you have any suggestions as to how best to solve this problem otherwise? I guess mutating the input-URL's scheme to always be a primary scheme just before it is passed to the open(url:) method might work, but seems rather hacky.

Thanks!

lozhuf avatar Jun 19 '17 12:06 lozhuf

FYI, an implementation of the hacky solution I described at the bottom could look something like this:


extension URLNavigator {
    func initialize() {
        self.scheme = "myapp"
        self.map("/users/<userId>") { (url, values) -> Bool in
            // ... do stuff
            print(url, values)
            return true
        }
    }
    
    /// open the url, but first tries to apply the shared `scheme` to the url before matching
    func openNormalizedURL(_ url:URL) -> Bool {
        var components = URLComponents(url: url, resolvingAgainstBaseURL: true)
        components?.scheme = self.scheme
        if let normalizedSchemeURL = components?.url {
            return Navigator.open(normalizedSchemeURL)
        } else {
            return Navigator.open(url)
        }
    }
}

// eg. the following all hit the same `URLOpenHandler`
Navigator.initialize()

Navigator.openNormalizedURL(URL(string:"//users/abc123")!)
Navigator.openNormalizedURL(URL(string:"https://users/abc123")!)
Navigator.openNormalizedURL(URL(string:"myapp://users/abc123")!)
Navigator.openNormalizedURL(URL(string:"foo://users/abc123")!)

lozhuf avatar Jun 19 '17 13:06 lozhuf

Can you share the code that caused an error? I think this might work.

Navigator.map("myapp://users/<id>", handler)
Navigator.map("othertarget://users/<id>", handler)
Navigator.map("https://users/<id>", handler)

devxoul avatar Jun 20 '17 05:06 devxoul

For example:

Navigator.map("/users/<id>", handler)

// then later:
Navigator.open("myapp://users/abc123")

The issue is that a scheme is required to have been set (either with scheme property, or in the map(:) method) before any open calls are made. I was hoping for a situation where scheme can just be ignored completely, so it doesnt matter what scheme is passed to open().

lozhuf avatar Jun 20 '17 08:06 lozhuf

Hmm, I'm not sure that I completely understood. Is this what you want to do? For example:

Navigator.map("*://users/<id>", handler) // map wildcard scheme

Then the following open() executes same handler even if the anyscheme and hello is not registered? 🤔

Navigator.open("anyscheme://users/123")
Navigator.open("hello://users/123")
Navigator.open("world://users/123")

devxoul avatar Jun 20 '17 09:06 devxoul

Kind of, but without the need for the wildcard. I think the closest to what i'm talking is about is how JLRoutes handles it... this seems like a very flexible solution - see the Schemes section of their readme: https://github.com/joeldev/JLRoutes

lozhuf avatar Jun 21 '17 07:06 lozhuf

This is not supported yet. Maybe I can consider to add this feature on next major update but currently I don't think this is necessary for general purpose.

devxoul avatar Jun 21 '17 07:06 devxoul