【Android×Kotlin】facebook sdkによる認証とデータ取得をfragmentに実装

最近Kotlinが流行ってるしKotlinで実装してみようと思ったものの、Kotlinでfacebook認証とデータの取得をfragmentに実装する例があまり見当たらなかったので書き残しておくことにしました。（Activityへの実装と大差ないですが。。。）

#実行環境
kotlin 1.0.4
facebook sdk 4.9.0
minSdkVersion 21

#手順
https://developers.facebook.com/docs/facebook-login/android
基本的に公式に書いてある通りですが、

1.諸々の情報を登録
2.xmlにボタンの実装
3.fragmentにeventを紐付ける

という手順になります。

#実装
1.諸々の情報を登録
AndroidManifestに以下を記述
facebook_app_idはdeveloperページから拾ってきて下さい。
詳しくはこちら（keyハッシュの登録等も必要です）
https://developers.facebook.com/quickstarts/1633358696979477/?platform=android

```xml
<string name="facebook_app_id">[facebook_app_id]</string>
<uses-permission android:name="android.permission.INTERNET"/>
<application android:label="@string/app_name" ...>
  <meta-data
    android:name="com.facebook.sdk.ApplicationId"
    android:value="@string/facebook_app_id" />
</application>
```

2.xmlにボタンの実装
ここは特に説明するまでもないと思いますが、対象となるfragmentのxmlにログイン処理を紐付けたいViewを定義します。今回はごく普通のButtonです。

```xml
<Button
  android:id="@+id/fbbutton"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"/>
```

3.fragmentにeventを紐付ける
公式のドキュメントがJavaで書かれているので慣れていないとKotlinへの書き換えに苦労するかもしれません。
匿名クラスの書き換えやSAM型であるonClickListenerのインターフェース名、メソッド名省略ですごくスッキリしたコードになります。

認証とデータの取得はonCreateView()で行います。
また2で作成したButtonへのEventの紐付けもここで行いましょう。

```kotlin

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        FacebookSdk.sdkInitialize(activity)
        this.callbackManager = CallbackManager.Factory.create()

        val bundle: Bundle? = arguments
        val rootView: View?
        rootView = inflater?.inflate(R.layout.fragment_login, container, false)

        val fbLoginButton = rootView?.findViewById(R.id.fbbutton)
        fbLoginButton?.setOnClickListener {
            LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile", "email"))
        }

        LoginManager.getInstance().registerCallback(callbackManager,
                object : FacebookCallback<LoginResult> {
                    override fun onSuccess(loginResult: LoginResult) {
                        val request = GraphRequest.newMeRequest(loginResult.accessToken
                        ) { obj, fbResponse ->
                        //fbResponseに認証後のユーザデータが入ります
　　　　　　　　　　　　　}
                        val parameters = Bundle()
                        //必要なfieldをここで指定します
                        parameters.putString("fields", "id,last_name,first_name,email")
                        request.parameters = parameters
                        request.executeAsync()
                    }
                    override fun onCancel() {
                        Log.e("cancel", "cancel")
                    }
                    override fun onError(exception: FacebookException) {
                        Log.e("error", exception.toString())
                    }
                })
        return rootView
    }
```

次に、onActivityResult()で、ログインの結果をcallbackManagerに転送します。

```kotlin
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
        super.onActivityResult(requestCode, resultCode, data)
        callbackManager?.onActivityResult(requestCode, resultCode, data)
}
```

以上になります。
fragmentに実装されたボタンをクリックするとfacebook sdkによる認証が行われ、指定したfieldのデータが取得できたかと思います。

#所感
地道に公式のドキュメントを読み解きながら実装すれば特に苦労するところもなかったと思うんですが楽をしようとして少し手間取りました。
Kotlinについては、もともとJavaをろくに書かずにSwiftからKotlinへジョブチェンジだったこともあり、おそらくJavaに慣れ親しんだ人よりはすんなりKotlinにコードを置き換えることが出来た気もします。
ここではないどこかで書くかもしれませんが、interface実装や関数リテラルもネイティブと相性がいいなぁという印象です。