IFTTTConnectSDK 2.8.0

IFTTTConnectSDK 2.8.0

Siddharth Sathyam 维护。



  • 作者:
  • Siddharth Sathyam

IFTTT SDK

IFTTT SDK 是一个 Swift 编写的 iOS 库,允许用户直接在您的应用程序中激活可编程连接。您可以在 这里 找到 API 文档。

特点

  • 通过连接按钮轻松将您的服务认证到IFTTT
  • 通过代码或界面构建器使用 IBDesignable 配置连接按钮
  • 配置 ConnectButtonController 以处理连接激活流程
  • (从 2.5.0 版本开始) 提供用于通过 IFTTT 位置服务 使用 Apple CoreLocation 区域监控 的原生物理围栏功能。

要求

  • iOS 10.0+
  • Xcode 11+
  • Swift 4.0

安装

Swift包管理器

在Xcode中,选择文件 > Swift包 > 添加包依赖,并输入仓库URL https://github.com/IFTTT/ConnectSDK-iOS

CocoaPods

CocoaPods是一个用于Cocoa项目的依赖管理器。有关使用和安装说明,请访问他们的网站。要使用CocoaPods将Connect SDK集成到Xcode项目中,在您的Podfile中指定它。

pod 'IFTTTConnectSDK'

Carthage

Carthage是一个去中心化的依赖管理器,它构建你的依赖并提供二进制框架。要使用Carthage将Connect SDK集成到Xcode项目中,在您的Cartfile中指定它。

github "IFTTT/ConnectSDK-iOS"

使用Carthage生成框架后,将库或框架拖放到XCode项目设置中目标的“框架、库和嵌入内容”部分。

升级到2.6.0

在2.6.0之前的SDK版本中使用Carthage时,输出构建工件名称为IFTTT_SDK.*。但是,从2.6.0版本开始,输出的Carthage构建工件将具有名称IFTTTConnectSDK.*。您需要删除现有的IFTTT_SDK.*文件,并用新生成的IFTTTConnectSDK.*文件替换它。

手动方式

嵌入式框架

  • 下载项目文件夹,并将 IFTTT SDK.xcodeproj 拖动到应用项目的 Xcode 项目导航器中。

    它应该出现在应用项目的蓝色项目图标下方。它是在所有其他 Xcode 组上方还是下方不影响。

  • 在项目导航器中选择 IFTTT SDK.xcodeproj,并验证部署目标与您的应用目标匹配。

  • 接下来,在项目导航器中(蓝色项目图标)选择应用项目以导航到目标配置窗口,然后在侧边栏的“目标”标题下选择应用目标。

  • 在该窗口的顶部标签栏中,打开“通用”面板。

  • 在“已嵌入的二进制文件”部分下点击 + 按钮。

  • 选择顶部的 IFTTTConnectSDK.framework 用于 iOS。

  • 就这样!

IFTTTConnectSDK.framework 已自动作为目标依赖项、链接框架和嵌入框架添加到“复制文件”构建阶段,这足以在模拟器和设备上构建。

设置

配置重定向

在连接激活期间,您的应用将收到针对 Connect 按钮 SDK 的重定向。您必须配置应用的 PLIST 文件以接受相同的批准 URI(s)提供的传入重定向这里

<key>CFBundleURLTypes</key>
<array>
	<dict>
		<key>CFBundleTypeRole</key>
		<string>Viewer</string>
		<key>CFBundleURLName</key>
		<string>com.ifttt.sdk.example</string>
		<key>CFBundleURLSchemes</key>
		<array>
			<string>groceryexpress</string>
		</array>
	</dict>
</array>

支持返回用户流程

当建立连接的用户已经是 IFTTT 的用户时,激活流程可能超出您的应用以验证用户的账户。

  • 如果已安装 IFTTT 应用,Connect 按钮 SDK 将打开它以处理连接激活流程。
  • 如果不安装 IFTTT 应用,用户将收到确认链接的电子邮件。为了提供良好的用户体验,我们提供用户电子邮件客户端的链接。您必须配置应用的 LSApplicationQueriesSchemes 以支持返回 IFTTT 用户。
<key>LSApplicationQueriesSchemes</key>
<array>
    <string>ifttt-handoff-v1</string>
    <string>message</string>
    <string>googlegmail</string>
    <string>ms-outlook</string>
    <string>ymail</string>
    <string>airmail</string>
    <string>readdle-spark</string>
</array>

连接按钮SDK的跳转重定向

使用ConnectionRedirectHandler处理这些重定向。

注意:redirectURL必须与在ConnectionConfiguration中提供的URL相同,并由ConnectButtonController使用。

func application(_ app: UIApplication, 
                  open url: URL, 
                  options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
	if connectionRedirectHandler.handleApplicationRedirect(url: url, options: options) {
	    // This is an IFTTT SDK redirect, it will take over from here
	    return true
	} else {
	    // This is unrelated to the IFTTT SDK
	    return false
	}
}

连接凭证提供者

  • 您需要在验证服务时向IFTTT SDK提供各种代码和令牌。

  • 创建一个符合ConnectionCredentialProvider的对象以处理这些要求。

  • oauthCode:您的服务中用户的OAuth代码。这用于在连接按钮激活流程中跳过连接到您的服务的步骤。我们需要此值以提供最佳的用户体验。

  • userToken:这是您的服务的IFTTT用户令牌。此令牌允许您获取仅与您的服务相关的IFTTT用户数据。例如,包括此令牌以获取用户配置连接的启用状态。它也是用于代表用户发出触发、查询和动作请求的令牌。

如何获取userToken

  1. 有关交换特定于用户令牌以进行用户认证请求的更多信息,请参阅认证

  2. 请注意,当连接激活时,ConnectButtonControllerDelegate返回用户令牌。您应该支持这两种方法来接收userToken,因为用户可能已经将您的服务连接到了IFTTT。

  • inviteCode:如果您的服务未发布,则需要此值。您可以在这里找到IFTTT平台的邀请代码。如果您的服务已发布,则返回nil。
struct Credentials: ConnectionCredentialProvider {  
  /*
    Provides the partner's OAuth code for a service 
    during authentication with a `Connection`.
  */
  var oauthCode: String { 
    return theOAuthCodeForYourService
  }
  
  /* 
    Provides the service's token associated with IFTTT.
  */
  var userToken: String? { 
    return yourAppsKeychain["key_for_ifttt_token"]
  }
  
  /* 
    Provides the invite code for testing an unpublished 
    `Connection`'s services with the IFTTT platform.
  */
  var inviteCode: String? { 
    return """
    Invite code from platform.ifttt.com or nil if your service is published
    """
  }
}

连接按钮

连接按钮为您提供了一种一致且简单的方式,让您的用户激活编程连接。

初始化

  • 将一个 ConnectButton 添加到你的视图控制器中
  • ConnectButton 支持 @IBDesignable,允许你在 Storyboard 中直接添加它。
  • 或者你可以手动创建它 let connectButton = ConnectButton()

布局和自定义

Connect Button 设计得可以像任何 UIKit 控件一样融入 UI。在创建布局时,有一些事情你应该知道。

  1. ConnectButton 设计得可以放在浅色背景上。 浅色风格 浅色风格

  2. ConnectButton 有固定的70高度和最大329宽度

  • 带有底部文本的 ConnectButton 的实际高度将略大于此,以适应文本的空间。你应该允许 ConnectButton 计算其高度,而不是对它设置任何布局约束,因为这将导致无效的布局。
  • 水平方向上,ConnectButton 是灵活的。如果你将其放置在一个比其最大宽度更宽的容器中,它会在该容器中居中。
  1. ConnectButton 将在用户第一次激活连接时提示用户输入他们的电子邮件。你必须为你的 UI 中键盘的展示容留空间。

Keyboard presentation

配置 ConnectButtonController

一旦你在 UI 中有了 ConnectButton,你需要将其附加到 ConnectButtonController 上。控制器负责连接激活流程。

首先,你需要设置一个 ConnectionConfiguration。第二,你需要配置一个 ConnectButtonControllerDelegate

连接配置

此配置类型提供使用按钮时所需的连接信息以及用户信息。

  1. connectionId连接的标识符。您可以在platform.ifttt.com上找到您程序化连接的标识符。
  2. suggestedUserEmail:用户为您的服务使用的电子邮件地址。这使我们能够预先填充电子邮件。
  3. credentialProvider:在设置中设置的连接凭证提供程序
  4. redirectURL:在设置中配置的重定向URL
  5. skipConnectionConfiguration:一个布尔值,允许跳过连接配置。有关更多信息,请参阅配置跳过

ConnectButtonControllerDelegate

ConnectButtonControllerDelegate用于向您的应用传递重要信息。

从iOS 13开始,如果我们无法访问FFT app,我们需要访问UIWindow以显示OAuth流。这通过实现以下方法来完成:

func webAuthenticationPresentationAnchor() -> UIWindow {
  return theWindowToShowTheOAuthFlowOn
}

在iOS 12和更早版本中,我们需要定期访问当前视图控制器,以打开Safari以打开OAuth流实例。在这个方法中,简单地返回包含ConnectButton的视图控制器。

func presentingViewController(for connectButtonController: ConnectButtonController) -> UIViewController {
	return theViewControllerContainingTheConnectButton
}

连接激活完成时,控制器会调用该代理方法通知您的应用。如果成功,此方法会传递回更新的连接和IFTTT用户令牌。在此处保存此令牌很重要。您需要next time with ConnectionCredentialProvider,当下次用户访问您应用中的连接页面时。

func connectButtonController(_ connectButtonController: ConnectButtonController, 
                             didFinishActivationWithResult result: Result<ConnectionActivation, ConnectButtonControllerError>) {
  switch result {
  case .success(let activation):
    // A Connection was activated and we received the user IFTTT token
    // Let's update our credential for this user
    if let token = activation.userToken {
        ourConnectionCredentials.loginUser(with: token)
    }
      
  case .failure(let error):
    break 
  }
}

最后,当连接被禁用时,还有一个回调您可以调整UI。

func connectButtonController(_ connectButtonController: ConnectButtonController,
                             didFinishDeactivationWithResult result: Result<Connection, ConnectButtonControllerError>) {
  switch result {
  case .success(let updatedConnection):
    // The user disabled this Connection
        
  case .failure(let error):
    // Something went wrong while disabling the Connection 
  }
}

注意 这些代理方法返回在Connect Button SDK中定义的Result。我们将在未来的更新中迁移到标准的Swift库中的Result。在此期间,您可以在项目中同时使用两者而不会发生冲突。

创建控制器

设置好ConnectionConfiguration和代理后,您可以实例化控制器。

public init(connectButton: ConnectButton,
            connectionConfiguration: ConnectionConfiguration,
            delegate: ConnectButtonControllerDelegate)

就这样!您现在可以直接在您的应用中启动程序化连接了。

认证

为了使SDK能够检索特定用户的连接状态,并允许SDK帮助禁用连接,它需要进行用户认证,这需要使用一个IFTTT用户令牌。这个令牌与用户通过服务认证流程在您的服务中进行认证时返回的令牌相同。

用户认证请求是指在包含特定于用户的令牌的 Authorization 标头的请求。这种方法允许您从不适合暴露服务密钥的移动应用或浏览器等地方调用API。

交换用户令牌

URL: POST https://connect.ifttt.com/v2/user_token

此端点可用于获取特定用户的令牌,从而使您能够进行用户认证请求。

示例:使用用户ID和OAuth令牌进行服务认证获取用户令牌

HTTP 请求
POST /v2/user_token?user_id=123&access_token=abc
Host: connect.ifttt.com
IFTTT-Service-Key: 6e7c8978c07a3b5918a237b9b5b1bb70
Content-Type: application/json
HTTP 响应
{
  "type": "user_token",
  "user_token": "e1hMBWw44mJM902c6ye9mmuS3nd4A_8eTCU99D4a5KQW7cT1"
}

为了明确本例中使用的变量

变量 详细信息
user_id 123 您的服务上用户的id,必须与您的[用户信息]端点提供的id相匹配
access_token abc 您代表用户在用户将IFTTT账户连接到您的服务时颁发给IFTTT的OAuth访问令牌
IFTTT-Service-Key 6e7... 您的秘密服务密钥
user_token e1h... 您将用于代表IFTTT用户进行请求的新用户令牌

在这些参数中,

  • 您可以在IFTTT平台的API选项卡下的“服务密钥”标题中找到IFTTT-Service-Key。当您从后端服务器调用API时,可以使用这种方法。
  • access_token 是指 您代表此用户向 IFTTT 发行的 OAuth 访问令牌,当他们将 IFTTT 账户连接到您的服务时获取。这使得我们比仅提供您的服务密钥时更能严格验证请求,而不需要用户经过重复的 OAuth 流程。

关于交换用户令牌的重要说明

您的 IFTTT 服务密钥应该始终保持机密。服务密钥可以用来代表任何用户发起调用,但用户令牌仅限于单个用户。这使得用户令牌的安全性大大降低。另一方面,您绝对不希望将服务密钥嵌入到移动应用中,因为这可能被最终用户读取。

因此,我们强烈建议您 在您的后端调用此 API,并将用户令牌返回到您的应用程序,而不是在应用程序内部直接调用 API。

高级

获取连接

您可以直接使用 ConnectionNetworkController 从 Connection API 获取 Connection。这不是一个必需的步骤。您也可以简单地允许 ConnectButtonController 来完成这项工作。

  • 使用 ConnectionNetworkController 获取您的服务的 Connection
  • Connection.Request 负责创建必要的 URLRequest
connectionNetworkController.start(request: .fetchConnection(for: id, credentialProvider: yourCredentialProvider)) { response
	switch response.result {
	case .success(let connection):
		let config = ConnectionConfiguration(connection: connection, 
                                         suggestedUserEmail: yourUsersEmail,
                                         credentialProvider: yourCredentialProvider,
                                         connectAuthorizationRedirectURL: theRedirectURLForYourIFTTTService)
				     
    let controller = ConnectButtonController(connectButton: self.connectButton,
                                             connectionConfiguration: config,
                                             delegate: self)
    
		self.connectButtonController = controller
	case .failure(let error):
		break
	}
}

一旦您有了 Connection,您可以使用一个接受 Connection 的替代初始化器来初始化 ConnectionConfiguration。这样做将跳过加载状态。

跟踪

为了不断创新和改进我们的SDK,IFTTT可能会从软件中收集某些使用统计数据,包括但不限于匿名唯一标识符、软件版本号以及用户与SDK提供的UI元素的交互。告知您的客户他们可以选择退出信息收集是常见做法,也是您作为IFTTT SDK用户的责任。本节中的说明解释了您如何启用退出功能。当您正确实施时,如果拒绝同意,则不会收集信息。

收集的数据将用于改进SDK和IFTTT的相关服务,并按照IFTTT的隐私政策进行维护。

匿名ID

默认情况下,SDK将在用户与ConnectButton交互时跟踪用户交互。为了区分唯一安装,我们为每个应用程序安装随机生成一个UUID(匿名ID),并将其与事件请求一起发送。

禁用跟踪

如果您想退出跟踪,可以设置ConnectButtonController.analyticsEnabled = false。在调用此方法后,应用程序中所有的ConnectButton实例都会禁用跟踪,直到内存中存在为止。如果您想持久化用户禁用跟踪的偏好设置,应将其存储在持久存储中,并在每次应用程序启动时设置此变量。

本地化

Connect Button及其相应的流程可以显示与用户当前区域设置不同的翻译文本。为了传入不同的区域设置,请为ConnectButtonController初始化器的locale参数传入Swift Locale对象。例如,如果您想要在拉美西班牙语中显示Connect Button:

let locale = Locale(identifier: "es-419")
let config = ConnectionConfiguration(connection: connection, 
                                      suggestedUserEmail: yourUsersEmail,
                                      credentialProvider: yourCredentialProvider,
                                      connectAuthorizationRedirectURL: theRedirectURLForYourIFTTTService)
let controller = ConnectButtonController(connectButton: self.connectButton,
                                         connectionConfiguration: config,
                                         locale: locale,
                                         delegate: self)

如果未为本参数传入的区域设置找到翻译,Connect Button及其相应的流程将以英语显示。如果没有提供locale参数的值,将使用默认值Locale.current

以下语言支持文本翻译:

  • 英语 - 美国(en-US)
  • 英语 - 英国(en-GB)
  • 捷克语(cs)
  • 丹麦语(da)
  • 德语(de)
  • 西班牙语(es)
  • 西班牙语 - 拉丁美洲和加勒比地区(es-419)
  • 芬兰语(fi)
  • 法语(fr)
  • 法语 - 加拿大(fr-CA)
  • 意大利语(it)
  • 日语(ja)
  • 韩语(ko)
  • 挪威语 bokmål(nb)
  • 荷兰语(nl)
  • 波兰语(pl)
  • 葡萄牙语 - 巴西(pt-BR)
  • 葡萄牙语 - 葡萄牙(pt-PT)
  • 俄语(ru)
  • 瑞典语(sv)
  • 简体中文(zh-Hans)
  • 繁体中文(zh-Hant)

跳过配置

如果您想使用自己的连接配置用户界面,可以使用ConnectionConfiguration初始化器中的skipConnectionConfiguration参数。将此参数设置为true将指示IFTTT跳过连接配置屏幕。此参数默认为false。一旦用户点击连接按钮,他们将通过常规连接流程,但他们将不会看到连接配置屏幕,而是返回到您的应用。之后,您可以使用字段选项端点更新连接端点来支持您的UI,并允许用户配置连接。使用skipConnectionConfiguration=true创建的用户连接被视为待定,直到您使用更新连接端点更新它,否则它不会触发触发器或允许您运行其操作或查询。