原生 iOS 开发(Native iOS)

本模块带你用 Salesforce Mobile SDK 构建原生 iOS 应用:从创建外部客户端应用、用 forceios 生成 Swift 项目并运行,到理解 AppDelegate 与 SceneDelegate 驱动的启动流程,再到通过 RestClient publisher 访问 Salesforce 数据、为模板加删除按钮发送 REST 请求,最后用 CocoaPods 把 Mobile SDK 集成进既有项目。...

📅 2026/10/12 ✍️ ponybai 🏷️ salesforce, headless

一、开始使用 Native iOS 开发(01 Get Started with Native iOS Development)

slide_2
slide_5

本单元介绍 Salesforce Mobile SDK for iOS 的两大核心特性,指导你安装 Mobile SDK、用 forceios 创建原生 iOS 项目并指定应用配置选项,最后运行 Xcode 模板应用。配套的 Trail Together 视频由专家带你一步步完成本单元操作,可以边看边跟着做(可选,不做也能拿徽章)。

开始之前:创建外部客户端应用(Before You Start: Create an External Client App)

slide_3

每款 Salesforce 移动应用都离不开一个外部客户端应用(External Client App):它授权你的应用与 Salesforce 通信,并安全访问 Salesforce API。动手之前,请先完成 Set Up Your Mobile SDK Development Environment 项目和 Salesforce Mobile SDK Basics 徽章,且必须使用同一个 Trailhead Playground 或 Developer Edition,否则无法完成本模块的动手挑战。

创建并保存外部客户端应用后,记录两个关键值:

  • Callback URL(回调 URL);
  • Consumer Key(消费者密钥)。

这两个值会在配置应用鉴权时用到。注意:Mobile SDK 应用不使用 consumer secret,因此该值可以直接忽略。

Native iOS 开发(Native iOS Development)

slide_4

Salesforce Mobile SDK 为构建访问 Salesforce 的原生 iOS 应用提供技术与工具,从多个方面简化开发:

  • 自动完成 OAuth2 登录流程,集成登录与可选 passcode 变得轻而易举;
  • 通过包装方法访问 Salesforce REST API,让 SOQL 查询、SOSL 搜索、CRUD 操作都变得简单;
  • 可用 Objective-C 或 Swift 编写原生应用,Swift 是推荐路径。

本模块要做四件事:创建简单 Swift 应用 → 运行 Xcode 模板项目 → 修改它以删除记录 → 用 CocoaPods 把 Mobile SDK 加入既有项目。

用 Forceios 创建 iOS 项目(Create an iOS Project with Forceios)

slide_6

用 forceios 创建项目很简单。在终端窗口输入 forceios,工具会提示你为新项目输入配置值,使用如下配置:

  • Application type:native_swift(或直接回车使用默认值);
  • Application name:MyTrailNativeApp;
  • Package name:com.mytrail.ios;
  • Organization name:MyApps, Inc.;
  • Output directory:TrailiOSApps。

随后出现一串日志消息,最后是祝贺信息——你的新原生 iOS 应用已准备好运行。实际生产中 forceios 并非必需:你也可以手动创建原生 iOS 项目(不使用 forceios、npm 或 CocoaPods),详见文末 Resources。

运行你的新 iOS 应用(Run Your New iOS App)

slide_7

forceios 生成的项目会执行一次简单的 SOQL 查询,并展示一个账户表格,每个账户可下钻查看其联系人详情。运行步骤如下:

  1. 在 Xcode 中 File → Open,导航到 TrailiOSApps 文件夹,选中 MyTrailNativeApp.xcworkspace(务必打开 workspace 文件而非 project 文件);
  2. 在 bootconfig.plist 的 Root 节点里,把 remoteAccessConsumerKey 设为外部客户端应用的消费者密钥、oauthRedirectURI 设为回调 URL;
  3. Product → Run(⌘R),用 Developer Edition 的用户名密码登录;若组织配置了双因素认证,完成 2FA 请求;
  4. 提示时点击 Allow 允许应用访问 Salesforce 数据,即可看到 DE 组织里定义的账户名称表格。

如上图所示,登录并授权后,模板应用会列出组织中的账户记录,点击任一账户即可下钻查看联系人。

二、理解 Forceios 原生应用(02 Understand Forceios Native Apps)

slide_8
slide_9

本单元讲解原生 iOS 应用是如何组装起来的:整体的 MVC 应用流、启动时的事件顺序,以及 AppDelegate 与 SceneDelegate 如何把控制权交给你的内容。本单元 Trail Together 视频从 14:49 处开始,可回看前面部分。

应用流程概览(Overview of Application Flow)

slide_10

从表面看,Mobile SDK 原生应用只是一个普通的 iOS 应用,可用 MVC(Model-View-Controller) 架构来理解:

  • Model 是 Salesforce Platform 数据库 schema;
  • View 来自项目中的 nib 与实现文件(SwiftUI);
  • Controller 是 iOS Cocoa Touch 类、Salesforce Mobile SDK 类以及你的自定义类的组合。

和所有 iOS 应用一样,Mobile SDK 原生应用从一个样板 main 模块开始,建立主事件循环(Xcode 自动生成,通常无需改动)。iOS 13 的 Mobile SDK 模板还定义了以下可自定义的类:AppDelegate(SDK 初始化)、SceneDelegate(场景生命周期与用户鉴权)、InitialViewController(登录界面容器)以及根视图控制器(应用内容)。forceios 原生应用默认用 MobileSyncSDKManager(SalesforceManager 的专门子类)初始化,启用完整 Mobile SDK 功能。

上图展示了使用最全面的 SDK manager——MobileSyncSDKManager 时,原生应用的启动流程。

应用启动流程(Application Launch Flow)

slide_11

当用户打开应用,会发生一串相当复杂的事件:

  1. 应用配置;
  2. 初始化 Salesforce Mobile SDK;
  3. 校验应用 passcode(可选);
  4. 执行 Salesforce 登录与鉴权;
  5. 启动应用。

SDK manager 对象强制正确的启动顺序,让你不必操心大部分启动事件。forceios 应用使用 MobileSyncSDKManager(SalesforceManager 子类,额外启用离线特性)调用 initializeSDK() 初始化。SalesforceManager 内部为鉴权、PIN 失败、前台状态等事件设置观察者。需要牢记的一点是:代码必须始终在这单一共享实例上调用 SDK manager 方法。

AppDelegate 类(AppDelegate Class)

slide_12

Mobile SDK 初始化后,AppDelegate 实现你可按需自定义的 UIApplicationDelegate 协议方法,每个方法都带注释指导。例如:

  • 自定义新 scene session 配置:改 application(_:configurationForConnecting:options:) 的返回值;
  • 清理废弃 scene 资源:用 application(_:didDiscardSceneSessions:) 释放资源;
  • 注册推送通知:按 application(_:didFinishLaunchingWithOptions:) 注释操作,iOS 端需要扩展处理解密;
  • 注册设备 token:application(_:didRegisterForRemoteNotificationsWithDeviceToken:) 回调传入 token;
  • 处理推送注册失败:在 application(_:didFailToRegisterForRemoteNotificationsWithError:) 中处理;
  • 启用 IDP 服务:按 application(openURL:options:) 注释把应用作为其他 Mobile SDK 应用的身份提供者。

SceneDelegate 类(SceneDelegate Class)

slide_13

在 iOS 13+ 的 Swift 应用中,SceneDelegate 是应用的"发射台":它管理场景生命周期事件(连接、进入前后台、活跃/非活跃、调整大小),并在 Mobile SDK 术语里负责:必要时显示 Salesforce 登录界面、登出时重置视图状态、导入 SmartStore 与 Mobile Sync 的配置文件、把 window 根视图设为应用首个自定义视图。

例如 setupRootViewController() 会先加载 SmartStore 与 Mobile Sync 的离线配置,再设置 self.window?.rootViewController = UIHostingController(rootView: AccountsListView())——这里的 AccountsListView 是展示组织账户名称列表的自定义 SwiftUI 视图。从这一刻起,应用的内容、流程与意图就交回到你的自定义代码手中。

三、通过 REST API 访问 Salesforce 数据(03 Access Salesforce Data through REST APIs)

slide_14
slide_15

本单元讲解原生应用如何拉取 Salesforce 数据:构建 REST 请求、通过 RestClient publisher 发送,并了解 SmartStore 与 Mobile Sync publisher 提供的同款离线模式。本单元 Trail Together 视频从 16:05 处开始。

发送 REST 请求(Sending REST Requests)

slide_16

在自定义视图中,你通过 Salesforce API 访问 org 数据。SwiftUI 应用采用视图-模型(view-model)架构:视图类定义界面,运行时调用配对的模型类获取数据。在 Mobile SDK Swift 模板里,模型类位于 Models 文件夹。例如 ContactsForAccountModel.swift 负责请求某账户的联系人列表,处理返回记录后把联系人信息交给 ContactsForAccountListView。

一次数据请求的流程是:模型构建 REST 请求 → 发送给 Salesforce → 返回响应 → 模型解码为 Swift 对象 → 视图渲染结果。RestClient 是所有 REST 服务的入口。

使用 RestClient Publisher(Using the RestClient Publisher)

slide_17

RestClient 是所有 REST 服务的入口,始终通过共享实例访问。标准"发送请求"序列如下:

  1. 创建并初始化 RestRequest 实例——RestClient 提供大量工厂方法,示例创建一个 SOQL 查询请求;
  2. 把请求对象发送给 Salesforce——RestClient 自动用当前用户凭证鉴权。

处理响应则借助 Mobile SDK 的 Swift Combine publisher:RestClient.shared.publisher(for:) → receive(on: RunLoop.main) → tryMap { $0.asData() } → decode(ContactResponse) → assign(to: \.contacts)。若网络调用失败或 Salesforce 返回错误,处理会落到 .catch 块。模板中的 fetchContactsForAccount() 方法演示了这条完整调用链。

其他选项(Other Options)

slide_18

RestClient.shared.publisher 并非获取 Salesforce 数据的唯一途径。模板里的 AccountsListModel 还使用了另外两个 publisher:SmartStore publisher 与 Mobile Sync publisher——它们正是 Mobile SDK 的两大离线特性:

  • SmartStore:设备上的加密本地存储,作为 Salesforce 记录的离线仓库,网络断开时用户仍可继续工作;
  • Mobile Sync:负责获取 Salesforce 记录、存入 SmartStore soup(类似数据库表),并在下载新记录或上传本地更改时保持 SmartStore 与服务端记录同步。

这些 publisher 在 Swift 类扩展中定义,代码很薄——实际功能委托给 SmartStore 或 Mobile Sync 方法完成。

四、修改 Forceios 原生应用(04 Modify the Forceios Native App)

slide_19
slide_20

本单元让模板应用变得可交互:在联系人详情视图加一个删除按钮、用 action sheet 确认、从模型发送 REST 删除请求,并在模拟器中测试。本单元 Trail Together 视频从 18:11 处开始。

自定义 Forceios Swift 应用(Customizing a Forceios Swift App)

slide_21

forceios 生成的 Swift 模板展示组织中的账户名称列表:可查看所选账户详情、进而查看账户的联系人列表、再选中联系人查看详情——但用户只能看,不能改。本单元目标:给联系人详情视图加一个"删除"按钮,用户点击后:

  1. 先弹出确认(action sheet),防止误删;
  2. 发送 REST DELETE 请求删除所选 Contact 记录。

练习可复用开篇单元创建的 Mobile SDK workspace。这个练习同时涉及 UI(SwiftUI 视图)与数据(模型)两方面。

视图与模型(Views and Models)

slide_22

SwiftUI 应用把 UI 与数据分离。看 Xcode 项目的 Classes 文件夹,包含两个子文件夹:

  • SwiftUI 文件夹(视图):SwiftUI 布局 struct,声明式配置界面内容与外观;
  • Models 文件夹(模型):运行时为视图提供数据,如获取账户名或删除 Contact 记录,通常含一个核心类 + 若干数据 struct。

每个模型与配对的视图共享文件名前缀:ContactDetailsModel.swift 对应 ContactDetailsView.swift,AccountsListModel ↔ AccountsListView。视图调用模型,模型完成实际工作。

添加删除按钮(Add the Delete Button)

slide_23

先做视觉部分:在 ContactDetailsView.swift 里把现有 List 包进 VStack,再在 List 下方加一个 Button(action 先 print 到控制台)。

为保护数据,添加 @State deleteWarning 状态变量,点击按钮后弹出一个 action sheet(含 Cancel 与 OK 两个按钮)。然后点 Run 测试:iPhone 模拟器启动后显示 Salesforce 登录界面,登录并授权数据访问。

在 Accounts 视图点击任一账户名查看联系人列表(如上图),再点任一联系人进入 ContactDetails 视图,点击底部的 Delete Contact 按钮,检查 Xcode 调试控制台是否输出 "Delete Contact button tapped."。想换颜色?改 Button 的 foregroundColor 与 background 属性,停止并重启应用即可看到变化。

发送删除请求到 Salesforce(Send the Delete Request to Salesforce)

slide_24

让按钮真正删除记录,需要在模型源文件里加代码。在 ContactDetailsModel.swift 中定义一个 deleteContact(contact: Contact) 方法:

  1. 用 RestClient.shared.requestForDelete(withObjectType: "Contact", objectId: contact.Id, apiVersion: nil) 构建删除请求;
  2. 用 RestClient.shared.send(request:) 发送,第二参数传入完成闭包;
  3. 在闭包里用 switch 处理 .success(打印 "Contact deleted.")与 .failure(打印友好错误,可能因该联系人关联 case 或其他依赖)。

最后在 action sheet 的 OK 按钮里创建 ContactDetailModel 实例并调用 deleteContact(contact:)。生产级可把 send 换成 Combine publisher 并发布删除结果,让视图 UI 或 alert 向用户反馈成败。

动手试试(Try It Out!)

slide_25

在 iOS 模拟器里构建并运行代码。注意:Developer Edition 里预置的默认联系人往往都是其他记录的父记录,删除它们会返回错误。为准备测试,登录你的 Developer Edition 组织,创建一个或多个不拥有子记录的测试联系人,再运行应用删除这些联系人以验证流程。

生产级优化方向:把删除结果发布到 UI(用 Combine publisher + alert),让用户明确知道删除成功与否,而不是回到列表页才发现联系人是否还在。

五、把 Mobile SDK 加入既有项目(05 Add Mobile SDK to an Existing Project)

slide_26
slide_27

本单元讲解如何用 CocoaPods 把 Mobile SDK 合并进既有 iOS 应用、如何更新既有 Mobile SDK 应用,以及 Mobile SDK 各 pod 之间的依赖关系。本单元 Trail Together 视频从 22:11 处开始。

用 CocoaPods 集成 Mobile SDK(Using CocoaPods with Mobile SDK)

slide_28

Mobile SDK 为每个模块提供 CocoaPods pod 规格(podspec):

  • SalesforceSDKCore:实现 OAuth、passcode、网络与 REST API;
  • SmartStore:实现安全离线存储,依赖 SalesforceSDKCore;
  • MobileSync:实现离线同步,依赖 SmartStore;
  • SalesforceAnalytics:上报 Mobile SDK 功能使用与流行度的匿名统计;
  • SalesforceSDKCommon:SDK 共享工具。

如上图所示,各 podspec 之间存在依赖关系(箭头从依赖方指向其依赖)。声明一个 pod 会自动带入其整条依赖链——例如声明 MobileSync 就自动得到 SmartStore 与 SalesforceSDKCore。

在 Podfile 中集成 Mobile SDK 的步骤:

  1. 把 SalesforceMobileSDK-iOS-Specs 仓库作为 source,且必须放在 CocoaPods Specs 源之前;
  2. 添加 use_frameworks! 支持动态框架;
  3. 声明需要的 pod:pod 'SalesforceSDKCore' 是最小配置,或声明 pod 'MobileSync' 自动带入 SmartStore 与 SalesforceSDKCore;
  4. 运行 pod install,之后务必只从生成的 .xcworkspace 打开项目(而非 .xcodeproj)。

可选 dev 分支流程:clone SalesforceMobileSDK-iOS 仓库 → git checkout dev → 根目录运行 ./install.sh → 每个 pod 加 :path 指向本地 clone。Objective-C 应用用尖括号导入头文件,如 #import <SalesforceSDKCore/SFRestAPI.h>。


文章来源:Trailhead - Native iOS