The '#' char gets converted to %23 causing the GET Request to fail - ios

I am a new Swift developer using Swift 3 developing an iOS app. I need to make a URL Request to get some data from the web. That URL contains a # character.
I use URLComponents with URLQueryItems to build the request URL. During this process the # char gets converted to %23 which I think is valid utf8 encoding. Unfortunately, this causes the GET to fail.
To test I pasted the URL into my browser and changed %23 back to # and it worked just fine.
How can I fix this so it does not change # to URL. I did find a post from a couple years ago but it was using old framework items so it does not apply to me.
Below is the playground I made to illustrate and test this.
// ------------------------------------------------------------------
//: Playground - TestBuildURLWithParameters
//
// I am using this playground to build the proper
// URL for the GET request to get the detailed
// rtesults for a specific athlete where the "Key"
// is their Bib Nbr. If the GET cant find the specific
// Atlete with that URL it redirects you to the list
// of athlete results (which is no go to me in this case)
//
// Currently, there is a big "gotcha". In building the URL
// using component and query items, the foundation classes
// replace the '#' sign in the URL with the %23 which represents
// the pound sign. Unfortunately, the causes the GET to fail
// and redirects to athlete list which is not helpful
// I am still trying to figure out how to FORCE it to keep
// the '#" character in the URL so it will work
//
// ------------------------------------------------------------------
import Foundation
import UIKit
let baseURLString = "http://www.ironman.com/triathlon/events/americas/ironman-70.3/augusta/results.aspx"
let rd = "20150927"
let race = "augusta70.3"
let bibID = "93"
var detail = "1#axzz4FGGcjBOn"
print("Detail w/o unicocde: \(detail)")
detail = "1\u{0023}axzz4FGGcjBOn"
print("Detail with unicocde: \(detail)")
var components = URLComponents(string: baseURLString)!
var queryItems: [URLQueryItem] = [] // All Items after the "?"
let baseParams =
[
"rd": rd,
"race": race,
"bidID": bibID, // Note: HTML mispelled bib with bid so "bidID" is the URL search
"detail": detail
]
for (key, value) in baseParams
{
let item = URLQueryItem(name: key, value: value)
queryItems.append(item)
}
components.queryItems = queryItems // what does this look like
print("components: \(components)") // see it

It is not a good way to include fragment part of URL into query items.
Try this:
import Foundation
let baseURLString = "http://www.ironman.com/triathlon/events/americas/ironman-70.3/augusta/results.aspx"
let rd = "20150927"
let race = "augusta70.3"
let bibID = "93"
var detail = "1"
//# split the last query item and the fragment
let fragment = "axzz4FGGcjBOn"
var components = URLComponents(string: baseURLString)!
var queryItems: [URLQueryItem] = []
let baseParams =
[
"rd": rd,
"race": race,
"bidID": bibID,
"detail": detail
]
for (key, value) in baseParams
{
let item = URLQueryItem(name: key, value: value)
queryItems.append(item)
}
components.queryItems = queryItems
components.fragment = fragment
print("components: \(components)")

If you need you can choose the character that will receive the encoding.
In the charactersIn: you put all characters you want to encode.
Then you use the .inverted so all the others characters will go normal like this:
let customAllowedSet = NSCharacterSet(charactersIn:"=\"%/<>?#\\^`{|}").inverted
let encondedString = originalString.addingPercentEncoding(withAllowedCharacters: customAllowedSet)
print("enconded string: \(encondedString)")

Encode your parameters and then add it to URL, this will encode # before hitting API and you'll get desired result.
To encode parameters, you can use below code.
var parameterString = "your parameter string"
var encodedString = parameterString .addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(encodedString !)

I did get an answer via email from a friend that works for now. Basically, I added the query items manually to the URL using the URL extension below so it didn't monkey with the '#' char:
extension URL {
func appendingNonEscapedQueryItems(_ queryItems: [URLQueryItem]) -> URL {
let url = self
var urlString = url.absoluteString
for queryItem in queryItems {
let queryName = queryItem.name
guard let queryValue = queryItem.value else {
continue
}
let query = queryName + "=" + queryValue
if queryItem == queryItems.first {
urlString = urlString + "?" + query
}
else
{
urlString = urlString + "&" + query
}
}
return URL(string: urlString)!
}
}
...
let requestURL = components.url!.appendingNonEscapedQueryItems(queryItems)
print("URL \(requestURL)")

Related

Get the value of URL Parameters in WKWebView and create new URL

I'm trying to get the current URL of the WKWebView, search/copy one value out of it, and create a new URL.
I use Swift and have this an URL like that https://example.org/bundle-572974a2.html and try to get the following value 572974a2.
My intention is to create a new URL with that value. The numbers can change from time to time.
I use this code to get the current WKWebView URL. I think I have to convert this to a string first.
let oldURL = webView.url
And I use this code to create my new URL.
var components = URLComponents()
components.scheme = "https"
components.host = "new-example.org"
components.path = "/g"
components.queryItems = [
URLQueryItem(name: "newbundle", value: "XXXXXXXX")
]
let newURL = components.url
How can I change/paste the value: "XXXXXXXX" with the value 572974a2 of the old URL?
Some simple URL manipulation and string handling will get you the number from the old URL:
let oldURL = URL(string: "https://example.org/bundle-572974a2.html")! // An example
let name = oldURL.deletingPathExtension().lastPathComponent // bundle-572974a2
let number = name.dropFirst(7) // remove "bundle-"
This assumes the number will always be preceded by "bundle-" (or any seven-letter sequence really. If that can vary then the use of dropFirst(7) will need to be replaced with code that can handle strings like "bundle-572974a2" and remove the part you don't want.
Then building the new URL becomes:
var components = URLComponents()
components.scheme = "https"
components.host = "new-example.org"
components.path = "/g"
components.queryItems = [
URLQueryItem(name: "newbundle", value: String(number))
]
let newURL = components.url
In a case where you might have both a prefix and a suffix you need to remove, the following would be one way to remove them. This code assumes there will be a prefix to remove if there is a suffix to remove. If there is a suffix and no prefix to remove then this code gives the wrong result.
var number = url.deletingPathExtension().lastPathComponent
if let hyphen = number.firstIndex(of: "-") {
number = String(number[number.index(after: hyphen)...])
}
if let hyphen = number.lastIndex(of: "-") {
number = String(number[..<hyphen])
}
P.S. String manipulation in Swift is a pain.

Get correct parameter value from URL in "/:id=" format using regex

What is the best way to get the id value from this url:
URL(string: "urlScheme://search/:id=0001")
I've been trying to route this URL using a deep link request. However, my url routing solution JLRoutes shows the parameters as key = id and value = :id=0001.
I instead need the parameters to be key = id and value = "0001".
In an ideal world I would just be using a URL string like "urlScheme://search/0001" and not have any problem but the ":id=" part has to be in there. George's comment about converting the parameter to a URL in of itself and using .pathComponents.last does work, but I think a regex solution is probably going to scale better going forward.
The answer from #George should work fine, but two things struck me: you decided you wanted a regex solution, and to make this generic seemed to be asking for a recursive solution.
The below approach uses regex to identify up to the last /: delimiter, then has to do a bit of inelegant string handling to split it into the base string and the final pair of (key: value) params. I'd hoped to be able to write a regex that just matches those final parameters as that would be a far cleaner range to work with, but haven't managed it yet!
func paramsFrom(_ str: String) -> [String: String] {
guard let baseRange = str.range(of:#"^.+\/:"#, options: .regularExpression ) else { return [:] }
let base = String(str[baseRange].dropLast(2))
let params = str.replacingCharacters(in: baseRange, with: "").components(separatedBy: "=")
return [params.first! : params.last!].merging(paramsFrom(base)){(current, _) in current}
}
using this on your example string returns:
["id": "0001", "title": "256", "count": "100"]
EDIT:
Managed to dig out the old regex brain cells and match just the final pair of parameters. You could adapt the above to use the regex
(?<=\/:)[a-zA-Z0-9=]+$
and the have slightly cleaner string handling as the shortened base string becomes
String(str.dropLast(str[paramsRange].count))
If your URL is in the form of an actual URL query, e.g. urlScheme://search?id=0001, there is a nice way to do this.
With thanks to vadian, this is really simple. You can just do the following:
let components = URLComponents(string: "urlScheme://search?id=0001&a=2")!
let dict = components.queryItems?.reduce(into: [:]) { partialResult, queryItem in
partialResult[queryItem.name] = queryItem.value
}
Or a slightly more compact version for dict:
let dict = components.queryItems?.reduce(into: [:], { $0[$1.name] = $1.value })
Result from given input:
["id": "0001", "a": "2"]
If you must use the current URL form
You can replace the URL string, such as:
let urlStr = "urlScheme://search/:id=0001/:a=2"
let comps = urlStr.components(separatedBy: "/:")
let newUrl: String
if comps.count > 1 {
newUrl = "\(comps.first!)?\(comps.dropFirst().joined(separator: "&"))"
} else {
newUrl = urlStr
}
print(newUrl)
Prints: urlScheme://search?id=0001&a=2
Original answer (slightly modified)
If you have a URL with queries separated by /: you can use the following:
// Example with multiple queries
let url = URL(string: "urlScheme://search/:id=0001/:a=2")!
let queries = url.lastPathComponent.dropFirst().split(separator: "/:")
var dict = [String: String]()
for query in queries {
let splitQuery = query.split(separator: "=")
guard splitQuery.count == 2 else { continue }
let key = String(splitQuery.first!)
let value = String(splitQuery[1])
dict[key] = value
}
print(dict)
Result is same as before.
You can use next regex approach to enumerate parameters in your url path:
let urlString = "urlScheme://search/:id=0001" as NSString
let regex = try! NSRegularExpression(pattern: "([^:\\/]+)=([0-9]+)")
if let match = regex.matches(in: urlString as String, options: [], range: NSMakeRange(0, urlString.length)).first, match.numberOfRanges == 3 {
let key = urlString.substring(with: match.range(at: 1))
let value = urlString.substring(with: match.range(at: 2))
print(key, ":", value)
}
// Prints
id : 0001

Alamofire returning nil as response for google snap to road api call and shows Alamofire.AFError.invalidURL [duplicate]

If I encode a string like this:
var escapedString = originalString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
it doesn't escape the slashes /.
I've searched and found this Objective C code:
NSString *encodedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(
NULL,
(CFStringRef)unencodedString,
NULL,
(CFStringRef)#"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8 );
Is there an easier way to encode an URL and if not, how do I write this in Swift?
Swift 3
In Swift 3 there is addingPercentEncoding
let originalString = "test/test"
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
print(escapedString!)
Output:
test%2Ftest
Swift 1
In iOS 7 and above there is stringByAddingPercentEncodingWithAllowedCharacters
var originalString = "test/test"
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())
println("escapedString: \(escapedString)")
Output:
test%2Ftest
The following are useful (inverted) character sets:
URLFragmentAllowedCharacterSet "#%<>[\]^`{|}
URLHostAllowedCharacterSet "#%/<>?#\^`{|}
URLPasswordAllowedCharacterSet "#%/:<>?#[\]^`{|}
URLPathAllowedCharacterSet "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet "#%<>[\]^`{|}
URLUserAllowedCharacterSet "#%/:<>?#[\]^`
If you want a different set of characters to be escaped create a set:
Example with added "=" character:
var originalString = "test/test=42"
var customAllowedSet = NSCharacterSet(charactersInString:"=\"#%/<>?#\\^`{|}").invertedSet
var escapedString = originalString.stringByAddingPercentEncodingWithAllowedCharacters(customAllowedSet)
println("escapedString: \(escapedString)")
Output:
test%2Ftest%3D42
Example to verify ascii characters not in the set:
func printCharactersInSet(set: NSCharacterSet) {
var characters = ""
let iSet = set.invertedSet
for i: UInt32 in 32..<127 {
let c = Character(UnicodeScalar(i))
if iSet.longCharacterIsMember(i) {
characters = characters + String(c)
}
}
print("characters not in set: \'\(characters)\'")
}
You can use URLComponents to avoid having to manually percent encode your query string:
let scheme = "https"
let host = "www.google.com"
let path = "/search"
let queryItem = URLQueryItem(name: "q", value: "Formula One")
var urlComponents = URLComponents()
urlComponents.scheme = scheme
urlComponents.host = host
urlComponents.path = path
urlComponents.queryItems = [queryItem]
if let url = urlComponents.url {
print(url) // "https://www.google.com/search?q=Formula%20One"
}
extension URLComponents {
init(scheme: String = "https",
host: String = "www.google.com",
path: String = "/search",
queryItems: [URLQueryItem]) {
self.init()
self.scheme = scheme
self.host = host
self.path = path
self.queryItems = queryItems
}
}
let query = "Formula One"
if let url = URLComponents(queryItems: [URLQueryItem(name: "q", value: query)]).url {
print(url) // https://www.google.com/search?q=Formula%20One
}
Swift 4 & 5
To encode a parameter in URL I find using .alphanumerics character set the easiest option:
let urlEncoded = value.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
let url = "http://www.example.com/?name=\(urlEncoded!)"
Using any of the standard Character Sets for URL Encoding (like .urlQueryAllowed or .urlHostAllowed) won't work, because they do not exclude = or & characters.
Note that by using .alphanumerics it will encode some characters that do not need to be encoded (like -, ., _ or ~ -– see 2.3. Unreserved characters in RFC 3986). I find using .alphanumerics simpler than constructing a custom character set and do not mind some additional characters to be encoded. If that bothers you, construct a custom character set as is described in How to percent encode a URL String, like for example:
// Store allowed character set for reuse (computed lazily).
private let urlAllowed: CharacterSet =
.alphanumerics.union(.init(charactersIn: "-._~")) // as per RFC 3986
extension String {
var urlEncoded: String? {
return addingPercentEncoding(withAllowedCharacters: urlAllowed)
}
}
let url = "http://www.example.com/?name=\(value.urlEncoded!)"
Warning: The urlEncoded parameter is force unwrapped. For invalid unicode string it might crash. See Why is the return value of String.addingPercentEncoding() optional?. Instead of force unwrapping urlEncoded! you can use urlEncoded ?? "" or if let urlEncoded = urlEncoded { ... }.
Swift 5:
extension String {
var urlEncoded: String? {
let allowedCharacterSet = CharacterSet.alphanumerics.union(CharacterSet(charactersIn: "~-_."))
return self.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
}
}
print("\u{48}ello\u{9}world\u{7}\u{0}".urlEncoded!) // prints Hello%09world%07%00
print("The string ü#foo-bar".urlEncoded!) // prints The%20string%20%C3%BC%40foo-bar
Swift 3:
let originalString = "http://www.ihtc.cc?name=htc&title=iOS开发工程师"
1. encodingQuery:
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)
result:
"http://www.ihtc.cc?name=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88"
2. encodingURL:
let escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
result:
"http:%2F%2Fwww.ihtc.cc%3Fname=htc&title=iOS%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88"
Swift 4 & 5 (Thanks #sumizome for suggestion. Thanks #FD_ and #derickito for testing)
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: ";/?:#&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
Swift 3
let allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed.remove(charactersIn: ";/?:#&=+$, ")
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
Swift 2.2 (Borrowing from Zaph's and correcting for url query key and parameter values)
var allowedQueryParamAndKey = NSCharacterSet(charactersInString: ";/?:#&=+$, ").invertedSet
paramOrKey.stringByAddingPercentEncodingWithAllowedCharacters(allowedQueryParamAndKey)
Example:
let paramOrKey = "https://some.website.com/path/to/page.srf?a=1&b=2#top"
paramOrKey.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey)
// produces:
"https%3A%2F%2Fsome.website.com%2Fpath%2Fto%2Fpage.srf%3Fa%3D1%26b%3D2%23top"
This is a shorter version of Bryan Chen's answer. I'd guess that urlQueryAllowed is allowing the control characters through which is fine unless they form part of the key or value in your query string at which point they need to be escaped.
Swift 4:
It depends by the encoding rules followed by your server.
Apple offer this class method, but it don't report wich kind of RCF protocol it follows.
var escapedString = originalString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
Following this useful tool you should guarantee the encoding of these chars for your parameters:
$ (Dollar Sign) becomes %24
& (Ampersand) becomes %26
+ (Plus) becomes %2B
, (Comma) becomes %2C
: (Colon) becomes %3A
; (Semi-Colon) becomes %3B
= (Equals) becomes %3D
? (Question Mark) becomes %3F
# (Commercial A / At) becomes %40
In other words, speaking about URL encoding, you should following the RFC 1738 protocol.
And Swift don't cover the encoding of the + char for example, but it works well with these three # : ? chars.
So, to correctly encoding each your parameter , the .urlHostAllowed option is not enough, you should add also the special chars as for example:
encodedParameter = parameter.replacingOccurrences(of: "+", with: "%2B")
Hope this helps someone who become crazy to search these informations.
Everything is same
var str = CFURLCreateStringByAddingPercentEscapes(
nil,
"test/test",
nil,
"!*'();:#&=+$,/?%#[]",
CFStringBuiltInEncodings.UTF8.rawValue
)
// test%2Ftest
Swift 4.2
A quick one line solution. Replace originalString with the String you want to encode.
var encodedString = originalString.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: "!*'();:#&=+$,/?%#[]{} ").inverted)
Online Playground Demo
This is working for me in Swift 5. The usage case is taking a URL from the clipboard or similar which may already have escaped characters but which also contains Unicode characters which could cause URLComponents or URL(string:) to fail.
First, create a character set that includes all URL-legal characters:
extension CharacterSet {
/// Characters valid in at least one part of a URL.
///
/// These characters are not allowed in ALL parts of a URL; each part has different requirements. This set is useful for checking for Unicode characters that need to be percent encoded before performing a validity check on individual URL components.
static var urlAllowedCharacters: CharacterSet {
// Start by including hash, which isn't in any set
var characters = CharacterSet(charactersIn: "#")
// All URL-legal characters
characters.formUnion(.urlUserAllowed)
characters.formUnion(.urlPasswordAllowed)
characters.formUnion(.urlHostAllowed)
characters.formUnion(.urlPathAllowed)
characters.formUnion(.urlQueryAllowed)
characters.formUnion(.urlFragmentAllowed)
return characters
}
}
Next, extend String with a method to encode URLs:
extension String {
/// Converts a string to a percent-encoded URL, including Unicode characters.
///
/// - Returns: An encoded URL if all steps succeed, otherwise nil.
func encodedUrl() -> URL? {
// Remove preexisting encoding,
guard let decodedString = self.removingPercentEncoding,
// encode any Unicode characters so URLComponents doesn't choke,
let unicodeEncodedString = decodedString.addingPercentEncoding(withAllowedCharacters: .urlAllowedCharacters),
// break into components to use proper encoding for each part,
let components = URLComponents(string: unicodeEncodedString),
// and reencode, to revert decoding while encoding missed characters.
let percentEncodedUrl = components.url else {
// Encoding failed
return nil
}
return percentEncodedUrl
}
}
Which can be tested like:
let urlText = "https://www.example.com/폴더/search?q=123&foo=bar&multi=eggs+and+ham&hangul=한글&spaced=lovely%20spam&illegal=<>#top"
let url = encodedUrl(from: urlText)
Value of url at the end: https://www.example.com/%ED%8F%B4%EB%8D%94/search?q=123&foo=bar&multi=eggs+and+ham&hangul=%ED%95%9C%EA%B8%80&spaced=lovely%20spam&illegal=%3C%3E#top
Note that both %20 and + spacing are preserved, Unicode characters are encoded, the %20 in the original urlText is not double encoded, and the anchor (fragment, or #) remains.
Edit: Now checking for validity of each component.
For Swift 5 to endcode string
func escape(string: String) -> String {
let allowedCharacters = string.addingPercentEncoding(withAllowedCharacters: CharacterSet(charactersIn: ":=\"#%/<>?#\\^`{|}").inverted) ?? ""
return allowedCharacters
}
How to use ?
let strEncoded = self.escape(string: "http://www.edamam.com/ontologies/edamam.owl#recipe_e2a1b9bf2d996cbd9875b80612ed9aa4")
print("escapedString: \(strEncoded)")
Had need of this myself, so I wrote a String extension that both allows for URLEncoding strings, as well as the more common end goal, converting a parameter dictionary into "GET" style URL Parameters:
extension String {
func URLEncodedString() -> String? {
var escapedString = self.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
return escapedString
}
static func queryStringFromParameters(parameters: Dictionary<String,String>) -> String? {
if (parameters.count == 0)
{
return nil
}
var queryString : String? = nil
for (key, value) in parameters {
if let encodedKey = key.URLEncodedString() {
if let encodedValue = value.URLEncodedString() {
if queryString == nil
{
queryString = "?"
}
else
{
queryString! += "&"
}
queryString! += encodedKey + "=" + encodedValue
}
}
}
return queryString
}
}
Enjoy!
This one is working for me.
func stringByAddingPercentEncodingForFormData(plusForSpace: Bool=false) -> String? {
let unreserved = "*-._"
let allowed = NSMutableCharacterSet.alphanumericCharacterSet()
allowed.addCharactersInString(unreserved)
if plusForSpace {
allowed.addCharactersInString(" ")
}
var encoded = stringByAddingPercentEncodingWithAllowedCharacters(allowed)
if plusForSpace {
encoded = encoded?.stringByReplacingOccurrencesOfString(" ", withString: "+")
}
return encoded
}
I found above function from this link: http://useyourloaf.com/blog/how-to-percent-encode-a-url-string/.
let Url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")
None of these answers worked for me. Our app was crashing when a url contained non-English characters.
let unreserved = "-._~/?%$!:"
let allowed = NSMutableCharacterSet.alphanumeric()
allowed.addCharacters(in: unreserved)
let escapedString = urlString.addingPercentEncoding(withAllowedCharacters: allowed as CharacterSet)
Depending on the parameters of what you are trying to do, you may want to just create your own character set. The above allows for english characters, and -._~/?%$!:
What helped me was that I created a separate NSCharacterSet and used it on an UTF-8 encoded string i.e. textToEncode to generate the required result:
var queryCharSet = NSCharacterSet.urlQueryAllowed
queryCharSet.remove(charactersIn: "+&?,:;#+=$*()")
let utfedCharacterSet = String(utf8String: textToEncode.cString(using: .utf8)!)!
let encodedStr = utfedCharacterSet.addingPercentEncoding(withAllowedCharacters: queryCharSet)!
let paramUrl = "https://api.abc.eu/api/search?device=true&query=\(escapedStr)"
SWIFT 4.2
Sometimes this happened just because there is space in slug OR absence of URL encoding for parameters passing through API URL.
let myString = self.slugValue
let csCopy = CharacterSet(bitmapRepresentation: CharacterSet.urlPathAllowed.bitmapRepresentation)
let escapedString = myString!.addingPercentEncoding(withAllowedCharacters: csCopy)!
//always "info:hello%20world"
print(escapedString)
NOTE : Don't forget to explore about bitmapRepresentation.
version:Swift 5
// space convert to +
let mstring = string.replacingOccurrences(of: " ", with: "+")
// remove special character
var allowedQueryParamAndKey = NSCharacterSet.urlQueryAllowed
allowedQueryParamAndKey.remove(charactersIn: "!*'\"();:#&=+$,/?%#[]%")
return mstring.addingPercentEncoding(withAllowedCharacters: allowedQueryParamAndKey) ?? mstring
Swift 5
You can try .afURLQueryAllowed option if you want to encode string like below
let testString = "6hAD9/RjY+SnGm&B"
let escodedString = testString.addingPercentEncoding(withAllowedCharacters: .afURLQueryAllowed)
print(escodedString!)
//encoded string will be like en6hAD9%2FRjY%2BSnGm%26B

Unable to encode String for URL in Swift 3

I used to develop iOS Apps using Objective-C. Now I have recently migrated to Swift. In my app, I have a button that opens MS Outlook App with the pre-filled Subject and Body.
I did a similar App in Objective-C and used the below code to Encode my String for URL.
NSString *emailSubject = #"Test Subject";
NSString *encodedSubject = [emailSubject stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]];
Now I am unable to do the same in Swift 3. Below is the code that I tried.
var subjectText: String = "Test Subject"
var encodedSubject = subjectText.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
var stringURL: String = "ms-outlook://compose?subject=" + subjectText + "&body=TestingEmailNow"
// Convert the string to a URL.
var url = URL(string: stringURL)
// Open the app that responds to the URL scheme (should be Outlook).
UIApplication.shared.openURL(url!)
The error that I am getting is below.
fatal error: unexpectedly found nil while unwrapping an Optional value
2017-06-07 04:29:35.158030+0400 My App[1286:405793] fatal error: unexpectedly found nil while unwrapping an Optional value
I know that this error is coming due to the space in my Subject. I can say this because if I remove the space, I don't even have to encode it. It works directly. What am I doing wrong over here?
You made a simple mistake.
check your line
var stringURL: String = "ms-outlook://compose?subject=" + subjectText + "&body=TestingEmailNow"
you are using subjectText instead of encodedSubject
Complete code:
var subjectText: String = "Test Subject"
var encodedSubject = subjectText.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
if let encodedSubject = encodedSubject {
var stringURL: String = "ms-outlook://compose?subject=" + encodedSubject + "&body=TestingEmailNow"
// Convert the string to a URL.
var url = URL(string: stringURL)
if let url = url {
// Open the app that responds to the URL scheme (should be Outlook).
UIApplication.shared.openURL(url)
}
}
Variable used was the problem but I'd also suggest using URLComponents instead of building the URL as string.
var subjectText: String = "Test Subject"
var components = URLComponents()
components.scheme = "ms-outlook"
components.host = "compose"
components.queryItems = [
URLQueryItem(name: "subject", value: subjectText),
URLQueryItem(name: "body", value: "TestingEmailNow")
]
if let url = components.url {
UIApplication.shared.openURL(url)
}

How to send litter '&' as url parameter - swift

I have a code to update name of department in the database .. I use this encoding code :
let myurlstring="http:example/updateDepartment.php?deptName="+"\(deptName)"+"&id="+"\(deptID)"
let escapedString = myurlstring.addingPercentEncoding(withAllowedCharacters:NSCharacterSet.urlQueryAllowed)
let myUrl = URL(string:escapedString!)!
It works very well , but when deptName string contains this litter & it's not working.
example1 : send request with deptName = "CIT and Network" it will work .
example2 : send request with deptName = "CIT & Network" will be in the database as only "CIT" any litter after & will be skipped.
any help ?
Use URLComponents + URLQueryItem instead. It can be used to encode the query part from structured input:
var comp = URLComponents(string: "http://example.com")!
comp.path = "/some path to/update.php"
comp.queryItems = [
URLQueryItem(name: "deptName", value: "CIT & Network"),
URLQueryItem(name: "id", value: "123456"),
]
let url = comp.url!
print(url)
// http://example.com/some%20path%20to/update.php?deptName=CIT%20%26%20Network&id=123456

Resources