[IOS]使用Gmail API从多个用户的Gmail帐户获取电子邮件。


本文所讲的

我意外地迷上了标题的内容,但是我能够解决它,所以我将分享当时的经验。
实际的执行过程也将详细说明。
请从准备实际步骤开始。

我想做什么

我想制作一个简单的Gmail客户端应用程序=类似邮件程序的应用程序。

我希望OAuth2授权用户访问多个Gmail帐户中的数据。

这次有多个帐户这一事实很重要。
我是邮递员,所以我希望能够注册多个Gmail帐户。

我意外上瘾了

仅查看官方Gmail API参考,我无法实现上述多个帐户的OAuth身份验证。
我沉迷于执行Google的OAuth身份验证,而不是Gmail API。

总之,有两种类型的OAuth库可用于使用当前的Google API,即Google/SignInGTMAppAuth。就本文而言,使用后一种GTMAppAuth

我尝试使用以前的Google/SignIn,但完全无法使用,花了大约3天的时间。很难... ??

官方API参考仅提及SignIn,所以我什至不认为库本身是不同的...

截至2017年6月,在iOS应用程序开发

中用作在Google API中使用OAuth库的内容

首先,此官方参考Gmail api | Google Developers中的iOS快速入门(使用Google的" Gmail API")使用名为Google/SignIn的库对用户进行OAuth2身份验证。

使用了另一个官方库GTMAppAuth,出于此目的,该库未出现在参考文献中。

GoogleSignIn和GTMAppAuth

我说的是谁没有出现在参考文献中,但这是官方Google博客上有关API的重要文章。

日本Google Developers:更新本机应用OAuth交互以提高可用性和安全性/ 2016年9月9日,星期五

下面,引自上述文章

为支持此迁移,我们已根据您可用的最新最佳实践发布了库和示例。

  • Google登录:适用于Android和iOS。推荐的SDK,用于通过Google帐户和OAuth登录。
  • AppAuth:适用于Android,iOS和OSX。可以与OAuth提供程序(例如Google)一起使用的开源OAuth客户端库。此外,我们还提供了GTMAppAuth(适用于iOS和OS X)库,该库在Objective-C的Google API客户端库和GTM会话提取程序项目中支持AppAuth。

它是

我不太了解,但是如果您想实现所谓的"使用Google登录"之类的功能,则可以使用Google/SignIn(GIDSignIn),并且只需要使用OAuth这样的访问令牌。 !!在这种情况下,似乎应该使用GTMAppAuth
如果您输入有误,请告诉我... ??

如果您用

GTMAppAuth谷歌搜索,您会发现很多英文文章。
也有这样的文章(?)。

实施OAuth 2.0·MailCore / mailcore2 Wiki --Github
在2017年1月,不推荐使用GTMOAuth2,因此以后应该使用GTMAppAuth!然后。
到目前为止,您一直使用GTMOAuth2

很难用英语阅读认证,这很难理解。喂?
我的日语不太多,所以希望本文对日语有帮助...

为此,Google登录(GID登录)无法执行的操作

  • 具有多个帐户的API调用

    • 仅在登录时才能获取传递给命中该API的类的身份验证信息。
    • 您一次只能使用一个帐户登录。
  • 我首先需要身份验证信息,但是"登录"的概念有点不同...

    • 我希望您像访问会话一样暂时批准用户,而不是半永久性地(直到用户断开连接)批准访问令牌。
  • 将凭证保存到舒适的钥匙串中

    • 我第二次打开应用程序后的自动登录不起作用。

凿岩力

Gmail API客户端库中的Objective-C示例使用GTMAppAuth,所以我到了那里,但是通常如何找到它...

使用OAuth 2.0访问Google API | Google身份平台| Google Developers的底部有一个指向GTMAppAuth的链接,当您搜索" Google OAuth"时会首先显示。

嗯,即使我用" Gmail API"谷歌搜索,也不会出来。

GTMAppAuth没有参考页,因此,截至2017年6月,Github存储库中的README是唯一的官方资料。

我想提高自己的Google技能和英语技能。
它变得像一首诗。
接下来,我们将使用GTMAppAuth以日语输入实际过程!

准备

您可以在Google Developers中进行设置!请从Xcode方面的准备工作开始!不使用GoogleService-Info.plist。

Google Developers方面的准备工作

首先,要使用Google API,您需要在Google Developers上创建一个应用程序并启用该API。

基础知识是iOS快速入门| Gmail API | Google Developers,但这一次有所不同,因此我将对其进行解释。

首先,在Xcode中创建一个新项目,并记下Bundle ID。

转到

添加Google服务| Google Developers。
因此,输入您喜欢的应用程序名称,并为iOS Bundle ID输入您先前创建的项目的Bundle ID。

スクリーンショット 2017-06-03 22.17.54.png

中,单击红色↑箭头所指向的按钮。

スクリーンショット 2017-06-03 22.21.39.png

↑单击红色箭头指向的按钮。

スクリーンショット 2017-06-03 22.21.56.png

↑单击红色箭头指向的按钮。

然后,将出现"下载GoogleService-Info.plist",但是这次我将不使用它,因此您不必下载它。
然后,在此之下,它表示将Google/SignIn添加到Podfile,但是我也不使用它,因此也不会添加它。

スクリーンショット 2017-06-03 22.24.01.png

↑在此页面上不执行任何操作,然后按"启用Gmail API"。

スクリーンショット 2017-06-03 22.29.40.png

↑然后,您将转到此屏幕,因此选择刚输入的应用程序名称,然后按继续。

スクリーンショット 2017-06-03 22.30.23.png

↑Gmail API已启用。按继续到凭据。

スクリーンショット 2017-06-03 22.31.03.png

↑设置要用于Gmail API的API,设置将API调用到iOS的位置,检查用户数据,然后继续下一步。

然后,您将被告知"已经存在适合此目的的身份验证信息",所以轻声说"啊,是",然后按"完成"。

对不起,我不需要操纵此身份验证信息,大声笑
似乎在启用API后会自动创建它。

这样就完成了Google方面的设置!
如果您在OAuth 2.0客户端ID字段中拥有凭据" {Bundle ID}的iOS客户端(由Google服务自动创建)",那就可以了!

请保持浏览器窗口打开,因为稍后您将使用此页面上的信息。

Xcode方面的准备工作

图书馆安装

使用CocoaPods安装该库。
Podfile的内容如下所示。

1
2
3
4
5
6
platform :ios, '8.0'
use_frameworks!
target 'TestApp' do
    pod 'GoogleAPIClientForREST/Gmail', '~> 1.3.0'
    pod 'GTMAppAuth'
end

请将

目标的项目名称更改为您自己的项目。
截至2017年6月,最新版本的GoogleAPIClientForREST1.3.0

与参考的区别是

1
    pod 'GTMAppAuth'

这是

部分。

pod install并打开TestApp.xcworkspace

库的内容是Objective-C,但使用pod时不需要Bridging-Header等。

添加URL类型

重定向将在使用户使用OAuth2批准该应用的过程中完成,因此请正式添加URL类型。

首先,从您保持打开状态的Google API凭据页面中,跳至您之前创建的凭据详细信息页面(单击名称)。

然后将值复制到" iOS URL方案"字段中。

返回到

Xcode,按Info URL Types,然后将值粘贴到URL Scheme字段中。
其他值可以保留为空。

执行

我将用Swift替换

GTMAppAuth的自述文件中写的内容。

GTMAppAuth无法加载问题

我终于写了! Xcode无法识别GTMAppAuth ...

[XCode]当找不到添加和导入的头文件时采取的3个动作

至于

,在我的情况下,如果Always Search User Paths更改为Yes,它将被读取。

OAuth验证

最后从这里编写代码!

AppDelegate

首先是AppDelegate。仅摘录必要的部分。

AppDelegate.swift

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// AppAuthのimportを忘れずに!
import AppAuth
import UIKit
import CoreData

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    // メンバ変数を宣言します。
    var currentAuthorizationFlow: OIDAuthorizationFlowSession?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        return true
    }

    // ????????????
    // ?メソッドの記述を省略?
    // ????????????

    // 以下のメソッドを書き足します。
    // 上で追加したURL Schemeでのリダイレクトを受けた際の処理です
    @available(iOS 9.0, *)
    func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
        // Sends the URL to the current authorization flow (if any) which will
        // process it if it relates to an authorization response.
        if (currentAuthorizationFlow?.resumeAuthorizationFlow(with: url))! {
            currentAuthorizationFlow = nil
            return true
        }
        // Your additional URL handling (if any) goes here.
        return false
    }

}

进行三处更改:import AppAuthcurrentAuthorizationFlow的声明以及底部方法的实现。

点击Google的OAuth API

接下来,实际点击Google的OAuth API。
在Github示例(GTMAppAuth / Example-iOS /)中,我在视图控制器中编写了该代码,但是我为Google OAuth处理创建了一个单独的类,以便将处理与视图控制器分开。
因此,可以将后续处理写入视图控制器或其他位置。

首先,从常量和变量声明开始。

1
2
3
4
5
private let scopes        = [kGTLRAuthScopeGmailModify]
private let kClientID     = クライアントID
private let kRedirectURL  = URL.init(string: "リバースクライアントID:/oauthredirect")
private let configuration = GTMAppAuthFetcherAuthorization.configurationForGoogle()
private var authorization: GTMAppAuthFetcherAuthorization?

范围

范围是对此应用程序要求用户访问的用户信息的访问权限。
您可以从"选择身份验证范围" |" Gmail API" |" Google开发者"中查看列表。选择您需要获得批准的最低权限。

kClientID

这是上面创建的认证信息的"客户端ID"。
从Google API凭据页面复制并粘贴您的客户端ID。
就像123456789-hogehoge.apps.googleusercontent.com

kRedirectURL

重定向到的URL。这是我之前添加到" URL类型"中的一个。
Github示例(GTMAppAuth / Example-iOS / Source / GTMAppAuthExampleViewController.m
在第46和47行中,
com.googleusercontent.apps.YOUR_CLIENT:/oauthredirect
看起来像这样,在这里也一样。

从Google API凭据页面上的" iOS URL方案"字段中复制值,

1
URL.init(string: com.googleusercontent.apps.123456789-hogehoge:/oauthredirect)

让我们将其粘贴为

配置

这是请求(OIDAuthorizationRequest)发送到服务(这次是Google)以请求OAuth时所需的设置。
这次,GTMAppAuth将为Google准备设置,因此只需输入GTMAppAuthFetcherAuthorization.configurationForGoogle()的返回值即可!

授权书

包含当用户批准显示的范围时Google发送的凭据对象。

接下来,请求发送给Google。

1
2
3
4
5
6
let request = OIDAuthorizationRequest.init(configuration: configuration,
                                           clientId: kClientID,
                                           scopes: self.scopes,
                                           redirectURL: kRedirectURL!,
                                           responseType: OIDResponseTypeCode,
                                           additionalParameters: nil)

发送请求。

1
2
3
4
5
6
7
8
9
appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request,
                                                              presenting: self.delegate as! UIViewController,
                                                              callback: { (authState, error) in
            if (authState != nil) {
                // 認証情報オブジェクトを生成
                self.authorization = GTMAppAuthFetcherAuthorization.init(authState: authState!)
                let accessToken = authState?.lastTokenResponse?.accessToken
                print("Authorization トークンを取得しました:\(String(describing: accessToken))")
        })

这是OAuth身份验证处理代码的结尾!
执行OIDAuthState.authState()时,将提示用户批准OAuth。
代码本身很短。
该区域几乎是自述文件,因此,如果您想查看头部系列,请使用google / GTMAppAuth
-见Github!

Gmail API点击

这是最终符合您喜欢的API的代码。 ?(?)?

中,GTMAppAuth README使用名为GTMSessionFetcherService的类,但是在这方面,iOS快速入门中使用的GTLRService更为方便。
这是因为查询构造更容易理解,并且响应的JSON解析是在内部完成的,并作为专用对象返回。

另外,如果您创建自己的特定于API的类,则我认为它更易于使用。
我只会写精华!

以users.messages.list为例。

1
2
3
4
5
6
7
8
import GoogleAPIClientForREST

let query = GTLRGmailQuery_UsersMessagesList.query(withUserId: userId)
let service = GTLRGmailService()
service.authorizer = GTMAppAuthFetcherAuthorization.init(fromKeychainForName: "NAME")
service.executeQuery( query,
                      delegate: self,
                      didFinish: #selector(callback) )

查询

API请求查询。
不,它实际上是一个请求路径,即使它是一个查询。
通过使用GTLRGmailQuery_HogeHoge的查询方法(GTLRQuery类的子类)可以轻松生成它。
API参考| Gmail API | Xcode通过在查看Google Developers时键入相似的单词来为您提供补充!

顺便说一句,userID这是一个邮件地址。

服务

一个实际发送请求的对象。
对于Gmail,它是GTLRGmailService类的实例!

service.authorizer

凭据对象(GTMAppAuthFetcherAuthorization)。通过将正确的凭据对象放入service.authorizer,它将自动在请求标头中插入访问令牌。

这里,从iOS钥匙串中提取并保存了过去保存的身份验证信息。
稍后将描述保存认证信息。

service.executeQuery

查询执行!
使用选择器指定回调。

回调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func callback( ticket : GTLRServiceTicket,
                         finishedWithObject response : GTLRGmail_ListMessagesResponse,
                         error : NSError? ){
        if let error = error {
            print("メッセージリストの取得に失敗しました。")
            print(error)
            return
        }
        print("メッセージリストの取得に成功しました。")
        print(response.messages!)
        print(response.nextPageToken!)
        print(response.resultSizeEstimate!)

    }

finishWithObject

由于响应的类型根据您命中的API而有所不同,因此finishedWithObject的类型也依赖于Xcode的完成。
没有全面的清单...

嗯,这就是为什么我能够使用API??! !!
耶! !!好有趣! !!今天是API美好的一天! !!

保存凭据

使用

,接下来要担心的是保存身份验证信息。

使用OAuth进行身份验证后,请在无需明确许可的情况下使用该应用。为此,我们要保存在应用程序中首先获得的凭据。

GTMAppAuthFetcherAuthorization

GTMAppAuthFetcherAuthorization是用于OAuth身份验证的凭据类,它将保存您的钥匙串!

1
2
3
4
5
6
7
8
// Serialize to Keychain
GTMAppAuthFetcherAuthorization.save(_authorization, toKeychainForName: kGTMAppAuthExampleAuthorizerKey)

// Deserialize from Keychain
let authorization = GTMAppAuthFetcherAuthorization.init(fromKeychainForName: kGTMAppAuthExampleAuthorizerKey)

// Remove from Keychain
GTMAppAuthFetcherAuthorization.removeFromKeychain(forName: kGTMAppAuthExampleAuthorizerKey)

容易。
只要保存保存时指定的toKeychainForName:,就可以随时恢复它。
我在Google/SignIn(GIDSignIn) ...

中找不到这样的功能

可以使用任何密钥保存身份验证信息的事实意味着,如果您保存密钥以保存每个帐户的身份验证信息,则可以使用多个帐户进行API调用!耶!

设置多个时,最好更改在appDelegate中声明的变量的位置。

奖励:我想获取用户信息

如果使用

GIDSignIn,则登录时将返回用户的信息,但是在GTMAppAuth的情况下,则没有此类信息...

自2016年2月宣布Google People API以来,我还尝试将其用作API惯例。

由于似乎很长,所以我将分篇。

[iOS]使用Google People API获取用户信息

概括

  • 使用Google的API时,OAuth有GoogleSignInGTMAppAuth库。
  • 如果您不想"使用Google登录",而只想使用OAuth访问令牌,请使用GTMAppAuth