Option 2: Add Mobile SDK Setup Code Manually
If you prefer the freedom of writing all your code from scratch, you can create a project without copying Mobile SDK template files into your workspace. You can—and should—consult the template code to pick up boilerplate implementations for certain features.
Where possible, we changed noninclusive terms to align with our company value of Equality. We maintained certain terms to avoid any effect on customer implementations.
The procedure here creates a basic Mobile SDK Swift app that implements an AppDelegate
- SceneDelegate
flow.
When you insert Mobile SDK into an iOS project without importing template files, you’re responsible for reconfiguring the app lifecycle according to Mobile SDK guidelines. For example, here are some required tasks:
- Configure
SalesforceApp
as the main class - Initialize Mobile SDK
- Call Mobile SDK to prompt for customer login and handle user switching
For a few optional features, Mobile SDK provides specific customizations that you can drop into your code.
As benefits, you have some additional flexibility to suit your development needs:
-
Code in Swift (recommended)
or
Objective-C (to support older apps; not described in this procedure)
-
Use
AppDelegate
for app-level initialization, andSceneDelegate
to handle all UI lifecycle events. This path is recommended; it supports multiple windows in iPadOS, clarifies multi-scene handling, and separates app-level and scene-level code.or
Use
AppDelegate
alone to handle app initialization and UI lifecycle events. This path is an option only for single-window apps that don’t require multiple window support in iPadOS. If you choose this route, it’s up to you to find places inAppDelegate
for all Mobile SDK code that’s added here inSceneDelegate
. See the iOS Native Template for examples.
These instructions provide minimal steps for enabling Mobile SDK in a runnable Swift app. At the end of this procedure, you can find additional sections on setting up optional features such as push notifications and IDP apps.
- Create an Xcode Swift Project
- Add Mobile SDK Libraries to Your Project
- Configure Your Project’s Build Settings
Mobile SDK uses the project’s main Info.plist
file to set the default Salesforce login host. In Xcode 12.4, the app wizard creates the Info.plist
file for you. In Xcode 13, the app wizard for the SwiftUI interface doesn’t create the file, but you can copy one from a Mobile SDK template app.
- Xcode 12.4
- In the Project Navigator, control-click MyMobileSDKApp | MyMobileSDKApp | Info.plist and select Open As | Source Code.
-
Add the following key-value pair to the top-level dictionary:
- Xcode 13
Copy the Info.plist file to your project from the iOS Native Swift template. When the file is in place, adjust your Project Settings as follows:
- In your Project settings, select Build Phases.
-
Under Copy Bundle Resources, select
Info.plist
, if it’s present, and click Remove Items (-). - In Build Settings, search for “Info.plist File”.
- Set Generate Info.plist File to No.
- Set Info.plist File to the file’s path in your project (for example, “MyMobileSDKApp/Info.plist”.)
Mobile SDK looks for a bootconfig.plist
file to help your app start with the correct connected app values. You can copy this file to your project from a Mobile SDK iOS template project, but be sure to reset the values to your app’s preferences—especially remoteAccessConsumerKey
and oauthRedirectURI
.
-
In an external text editor, create an empty text file.
-
Copy the following text into the new file:
-
Save the file as
bootconfig.plist
in your MyMobileSDKApp project's local disk directory. -
In Xcode’s Project Explorer, control-click MyMobileSDKApp | MyMobileSDKApp and select Add Files to “MyMobileSDKApp”.
-
Select
bootconfig.plist
. -
To do now (if your connected app is available) or before you release your app:
- Open
bootconfig.plist
in the Xcode editor. - Replace the
remoteAccessConsumerKey
value with the Consumer Key from your org's connected app. - Replace the
oauthRedirectURI
value with the Callback URL from your org’s connected app.
- Open
If you tell the Xcode 12.4 app wizard to create a UIKit App Delegate lifecycle, it creates AppDelegate
and SceneDelegate
classes. The Xcode 13 app wizard doesn’t offer a lifecycle choice and doesn’t create an AppDelegate
class. However, you can create the basic minimal version from scratch using the following instructions.
-
Xcode 12.4: Start with the
AppDelegate
class in your project, keeping the three standard lifecycle functions.Xcode 13:
-
In your project's MyMobileSDKApp | MyMobileSDKApp folder, control-click the
MyMobileSDKAppApp.swift
file and click Delete. -
Click Move to Trash.
-
Control-click MyMobileSDKApp | MyMobileSDKApp and select New File.
-
Select Swift File, name it “AppDelegate”, and then click Create. Xcode creates a file with one line:
-
-
Paste the following boilerplate implementation of the
AppDelegate
life cycle methods. -
Remove the
@main
attribute above theAppDelegate
class declaration. Themain.swift
file has assumed the role of main. -
Import all Mobile SDK modules.
-
At the top of the class, override the
init()
method to initialize Mobile SDK. For example, to initialize all Mobile SDK libraries, callinitializeSDK()
onMobileSyncSDKManager
:
To access Salesforce data, your app’s users must authenticate with a Salesforce org. Salesforce sends a login screen to your app to collect the user’s credentials and then returns OAuth tokens to your app.
Your app must include a view controller whose sole purpose is to host the Salesforce login screen. When no customer is logged in, your app sets this view controller as the root view. Traditionally, Mobile SDK apps name this view controller class InitialViewController
. It requires only a stub implementation.
-
In your project, control-click MyMobileSDKApp | MyMobileSDKApp and select New File.
-
Select Swift File, name it “InitialViewController”, and then click Create.
-
Add the following body:
Use the SceneDelegate
class to handle Salesforce logins, user switching, and root view instantiation. Login is required when no user is logged in—when the app originally launches, and when the current user logs out. User changes occur between users who have logged in previously and remain authenticated. Mobile SDK AuthHelper
functions simplify how these cases are handled:
AuthHelper.loginIfRequired(_:)
decides for you whether login is neededAuthHelper.registerBlock(forCurrentUserChangeNotifications:)
listens for user change events.
These functions let you determine what happens after the login or change occurs. Typically, you respond by setting your app’s main view as the root view.
In the scene lifecycle, specific junctures are ideal for each of these AuthHelper
calls. For example, register the block that handles user changes only one time, when the scene is first initialized. Also, call AuthHelper.loginIfRequired(_:_:)
whenever the scene comes to the foreground. If the current user remains logged in, Mobile SDK merely executes your completion block.
At app startup, you set InitialViewController
as the first root view controller. This view hosts the Salesforce login screen and, after a successful login, is replaced by your app’s root view controller. At runtime, if the current user logs out, you dismiss the current root view controller and replace it with InitialViewController
. In both cases, after a new user logs in, you dismiss InitialViewController
and set your app’s first view as the root view controller.
Xcode 13 only: In Xcode 13, the SwiftUI interface no longer uses SceneDelegate
. However, iOS still supports it, and Mobile SDK currently uses it. Follow these steps to create it.
-
In your project, control-click MyMobileSDKApp | MyMobileSDKApp and select New File.
-
Select Swift File, name it “SceneDelegate”, and then click Create.
-
Copy the following implementation into your new file.
Xcode 12.4 and Xcode 13:
-
At the top of your project’s
SceneDelegate
class, be sure that you’ve declared aUIWindow
variable: -
At the bottom of the SceneDelegate class body, implement a private function named
resetViewState(_:)
that takes an escaping closure as its sole parameter. This function dismisses the current root view controller and then executes the given closure: -
Implement a private function named
setupRootViewController()
that launches your app’s custom views. For this simple exercise, you can set the root view to the SwiftUIContentView
provided by the Xcode template.The Xcode template’s
ContentView
requires no additional setup or cleanup. For a more elaborate example, seesetupRootViewController(_:)
in the MobileSyncExplorerSwift template. -
In the
scene(_:willConnectTo:options:)
function, provide code that sets up the window scene. Replace all existing code with the following lines: -
Register a callback block for user change events. Using the private functions you added, provide a closure that resets the view state and then presents your app’s root view.
-
Implement a private function named
initializeAppViewState()
that setsInitialViewController
as the root view. Notice that this function first makes sure that the app is on the main UI thread. If the app is on some other thread, it switches to the main thread and calls itself recursively. -
In the
sceneWillEnterForeground(_:)
listener function:- To set the root view to
InitialViewController
, callinitializeAppViewState()
. - Call
AuthHelper.loginIfRequired(_:)
with a closure that sets the root view controller to your app’s main view.
- To set the root view to
- In Xcode, select Product | Run (⌘R).
- If the Salesforce login screen appears, you’re done!
Your new project is ready for customization. You can now add your own assets and set up your scene flow. You can also add optional push notification and IDP features, as follows.
Another reminder! Before posting your app to the App Store, be sure to update the remoteAccessConsumerKey
and oauthRedirectURI
in the bootconfig.plist
file with settings from your connected app. See Get Started with Native iOS Development.
- To support Salesforce push notifications, add code to register and handle them. You can copy boilerplate implementations of the following methods from the
AppDelegate
class of the Mobile SDK iOSNativeSwiftTemplate app:registerForRemotePushNotifications()
application(_:didRegisterForRemoteNotificationsWithDeviceToken:)
—Be sure to uncomment the one line of implementation code!didRegisterForRemoteNotifications(_:)
application(_:didFailToRegisterForRemoteNotificationsWithError:)
- Salesforce uses encryption on notifications, which requires you to implement a decryption extension and then to request authorization through the
UNUserNotificationCenter
object. See Code Modifications (iOS).
Mobile SDK supports configuration of identity provider (IDP) apps. See Identity Provider Apps. If you’ve implemented IDP functionality, you enable it by customizing AppDelegate
and SceneDelegate
.
-
In your
AppDelegate
class, add the following boilerplate functions from theAppDelegate
class of the Mobile SDK iOSNativeSwiftTemplate app:application(_:open:_:)
enableIDPLoginFlowForURL(_:_:)
-
In your
SceneDelegate
class, add the following functions.
You can use the InitialViewController
class to cosmetically customize the login view before the login screen appears. Here’s an example that brands the pre-login screen with your app’s name, using the default Salesforce background color. If you use this class to create resources that can be recreated, be sure to implement the didReceiveMemoryWarning()
override to dispose of them. See the Xcode UIViewController documentation.
Offline configuration files let you define your SmartStore and Mobile Sync setups in static XML files instead of code. These files must be named userstore.json and usersyncs.json and be referenced in your Xcode project. You can then load them by calling the following methods:
- Salesforce login is required, or
- When a change of users occurs
The Mobile SDK native Swift template keeps things simple by calling the two setup functions whenever it sets the root view controller. This task falls to a private function, setupRootViewController()
, that in turn is called as follows:
- In
sceneWillEnterForeground(_:)
, where it’s called in a block that runs after a Salesforce login occurs. - In
scene(_:willConnectTo:options:)
, where it’s called in a block that handles current user change notifications.
Mobile SDK defines a utility class, AuthHelper
, that coordinates the internal moving parts for login and user change events. For a complete example, see the SceneDelegate class in the Mobile Sync Explorer Swift template.
If your app defers login, where and when you call AuthHelper.loginIfRequired(_:)
is up to you. In all cases, be sure to precede the call by setting the root view controller to IntialViewController
, as shown here.