19
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GoogleアカウントにサインインからのAlamofireでGoogle Drive APIを叩くまで

Posted at

最近、iOSアプリでGoogle Driveのスプレッドシート一覧を取得したくて色々と調べてました。
サンプルとして、GoogleアカウントにサインインしてREST APIを叩くまでのアプリを作ってみたので、
似たようなことをしたい方がいたら参考にしてください。

環境

  • Swift 2.1.1
  • Xcode 7.2
  • CocoaPods 0.39.0

1. プロジェクトの作成

まずはXcodeでプロジェクトを新規に作成し、CocoaPodsで必要なライブラリをインストールします。

Podfile
platform :ios, '8.0'

use_frameworks!

pod 'Google/SignIn' # Googleアカウント認証
pod 'Alamofire'     # HTTPクライアント
pod 'SwiftyJSON'    # JSONパーサ

target 'TestGoogle' do

end

2. Google Developers Consoleでプロジェクト作成

このページGET A CONFIGURATION FILEというリンクからGoogleのサービスを有効にするための設定ファイルを取得します。

  1. アプリ名、Bundle IDを入力します。アプリ名は適当、Bundle IDは先ほど作ったXcodeプロジェクトのそれを入力してください。
  2. Google Sign-Inを有効にしてGenerate configuration filesをクリックしてください。
  3. GoogleService-info.plistをダウンロードします。このファイルは後で使います。

3. Drive APIを有効にする

先ほど作成したGoogleアプリのプロジェクトをここから選択し、Drive APIを有効にします。

  1. ダッシュボードで「Google APIを利用する」をクリックします。
    api.png

  2. Drive APIをクリックし、「APIを有効にする」をクリックします。
    api2.png

4. iOSアプリにGoogleプロジェクトの情報を組み込む

コードを書く前の最後の下準備になります。

  1. ダウンロードしたGoogleService-Info.plistをXcodeのプロジェクトトップに配置します。
    plist.png

  2. Info > URL TypesにGoogleService-Info.plistに書かれているREVERSED_CLIENT_IDとiOSアプリのBundle IDを入力します。
    info.png

  3. <プロジェクト名>-Bridging-Header.hというヘッダーファイルを作成し、プロジェクトトップに配置します。ヘッダーファイルには#import <Google/SignIn.h>とだけ記述してください。

  4. 最後にBuild Settings > Swift Compiler - Code Generation > Objective-C Bridging Headerに先ほど作成した<プロジェクト名>-Bridging-Header.hを入力してください。

5. コーディング

いよいよコーディング(+ストーリーボードの編集)を行います。最終的に、ボタンを押すとログインユーザ自身がオーナーのスプレッドシート一覧が取得できるようなアプリを作ってみます。
sample.gif

5.1. AppDelegate.swift

AppDelegate.swift
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        var configureError: NSError?
        GGLContext.sharedInstance().configureWithError(&configureError)
        assert(configureError == nil, "Error configuring Google services: \(configureError)")

        GIDSignIn.sharedInstance().delegate = self
        return true
    }

    func application(application: UIApplication,
        openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
            return GIDSignIn.sharedInstance().handleURL(url,
                sourceApplication: sourceApplication,
                annotation: annotation)
    }

    @available(iOS 9.0, *)
    func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
        return GIDSignIn.sharedInstance().handleURL(url,
            sourceApplication: options[UIApplicationOpenURLOptionsSourceApplicationKey] as! String?,
            annotation: options[UIApplicationOpenURLOptionsAnnotationKey])
    }

    func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!,
        withError error: NSError!) {
            if (error == nil) {
                let name = user.profile.name
                NSNotificationCenter.defaultCenter().postNotificationName(
                    "ToggleAuthUINotification",
                    object: nil,
                    userInfo: ["statusText": "Signed in user: \(name)"])
            } else {
                print("\(error.localizedDescription)")
                NSNotificationCenter.defaultCenter().postNotificationName(
                    "ToggleAuthUINotification", object: nil, userInfo: nil)
            }
    }

    func signIn(signIn: GIDSignIn!, didDisconnectWithUser user:GIDGoogleUser!,
        withError error: NSError!) {
            NSNotificationCenter.defaultCenter().postNotificationName(
                "ToggleAuthUINotification",
                object: nil,
                userInfo: ["statusText": "User has disconnected."])
    }
}

5.2. Main.storyboard

ログイン状況を表すラベル、ログインボタン、スプレッドシート一覧を取得するボタンを配置します。

main.png

5.3. ViewController.swift

ViewController.swift
import UIKit
import Alamofire
import SwiftyJSON

class ViewController: UIViewController, GIDSignInUIDelegate {

    // 関連付けを忘れないように
    @IBOutlet weak var statusText: UILabel!
    @IBOutlet weak var signInButton: GIDSignInButton!
    @IBOutlet weak var fileListButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        GIDSignIn.sharedInstance().uiDelegate = self
        // Drive APIを叩くのでこれをscopeに足すこと
        GIDSignIn.sharedInstance().scopes.append("https://www.googleapis.com/auth/drive.readonly")

        // 自動ログイン
        GIDSignIn.sharedInstance().signInSilently()

        NSNotificationCenter.defaultCenter().addObserver(self,
            selector: "receiveToggleAuthUINotification:",
            name: "ToggleAuthUINotification",
            object: nil)

        statusText.text = "Initialized Swift app..."
        toggleAuthUI()
    }

    deinit {
        NSNotificationCenter.defaultCenter().removeObserver(self,
            name: "ToggleAuthUINotification",
            object: nil)
    }

    func toggleAuthUI() {
        if (GIDSignIn.sharedInstance().hasAuthInKeychain()){
            signInButton.hidden = true
        } else {
            signInButton.hidden = false
            statusText.text = "Google Sign in\niOS Demo"
        }
    }

    func receiveToggleAuthUINotification(notification: NSNotification) {
        if (notification.name == "ToggleAuthUINotification") {
            self.toggleAuthUI()
            if notification.userInfo != nil {
                let userInfo:Dictionary<String,String!> =
                notification.userInfo as! Dictionary<String,String!>
                self.statusText.text = userInfo["statusText"]
            }
        }
    }

    // 関連付けを忘れないように
    @IBAction func getFileList(sender: AnyObject) {
        let me = GIDSignIn.sharedInstance().currentUser
        let email = me.profile.email
        let token = me.authentication.accessToken

        let url = "https://www.googleapis.com/drive/v2/files"
        let method = Alamofire.Method.GET
        // MIME Typeがスプレッドシートで、オーナーに自身を含むものを検索
        let query = "mimeType = 'application/vnd.google-apps.spreadsheet' and '" + email + "' in owners"

        Alamofire.request(method, url, parameters: [ "access_token": token, "q":  query ])
            .responseJSON { response in
                let json = JSON(response.result.value!)
                for (_, sub): (String, JSON) in json["items"] {
                    print(sub["title"].string! + ", " + sub["id"].string!)
                }
        }
    }
}

以上で完成です!
公式のドキュメントが古かったりして少し苦労しましたが、
これでサインインからREST APIを叩くまで一通りできるようになりました。

19
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?