2
0

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 3 years have passed since last update.

HMSアプリにGoogleログイン、Facebookログイン、Twitterログインを実装する方法

Last updated at Posted at 2020-12-25

ソーシャルログインについて

ソーシャルログインとはユーザーが自分の所有しているSNSアカウントを使って、ログインや新規登録をする機能です。メールアドレスや電話番号などの入力がなくなるので、その利便さがユーザーエクスペリエンスの向上につながります。そのため、最近ソーシャルログインを実装したアプリが増えています。

国内でよく使われているソーシャルログインはLINE、Google、Facebook、Twitterなどあります。

image.png

HUAWEI Auth Service

HUAWEI Auth Serviceはファーウェイが提供しているソーシャルログイン機能です。このソーシャルログイン機能はAndoidでもiOSでも実装可能です。また、GMSのAndroid端末でもHMSのAndroid端末でも使用可能です。HUAWEI Auth ServiceがサポートしているSNSアカウントの認証トークンさえあればログインできます。

現在HUAWEI Auth ServiceがサポートしているSNSアカウントは次の表に示します。

SNSアカウント Android iOS Web
HUAWEI ID
HUAWEI GameCenter account
WeChat account
QQ account
Weibo account
Apple ID
Google account
Google Play Games account
Facebook account
Twitter account

HUAWEI Auth Serviceの実装方法

ソーシャルログインの流れは次のようになります。

  1. SNSアカウントの認証サーバーから認証トークンを取得する
  2. 取得した認証トークンをHUAWEI Auth Serviceの認証サーバーに渡し、ログインする

ここで注意しなければならないのは、HUAWEI Auth Serviceは(2)の機能のみを提供しているということです。(1)の機能は含まれていません。

本稿は(1)と(2)の実装方法をすべて紹介します。

開発準備

  1. AppGallery Connectに入って、[My project]をクリックする
  2. 左側のメニューから[Auth Service]をクリックし、Auth Serviceを開く
  3. [Enable now]をクリックし、Auth Serviceを有効にする

image.jpg

[Huawei account]、[Facebook]、[Twitter]、[Google]を有効にする。SNS開発者アカウントのApp IDやApp Keyもここに設定します。

image.jpg

image.jpg

build.gradleにライブラリを追加します。

build.gradle
implementation 'com.huawei.agconnect:agconnect-core:1.4.2.301'
implementation 'com.huawei.agconnect:agconnect-auth:1.4.2.301'

HUAWEI IDのトークン取得の実装方法

build.gradle
implementation 'com.huawei.hms:hwid:5.0.5.301'

HuaweiIdAuthServiceを生成し、Activityを起動します。

MainActivity.kt
val huaweiIdAuthParamsHelper = HuaweiIdAuthParamsHelper(HuaweiIdAuthParams.DEFAULT_AUTH_REQUEST_PARAM).apply {
    setScopeList(arrayListOf(Scope(CommonConstant.SCOPE.ACCOUNT_BASEPROFILE)))
}
val huaweiIdAuthParams: HuaweiIdAuthParams = huaweiIdAuthParamsHelper.setAccessToken().createParams()
val huaweiIdAuthService: HuaweiIdAuthService = HuaweiIdAuthManager.getService(activity, huaweiIdAuthParams)
startActivityForResult(huaweiIdAuthService.signInIntent, REQUEST_CODE_SIGN_IN_HUAWEI_ID)

HUAWEI IDのアクセストークンはonActivityResultに返ってきます。

MainActivity.kt
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    ...

    when (requestCode) {
        REQUEST_CODE_SIGN_IN_HUAWEI_ID -> {
            val authHuaweiIdTask = HuaweiIdAuthManager.parseAuthResultFromIntent(data)
            if (authHuaweiIdTask.isSuccessful) {
                // HUAWEI IDのアクセストークン = authHuaweiIdTask.result.accessToken
                val credential = HwIdAuthProvider.credentialWithToken(authHuaweiIdTask.result.accessToken)
            }
        }
    }
}

Facebookのトークン取得の実装方法

Facebookログインのクイックスタートにしたがって、リソースやソースコードを自分のプロジェクトにコピペします。

image.jpg

build.gradle
implementation 'com.facebook.android:facebook-login:8.1.0'
strings.xml
<string name="facebook_app_id">xxxxxxxxxxxxxx</string>
<string name="fb_login_protocol_scheme">xxxxxxxxxxxxxx</string>
main_fragment.xml
<com.facebook.login.widget.LoginButton
    android:id="@+id/button_sign_in_facebook"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    ...
    FacebookSdk.sdkInitialize(applicationContext)
}
MainFragment.kt
private val facebookCallbackManager: CallbackManager = CallbackManager.Factory.create()

override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
): View? {
    ...

    binding.buttonSignInFacebook.registerCallback(
            facebookCallbackManager,
            object : FacebookCallback<LoginResult?> {
                override fun onSuccess(result: LoginResult?) {
                    result?.let { result ->
                        // アクセストークン = result.accessToken.token
                        val credential = FacebookAuthProvider.credentialWithToken(result.accessToken.token)
                    }
                }

                override fun onCancel() {
                }

                override fun onError(error: FacebookException?) {
                }
            })

    ...
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    ...

    facebookCallbackManager.onActivityResult(requestCode, resultCode, data)
}

Twitterのトークン取得の実装方法

TwitterのアプリID、アプリキー、アプリキーシークレットはTwitter Developer Portalから見られます。

image.jpg

image.jpg

build:gradle
implementation 'com.twitter.sdk.android:twitter:3.3.0'
strings.xml
<string name="twitter_app_id">xxxxxx</string>
<string name="twitter_app_key">xxxxxxxxxxxxxxxxxxxxxxxx</string>
<string name="twitter_app_key_secret">xxxxxxxxxxxxxxxxxxxxx</string>
main_fragment.xml
<com.twitter.sdk.android.core.identity.TwitterLoginButton
    android:id="@+id/button_sign_in_twitter"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    />
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    ...

    val twitterAuthConfig = TwitterAuthConfig(
            getString(R.string.twitter_app_key),
            getString(R.string.twitter_app_key_secret)
    )
    val twitterConfig: TwitterConfig = TwitterConfig.Builder(applicationContext).twitterAuthConfig(
            twitterAuthConfig
    ).build()
    Twitter.initialize(twitterConfig)
}

// Twitterのログインロジックがフラグメントにある場合
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    ...

    supportFragmentManager.findFragmentByTag(MainFragment.TAG)?.let {
        it.onActivityResult(requestCode, resultCode, data)
    }
}
MainFragment.kt
override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
): View? {
    ...

    binding.buttonSignInTwitter.callback = object : com.twitter.sdk.android.core.Callback<TwitterSession>() {
        override fun success(result: Result<TwitterSession>?) {
            result?.let { result ->
                // アクセストークン = result.data.authToken.token
                // アクセストークンシークレット = result.data.authToken.secret
                val credential = TwitterAuthProvider.credentialWithToken(
                        result.data.authToken.token,
                        result.data.authToken.secret
                )
            }
        }

        override fun failure(exception: TwitterException?) {
        }
    }

    ...
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    ...

    binding.buttonSignInTwitter.onActivityResult(requestCode, resultCode, data)
}

Googleのトークン取得の実装方法

認証情報の作成

Google Developer Consoleで認証情報を作成します。

ここで注意しなければならないことがあります。HMS端末にGMSが入っていないので、Googleが提供しているSDKが使えません。そのため、Google Developer Consoleで認証情報を作成するときに、ウェブアプリケーションを選ばなければなりません。

image.jpg

作成したら、クライアントIDとクライアントシークレットが表示されます。

また、リダイレクトURI(URI)を設定しなければなりません。このURIは公開されている実在のページやAPIじゃなくてもよいです。httpまたはhttpsから始まるURIであればよいです。

image.jpg

GoogleのSDKを使わないので、build.gradleに追加するコードがありません。

認証コードの取得

https://accounts.google.com/o/oauth2/auth でGoogleアカウントの認証コードを取得します。

https://accounts.google.com/o/oauth2/auth はGETメソッドのAPIです。まずURLを作ります。

GoogleAuth.kt
companion object {
    private const val AUTH_LINK = "https://accounts.google.com/o/oauth2/auth"
    private const val CLIENT_ID = "your client id"
    private const val SCOPE = "https://www.googleapis.com/auth/userinfo.profile"
    const val REDIRECT_URI = "https://your.redirecturi.com/auth"

    }

private fun mapToString(map: Map<String, String>): String {
    var query = ""
    var count = 0
    map.forEach { (key, value) ->
        if (count > 0) {
            query += "&"
        }
        query += "$key=$value"
        count++
    }

    return query
}

fun createAuthLink(): String {
    val map: Map<String, String> = hashMapOf(
            "client_id" to CLIENT_ID,
            "scope" to SCOPE,
            "response_type" to "code",
            "redirect_uri" to REDIRECT_URI
    )

    return AUTH_LINK + "?" + mapToString(map)
}

URLを内部WebViewで開きます。

MainFragment.kt
val googleAuth = GoogleAuth()
val link = googleAuth.createAuthLink()
val intent = Intent(context, WebViewActivity::class.java).apply {
    putExtra("link", link)
}

startActivity(intent)

内部WebViewで開くので、WebViewのActivityを作ります。

AndroidManifest.xml
<activity android:name=".WebViewActivity"></activity>

WebViewを作るときのポイントは次の通りです。

  1. JavaScriptを有効にする
  2. ユーザーエージェントを通常のブラウザと同じものにする
  3. shouldOverrideUrlLoadingを必ずオーバーライドする
  4. shouldOverrideUrlLoadingのリンクがGoogle Developer Consoleに設定したリダイレクトURIと同じであれば、リダイレクトをせずにMainActivityに転送する
  5. Google Developer Consoleに設定したリダイレクトURIと違えば、WebView内で開く
WebViewActivity.kt
class WebViewActivity : AppCompatActivity() {

    private lateinit var binding: WebViewActivityBinding

    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.inflate<WebViewActivityBinding>(
                layoutInflater,
                R.layout.web_view_activity,
                null,
                false
        )
        setContentView(binding.root)

        with(binding) {
            webView.settings.javaScriptEnabled = true
            webView.settings.domStorageEnabled = true
            webView.settings.userAgentString = "Mozilla/5.0 (Linux; Android 10; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.62 Mobile Safari/537.36"

            webView.webViewClient = object : WebViewClient() {
                override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
                    request?.url?.let { url ->
                        if (url.toString().contains(GoogleAuth.REDIRECT_URI)) {
                            val intent = Intent(applicationContext, MainActivity::class.java).apply {
                                data = url
                                flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
                            }
                            startActivity(intent)
                            return true
                        }

                        view?.loadUrl(url.toString())
                    }

                    return false
                }
            }

            intent?.getStringExtra("link")?.let { url ->
                webView.loadUrl(url)
            }
        }

        window.setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
    }
}

MainActivityで認証コードを取得します。

MainActivity.kt
val code = intent?.data?.getQueryParameter("code")

認証コードをトークンに変換

https://oauth2.googleapis.com/token で認証コードをトークンに変換します。

GoogleAuth.kt
companion object {

    private const val TOKEN_LINK = "https://oauth2.googleapis.com/token"
    private const val CLIENT_ID = "Your client id"
    private const val CLIENT_SECRET = "Your client secret"
    private const val SCOPE = "https://www.googleapis.com/auth/userinfo.profile"
    const val REDIRECT_URI = "https://your.redirecturi.com/auth"
    }

fun getToken(context: Context, code: String, listener: Response.Listener<String>, errorListener: Response.ErrorListener) {
    val queue = Volley.newRequestQueue(context)

    val postRequest: StringRequest = object : StringRequest(
            Method.POST,
            TOKEN_LINK,
            listener,
            errorListener) {
        override fun getBodyContentType(): String {
            return "application/x-www-form-urlencoded"
        }

        override fun getParams(): Map<String, String> {
            val params: MutableMap<String, String> = HashMap()
            params["code"] = code
            params["client_id"] = CLIENT_ID
            params["client_secret"] = CLIENT_SECRET
            params["redirect_uri"] = REDIRECT_URI
            params["grant_type"] = "authorization_code"
            return params
        }
    }

    queue.add(postRequest)
}
MainFragment.kt
private fun signInGoogleCode(code: String) {
    val context: Context = context ?: return
    val googleAuth = GoogleAuth()
    googleAuth.getToken(
        context,
        code,
        object : Response.Listener<String>{
            override fun onResponse(response: String?) {
                response?.let { response ->
                    val jsonObject = JSONObject(response)
                    if (jsonObject.has("id_token")) {
                        // トークンはhttps://oauth2.googleapis.com/tokenのレスポンスのid_token
                        val idToken = jsonObject.getString("id_token")
                        val credential = GoogleAuthProvider.credentialWithToken(idToken)
                    }
                }
            }
        },
        object : Response.ErrorListener{
            override fun onErrorResponse(error: VolleyError?) {
            }
        }
    )
}

各トークンによるHuawei Auth Serviceの認証の実装方法

MainFragment.kt
private fun signIn(credential: AGConnectAuthCredential) {
    AGConnectAuth.getInstance().signIn(credential).addOnSuccessListener { result ->
        // ユーザーオブジェクト
        val user = result.user

        // ユーザーのユニークなID
        val uid = user.uid

        // ユーザーのメールアドレス
        val email = user.email

        // ユーザーの電話番号
        val phone = user.phone

        // ユーザーの画像
        val photo = user.photoUrl

        // ユーザー名
        val name = user.displayName
    }.addOnFailureListener {
    }
}

一言

HMS端末のアプリではGoogleログインが使えないと勘違いするかもしれませんが、ちゃんと使えます!

GitHub

https://github.com/Rei2020GitHub/MyPublicProject/tree/master/AuthDemo

参考

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?