I noticed that there is a problem on iOS 17 that didn’t occur on iOS 16. I’m trying to open another app which expects to receive a url (I can’t change the expected type). However, when I generate the URL, the 2 dots from of the https are eliminated.
Below is an example code very similar to the original:
extension URL {
public var addAppDomainPrefix : URL? {
let APP_DOMAIN : String = "APPTEST://"
var finalURL: URL? = URL(string: "(APP_DOMAIN)(self.absoluteString)")
return finalURL
}
}
In this case if my self.absoluteString is "https://www.google.it" I expect this result:
finalURL -> "APPTEST://https://www.google.it"
while instead I get this
finalURL -> "APPTEST://https//www.google.it"
Reading on various discussions in iOS 17 the way in which a URL is checked has been changed, however I also tried to use the encodingInvalidCharacters parameter but it doesn’t work anyway.
Could you help me? Thank you !
2
Answers
The short version: if you are using
APPTEST:
as the URL scheme, then you can’t puthttps:
into the hostname, even of a custom URL, where you’ve defined custom scheme’s format.I’ve only used
URL
framework sparingly in the last few years, but there is a clear trend of making incremental fixes, that this worked in iOS 16 should not lead to an assumption that this should continue to work in iOS 17.Having a ":" in a hostname is problematic, doing a DNS lookup on that is not going to work, esp. in the real world.
The problem is that in a URL, a colon is a reserved character and must not appear (unescaped) in either the domain name or in the first segment of the path. See RFC 3986: Section 3: Syntax Components.
Apple’s URL implementation conforms to this specification.
So, within these constraints, a few observations:
It must be noted that the
APPTEST:
URI really should not have the//
given that you do not have an “authority”, but rather are just providing a custom scheme with its own payload. Thus, it really should beAPPTEST:…
, notAPPTEST://…
.So, theoretically, you can use the following, which preserves the colon:
That appears to do the job for us here:
FWIW, Apple’s Defining a custom URL scheme for your app does not use
//
, either.If you must include the
//
for some reason, then you must conform to RFC 3986 and percent code reserved characters in the authority/host:And then you can do:
IMHO, this is an anti-pattern (building a URL, storing some arbitrary payload as the authority/host), but it might be a work-around in this particular case.
I should note that for both of these approaches,
canOpen
returnsfalse
, even thoughopen
works (setting aside the idiosyncracies of the app with which you are attempting to communicate). ThecanOpen
must be doing some additional URL validation that is not necessary.But, I would contend that, while I cannot defend Apple’s decision to simply omit the colon found in an authority/host in iOS 17 (it should either percent-escape it or just return
nil
), their attempt to adhere to RFC 3986 is understandable.But if that app with which you are interfacing requires the
//
, that violates section 3 of RFC 3986. And if the app is not accepting percent escaping of the://
in the URL payload, that also is a mistake on their part.