XCode+Swift+XPC: How to start and deploy a Swift XPC target on MacOS

DISCLAIMER: I am relatively new to MacOS/XCode


I want to build a simple XPC Launch Agent in Swift (ie: in

~/Library/LaunchAgents
) but I could not find much documentation.
I started with XCode XPC template but I do not know if it was a good idea for my swift project.
I notice I should also have
~/Library/LaunchAgents/com.demo.myservice.plist


Versions:
- MaOS: 10.13.2
- Xcode: 9.2


Instruction to create the XCode XPC Project with XCode:

  1. File > New project
  2. I chose the MacOS template: XPC
  3. I create the bundle ‘com.demo.myservice’
  4. It creates me an Objective-C project. So I delete all files (ie:
    myserviceProtocol.h
    ,
    myservice.h
    ,
    myservice.m
    ,
    main.m
    and
    Info.plist
  5. Create the files:

myserviceProtocol.swift


import Foundation
@objc(myserviceProtocol) protocol myserviceProtocol {
  func ping()
}


myservice.swift

import Foundation
class myservice : NSObject, myserviceProtocol {
  func ping() {
    print("ping")
  }
}


main.swift


import Foundation


class ServiceDelegate : NSObject, NSXPCListenerDelegate {
  func listener(_ listener: NSXPCListener, shouldAcceptNewConnection newConnection: NSXPCConnection) -> Bool {
    newConnection.exportedInterface = NSXPCInterface(with:myserviceProtocol.self)


    let exportedObject = myservice()
    newConnection.exportedObject = exportedObject
    newConnection.resume()
    return true
  }
}


let delegate = ServiceDelegate()
let listener = NSXPCListener.service()
listener.delegate = delegate; listener.resume()


Info.plist


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>KeepAlive</key>
      <true/>
    <key>Label</key>
      <string>com.demo.myservice</string>
    <key>ProgramArguments</key>
    <array>
       <string>myservice</string>
    </array>
    <key>RunAtLoad</key>
      <true/>
  </dict>
</plist>


  1. I build it. No problem
  2. I copied
    Info.plist
    into ~/Library/LaunchAgents/ :
cp ~/Documents/myservice/myservice/Info.plist ~/Library/LaunchAgents/com.demo.myservice.plist


I retrieve my userid with

id -u (it returns 501)

And then I try to execute it from the command line (as it does not seem to do anything from Xcode):


sudo launchctl debug user/501/com.demo.myservice /Users/olivier/Library/Developer/Xcode/DerivedData/myservice-hbwefcgibyqbajguvblgcmxsnrmd/Build/Products/Debug/myservice.xpc
Configuration failed: 113: Could not find specified service
Could not find service "com.demo.myservice" in domain for uid: 501


I am not really sure of what I am doing. Was I right to use

XPC
template to create my swift XPC.

Was I right to use XPC template to create my swift XPC.

No. That creates a XPC Service, and you want to create a launchd agent that happens to vend an XPC service (lower case, and yes, I know that’s confusing). These are very different beasts.

The best place to start with a launchd agent is the macOS > Command Line Tool template. You then need to instantiate your listener with

-initWithMachServiceName:
rather than
+serviceListener
(because the latter is only available to XPC Services).

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
XCode&#43;Swift&#43;XPC: How to start and deploy a Swift XPC target on MacOS
 
 
Q