【Swift5】Twitterログインしてトークン情報を取得する

##やったこと

1. Twitterへのアクセス許可のフロー(Twitterログイン)を実装(よく見るやつ)
![IMG_5298.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/377795a8-660e-1477-fb6b-9c61fe93c706.png)

2. Twitterにログイン後、トークン情報を取得し、アラート表示
![S__63528969.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/ee3a15f2-8c65-b99f-2b2d-5039ba807cc4.jpeg)


##動作環境
- Swift5
- Xcode10.3 

##Twitterログインで取得できる情報

- id
- ハンドルネーム
- 出身地
- URL
- 説明
- プロフィール画像等

基本的なプロフィール情報は取得できるようです。

##Twitter developperに登録
[Twitter developper](https://developer.twitter.com/en/apps)にアプリケーションの登録を行います。
1アカウントで登録はデフォルトで10個までだそうです。
→ソース：https://www.itmedia.co.jp/news/articles/1807/26/news079.html

<img width="800" alt="スクリーンショット 2019-09-23 12.13.55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/f702358a-4dd6-8d71-9c11-e81277b4f996.png">
<img width="800" alt="スクリーンショット 2019-09-23 12.14.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/3f7e0f30-14a2-a609-9775-c1947508d27a.png">

文字数を守って英文で記載し、登録をします。
内容に関しては、そこまで規制が厳しくなく、少し抽象的な内容でも問題なさそうな印象でした。

なお、登録に必要な内容は以下になります。

##TwitterAPI使用登録に必要なアプリケーション情報

- アプリケーション名（必須）
- アプリケーションの説明（必須）
- ウェブサイトのURL （必須）　**※ウェブサイトのURLに関してを参照**
- アプリケーションをTwitterでのログインに使用できるようにするか
- コールバックURL (required) **※コールバックURLの注意事項**
- アプリケーションの使用方法（必須）(最小文字数100)

##### ※ウェブサイトのURLに関して
- ウェブサイトのURLは、アプリケーションによって作成されたツイートの帰属を特定するために使用され、ユーザー向けの承認画面に表示されます。

##### ※コールバックURLの注意事項
- OAuth 1.0aアプリケーションは、リクエストトークンステップでoauth_callbackURLを指定する必要があり、これは、ここで提供されているURLと一致する必要があります。
- アプリケーションでコールバックの使用を制限するには、これらを空のままにします。
- アプリケーション側のコールバックするURLと、登録しているURLが異なるとログインできないので注意です
- [TwitterのAPIでcallbackURLをチェックするようになった](https://qiita.com/non0311/items/48a6b25097d1783eab23)

上記でも記載しましたが、oauth/request_tokenをリクエストする時のoauth_callbackパラメータに入るURLが、
Twitterの開発アカウントの設定画面のcallbackURLで設定したURLと一致していないと、
動作する際に正常にコールバックされないので注意が必要です。

##アプリケーションの登録

登録をするとダッシュボードにアプリが追加されます。
<img width="804" alt="スクリーンショット 2019-09-23 12.16.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/e869f86a-ea42-7a8d-f6ac-2c398ef9b16f.png">
それに伴い、アプリケーションに紐づいたAppIDが発行されます。

##TwitterKitの懸念点
TwitterKitは公式サポートが終了しています。(公式のSDKのサポート期間は2018年10月31日で終了)それに伴い、今回は、[OAuthSwift](https://github.com/OAuthSwift/OAuthSwift)を使用しました。

- [Twitter Kit SDKのサポート終了のお知らせ](https://blog.twitter.com/developer/ja_jp/topics/community/2018/TKSDK_tr.html)

##CarthageのOAuthSwiftを使用

続いて、Xcode上での設定を進めていきます。
CarthageのOAuthSwiftを使用します。

https://github.com/OAuthSwift/OAuthSwift

Carthageの導入手順に関しては、[この記事](https://qiita.com/ShinokiRyosei/items/9b856ebdec5379b6c631)がわかりやすかったです。
今回は、carthageのインストールまでできているので、主に以下のような手順でインストールできました。
1. ターミナル上でプロジェクトに移動
2. ```touch Cartfile```実行
3. ```vim Cartfile```でCartfileを編集
4. ```github "OAuthSwift/OAuthSwift" ~> 2.0.0```と入力
5. ```esc＋「:wq」```で保存後、```carthage update --platform ios```を実行

ここまで完了したら、[この記事](https://qiita.com/ShinokiRyosei/items/9b856ebdec5379b6c631)を参考に、Xcode上でOAuthSwiftを使えるように設定を加えます。


##Xcodeで実装

今回は、こちらの記事→[OAuthSwiftを使用してTwitterのアクセストークンを取得するシンプルなサンプル【Swift3.0】【OAuthSwift1.1.1】](https://qiita.com/fromage-blanc/items/739622dee826806c12d5)を参考にして実装しました。

### ■ViewControllerの実装
```ViewController.swift
import UIKit
import OAuthSwift

struct Const {
    static let consumerKey = "KWQW9ZMqPM12345S58Df12345"
    static let consumerSecret = "CohXdQ6skhg0zZ12345Wi32jimmSazNKjgqovFs6G9vaM12345"
}

class ViewController: UIViewController {
    
    var oauthswift: OAuthSwift?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    /// ボタン押下
    ///
    /// - Parameter sender: UIButton
    @IBAction func clickButton(_ sender: UIButton) {
        doOAuthTwitter()
    }
    
    /// OAuth1ログイン処理
    func doOAuthTwitter(){
        
        let oauthswift = OAuth1Swift(
            consumerKey: Const.consumerKey,
            consumerSecret: Const.consumerSecret,
            requestTokenUrl: "https://api.twitter.com/oauth/request_token",
            authorizeUrl:    "https://api.twitter.com/oauth/authorize",
            accessTokenUrl:  "https://api.twitter.com/oauth/access_token"
        )
        self.oauthswift = oauthswift
        oauthswift.authorizeURLHandler = getURLHandler()
        
        // コールバック処理
        oauthswift.authorize(withCallbackURL: URL(string: "TwitterLoginSampleOAuth://")!,
                             completionHandler:
            { result in
                switch result {
                case .success(let (credential, _, _)):
                    print(credential.oauthToken)
                    print(credential.oauthTokenSecret)
                    self.showAlert(credential: credential)
                    print("success")
                case .failure(let error):
                    print(error.localizedDescription)
                    print("failure")
                }
        }
        )
    }
    
    /// ログイン画面起動に必要な処理
    ///
    /// - Returns: OAuthSwiftURLHandlerType
    func getURLHandler() -> OAuthSwiftURLHandlerType {
        if #available(iOS 9.0, *) {
            let handler = SafariURLHandler(viewController: self, oauthSwift: self.oauthswift!)
            handler.presentCompletion = {
                print("Safari presented")
            }
            handler.dismissCompletion = {
                print("Safari dismissed")
            }
            return handler
        }
        return OAuthSwiftOpenURLExternally.sharedInstance
    }
    
    /// アラート表示
    ///
    /// - Parameter credential: OAuthSwiftCredential
    func showAlert(credential: OAuthSwiftCredential) {
        var message = "oauth_token:\(credential.oauthToken)"
        if !credential.oauthTokenSecret.isEmpty {
            message += "\n\noauth_token_secret:\(credential.oauthTokenSecret)"
        }
        let alert = UIAlertController(title: "ログイン",
                                      message: message,
            preferredStyle: UIAlertController.Style.alert)
        alert.addAction(UIAlertAction(title: "OK",
                                      style: UIAlertAction.Style.default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }
}

```

### ■AppDelegateの実装

```AppDelegate.swift

import UIKit
import OAuthSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    /****追加した処理****/
    func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
        applicationHandle(url: url)
        return true
    }
}

extension AppDelegate {
    /// コールバック処理
    ///
    /// - Parameter url: URL
    func applicationHandle(url: URL) {
        if (url.host == "oauth-callback") {
            // URLを指定する場合はここで設定する
            OAuthSwift.handle(url: url)
        } else {
            OAuthSwift.handle(url: url)
        }
    }
}
```

### ■infoplistの設定
URL Schemesを設定します。
<img width="594" alt="スクリーンショット 2019-09-26 8.51.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/279d13e8-02ac-33d4-a60d-eb6091507929.png">

実装内容は以上になります。
なお、「一応動くレベル」で実装したものになりますので、不適切な処理等ありましたらコメントいただけますと幸いです。:bow_tone1:

###■注意点

コールバックURLの設定が正しくないと正常に動作しないので、
ログインは成功するのにコールバックがうまくいかない時は以下を確認しましょう。

- Twitterdevelopper→```TwitterLoginSampleOAuth://```を設定
- ViewController側→```TwitterLoginSampleOAuth://```を設定
- infoplist→```TwitterLoginSampleOAuth```を設定


##参考

- [OAuthSwiftを使用してTwitterのアクセストークンを取得するシンプルなサンプル【Swift3.0】【OAuthSwift1.1.1】](https://qiita.com/fromage-blanc/items/739622dee826806c12d5)
- [API reference index](https://developer.twitter.com/en/docs/api-reference-index)
- [エラーコード一覧](https://developer.twitter.com/en/docs/basics/response-codes)
- [Twitter 開発者 ドキュメント日本語訳](http://westplain.sakuraweb.com/translate/twitter/Documentation/OAuth/Overview/OAuth-FAQ.cgi)