URLQueryItems中特殊字符未被正确编码。

6

我需要在我的应用程序中创建Firebase深度链接,以便使用UIActivityViewController在不同平台上共享它们。 为了创建这些链接,我使用以下代码和URLQueryItem来获取我将与其他应用程序共享的URL:

func createURLWithComponents(EventToUrl: Event) -> URL? {

    var urlComponents = URLComponents()
    urlComponents.scheme = "https"
    urlComponents.host = "www.example.com"
    urlComponents.path = "/"

    // add params
    let id = URLQueryItem(name: "id", value: EventToUrl.eventID)

    print(EventToUrl.name)
    let name = URLQueryItem(name: "name", value: EventToUrl.name)
    print(name.description)
    print(name.value)
    let photo = URLQueryItem(name: "photo", value:  EventToUrl.photoUrl)
    let created = URLQueryItem(name: "created", value: EventToUrl.creationDate )
    let participants = URLQueryItem(name: "participants", value: String(EventToUrl.Participants.count) )
    let place = URLQueryItem(name: "place", value: EventToUrl.Places[0].name)
    let time = URLQueryItem(name: "time", value: EventToUrl.time[0].TimestampString)
    urlComponents.queryItems = [id, name, photo, created, participants , place , time]

    let dynamicLinkDomain : String = "***.app.goo.gl"
    var deepLink = URLComponents()
    deepLink.scheme = "https"
    deepLink.host = dynamicLinkDomain
    deepLink.path = "/"

    let link = URLQueryItem(name: "link", value:  urlComponents.url?.absoluteString)
    let apn = URLQueryItem(name: "apn", value: "***" )
    let ibi = URLQueryItem(name: "ibi", value: "***" )
    let d = URLQueryItem(name: "d", value: "1")
    deepLink.queryItems = [link, apn, ibi, d]
    print(deepLink.url?.absoluteString)
    print(deepLink.url)

    return deepLink.url
}

这是我发送给他的链接:
https://***.app.goo.gl/?link=https://www.example.com/?id%3D-KZYfNRCXdSqUG72FmEQ%26name%3Djeremie's%2520Event%26photo%3D%26created%3D%26participants%3D1%26place%3DLa%2520Piazza%26time%3D1482362284.50304&apn=***&ibi=***&d=1

https://.app.goo.gl/?link=https://www.example.com/?id%3D-KZYfNRCXdSqUG72FmEQ%26name%3Djeremie's%2520Event%26photo%3D%26created%3D%26participants%3D1%26place%3DLa%2520Piazza%26time%3D1482362284.50304&apn=&ibi=***&d=1

如您所见,如果活动名称包含“ ' ”字符(Jeremie's event),URLQueryItem将无法正确编码此字符(在我的Android应用程序中,系统功能会将其转换为“'” -->%27)。我该如何对其进行编码? PS:我尝试使用 addingPercentEncoding(withAllowedCharacters: .urlFragmentAllowed),但没有成功... 谢谢您的帮助!


1
是的,这真的很令人沮丧,因为它无法正确编码+字符。你要么使用.urlQueryAllowed并删除一些字符,要么自己手动构建。请参见 https://dev59.com/oJTfa4cB1Zd3GeqPXeqS#35912606(适用于Swift 2)或https://dev59.com/yZnga4cB1Zd3GeqPa5mP#38798445(适用于Swift 3)。 - Rob
@Rob 如果我想使用你的解决方案(第一个带扩展名的)https://dev59.com/oJTfa4cB1Zd3GeqPXeqS#35912606,我应该在 func URLQueryParameterAllowedCharacterSet() 中添加 " ' "字符吗? - jerem
不,你不想添加它。如果允许的字符集中没有它,你想要将其排除在外,这样它就会被百分号转义。 - Rob
1个回答

2
我发现一个解决方案比其他的简单一些(至少对我来说是这样)。我按照正常方式构建了我的URLComponents,但在获取url之前,我取出了urlComponents.string并用符号替换了特殊代码。我将该字符串通过addingPercentEncoding运行,然后从该字符串生成url。
let stringWithoutBS = urlComponents.string!.replacingOccurrences(of: "%27", with: "'")
        //ignore the force unwrap

guard let encodedURL = stringWithoutBS.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed) else {
            print("unhelpful message")
            return nil
        }

var correctURL = URL(string: encodedURL)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接