快速地,Salesforce是一个框架,用于快速开发与之交互的本地iOS移动应用程序。

更新,2018年10月10日:Salesforce现在变得更加易于设置,配置和使用。 在GitHub上检查当前版本的README文件。

Swiftly Salesforce是一个框架,用于快速开发与Salesforce平台进行交互的本机iOS移动应用程序。

  • 苹果公司的“安全,快速和交互式的现代编程语言”完全用Swift编写。
  • 为复杂的异步Salesforce API交互提供简洁,轻松的编码
  • 自动透明地管理Salesforce OAuth2授权过程(“ OAuth舞步”)
  • 适用于iOS的Salesforce Mobile SDK的更简单,更轻便的替代方案
  • 易于安装和更新

如何快速设置Salesforce?

您可以按照以下步骤在几分钟内启动并运行:

  1. 免费获得Salesforce开发人员版
  2. 设置Salesforce联网应用
  3. 在iOS上注册您的Connected App的回调URL方案(请参阅附录)
  4. 快速将Salesforce添加到您的Xcode项目:
    pod 'SwiftlySalesforce'添加到项目的Podfile中(请参阅附录),
    或仅将这些Swift源文件复制到您的项目中,然后添加相关框架
  5. Swift Salesforce配置您的应用程序委托(请参阅附录)
  6. 为salesforce.com添加ATS例外(请参阅附录)

最低要求:

  • iOS 10.0
  • 迅捷3
  • Xcode 8

文献资料

文档在这里。 尤其要查看Salesforce类的公共方法-这些可能是您需要从代码中调用的所有方法。

例子

下面是一些示例,以说明如何快速使用Salesforce以及如何链接复杂的异步调用。 您还可以在这里找到完整的示例应用程序; 它从Salesforce检索登录用户的任务记录,并使用户能够更新任务的状态。

Salesforce迅速自动管理整个Salesforce OAuth2流程(“ OAuth交流”)。 如果Swiftly Salesforce具有有效的访问令牌,它将在每个API请求的标头中包含该令牌。 如果令牌已过期,并且Salesforce拒绝该请求,则Swiftly Salesforce将尝试刷新访问令牌,而不会打扰用户重新输入用户名和密码。 如果Swiftly Salesforce没有有效的访问令牌或无法刷新它,则Swiftly Salesforce会将用户定向到Salesforce托管的登录表单。

在后台,Swiftly Salesforce充分利用Alamofire和PromiseKit这两个非常广泛采用的框架,用于优雅地处理网络请求和异步操作。

示例:将您的应用程序配置为与Salesforce对话

 导入UIKit 
迅速导入Salesforce
  @UIApplicationMain 
AppDelegate类:UIResponder,UIApplicationDelegate,LoginDelegate {
  var window:UIWindow? 
  /// Salesforce Connected App属性(替换为您自己的…) 
让ConsumerKey =“ 3MVG91 ...”
让redirectURL = URL(字符串:“ taskforce:// authorized”)!
  func application(_ application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplicationLaunchOptionsKey:Any]?)->布尔{ 
configureSalesforce(consumerKey:ConsumerKey,redirectURL:redirectURL)
返回真
}
  func application(_ app:UIApplication,打开url:URL,选项:[UIApplicationOpenURLOptionsKey:Any] = [:])-> Bool { 
handleRedirectURL(URL:网址)
返回真
}
}

在上面的示例中,请注意以下内容:

  1. 您的应用程序委托应实现LoginDelegate
  2. consumerKeyredirectURL的值替换为Connected App中定义的值
  3. 如图所示,调用configureSalesforce()handleRedirectURL()

示例:检索Salesforce记录

以下将检索帐户记录的所有字段:

  salesforce.retrieve(类型:“帐户”,ID:“ 0013000001FjCcF”) 

要指定应检索的字段:

  let字段= [“ AccountNumber”,“ BillingCity”,“ MyCustomField__c”] 
salesforce.retrieve(类型:“帐户”,ID:“ 0013000001FjCcF”,字段:字段)

请注意, retrieve()是一个异步函数,其返回值是一个“承诺”,将在将来的某个时刻实现:

 让诺言= salesforce.retrieve(类型:“帐户”,ID:“ 0013000001FjCcF”) 

我们可以添加一个闭包,当实现诺言时将在以后调用它:

 答应。然后{ 
queryResult在
用于queryResult.records {
//解析记录字段和值的JSON字典,并做一些有趣的事情……
}
}

示例:更新Salesforce记录

  salesforce.update(类型:“任务”,ID:“ 00T1500001h3V5NEAU”,字段:[“状态”:“已完成”]) 
。然后 {
(_)->()在
//更新本地模型
}。始终{
//更新用户界面
}

无论promise链中其他位置是成功还是失败,都将调用always关闭。

示例:查询

  let soql =“从帐户WHERE BillingPostalCode ='\(postalCode)'中选择ID,名称 
salesforce.query(soql:soql)

请参阅下一个示例来处理查询结果。

示例:链接异步请求

假设我们要从自定义的Apex REST资源中检索一个随机的邮政编码,然后在查询中使用该邮政编码:

  //链式请求 
首先{
//发出自定义Apex REST资源的GET请求
//(将其包含在“ first”块中是可选的,可以使事情保持整洁。)
salesforce.apexRest(路径:“ / MyApexResourceThatEmitsRandomZip”)
}。然后 {
//查询该邮政编码中的帐户
造成
卫队让zip = result [“ zip”]为? 其他字符串{
抛出TaskForceError.generic(100,“无法从我们的自定义REST端点获取随机邮政编码!”)
}
let soql =“选择帐户的ID,名称,WILLE BillingPostalCode ='\(zip)'”
返回salesforce.query(soql:soql)
}。然后 {
queryResult在
用于queryResult.records {
如果让name = record [“ Name”]为? 字符串{
打印(“帐户名= \(名称)”)
}
}
}

您可以多次重复此链接,将一个异步操作的结果作为下一个输入的输入。 或者,您可以生成多个同时执行的操作,并轻松地指定在所有操作完成时,或仅在第一个操作完成时或在任何一个操作失败时执行的逻辑。PromiseKit是一个功能强大的框架,用于处理多个异步操作,这些操作将否则很难协调。 有关更多示例,请参见PromiseKit文档。

示例:处理错误

以下代码改编自示例文件TaskStore.swift,并显示了如何处理错误:

 首先{ 
//获取当前用户的ID
salesforce.identity()
}。然后 {
//查询用户拥有的任务
中的userInfo
警卫让userID = userInfo.userID else {
抛出TaskForceError.generic(代码:100,消息:“无法确定用户ID”)
}
let soql =“从任务WHERE OwnerId ='\(userID)'ORDE R BY CreatedDate DESC中选择SELECT Id,Subject,Status,What.Name
返回salesforce.query(soql:soql)
}。然后 {
//将JSON解析为Task实例
(结果:QueryResult)->()在
让任务= result.records.map {Task(dictionary:$ 0)}
//对任务做一些有趣的事情...
} .catch {
错误中
//处理错误…
}

您还可以从错误中恢复,并使用recover闭包继续执行链。 以下代码片段来自PromiseKit的文档:

  CLLocationManager.promise()。recover {err in 
后卫!err.fatal else {throw err}
返回CLLocationChicago
}。然后{
//用户的位置;如果发生错误,则返回芝加哥
} .catch {err in
//错误是致命的
}

示例:检索对象元数据

例如,如果您要确定用户是否有权更新或删除记录,以便可以在用户界面中禁用编辑,或者要检索选择列表中的所有选项,而不是在移动应用中对其进行硬编码,然后调用salesforce.describe()来检索对象的元数据:

 首先{ 
salesforce.describe(“帐户”)
}。然后 {
(accountMetadata)->()在
saveButton.enabled = accountMetadata.isUpdateable
让industryOptions = accountMetadata.fields [“ Industry”] ?. picklistValues
} .catch {
错误中
debugPrint(错误)
}

示例:注销

如果要注销当前的Salesforce用户,然后清除所有本地缓存​​的数据,则可以调用以下命令。 Salesforce迅速撤消并删除所有存储的凭据,并在Salesforce登录页面上自动显示Safari View Controller,以供其他用户登录。

  //例如,在点击应用的“注销”按钮时调用 
如果让app = UIApplication.shared.delegate为? LoginDelegate {
app.logout()。then {
()->()在
//清除所有缓存的数据并重置UI
返回
} .catch {
错误中
debugPrint(错误)
}
}

快速Salesforce的主要组件

  • Salesforce.swift:这是您与Salesforce平台的Swift界面,可能是您将引用的唯一文件。 它具有查询,检索,更新和删除记录以及访问自定义Apex REST端点的方法。
  • Router.swift:充当Alamofire请求的“路由器”。 较重要且常用的Salesforce REST API端点表示为枚举值,其中包括一个用于自定义Apex REST端点的值。
  • AuthData.swift:保存对Salesforce REST API的每个请求所需的令牌和其他数据的Swift结构。 这些值安全地存储在iOS钥匙串中。
  • Extensions.swift: Swiftly Salesforce的其他组件使用的Swift扩展。 您可能在自己的代码中使用的扩展名是DateFormatter.salesforceDateTimeDateFormatter.salesforceDate ,用于将Salesforce日期/时间和日期值与字符串进行转换,以进行JSON序列化。
  • AuthManager.swift:协调OAuth2授权过程,并安全地存储和检索结果访问令牌。 访问令牌必须包含在对Salesforce REST API的每个HTTP请求的标头中。 如果访问令牌已过期,则AuthManager将尝试刷新它。 如果刷新过程失败,则AuthManager将调用其委托对用户进行身份验证,即显示由Salesforce托管的Web登录表单。 默认实现使用Safari View Controller(iOS 9中的新增功能)通过OAuth2“用户代理”流程对用户进行身份验证。 尽管“用户代理”流程比OAuth2的“用户名密码”流程更为复杂,但这是向Salesforce验证用户身份的首选方法,因为其凭据永远不会由客户端应用程序处理。

依赖框架

Swiftly Salesforce利用的出色Swift框架:

  • PromiseKit:“不仅是承诺的实现,它还是帮助函数的集合,这些函数也使我们作为iOS开发人员使用的典型异步模式也令人愉快。”
  • Alamofire:“ Swift中的优雅HTTP网络”
  • Locksmith:“一个强大的,面向协议的库,用于在Swift中使用钥匙串。”

资源资源

如果您不熟悉Swift,Salesforce平台或Salesforce REST API,则可能会发现以下有用的资源:

  • Salesforce REST API开发人员指南
  • Salesforce应用程序云:又名Salesforce平台
  • Salesforce开发人员:Salesforce开发人员的官方网站; 培训,文档,SDK等
  • Salesforce合作伙伴社区:与Salesforce ISV进行“创新,发展,联系”。 加入Salesforce + iOS MobileChatter组
  • 适用于iOS的Salesforce Mobile SDK:Salesforce支持的SDK,用于开发移动应用程序。 用Objective-C编写。 也适用于Android
  • Salesforce Swift应用程序:有关将Swift与Salesforce Mobile SDK结合使用的博客文章。 乔纳森·詹金斯(Jonathan Jenkins)
  • 何时使用Salesforce1平台与创建自定义应用程序
  • Alamofire:AFNetworking的Swift版本,“……是iOS和OS X上最受欢迎的第三方库之一。”此处的教程。
  • 带有REST API的iOS应用:关于Swift,REST API,JSON和Alamofire入门的好书。 “只需要立即完成实际工作就可以了:与Web服务接口并在UI中显示结果。” GrokSwift的Christina Moulton
  • Salesforce Mobile SDK快速入门:William Welbes的博客文章

关于我

我是Salesforce的一名资深技术“传播家”,并且与正在使用Salesforce平台构建应用程序的ISV合作伙伴一起工作。

联系

欢迎提出问题,建议,错误报告和代码贡献:

  • 打开GitHub问题
  • Twitter @ mike4aday
  • 加入Salesforce合作伙伴社区并发布到“ Salesforce + iOS移动”聊天小组

附录

快速将Salesforce添加到您的CocoaPods Podfile

快速将Salesforce添加到简单的Podfile中:

 target 'MyApp' do 
use_frameworks!
pod 'SwiftlySalesforce'
# Another pod here
end

详情请参阅Podfile

在iOS上注册连接的应用程序的回调URL方案

成功获得OAuth2授权后,Salesforce将Safari View Controller重定向回您在Connected App设置中指定的回调URL,并将访问令牌(除其他外)附加到该回调URL。 将以下内容添加到应用程序的.plist文件中,以便iOS知道如何处理URL,并将其传递给应用程序的委托。

   
CFBundleURLTypes


CFBundleURLName
SalesforceOAuth2CallbackURLScheme
CFBundleURLSchemes




然后,您只需要在应用程序委托类中添加一行,以便Swiftly Salesforce将处理回调URL和附加的凭据。

  func application(_ app:UIApplication,打开url:URL,选项:[UIApplicationOpenURLOptionsKey:Any] = [:])-> Bool { 
handleRedirectURL(redirectURL:url为URL)
返回真
}

迅速配置您的App代表

更新您的应用程序委托类,使其:

  • 使用连接的应用程序的使用者密钥和回调URL快速配置Salesforce
  • 实现LoginDelegate –但是,由于Swift协议扩展的LoginDelegate ,您无需实现任何方法
  • 当iOS要求打开回调URL时,调用handleRedirectURL(url:)
 导入UIKit 
迅速导入Salesforce
  @UIApplicationMain 
AppDelegate类:UIResponder,UIApplicationDelegate,LoginDelegate {
  var window:UIWindow? 
  /// Salesforce Connected App属性(替换为您自己的...) 
let ConsumerKey =“ ”
让redirectURL = URL(string:“ ”)!
  func application(_ application:UIApplication,didFinishLaunchingWithOptions launchOptions:[UIApplicationLaunchOptionsKey:Any]?)->布尔{ 
configureSalesforce(consumerKey:ConsumerKey,redirectURL:redirectURL)
返回真
}
  func application(_ app:UIApplication,打开url:URL,选项:[UIApplicationOpenURLOptionsKey:Any] = [:])-> Bool { 
handleRedirectURL(URL:网址)
返回真
}
}

为Salefsorce添加ATS例外

在撰写本文时,您需要向iOS应用程序的.plist文件添加应用程序传输安全性(ATS)异常,以使其能够连接至salesforce.com,如下所示:

   
NSAppTransportSecurity

NSExceptionDomains

salesforce.com

NSExceptionRequiresForwardSecrecy

NSIncludesSubdomains