Charlie Charlie - 7 months ago 47
Swift Question

AppleWatch Messages URL works hard coded but not with variables

TLDR When I hard code phone numbers into a URL it opens in watch messages correctly, but when I use a variable string with the numbers typed in exactly the same way inside of it, it doesn't.

Example:

NSURL(string: "sms:/open?addresses=8888888888,9999999999,3333333333&body=Test")


Above code works but below code doesn't:

let hardCode = "8888888888,9999999999,3333333333"
NSURL(string: "sms:/open?addresses=\(hardCode)&body=Test")


FULL DETAILS:
I am making a URL from variables to open messages on the Apple Watch with pre-filled contents. I am getting the phone numbers from the contact book and storing them in an array. They are provided in this format:

(###) ###-#### but need to be ##########

I tested the code by hard-coding phone numbers into the URL and it works properly with all contacts and completed body:

if let urlSafeBody = urlSafeBody, url = NSURL(string: "sms:/open?addresses=8888888888,9999999999,3333333333&body=\(urlSafeBody)") {
print("FINAL URL: \(url)")
WKExtension.sharedExtension().openSystemURL(url)
}


But when I build the phone number values programmatically it does not work:

//holds phone numbers without special chars
var tempArray: [String] = []

//if I can access the unformatted numbers
if let recips = saveData["recips"] as? [String] {
//for each number provided
recips.forEach { (person: String) in
//remove all non-numerical digits
//person is now (###) ###-####
let newPerson = person.digitsOnly()
//newPerson is ##########
print(person)
print("->\(newPerson)")
//add formatted number to tempArray
tempArray.append(newPerson)
}

}
//combine all numbers with "," between as a string
let recipString = tempArray.joinWithSeparator(",")
//recipString contains ##########,##########,##########...

extension String {

func digitsOnly() -> String{
let stringArray = self.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")

return newString
}
}


I then add the "recipString" variable to the NSURL in the below code:

let messageBody = "test"
let urlSafeBody = messageBody.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())

if let urlSafeBody = urlSafeBody, url = NSURL(string: "sms:/open?addresses=\(recipString)&body=\(urlSafeBody)") {
print("FINAL URL: \(url)")
WKExtension.sharedExtension().openSystemURL(url)
}


The FINAL URL print shows the correct string, but the messages app does not open properly, and shows quick reply menu instead of composed message window. It matches the functioning hard coded number version exactly, but behaves differently.

Totally lost, hope someone can help!

UPDATE 1
Here are the debug prints for both versions of the URL:

Manually declared (not created from recipString but actually declared in the URL string explicitly):

This version works


FINAL URL: sms:/open?addresses=0000000000,1111111111,2222222222,3333333333,4444444444&body=test


Variable created (using recipString):

This version doesn't


FINAL URL: sms:/open?addresses=0000000000,1111111111,2222222222,3333333333,4444444444&body=test


I have also tried applying url encoding to the "recipString" variable by using the below if let:

if let urlSafeRecip = recipString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) {

if let urlSafeBody = urlSafeBody, url = NSURL(string: "sms:/open?addresses=\(urlSafeRecip)&body=\(urlSafeBody)") {
print("FINAL URL: \(url)")
WKExtension.sharedExtension().openSystemURL(url)
}
}


UPDATE 2
I tested to see if the hardcode version of numbers matches the recipString exactly via this code:

let hardCode = "0000000000,1111111111,2222222222,3333333333,4444444444"

let isEqual = (hardCode == recipString)

if isEqual {
print("hardCode matches recipString")
}
else {
print("hardCode does not match recipString")
}


Debug prints:


hardCode matches recipString


UPDATE 3

I have confirmed that:

When a URL is made with hard coded numbers vs. numbers that I make from variables, checking == between them returns true.

In every test I can do between the two version of the url, it matches.

NOTES AFTER CORRECT ANSWER FOUND:

This type of URL formatting will ONLY work with multiple addresses in the URL. If you do not have multiple addresses you will need to do the following, which is undocumented but none-the-less works. I found this by bashing my face on the keyboard for hours, so if it helps you an upvote is deserved :)

follow the answer marked below, and then use this type of logic check before making the URL in the doItButton() function he mentioned:

func setupAndSendMsg(saveData: NSDictionary) {
if let urlSafeBody = createBody(saveData) {
let theNumbers = createNumbers(saveData).componentsSeparatedByString(",")
print(theNumbers.count-1)
if theNumbers.count-1 > 0 {
if let url = NSURL(string: "sms:/open?addresses=\(createNumbers(saveData))&body=\(urlSafeBody)") {
print(url)
WKExtension.sharedExtension().openSystemURL(url)
}
} else {
if let url = NSURL(string: "sms:/open?address=\(createNumbers(saveData)),&body=\(urlSafeBody)") {
print(url)
WKExtension.sharedExtension().openSystemURL(url)
}
}

}
}

Answer

My guess is that it is not the acctual openSystemUrl call that is the problem. I believe there must be something with the code that is building the number string programmatically.

The code bellow is a simplified version of all the code you have posted. I have confirmed that it is working on my Apple Watch. It opens the Messages app with pre-populated numbers & body text.

Take one more look at your code and see if there is something your missing. If you can't find anything, just delete the code and re-write it, probably will be faster then spotting the weird issue.

Once again the code bellow is confirmed working as expected, so you should be able to get it to work. (or just copy & paste my code) :)

class InterfaceController: WKInterfaceController {

  @IBAction func doItButton() {
    if let urlSafeBody = createBody() {
      if let url = NSURL(string: "sms:/open?addresses=\(createNumbers())&body=\(urlSafeBody)") {
        print(url)
        WKExtension.sharedExtension().openSystemURL(url)
      }
    }
  }

  private func createBody() -> String? {
    let messageBody = "hello test message"
    return messageBody.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())
  }

  private func createNumbers() -> String {
    let numbers = ["(111) 222-3333", "(444) 555-6666"]
    var tempArray: [String] = []
    numbers.forEach { (number: String) in
      tempArray.append(number.digitsOnly())
    }

    return tempArray.joinWithSeparator(",")
  }      
}

extension String {
  func digitsOnly() -> String{
    let stringArray = self.componentsSeparatedByCharactersInSet(
      NSCharacterSet.decimalDigitCharacterSet().invertedSet)
    let newString = stringArray.joinWithSeparator("")

    return newString
  }
}

With above said I would recommend against using undocumented Apple features for anything you plan on putting on the App Store for the reasons already mentioned in comments.