Category Archives: Salesforce Mobile SDK for iOS

Adding iOS App Extensions to Salesforce Mobile SDK Apps

If you’re an iOS developer who wants to use cool iOS app extensions in your Salesforce Mobile SDK app–this post’s for you.

iOS app extensions provide opportunities for developers to present their app’s functionality outside of their app context. With Mobile SDK, for example, you can use an extension to show a “most recently used” (MRU) list of accounts in the Today view and also when the user applies 3D Touch to your app icon. The realm of possibilities for extension functionality is vast. If you’re not familiar with iOS app extensions, get started at https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html (or search for “iOS app extensions” at https://developer.apple.com/library).

This post gives you some pointers for combining iOS app extensions with Mobile SDK 5.0 native apps. The instructions here are generic enough to be used with all types of extensions. To study a functioning example of an iOS app extension working in a Mobile SDK app, see the SmartSyncExplorer sample app at https://github.com/forcedotcom/SalesforceMobileSDK-iOS/tree/master/native/SampleApps/SmartSyncExplorer. The SmartSyncExplorer app demonstrates 3D Touch and Today view extensions. It also showcases the use of SmartStore in the extension’s widgetPerformUpdateWithCompletionHandler: method.

Let’s get going with configuring your Xcode workspace and customizing your app.

Configure Your Workspace

When you create an iOS app extension in Xcode, you add another build target to your app. Extensions require your main app target and the extension app target to join the same app group. You configure this relationship in your app’s Xcode workspace configuration.

The following steps don’t directly provide instructions for creating an extension–how you handle step 1 is between you and iOS. The subsequent steps describe the Xcode workspace changes that Mobile SDK and iOS require.

  1. In your Mobile SDK app, create an extension target as described in the Apple developer documentation.
  2. Select the top-level node of your Mobile SDK project in the Xcode Project Navigator. This step opens your app’s configuration wizard.
  3. Click General, and then specify a unique bundle identifier for the Mobile SDK app target. This screen capture shows where to set this identifier for a Mobile SDK app target.Bundle setting for iOS app extensons
  4. Repeat the bundle identifier step for the extension target. This identifier must also be unique.
  5. Enable App Groups and Keychain Sharing in your Mobile SDK target.
    1. In your app configuration, choose your Mobile SDK app target and click Capabilities.
    2. Under App Groups, select or create an app group. Use a unique label that identifies your app, such as “group.myapp.shared”.
    3. Under Keychain Sharing, select or create a keychain group. Use a unique label that identifies your app, such as “com.myapp.MyApp”. App group and keychain sharing settings for Mobile SDK app using iOS app extensions
  6. Repeat the App Groups and Keychain Sharing steps for your extension target. NOTE : The two values in the Extension target must exactly match the corresponding values in the application target.App group and keychain sharing settings for iOS app extension

Customize Your Code

To support extensions, you change your AppDelegate class to make it aware of the extension, and then you add similar code to your app extension view controller.

By default, the Mobile SDK AppDelegate class contains “bootstrapping” code that initializes the SDK. When you incorporate an iOS app extension, you add a couple of lines that tell the SDK that you’re working in an app group.

AppDelegate Code Changes

The following steps apply to the init method of your main app’s AppDelegate class.

  • In the init method, add calls to appGroupName and appGroupEnabled methods of SFSDKDatasharingHelper before the existing calls to SalesforceSDKManager.
// Insert these two lines, using your app group name
[SFSDKDatasharingHelper sharedInstance].appGroupName = 
    @"<your app group name>"; 
[SFSDKDatasharingHelper sharedInstance].appGroupEnabled = YES;

// Now it's OK to set SalesforceSDKManager properties ...
[SalesforceSDKManager sharedManager].connectedAppId = 
    @"<your consumer key>"
[SalesforceSDKManager sharedManager].connectedAppCallbackUri = 
    @"<your callback URL>";
[SalesforceSDKManager sharedManager].authScopes = 
    @[@"api", @"web", ...];
  • In the postLaunchAction block, use NSUserDefaults to cache a flag that indicates login success.
[SalesforceSDKManager sharedManager].postLaunchAction = 
    ^(SFSDKLaunchAction launchActionList) {
    ...
    /* Write a boolean indicating that user has logged in 
      using the app. You could share data between your app 
      and extension by saving it into your app group 
      using NSUserDefaults */
    [[NSUserDefaults initWithSuiteName:@"<your app group name>"] 
        setBool:@YES forKey:@"userLoggedIn"];
}

App Extension Code Changes

At runtime, your iOS app extension operates as a second app, so you have to “bootstrap” it as well. You apply the same appGroupName and appGroupEnabled changes as you did in the AppDelegate class. You also set the following SalesforceSDKManager properties in your extension view controller just as you do in your AppDelegate class:

[SalesforceSDKManager sharedManager].connectedAppId
[SalesforceSDKManager sharedManager].connectedAppCallbackUri
[SalesforceSDKManager sharedManager].authScopes

However, extensions can’t perform authentication tasks such as user logins. Instead, you check the NSUserDefaults value that you stored in the AppDelegate code to verify that a user has logged in before calling SalesforceSDKManager. The rest of your extension code is up to you.

The following steps walk you through the required customizations.

  • In your iOS app extension’s view controller class, find your extension’s initialization entry point and add the following Mobile SDK bootstrapping code there.
[SFSDKDatasharingHelper sharedInstance].appGroupName = 
    @"<your app group name>";
[SFSDKDatasharingHelper sharedInstance].appGroupEnabled = YES;

/* Before calling SalesforceSDKManager, check whether a user has 
logged in through the main app. As your condition, use the 
userLoggedIn Boolean value that you set in your app's 
postLaunchAction block. Remember that you saved this value in 
your app group using NSUserDefaults. */

if ([[NSUserDefaults initWithSuiteName:@"<your app group name>"] 
    boolForKey:@"userLoggedIn"]]) {
       
    // Now you can set the following SalesforceSDKManager properties 
    // as you did in your AppDelegate init method
    [SalesforceSDKManager sharedManager].connectedAppId = 
        @"<your consumer key>"
    [SalesforceSDKManager sharedManager].connectedAppCallbackUri = 
        @"<your callback URL>";
    [SalesforceSDKManager sharedManager].authScopes = 
        @[@"api", @"web", ...];
    // Call other Mobile SDK APIs
    // ...
}
// Continue with standard extension implementation
...
  • If the bootstrapping succeeds, your app can use the current user’s shared credentials to access Salesforce data directly in the extension. The following example shows typical REST API calls that you might add to an extension.
...
NSDictionary *fields = @{@"FirstName": @"\%",@"LastName": @"\%"};
SFRestRequest* request = [[SFRestAPI sharedInstance]
    requestForQuery:@"SELECT FirstName,LastName FROM Contact 
        ORDER BY CreatedDate DESC LIMIT 5"];
[[SFRestAPI sharedInstance] send:request delegate:self];
...

REMEMBER: It’s the developer’s responsibility to determine the user’s login status. The iOS app extension code must not attempt to invoke the SalesforceSDKManager object before the user successfully logs in.

For testing iOS app extensions, there’s one important restriction: You must use a real device. You can’t test iOS app extensions in an iOS simulator.

Conclusion

At this point, you’ve learned how to configure a Mobile SDK app to use an iOS app extension. Your next step should be to implement your own extension in a Mobile SDK app. The type of extension you implement is up to you. If you repurpose the code in the SmartSyncExplorer sample app, you can quickly get running with 3D press and Today screen extensions. By default, both widgets show a list of MRU contacts.

The iOS app extensions feature offers a plethora of other possibilities. We’d love to see what you come up with!

Resources

The following resources provide general information on using Mobile SDK for iOS.

Salesforce Mobile SDK Development Guide:
https://developer.salesforce.com/docs/atlas.en-us.mobile_sdk.meta/mobile_sdk/ios_intro.htm

Trailhead module:
https://trailhead.salesforce.com/modules/mobile_sdk_native_ios

Advertisements

iOS: How to Handle Upcoming ATS Restrictions in App Store Submissions

Mobile SDK 5.0 is coming soon–and so are some new restrictions on iOS App Store submissions.

Background

Here’s some background information on the restrictions, plus instructions for making sure your apps comply with the new requirements.

Starting on January 1, 2017, the App Store will reject apps whose info.plist files contain Apple Transport Security (ATS) exceptions.

This article summarizes Apple’s requirements for apps:

App Store Review for ATS

For more background details, see:

ATS Configuration Basics

What It Means for You

Until Nov. 9, 2016, Salesforce servers did not enforce Perfect Forward Secrecy (PFS). As a result, Mobile SDK iOS apps contained exceptions in the info.plist file to get around ATS incompatibilities with Salesforce servers. Nowadays, Salesforce servers are up-to-date with PFS support and are 100% compatible with Apple’s transport security policies.

Beginning Jan. 1, apps that contain these exceptions no longer satisfy App Store security requirements.  If you resubmit an app that contains these exceptions, it will automatically trigger a security review. In order to be accepted, you’re required to make the changes described here.

If you’re developing a new app with Mobile SDK 4.3 or earlier, the Mobile SDK template puts these exceptions in your info.plist file. Be sure to remove them before submitting your app.

How to Fix Your App

Fixing your app is actually simple. You just remove the exceptions from your info.plist file, rebuild, and resubmit to the App Store.

Salesforce Mobile SDK gives you two options for proactively fixing this problem in plenty of time:

  • Now that Salesforce servers comply with Apple’s policies, you can go ahead and remove your exceptions today, well before the deadline, and resubmit to the App Store. Follow the example link below to see what needs to be removed.
  • If you’re too busy to remove the exceptions now, there’ll be an easier way in mid-December: the Mobile SDK 5.0 release. The new release updates our app templates to remove these exceptions. If you simply upgrade your app with forceios 5.0, you’ll get the updated configuration for free–no manual labor required.

Example

To see an example of how we’ve removed the exceptions, check out this pull request:

iOS template for Mobile SDK 5.0:  https://github.com/forcedotcom/SalesforceMobileSDK-Templates/pull/6

 

 

 

Errors Creating Hybrid Apps in Mobile SDK 4.3

If you’re upgrading to Mobile SDK 4.3.x and plan to build hybrid apps, heed this tip!

Under certain conditions, the Cordova telemetry feature can cause forcedroid or forceios to fail with bewildering error messages. So far, we’ve seen this problem occur when:

  • You’ve installed the latest version of Cordova (6.2.0 or higher)
  • You’re using forcedroid or forceios to create a hybrid app

If both of the above are true, the script might throw an error such as the following:

“”. Should be in the format x[.y[.ignored]]

) is less than the minimum required version (5.4.0). Please update your version of Cordova.”

These errors occur if you haven’t preset telemetry to some value. Even if you don’t get weird error messages, you’ll still eventually get this prompt asking you to set the telemetry attribute:

May Cordova anonymously report usage statistics to improve the tool over time?

To avoid these hiccups, preset telemetry on or off before you run the script. Just type:

cordova telemetry <on|off>

Afterwards, forcedroid or forceios should work as expected.

For more information, type:

cordova telemetry -h

Mobile SDK 4.0.2 Is Now Available

 

Following close on the heels of our 4.0 major release and 4.0.1 patch, the 4.0.2 patch for Mobile SDK (Android and iOS) is now available. This patch primarily affects CocoaPods podspecs for iOS developers. We’ve also republished both forceios and forcedroid to keep them on the same version. See the section below for more details on what’s new.

To upgrade:

  1. Uninstall and reinstall forceios and forcedroid from npm.
  2. On iOS, rework your podspecs as described in the following section.
  3. If you use the GitHub repos, merge these tags:
    Android: https://github.com/forcedotcom/SalesforceMobileSDK-Android/tree/v4.0.2
    iOS: https://github.com/forcedotcom/SalesforceMobileSDK-iOS/tree/v4.0.2

CocoaPods Reorganization

In Mobile SDK for iOS 4.0.1, our podspec configuration didn’t exert enough control over external dependency versions. For 4.0.2, we’ve now removed the SalesforceMobileSDK-iOS podspec and replaced it with a separate podspec for each Mobile SDK module. We’ve also added a new GitHub repo, https://github/forcedotcom/SalesforceMobileSDK-iOS-Specs, that serves as the archive for all versions of our podspecs.

The new podspecs are:

SalesforceSDKCore—Implements OAuth and passcodes. All other pods except FMDB depend on this pod, either directly or indirectly.
SalesforceNetwork—Networking library (with transparent token refresh when session expires). Depends on SalesforceSDKCore.
SalesforceRestAPI—REST API wrappers for accessing Salesforce data. Depends on SalesforceNetwork.
FMDB—The Mobile SDK fork of FMDB, a third-party Objective-C wrapper for SQLite. This fork implements customized logging and
imports SQLCipher with full-text search support.
SmartStore—Implements secure offline storage. Depends on FMDB and SalesforceSDKCore.
SmartSync—Implements offline synchronization. Depends on SalesforceRestAPI and SmartStore.
SalesforceReact—Implements Salesforce Mobile SDK React Native bridges for apps written with React JavaScript and markup. Depends on SmartSync.

Here’s how to update your Podfile for the 4.0.2 patch.

1. In your project’s Podfile, add the SalesforceMobileSDK-iOS-Specs repo as a source before adding the CocoaPods source.

target 'YourAppName' do
# must get SalesforceMobileSDK-iOS-Specs 
# source first (before CocoaPods)! 
source 'https://github.com/forcedotcom/SalesforceMobileSDK-iOS-Specs.git' 
source 'https://github.com/CocoaPods/Specs.git'

2. Declare each pod on a separate line.

pod 'SalesforceSDKCore'
pod 'SalesforceNetwork'
pod 'SalesforceRestAPI'

Or, thanks to dependency chains, this will work if you’re using the current release:

pod 'SalesforceRestAPI'

If you currently have a podspec that calls pod SalesforceMobileSDK-iOS with subspecs for Mobile SDK modules, such as:

pod 'SalesforceMobileSDK-iOS', :subspecs =>[ 'SalesforceRestAPI' ]

Replace this call with individual pod calls, as shown above.

Working with an Unstable Branch

To work with an upcoming release of Mobile SDK, you clone the unstable branch of the SalesforceMobileSDK-iOS repo, and then pull resources from it.

  1. Clone github.com/forcedotcom/SalesforceMobileSDK-iOS locally at the desired commit.
  2. At the terminal window, run ./install.sh in the root directory of your clone.
  3. To each pod call in your Podfile, add a :path parameter that points to your clone. Note that you shouldn’t skip dependencies if you’re specifying a path—you need to call the pod command individually for each module.

Here’s the previous example repurposed to pull resources from a local clone:

target 'YourAppName' do
# must get SalesforceMobileSDK-iOS-Specs 
# source first (before CocoaPods)! 
source 'https://github.com/forcedotcom/SalesforceMobileSDK-iOS-Specs.git' 
source 'https://github.com/CocoaPods/Specs.git' 

pod 'SalesforceSDKCore', :path => 
    '/<path-to-clone-of>/SalesforceMobileSDK-iOS/' 
pod 'SalesforceNetwork', :path => 
    '/<path-to-clone-of>/SalesforceMobileSDK-iOS/' 
pod 'SalesforceRestAPI', :path => 
    '/<path-to-clone-of>/SalesforceMobileSDK-iOS/' 

end

For more information, see the Salesforce Mobile SDK Development Guide at https://github.com/forcedotcom/SalesforceMobileSDK-Shared/blob/master/doc/mobile_sdk.pdf?raw=true.

iOS 9 Bitcode Support and Salesforce Mobile SDK

In iOS 9, Apple introduced bitcode support. Bitcode images offer benefits for apps uploaded to iTunes Connect, as described here.

Salesforce Mobile SDK for iOS will add iOS bitcode support in its upcoming 4.0 release. However, if you’re a GitHub user and you just can’t wait–chafing at the bit, as it were–you can add this feature to your existing Mobile SDK 3.3 apps right away. Just “cherry-pick” the following pull request and apply it to your copy of Mobile SDK:
https://github.com/forcedotcom/SalesforceMobileSDK-iOS/pull/1201

Please note that:

  • Bitcode-enabled binaries are backwards compatible with iOS 7 and 8. However, the benefits of using bitcode apply only to iOS 9.
  • You can use bitcode-enabled static libraries in XCode 6 and 7. XCode 6 simply ignores the bitcode flag.