skip to Main Content

I created an Unwanted Communication Reporting Extension as per described here: https://developer.apple.com/documentation/sms_and_call_reporting/sms_and_call_spam_reporting

Followed the instructions and was able to get the report callback in my extension class, but when I try to make an API request to my HTTPS server, somewhere along the console log I get

nw_resolver_can_use_dns_xpc_block_invoke Sandbox does not allow access to com.apple.dnssd.service

and

Task <C31ADB51-B5C3-4E85-800E-405781F6A9ED>.<1> finished with error [-1003] Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={_kCFStreamErrorCodeKey=-72000, NSUnderlyingError=0x282d5c600 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)" UserInfo={_NSURLErrorNWPathKey=satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, _kCFStreamErrorCodeKey=-72000, _kCFStreamErrorDomainKey=10}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <C31ADB51-B5C3-4E85-800E-405781F6A9ED>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <C31ADB51-B5C3-4E85-800E-405781F6A9ED>.<1>"), NSLocalizedDescription=A server with the specified hostname could not be found., NSErrorFailingURLStringKey=https://sub.domain.com/debug, NSErrorFailingURLKey=https://sub.domain.com/debug, _kCFStreamErrorDomainKey=10}

So basically the dns lookup fails due to a sandbox restriction, but I was not able to allow the app sandbox access, that seems like a OSX specific capability.

Here is my code example that is in charge of the API reporting:

func reportToAPI(for request: ILClassificationRequest) {
    
    let payload: [String: AnyHashable] = [
        "data": "OK",
        "test": "payload"
    ]
    
    guard let url = URL(string: "https://sub.domain.com/debug") else {
        return
    }
    
    var request = URLRequest(url: url)
    
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.httpBody = try? JSONSerialization.data(withJSONObject: payload, options: .fragmentsAllowed)
    
    let task = URLSession.shared.dataTask(with: request) { data, _, error in
        guard let data = data, error == nil else {
            return
        }
        
        do {
            let response = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
            print(response)
        } catch {
            
        }
    }
    task.resume()
}

I also have my associated domains set up on both extension and main app’s target as classificationreport:sub.domain.com and domain.com, as well as my apple-app-site-association file uploaded as this:

{
"classificationreport": {
    "apps": ["L***.com.b***.smsreporting.unwantedreporting","L***.com.b***.smsreporting"]
}

Any help and guidance is appreciated as I am stuck at this point and lack of documentation on this is making things harder.

Edit: I am testing this on my own developer account, which is an individual membership, not organizational, if that matters.

2

Answers


  1. The error message suggests that the DNS lookup fails due to sandbox restrictions.
    The error you encountered, "Sandbox does not allow access to com.apple.dnssd.service," indicates that your app is restricted from accessing DNS services within the sandbox environment.

    You need to allow your app sandbox access to the necessary capabilities. Enabling capabilities required by your app might not be possible for an individual developer account. You may need an organizational membership.

    Regarding your code, everything seems to be in order. However, I would suggest making a few improvements to handle errors. Here’s an updated version of your code:

    func reportToAPI(for request: ILClassificationRequest) {
        let payload: [String: AnyHashable] = [
            "data": "OK",
            "test": "payload"
        ]
        
        guard let url = URL(string: "https://sub.domain.com/debug") else {
            print("Invalid URL")
            return
        }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        do {
            request.httpBody = try JSONSerialization.data(withJSONObject: payload, options: .fragmentsAllowed)
        } catch {
            print("Failed to serialize payload")
            return
        }
        
        let task = URLSession.shared.dataTask(with: request) { data, response, error in
            if let error = error {
                print("Error: (error.localizedDescription)")
                return
            }
            
            guard let data = data else {
                print("No data received")
                return
            }
            
            do {
                let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
                print("API response: (json)")
            } catch {
                print("Failed to parse API response: (error.localizedDescription)")
            }
        }
        
        task.resume()
    }
    

    Changes

    1. Improved error handling:
    • Added a do-catch block around the serialization of the payload to catch any serialization errors.
    • Added error handling for the case where no data is received from the API request.
    • Added error handling for parsing the API response.
    • Printed specific error descriptions when errors occur.
    1. Modified the print statement to provide more informative feedback, such as printing the API response or indicating the failure reason.
    Login or Signup to reply.
  2. It seems you call reportToAPI() in Unwanted Communication Reporting Extension.

    However if you add apple-app-site-association and Association Domain in .entitlement correctly. There is no need to create URLRequest by yourself. Apple will send the API on your behalf. (I think it’s for privacy reasons, like Message Filter Extension.)

    So classificationResponse should look like this:

    override func classificationResponse(for request:ILClassificationRequest) -> ILClassificationResponse {
        let payload: [String: AnyHashable] = [
            "data": "OK",
            "test": "payload"
        ]
        let action: ILClassificationAction = .reportJunk  // or .none, .reportNotJunk, .reportJunkAndBlockSender
        let response = ILClassificationResponse(action: action)
        response.userInfo = payload
    
        return response
    }
    

    By the way, we have encountered another issue: The Unwanted Communication Reporting Extension only sends the API request the first time in iOS 16, but it sends it every time in iOS 14.8.1. We are still unable to figure out the cause.

    If someone has experienced this issue or have any insights, please help us. Thank you in advance!

    (The details of this issue are as follows: The Unwanted Communication Reporting extension sends response over the network connection only ONCE after installing.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search