【Swift5】LINEログインしてプロフィール情報を取得する

#環境
- Xcode Version 10.2
- Swift5

#やること

![linelogin.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/10c0fb7d-7917-b31c-595a-e3e781b52ced.gif)

アプリからLINEログインして、プロフィール情報を取得します。

#LINE developersでアプリ登録
## ①LINE developersにログイン

https://developers.line.biz/ja/ からLINEログイン

今回は個人アカウントでの開発なので「LINEアカウントでログイン」を選択します。

<img width="437" alt="スクリーンショット 2019-04-14 13.40.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/30696565-c8ff-1392-b1a1-65a9cfe81fe4.png">

メールアドレスとパスワードの入力を求められるので、入力してログインします。
<img width="505" alt="スクリーンショット 2019-04-14 13.52.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/a142731b-7bef-920d-dc0d-0e6d3a23e4d7.png">


## ②プロバイダー・新規チャネルの作成

プロバイダーを作成後、チャネルを作成します。

<img width="399" alt="スクリーンショット 2019-06-23 20.49.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/2ba1fad5-48d4-cbb7-870a-ce2decebf5b0.png">


プロバイダーとは、ログイン時に提供元として表示される情報です。
ここに入力する情報は、LINEログイン時に表示されます。
チャネルは、アプリ単位で作成します。

ここでは、LINEログインを選択します。
<img width="409" alt="スクリーンショット 2019-06-23 20.53.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/9a7d91a2-8924-d625-37ea-23e162437e9d.png">

続いて、必要な情報を入力して登録します。
ユーザーに見える部分になるので、必要に応じて体裁を整えて入力します。
今回の入力内容は以下としました。

>
プロバイダー：TestProvider
アイコン：未設定
アプリ名：テストアプリ
アプリ説明：ログインのテストです。

※ちなみに、上記を入力した場合、LINEログイン時には以下のように表示されます。

<img width="375" alt="IMG_1440.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/60e7d6cf-3398-21a0-0c32-e51f459f404e.png">

<img width="375" alt="IMG_1441.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/9c0e1c79-12d2-5ed3-477f-2966e48d76ef.png">



入力内容ですが、説明が親切に記載されているので、記載内容に従って入力すればOKです。
(ほとんど後から編集が可能です。)

<img width="1141" alt="スクリーンショット 2019-06-23 20.59.47.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/645297ab-ce86-b381-c9b6-9964a35cc773.png">

<img width="1131" alt="スクリーンショット 2019-06-23 21.00.01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/8cbcf61c-1a0f-cecb-d7a9-4e1031b22b9b.png">

入力後、入力内容を確認して登録すると、チャネルが作成されます。

<img width="275" alt="スクリーンショット 2019-06-23 21.12.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/4ab18a41-a7f7-b8cd-c722-4805566d3342.png">

※今回は、テストのため非公開のままの設定にしておりますが、
リリース時などは公開にする必要があるかと思います。

## ③ChannelIdが発行されていることを確認

作成したチャネルをクリックすると、登録内容の編集が可能です。
**※openIdの申請等も、ここから行います。**


<img width="1137" alt="スクリーンショット 2019-06-23 21.02.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/8b32c6fa-7d82-e217-19de-5d7595bebfd9.png">

ChannelIdが発行されていることが確認できます。
これはアプリ側の設定に使用します。
<img width="1134" alt="スクリーンショット 2019-06-23 21.03.52.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/676caa2a-2a42-8a71-2bcc-c0231b49f17d.png">

## ④アプリのbundleIDを設定

アプリ設定を開くとbundleIDやschemeを設定することができます。
(アプリ未作成の状態であれば、アプリ作成後に設定しましょう。)

<img width="1140" alt="スクリーンショット 2019-06-23 21.04.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/e9f44933-0185-666a-f591-a2d9d57d42b4.png">

アプリ側(x-code)で設定しているbundleIDと異なると、
エラーになってしまい、LINEログインできないので、注意しましょう。:cold_sweat:

※ちなみに上記の場合、以下のようなエラーになりました。

```
error: authorizeFailed(reason: LineSDK.LineSDKError.AuthorizeErrorReason.webLoginError(error: "invalid_request", description: Optional("Invalid+URI+:+[line3rdp.hoge.LineLoginSample://authorize/]")))
```

ここまでできれば、LINE developersでの設定は完了です。


#X-codeでLINELoginを使用できるように設定

##①アプリとLINE developersの設定内容を紐付ける

基本的に、以下の記事を参照すればスラスラ進められます。
とても親切に記載されています。:innocent:

[LINE SDK for iOS プロジェクトを設定する](https://developers.line.biz/ja/docs/ios-sdk/swift/setting-up-project/)

主にやることは以下になります。(順不同)

- LINE SDKの導入(podとか Carthageとか)
- KeyChain Shahareingの設定をON
- Info.plistのURL Schemesに```line3rdp.$(PRODUCT_BUNDLE_IDENTIFIER)```を設定
- Info.plistのLineSDKConfigにChannelIdの設定

※参考画像
<img width="801" alt="スクリーンショット 2019-06-23 21.47.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/b48fc896-6c01-db2c-587f-4edafda176c7.png">

<img width="801" alt="スクリーンショット 2019-06-23 22.34.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/f9e8b9a5-406f-8811-0b96-095fea75d10c.png">


##②AppDelegateを実装する

```.swift
import UIKit
import LineSDK

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    
    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        return LoginManager.shared.application(app, open: url, options: options)
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // アプリの起動直後に、LoginManager.setupメソッドを呼び出す
        // https://developers.line.biz/ja/docs/ios-sdk/swift/integrate-line-login/
        // setupメソッドを呼び出した後で他のメソッドを呼び出したりすること
        LoginManager.shared.setup(channelID: "LINE developersで発行されたchannelIDを入力", universalLinkURL: nil)
        return true
    }
}
```

##③ログインボタンを実装する

これも基本的に、以下の記事を参照すればスラスラ進められます。
(なお、この記事の存在意義・・・)

[LINE SDK for iOS iOSアプリにLINEログインを組み込む](https://developers.line.biz/ja/docs/ios-sdk/swift/integrate-line-login/)

ログインボタンを配置するViewControllerは、以下のように実装しました。
方法として、2通り確認できたので、それぞれ記載します。

### 1.SDKの[LoginButton](https://developers.line.biz/ja/reference/ios-sdk-swift/Classes/LoginButton.html#/s:7LineSDK11LoginButtonC11permissionsShyAA0C10PermissionVGvp)を使用する方法

UIButtonをstorybord上に配置し、LoginButtonにOutlet接続しています。
<img width="256" alt="スクリーンショット 2019-06-23 22.29.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186535/386dad81-c92b-63bc-2564-1b84209f5c96.png">

実装内容は、以下になります。

- ログインボタン(LoginButton)の配置
- [LoginButtonDelegate](https://developers.line.biz/ja/reference/ios-sdk-swift/Protocols/LoginButtonDelegate.html)のデリゲートメソッドの実装
- アクセストークンの有効期限・アクセストークンをログ出力
- プロフィール情報(ユーザー名・ステータス・アイコン画像URL)をログ出力(実際はsecondViewでプロフィール情報を表示しましたが、コードが微妙そうなので載せませんw)

```.swift

import UIKit
import LineSDK

final class ViewController: UIViewController, LoginButtonDelegate {

    /// ログインボタン
    @IBOutlet weak var loginButton: LoginButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // delegateをセット
        self.loginButton.delegate = self
        // 設定しないとエラーになる↓(今回はプロフィール情報を取得する)
        self.loginButton.permissions = [.profile]
        
        // アクセストークンの有効期限
        if let token = AccessTokenStore.shared.current {
            print("Token expires at:\(token.expiresAt)")
            print(token.expiresAt.toStringWithCurrentLocale())
        }

        // 現在のアクセストークン
        if let token = AccessTokenStore.shared.current {
            print("Token value:\(token.value)")
        }
    }

    /// ログイン開始時に呼ばれる
    func loginButtonDidStartLogin(_ button: LoginButton) {
        print("Login Start")
    }

    /// ログイン成功時に呼ばれる
    func loginButton(_ button: LoginButton, didSucceedLogin loginResult: LoginResult) {
        print("Login Succeed")
        
        if let profile = loginResult.userProfile {
            print(profile.userID)
            print(profile.displayName)
            print(profile.pictureURL!)
            print(profile.statusMessage!)
        }
        // 画面遷移
        self.transitionSecondView()
    }
    
    /// ログイン失敗時に呼ばれる
    func loginButton(_ button: LoginButton, didFailLogin error: Error) {
        print("Login Faild")
    }
    
    /// 画面遷移
    func transitionSecondView() {
        let storyboard: UIStoryboard = self.storyboard!
        let secondView = storyboard.instantiateViewController(withIdentifier: "secondView")
        present(secondView, animated: true, completion: nil)
    }
}

extension Date {
    /// 現在時刻を取得
    ///
    /// - Returns: 現在時刻
    func toStringWithCurrentLocale() -> String {
        let formatter = DateFormatter()
        formatter.timeZone = TimeZone.current
        formatter.locale = Locale.current
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        return formatter.string(from: self)
    }
}
```

### 2. UIButtonから```LoginManager.shared.login```を使用する方法

ログインボタン押下時に、[LoginManager](https://developers.line.biz/ja/reference/ios-sdk-swift/Classes/LoginManager.html).shared.[login](https://developers.line.biz/ja/reference/ios-sdk-swift/Classes/LoginManager.html#/s:7LineSDK12LoginManagerC5login11permissions2in7options17completionHandlerAA0C7ProcessCSgShyAA0C10PermissionVG_So16UIViewControllerCSgAA0cD7OptionsVyAA6ResultOyAA0cP0VAA0A8SDKErrorOGctF)を呼ぶだけ。

実装内容は、以下になります。

- ログインボタン(UIBtton)の配置
- アクセストークンをログ出力
- プロフィール情報(ユーザー名・ステータス・アイコン画像URL)をログ出力

```.swift
    /// ログイン処理
    func login() {
        LoginManager.shared.login(permissions: [.profile], in: self) {
            result in
            switch result {
            case .success(let loginResult):
                if let profile = loginResult.userProfile
                    print(profile.displayName)
                    print(profile.pictureURL!)
                    print(profile.statusMessage!)
                }
                print("Login Token value:\(loginResult.accessToken.value)")
            case .failure(let error):
                print("error:",error)
            }
        }
    }
```

#まとめ

(openIdを使用しなければ)LINEのログインは初心者にもとても易しく、
日本語のリファレンスも整っているので、実装しやすい印象を受けました。
ご指摘、ご助言等ありましたらお願いいたします。

#参考

- [LINE SDK for iOS Swiftの概要](https://developers.line.biz/ja/docs/ios-sdk/swift/overview/)
- [LINE SDK v5.0 for iOS Swift](https://developers.line.biz/ja/reference/ios-sdk-swift/index.html)