iT邦幫忙

2021 iThome 鐵人賽

DAY 19
0
Mobile Development

Flutter - 從 Packages & Plugins 掌握原生系列 第 19

Day19 Plugin 從零開始到上架 - 取得授權碼(Android)

目標

取得INSTAGRAM_CLIENT_ID、INSTAGRAM_CLIENT_SECRET 和 REDIRECT_URI 後,我們就要透過這些資料拿到Instagram 用戶存取權杖,流程參考官方文件,所以我們要先開一個WebView,來取得短期權杖最後所需要的授權碼code,之後再透過此授權碼就能打api來取得短期權杖了

Android端

新建一個Activity AccessTokenActivity,來取得權杖,首先須先把之前取得資訊傳進AccessTokenActivity,在WebView 透過之前取得的資訊,在使用者點選正確流程後,即可取得授權碼,之後再透過viewModel 來取得短期權杖(下一篇內容)

class AccessTokenActivity : AppCompatActivity() {

    private lateinit var clientId: String
    private lateinit var clientSecret: String
    private lateinit var redirectUri: String

    private val viewModel: AccessTokenViewModel by viewModel()

    private val webView: WebView by lazy {
        findViewById<WebView>(R.id.webView)
    }
    
    companion object {
        private const val CLIENT_ID_EXTRA = "client_id"
        private const val CLIENT_SECRET_EXTRA = "client_secret"
        private const val REDIRECT_URI_EXTRA = "redirect_uri"

        fun createIntent(
            context: Context,
            clientId: String,
            clientSecret: String,
            redirectUri: String
        ): Intent {
            return Intent(context, AccessTokenActivity::class.java)
                .putExtra(CLIENT_ID_EXTRA, clientId)
                .putExtra(CLIENT_SECRET_EXTRA, clientSecret)
                .putExtra(REDIRECT_URI_EXTRA, redirectUri)
        }
    }
    
    private val webViewClient: WebViewClient = object : WebViewClient() {

        override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
            if (isAuthCodeExist(url)) {
                return false
            }
            return super.shouldOverrideUrlLoading(view, url)
        }

        @RequiresApi(Build.VERSION_CODES.N)
        override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                if (isAuthCodeExist(request.url.toString())) {
                    loadingDialog.startLoadingDialog()
                    getAccessToken(request.url.toString())
                    view.stopLoading()
                    return false
                }
                view.loadUrl(request.url.toString())
            }
            return false
        }
    }

    private inner class FlutterWebChromeClient : WebChromeClient() {
        override fun onCreateWindow(
            view: WebView, isDialog: Boolean, isUserGesture: Boolean, resultMsg: Message
        ): Boolean {
            val webViewClient: WebViewClient = object : WebViewClient() {
                @TargetApi(Build.VERSION_CODES.LOLLIPOP)
                override fun shouldOverrideUrlLoading(
                    view: WebView, request: WebResourceRequest
                ): Boolean {
                    if (isAuthCodeExist(request.url.toString())) {
                        return false
                    }
                    webView.loadUrl(request.url.toString())
                    return true
                }

                override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
                    if (isAuthCodeExist(url)) {
                        return false
                    }
                    webView.loadUrl(url)
                    return true
                }
            }
            val newWebView = WebView(webView.context)
            newWebView.webViewClient = webViewClient
            val transport = resultMsg.obj as WebView.WebViewTransport
            transport.webView = newWebView
            resultMsg.sendToTarget()
            return true
        }
    }
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_access_token)

        val intent = intent
        clientId = intent.getStringExtra(CLIENT_ID_EXTRA)!!
        clientSecret = intent.getStringExtra(CLIENT_SECRET_EXTRA)!!
        redirectUri = intent.getStringExtra(REDIRECT_URI_EXTRA)!!

        Log.d(
            "$TAG",
            "clientId = $clientId, clientSecret = $clientSecret, redirectUri = $redirectUri"
        )
        webView.loadUrl("https://www.instagram.com/oauth/authorize?client_id=$clientId&redirect_uri=$redirectUri&scope=user_profile,user_media&response_type=code")
        webView.settings.javaScriptEnabled = true

        // Open new urls inside the webview itself.
        webView.webViewClient = webViewClient

        // Multi windows is set with FlutterWebChromeClient by default to handle internal bug: b/159892679.
        webView.settings.setSupportMultipleWindows(true)
        webView.webChromeClient = FlutterWebChromeClient()
    }
    
    private fun isAuthCodeExist(url: String): Boolean {
        Log.d(TAG, "checkAuthCodeExist url = $url:")
        return url.startsWith(redirectUri)
    }
    
    private fun getAccessToken(url: String) {
        if (url.contains("code=")) {
            val startIndex = url.indexOf("code=", 0) + 5
            // #_ 是附加到重新導向 URI 的結尾,非代碼本身的一部分
            val endIndex = url.lastIndex - 1
            val code = url.substring(startIndex, endIndex)
            Log.d(TAG, "oauth authorize code = $code")
            viewModel.getAssessToken(
                clientId,
                clientSecret,
                code,
                redirectUri
            )
        } else {
            Log.d(TAG, "redirect url error = $url")
            setResult(RESULT_CANCELED)
            finish()
        }
    }
}

上一篇
Day18 Plugin 從零開始到上架 01
下一篇
Day20 Plugin 從零開始到上架 - 取得授權碼(iOS)
系列文
Flutter - 從 Packages & Plugins 掌握原生30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言