Android 版 App Flip

基於 OAuth 的 App Flip 鏈接 (App Flip) 將您的 Android 應用程序插入到 Google 帳戶鏈接流程中。傳統的帳戶鏈接流程要求用戶在瀏覽器中輸入其憑據。使用 App Flip 將用戶登錄推遲到您的 Android 應用程序,這允許您利用現有授權。如果用戶已登錄您的應用,則無需重新輸入憑據即可關聯其帳戶。在您的 Android 應用程序上實現 App Flip 需要進行少量的代碼更改。

在本文檔中,您將了解如何修改您的 Android 應用以支持 App Flip。

試試樣品

該應用程序鏈接翻轉的示例應用程序演示了一個App翻轉兼容的帳戶在Android上連接整合。您可以使用此應用來驗證如何響應來自 Google 移動應用的傳入 App Flip Intent。

示例應用程序預配置與整合應用翻轉測試工具為Android ,你可以用它來驗證您的Android應用的使用App翻轉整合之前配置帳戶與谷歌聯繫起來。此應用程序模擬啟用 App Flip 時由 Google 移動應用程序觸發的意圖。

怎麼運行的

執行 App Flip 集成需要以下步驟:

  1. 該谷歌應用程序檢查,如果您的應用程序安裝使用它的包名在設備上。
  2. Google 應用程序使用包簽名檢查來驗證安裝的應用程序是正確的應用程序。
  3. Google 應用構建了一個 Intent,以在您的應用中啟動指定的 Activity。此意圖包括鏈接所需的附加數據。它還通過 Android 框架解析此意圖來檢查您的應用程序是否支持 App Flip。
  4. 您的應用會驗證請求是否來自 Google 應用。為此,您的應用會檢查包簽名和提供的客戶端 ID。
  5. 您的應用程序向您的 OAuth 2.0 服務器請求授權碼。在此流程結束時,它會向 Google 應用返回授權代碼或錯誤。
  6. Google 應用檢索結果並繼續關聯帳戶。如果提供了授權代碼,令牌交換會在服務器到服務器之間進行,就像在基於瀏覽器的 OAuth 鏈接流中一樣。

修改您的 Android 應用以支持 App Flip

要支持 App Flip,請對您的 Android 應用程序進行以下代碼更改:

  1. 添加<intent-filter>AndroidManifest.xml文件與您在App翻轉意願字段中輸入的值相匹配的操作字符串。

    <activity android:name="AuthActivity">
      <!-- Handle the app flip intent -->
      <intent-filter>
        <action android:name="INTENT_ACTION_FROM_CONSOLE"/>
        <category android:name="android.intent.category.DEFAULT"/>
      </intent-filter>
    </activity>
    
  2. 驗證調用應用程序的簽名。

    private fun verifyFingerprint(
            expectedPackage: String,
            expectedFingerprint: String,
            algorithm: String
    ): Boolean {
    
        callingActivity?.packageName?.let {
            if (expectedPackage == it) {
                val packageInfo =
                    packageManager.getPackageInfo(it, PackageManager.GET_SIGNATURES)
                val signatures = packageInfo.signatures
                val input = ByteArrayInputStream(signatures[0].toByteArray())
    
                val certificateFactory = CertificateFactory.getInstance("X509")
                val certificate =
                    certificateFactory.generateCertificate(input) as X509Certificate
                val md = MessageDigest.getInstance(algorithm)
                val publicKey = md.digest(certificate.encoded)
                val fingerprint = publicKey.joinToString(":") { "%02X".format(it) }
    
                return (expectedFingerprint == fingerprint)
            }
        }
        return false
    }
    
  3. 從意圖參數中提取客戶端 ID 並驗證客戶端 ID 是否與預期值匹配。

    private const val EXPECTED_CLIENT = "<client-id-from-actions-console>"
    private const val EXPECTED_PACKAGE = "<google-app-package-name>"
    private const val EXPECTED_FINGERPRINT = "<google-app-signature>"
    private const val ALGORITHM = "SHA-256"
    ...
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
    
        val clientId = intent.getStringExtra("CLIENT_ID")
    
        if (clientId == EXPECTED_CLIENT &&
            verifyFingerprint(EXPECTED_PACKAGE, EXPECTED_FINGERPRINT, ALGORITHM)) {
    
            // ...authorize the user...
        }
    }
    
  4. 授權成功後,將生成的授權代碼返回給 Google。

    // Successful result
    val data = Intent().apply {
        putExtra("AUTHORIZATION_CODE", authCode)
    }
    setResult(Activity.RESULT_OK, data)
    finish()
    
  5. 如果發生錯誤,則返回錯誤結果。

    // Error result
    val error = Intent().apply {
        putExtra("ERROR_TYPE", 1)
        putExtra("ERROR_CODE", 1)
        putExtra("ERROR_DESCRIPTION", "Invalid Request")
    }
    setResult(-2, error)
    finish()
    

啟動意圖的內容

啟動您的應用的 Android Intent 包括以下字段:

  • CLIENT_IDString ):谷歌client_id您的應用程序下註冊。
  • SCOPEString[]請求範圍的列表。
  • REDIRECT_URIString ):重定向URL。

響應數據的內容

返回到谷歌應用程序的數據在你的應用程序通過調用設置setResult()該數據包括以下內容:

  • AUTHORIZATION_CODEString ):授權碼值。
  • resultCodeint ):通信的過程的成功或失敗以及取下列值之一:
    • Activity.RESULT_OK :表示成功;返回授權碼。
    • Activity.RESULT_CANCELLED :信號用戶已經取消了進程。在這種情況下,Google 應用程序將嘗試使用您的授權 URL 進行帳戶關聯。
    • -2 :表示已發生錯誤。下面描述了不同類型的錯誤。
  • ERROR_TYPEint ):錯誤的類型,這取下列值之一:
    • 1 :可恢復錯誤:谷歌應用程序會嘗試使用帳戶授權URL鏈接。
    • 2 :不可恢復的錯誤:谷歌應用程序異常退出帳戶鏈接。
    • 3 :無效或缺失請求參數。
  • ERROR_CODEint ):表示錯誤的性質的整數。要查看每個錯誤代碼的含義,指的錯誤代碼表
  • ERROR_DESCRIPTIONString ,可選):描述錯誤人類可讀狀態消息。

一種價值AUTHORIZATION_CODE預計當resultCode == Activity.RESULT_OK 。在其他情況下,該值AUTHORIZATION_CODE必須是空的。如果resultCode == -2 ,那麼ERROR_TYPE價值有望得到填充。

錯誤代碼表

下表顯示了不同的錯誤代碼以及每個錯誤代碼是可恢復的還是不可恢復的錯誤:

錯誤代碼意義可恢復不可恢復
1 INVALID_REQUEST
2 NO_INTERNET_CONNECTION
3 OFFLINE_MODE_ACTIVE
4 CONNECTION_TIMEOUT
5 INTERNAL_ERROR
6 AUTHENTICATION_SERVICE_UNAVAILABLE
8 CLIENT_VERIFICATION_FAILED
9 INVALID_CLIENT
10 INVALID_APP_ID
11 INVALID_REQUEST
12 AUTHENTICATION_SERVICE_UNKNOWN_ERROR
13 AUTHENTICATION_DENIED_BY_USER
14 CANCELLED_BY_USER
15 FAILURE_OTHER
16 USER_AUTHENTICATION_FAILED

對於所有的錯誤代碼,您必須通過返回錯誤結果setResult ,以確保適當的後退時被trigerred。