Using Siri with the Salesforce Mobile SDK

April 24, 2017 René Winkelmeyer

App extensions for iOS have been around for some time. They let you implement interesting use cases—if you know the right technology and some tips and tricks. In this blog post, you learn how to use the Salesforce Mobile SDK in conjunction with the SiriKit extension—and how to make Siri create Chatter posts for you.

iOS app extensions

An app extension lets you—as the name says—extend the functionality of an app. That means such an extension is always bound to a specific app and cannot be installed separately on a device. However, you can use it across several apps.

There are many different kinds of app extensions available. This list gives you a brief overview of some of the most common:

  • Today view in Notification Center
  • WatchKit (app/notification for Apple Watch)
  • Document providers
  • iMessage
  • SiriKit (custom voice interactions)
  • Share

Some of these extensions are clearly focused on consumer usage—so it may not make sense to apply business processes to them. But others can make sense. For example, SiriKit.


SiriKit is an extension of the iOS Siri functionality. App developers can set up their application for one of the different use cases that SiriKit offers and, with that, extend Siri.

While we probably won’t book a ride with Salesforce (but you can), or order some food (you can do that, too: think case creation in Service Cloud), we want to have some fun with Siri and Chatter. Check out this short video to see the example app in action:

Creating an app with the Mobile SDK

For creating an app that uses the Mobile SDK, it’s highly recommended to use our Mobile SDK installer. It’s distributed via npmjs and can be installed using npm with the command npm install forceios.

Once you’ve installed forceios, the steps for creating a new app are straightforward. In fact there are only two:

  1. Create a new directory on your local filesystem.
  2. Execute the forceios command within that directory.

This snippet shows the parameters that have been used to create the example app:

forceios create --apptype=native_swift --appname=SiriKitExample --packagename=com.winkelmeyer.salesforce.sirikit --organization=muenzpraeger

For iOS, you can select between different app types, that is, a native Swift app as for this blog post. Or you can go with Objective-C, ReactNative, or hybrid. The other parameters are similar to those that you’d need to set up a new iOS app manually via Xcode.

Once you’ve executed the command, the most current app template is downloaded via GitHub and populated with the provided parameter values. The Mobile SDK uses Cocoapods for handling library dependencies—that comes into play later.

Adding a SiriKit extension

As the name says, we’re going to extend the previously created iOS app. An app extension gets added by creating a new target within the Xcode workspace.

For this specific use case, we’re adding the Intents extension. An Intent specifies the SiriKit extension. Once we’ve done that, a new app target (ChatterIntent) gets added to the app.

So far, so good. Before we can use Siri, we first must enable the entitlement within the apps main target.

As a last step, we must set the Siri Usage Description in the apps Info.plist (in our example: “Using Siri with Salesforce”). This is the text that is presented to the user when the app is asking if they want to allow Siri usage.

This is how it looks on a device.

Our next step is to enable the Mobile SDK in the new intent target.

Marrying the app extension with the Mobile SDK

By default the Cocoapods file in the Mobile SDK is set up to support only the main target. As an app extension is just another target, we have to modify the Cocoapods Podfile in the projects root folder as shown here:

target 'SiriKitExample' do
    pod 'SalesforceAnalytics', :path => 'node_modules/SalesforceMobileSDK-iOS'
    pod 'SalesforceSDKCore', :path => 'node_modules/SalesforceMobileSDK-iOS'
    pod 'SmartStore', :path => 'node_modules/SalesforceMobileSDK-iOS'
    pod 'SmartSync', :path => 'node_modules/SalesforceMobileSDK-iOS'
    // Adding child target for newly created Intent
    target 'ChatterIntent' do
        pod 'SalesforceAnalytics', :path => 'node_modules/SalesforceMobileSDK-iOS'
        pod 'SalesforceSDKCore', :path => 'node_modules/SalesforceMobileSDK-iOS'
        pod 'SmartStore', :path => 'node_modules/SalesforceMobileSDK-iOS'
        pod 'SmartSync', :path => 'node_modules/SalesforceMobileSDK-iOS'

As you can see, we’re adding the target for the newly created intent as a child element to the existing app target. With this configuration, Cocoapods adds the needed Mobile SDK libraries directly to our intent target. Make sure that you run the pods update command in the Xcode’s project root folder so that the workspace file gets updated correctly.

Sharing the same credentials

While an app extension is bundled with an app, it doesn’t automatically use the same keychain. For that we have to configure all app targets to be in the same app group and in the same keychain group. If you haven’t used those before within iOS, read the official Apple documentation.

The Mobile SDK documentation describes how and where to configure those settings. It also explains how to code the authentication part within the app extension, so that it’s ensured that a user has authenticated successfully with their Salesforce org before they use the extension.

Handling intents

The SiriKit extension listens to user input and handles it via intents. The following diagram showcases a simplified intent-handling flow:

  1. The user requests the action via voice (“Send a message to xyz saying abc.”).
  2. Given the input, the system identifies the needed app extension. If all parameters—recipient and message in our case—are set, a handler asks the user for confirmation.
  3. The user confirms the valid input.
  4. Another handler takes the action, for example sending a post to Chatter.

The IntentHandler.swift file, which is automatically created by Xcode when you create the new target, contains several examples for the available handlers.

Querying from and posting to Salesforce

As you saw in the video, our app is querying Salesforce for the spoken name. To accomplish this, the function querySalesforceForUsers gets called when the handler for resolving the recipients is invoked.

func querySalesforceForUsers(forSendMessage intent: INSendMessageIntent, with completion: @escaping ([INPersonResolutionResult]) -> Void) {
    let query = "SELECT Name, Id FROM User WHERE Name='" + (intent.recipients?[0].displayName)! + "' LIMIT 3"
    let request = SFRestAPI.sharedInstance().request(forQuery:query)
    SFRestAPI.sharedInstance().send(request, delegate: self)

We’re passing an SOQL query with the request that takes the identified name as a parameter.

If a match is found, the returned REST data gets converted into an INPerson object. This kind of object is later used by SiriKit to identify the recipient and their address data.

    func convertUserSearchToINPerson(matchingContacts:  [NSDictionary]) -> [INPerson] {
        var people = [INPerson]()
        let unidString = matchingContacts[0].value(forKey: "Id") as! String
        let handle = INPersonHandle(value: unidString, type: INPersonHandleType.unknown)
        let person = INPerson(personHandle: handle, nameComponents: nil, displayName: matchingContacts[0].value(forKey: "Name") as? String, image: nil, contactIdentifier: nil, customIdentifier: unidString)
        return people

Code explanation:

  • Line 4: We’re reading the ID value of the user object from the REST data. This is necessary as we want to post to the user’s Chatter stream.
  • Line 6: During initialization of the INPersonHandle object, the previously read ID value gets passed as value. This parameter can later be referenced when the message gets sent.

Once Siri understands the message that we want to send, it fires of the handler for message sending.

    func handle(sendMessage intent: INSendMessageIntent, completion: @escaping (INSendMessageIntentResponse) -> Void) {
        postChatterMessage(message: intent.content!, userId: (intent.recipients?[0].personHandle?.value)!)
        let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
        let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity)

Based on the created INPersonHandle, we can now reference the value property of this object, which holds the Salesforce user ID.

    func postChatterMessage(message: String, userId: String) {
        let request = SFRestRequest(method: SFRestMethod.POST, path: "/services/data/v39.0/chatter/feed-elements", queryParams: nil)
        let json = "{"feedElementType":"FeedItem","subjectId":"" + userId + "","body":{"messageSegments":[{"type":"Text","text":"" + message + ""}]}}"
        request.setCustomRequestBodyData( .utf8)!, contentType: "application/json")
        SFRestAPI.sharedInstance().send(request, delegate: self)

Code explanation:

  • Line 2: We’re creating a new SFRequest using the Mobile SDK. This allows us to create custom requests that are not covered by the built-in Mobile SDK functions like request, requestForResource, and more.
  • Line 4: Manually build the Chatter Feed Element JSON that creates the new Chatter post.

That’s it!

Last but not least—debugging

As an app extension is a separate app, you cannot debug it like regular apps. Also the Swift print function doesn’t print anything out of the box to the Xcode debug console.

But it’s possible to debug. After you’ve launched the extension on your device (hint: SiriKit doesn’t run in the simulator; you need a real device), select Debug => Attach to Process by PID or Name and enter the name of the intent target like in the screenshot.

The debug may not work directly on first try. So don’t give up! I hope this saves you some headache in case you have to debug an extension.

Next steps

In this post you learned how to build an iOS SiriKit extension that turns your voice into Chatter posts by using forceios and the Mobile SDK. Try it out yourself by cloning the example app from this GitHub repo. If you want to learn more about how to use the Mobile SDK, check out our trail Develop with Mobile SDK on Trailhead.

About the author

René Winkelmeyer is a senior developer evangelist at Salesforce. He focuses on enterprise integrations, mobile, and security with the Salesforce platform. You can follow him on Twitter @muenzpraeger (

Previous Article
Lightning Components Performance Best Practices
Lightning Components Performance Best Practices

Lightning Components run at the client-side, in a single page (where they are created and destroyed as need...

Next Article
Google Maps with Lightning Components & Visualforce
Google Maps with Lightning Components & Visualforce

With Lightning Components, you can build single-page applications that use standard or custom components. Y...