Last July, I started writing a series focused on how the Salesforce platform can be utilized in a manner without a traditional Salesforce client. Here are links to the other articles in the series:
- Leveraging Salesforce Using Spring Boot
- Leveraging Salesforce Using a Client Written In Svelte
- Leveraging Salesforce Using a Client Written In Vue.js
- Leveraging Salesforce Using Mobile Applications Written (Once) In React Native
- Leveraging Salesforce Using a Client Written In Angular
A graphical representation of the series is shown below:
The illustration above shows how various client frameworks can access the Salesforce data without actually utilizing clients provided by the Salesforce ecosystem.
In November 2021, I started a new series to demonstrate the Salesforce Mobile SDK, which harnesses the power of the Salesforce platform within standalone mobile apps.
A graphical representation of this new series is shown below:
“Exploring the Salesforce Mobile SDK Using React Native” was the first article in this Mobile SDK series. I then switched gears for the “Exploring the Salesforce Mobile SDK Using Android Studio” article to leverage Android Studio. In this article, I will focus on using Xcode to produce the same application.
Benefits of the Salesforce Mobile SDK
The Salesforce Mobile SDK provides several benefits for software engineers:
- Allows custom mobile device applications to utilize Salesforce features and functionality
- Full access to Salesforce functionality (no need to reinvent the wheel)
- Applications can be distributed using the application store of the native device
- Processing push notifications from Salesforce
- The ability to work with Salesforce data in an offline mode
If your application landscape utilizes Salesforce for key aspects of business operability, then consider leveraging the Salesforce Mobile SDK. By doing so, you can integrate data maintained by Salesforce into key component locations, allowing you to make strong business decisions.
Benefits of Using Xcode
If your client base requires support for iOS devices and you wish to use Xcode for app development, then you’ll find value in the forceios
CLI for getting started quickly with Salesforce functionality.
Key features for teams employing Xcode include:
- Allows use of Swift or Objective-C as the base programming language
- Provides 100% native support for features and functionality on iOS devices
- Allows experienced iOS developers to quickly leverage Salesforce Mobile SDK functionality
- Improvements in error handling, because both Swift and Objective-C maintain a strong typing and error handling design
- Identify and fix build issues easier
It may be obvious but you must have an Apple computer to use Xcode. For this article, I will be using my 16” MacBook Pro from March 2020.
Now that we’re ready to dive in, let’s briefly review our use case.
Finny’s Foods: An Example Use Case
Having a son (Finny) born with special needs introduced a personal desire to gain an understanding and appreciation of the products we use in our daily life. Years before Finny was born, my wife (Nicole) and I lived a healthy lifestyle. However, as Nicole began deep-diving into the ingredients in the foods that made up our daily diet, we received a much-needed wake-up call.
Fast-forward to today, our diet consists of few processed foods, no gluten, low sugar, and very little dairy. As much as possible, our protein originates from grass-fed sources, and we always favor organic options. Don’t get me started on GMO.
For this series, our Finny’s Foods application provides a simple list of meals that are both acceptable to us and favored by Finny. For now, we will include two simple attributes for each meal:
- Name of the meal
- Rating (1 to 5, where a rating of 5 is an absolute favorite for Finny)
Over time, I plan to introduce other attributes (such as summary, ingredients, directions, and even a photo), but let’s walk before we run.
Getting Started with Xcode
In addition to installing git
and npm
on my MacBook Pro, I made sure my Xcode version was up to date. Next, I visited the following URL to make sure everything was set up and configured as expected:
Set Up Your iOS Development Environment
These steps include making sure Xcode, CocoaPods, node.js, npm, and the forceios
CLI are all installed.
Next, I executed forceios
from a terminal session with the following options:
forceios create
Enter your application type (native_swift or native, leave empty for native_swift): native_swift
Enter your application name: FinnysFoodsIOS
Enter your package name: com.gitlab.johnjvester.finnysfoods.ios
Enter your organization name (Acme, Inc.): JVC
Enter output directory for your app (leave empty for the current directory):
Once completed, I followed the steps provided by the forceios CLI:
******************************************************************************
*
* Next steps:
*
* Your application project is ready in FinnysFoodsIOS.
* To use your new application in XCode, do the following:
* - open FinnysFoodsIOS/FinnysFoodsIOS.xcworkspace in XCode
* - build and run
* Before you ship, make sure to plug your OAuth Client ID and Callback URI,
* and OAuth Scopes into FinnysFoodsIOS/FinnysFoodsIOS/bootconfig.plist
*
******************************************************************************
Creating the Meal Object in Salesforce
Before I could begin creating a new application in Xcode, I needed to establish the Meal object in Salesforce.
I already had a Developer org that I could use. (You can create a new one here.) So, I simply logged in using my email address and password for that org. Next, I navigated to the Apps | App Manager and the Setup perspective in Salesforce.
I created a new Lightning App called Meal:
On the remaining setup screens, I selected all the default settings and granted access to all Salesforce User Profiles.
Next, I visited the Objects & Fields | Object Manager menu option in the Salesforce Settings. Once I located the newly-created Meal item, I used the drop-down component to Edit the object.
I switched from the Details submenu to the Fields & Relationships option. I quickly realized I did not need to create a Name property for my Meal object since Salesforce already took care of that for me. I just needed to add the Rating field.
Using the New button, I selected the number field type and populated Step Two as noted below:
I used the default values and saved my new field. Now, I can use both the name and rating fields in my iOS application.
Using the Salesforce client, I populated some source data to develop the application in Xcode. Below is a summary of the submitted values:
Based upon the sample data, Finny always prefers ”Pizza” over “Chicken & Rice”.
Adding Meal Functionality in Xcode
With the source object and data configured, I used my Xcode application to open the finnys-foods-ios
project for the first time.
By default, the forceios
CLI creates a working application that displays Account and Contact information for the Salesforce org tied to the user account when running for the first time. To make things easier, I decided to go ahead and remove the following files from the project:
- AccountsListModel.swift
- AccountsListView.swift
- ContactDetailModel.swift
- ContactDetailsView.swift
- ContactsForAccountListView.swift
- ContactsForAccountModel.swift
Since I plan to cover offline functionality in a future article, I updated the configuration data in the userstore.json
to:
{
"soups": [
]
}
The usersyncs.json
file was also purged as shown below:
{
"syncs": [ ]
}
Next, I created a basic list view for the Meal__c object
in Salesforce, called MealsListView.swift
.
import Foundation
import SwiftUI
import Combine
import SalesforceSDKCore
struct MealsListView: View {
var body: some View {
Text("Finny's Foods (iOS)").bold()
}
}
struct MealsList_Previews: PreviewProvider {
static var previews: some View {
MealsListView()
}
}
To use the meals list view when the application starts, I updated the setupRootViewController()
method in the SceneDelegate.swift
file as shown below:
func setupRootViewController() {
// Setup store based on config userstore.json
MobileSyncSDKManager.shared.setupUserStoreFromDefaultConfig()
// Setup syncs based on config usersyncs.json
MobileSyncSDKManager.shared.setupUserSyncsFromDefaultConfig()
self.window?.rootViewController = UIHostingController(
rootView: MealsListView()
)
}
At this point, we have a functional iOS application that will merely show “Finny’s Foods (iOS)” using bold text.
Using Font Awesome in Xcode
Before I built out the rest of the application, I wanted to see how easy it would be to add Font Awesome icons in a Swift application created in Xcode. As you may recall, this task was super easy with React Native and not-so-easy in Android studio.
I was able to use the steps provided at the following URL to get things working in about 15 minutes. I fully expect those with Xcode experience to complete these steps in a fraction of the time:
As a result of these steps, the following supporting files are now part of my project:
- fa-brands-400.ttf
- fa-regular-400.ttf
- fa-solid-900.ttf
- icons.json
Creating a Meals List Model
The Xcode application needs to understand the Meal__c
object which is driving the Finny’s Foods application. I created a MealsListModel.swift
file which contained the following information:
import Combine
import SmartStore
import MobileSync
struct Meal: Hashable, Identifiable, Decodable {
let id: UUID = UUID()
let Id: String
let Name: String
let Rating__c: Int
}
struct MealResponse: Decodable {
var totalSize: Int
var done: Bool
var records: [Meal]
}
class MealsListModel: ObservableObject {
@Published var meals: [Meal] = []
private var mealsCancellable: AnyCancellable?
func fetchMeals(){
let request = RestClient.shared.request(forQuery: "SELECT Id, Name, Rating__c FROM Meal__c ORDER BY Name ASC", apiVersion: nil)
mealsCancellable = RestClient.shared.publisher(for: request)
.receive(on: RunLoop.main)
.tryMap({ (response) -> Data in
response.asData()
})
.decode(type: MealResponse.self, decoder: JSONDecoder())
.map({ (record) -> [Meal] in
record.records
})
.catch( { error in
Just([])
})
.assign(to: \.meals, on:self)
}
}
This file introduces a Meal object that contains the meta-data for each Meal__c
object stored in Salesforce. There is also a MealResponse
object, which represents the payload provided by Salesforce when asking for Meal__c
data.
With those two key structures defined, the fetchMeals()
method makes a RESTful API call to Salesforce, then maps any response data to a list of Meal objects. The MealsListView.swift
file created earlier then processes this data.
Updating the Meals List View
With the Meals List Model ready, the Meals List View can now be expanded to integrate with Salesforce and present data onto an iOS device. The first thing I had to do was establish a variable for the Meals List Model in the MealsListView.swift
file:
struct MealsListView: View {
@ObservedObject var viewModel = MealsListModel()
Next, I updated the body variable in the MealsListView.swift
file as shown below:
var body: some View {
Text("Finny's Foods (iOS)").bold()
List(viewModel.meals) { dataItem in
HStack(spacing: 10) {
VStack(alignment: .leading, spacing: 3) {
HStack {
Text(dataItem.Name)
}
}
}
}
.onAppear{ self.viewModel.fetchMeals() }
At this point, the iOS application shows the name of each meal on a new line. The fetchMeals()
method call retrieves data from Salesforce, processing each Meal__c
item as dataItem
.
However, I really wanted to add the star-rating system used in the React Native project. To do this, I updated the inner-most HStack
object as shown below:
HStack {
Text(dataItem.Name)
Text(" ")
switch dataItem.Rating__c {
case 5:
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15, style: .solid)
case 4:
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15)
case 3:
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15)
FAText(iconName: "star", size: 15)
case 2:
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15)
FAText(iconName: "star", size: 15)
FAText(iconName: "star", size: 15)
default:
FAText(iconName: "star", size: 15, style: .solid)
FAText(iconName: "star", size: 15)
FAText(iconName: "star", size: 15)
FAText(iconName: "star", size: 15)
FAText(iconName: "star", size: 15)
}
}
With these changes in place, the iOS application is ready for use.
Finny’s Foods in Action
Using Xcode, I used the Product menu option and selected the Run option.
First-time use will automatically redirect to a Salesforce login screen, where I used the same email address and password to access my Developer org. After signing in, the Finny’s Foods application appeared, including the five-star rating value for each item.
In a matter of minutes, we were able to create an iOS application using Xcode and the Salesforce Mobile SDK.
Conclusion
In this article, I introduced a custom mobile application that deploys natively from the Apple store and uses source code written in Swift. Along the way, we gained a basic understanding of how iOS-based applications are structured.
Starting in 2021, I have been trying to live by the following mission statement, which I feel can apply to any IT professional:
“Focus your time on delivering features/functionality which extends the value of your intellectual property. Leverage frameworks, products, and services for everything else.”
- J. Vester
The Salesforce Mobile SDK certainly adheres to my personal mission statement, which will benefit any feature team that requires Salesforce functionality as part of custom mobile applications running on iOS devices. Software engineers in this realm of development should certainly consider adding the Salesforce Mobile SDK as a project dependency.
If you wish to see the full source code for this article, visit my project on GitLab:
https://gitlab.com/johnjvester/finnys-foods-ios
Have a really great day!