Lật ứng dụng dành cho Android

Phương thức liên kết Lật ứng dụng dựa trên OAuth (App Flip) sẽ chèn ứng dụng Android của bạn vào Quy trình Liên kết Tài khoản Google. Quy trình liên kết tài khoản truyền thống đòi hỏi để nhập thông tin đăng nhập của họ vào trình duyệt. Việc sử dụng tính năng Lật ứng dụng sẽ trì hoãn người dùng đăng nhập vào ứng dụng Android của bạn. Tính năng này cho phép bạn tận dụng các uỷ quyền. Nếu người dùng đã đăng nhập vào ứng dụng của bạn, họ không cần nhập lại thông tin đăng nhập để liên kết tài khoản của họ. Số lượng mã tối thiểu bạn cần thực hiện các thay đổi để triển khai Lật ứng dụng trên ứng dụng Android của mình.

Trong tài liệu này, bạn tìm hiểu cách sửa đổi ứng dụng Android để hỗ trợ Lật ứng dụng.

Dùng thử mẫu

Ứng dụng mẫu liên kết App Flip minh hoạ chế độ tích hợp liên kết tài khoản tương thích với App Flip trên Android. Bạn có thể sử dụng ứng dụng này để xác minh cách phản hồi ý định Lật ứng dụng đến từ Ứng dụng di động của Google.

Ứng dụng mẫu được định cấu hình sẵn để tích hợp với Công cụ kiểm thử độ lật ứng dụng cho Android, mà bạn có thể sử dụng để xác minh việc tích hợp ứng dụng Android của bạn với Ứng dụng Lật trước khi bạn định cấu hình liên kết tài khoản với Google. Ứng dụng này mô phỏng ý định được các ứng dụng di động của Google kích hoạt khi Lật ứng dụng được bật.

Cách hoạt động

Bạn cần thực hiện các bước sau để tích hợp App Flip:

  1. Ứng dụng Google sẽ kiểm tra xem ứng dụng của bạn có được cài đặt trên thiết bị hay không bằng cách sử dụng package name (tên gói).
  2. Ứng dụng Google sử dụng quy trình kiểm tra chữ ký gói để xác thực rằng ứng dụng đã cài đặt ứng dụng chính xác là ứng dụng chính xác.
  3. Ứng dụng Google tạo ý định để bắt đầu một hoạt động được chỉ định trong ứng dụng của bạn. Ý định này bao gồm dữ liệu bổ sung cần thiết để liên kết. Quy trình này cũng kiểm tra để xem ứng dụng của bạn có hỗ trợ App Flip hay không bằng cách giải quyết ý định này thông qua khung Android.
  4. Ứng dụng của bạn xác thực rằng yêu cầu đến từ ứng dụng Google. Để làm như vậy, ứng dụng của bạn sẽ kiểm tra chữ ký gói và mã ứng dụng khách được cung cấp.
  5. Ứng dụng của bạn yêu cầu mã uỷ quyền từ máy chủ OAuth 2.0. Tại kết thúc luồng này, nó sẽ trả về mã uỷ quyền hoặc lỗi cho Ứng dụng Google.
  6. Ứng dụng Google truy xuất kết quả và tiếp tục liên kết tài khoản. Nếu mã uỷ quyền được cung cấp thì quá trình trao đổi mã thông báo sẽ diễn ra máy chủ đến máy chủ, giống như cách thực hiện trong liên kết OAuth dựa trên trình duyệt luồng.

Sửa đổi ứng dụng Android của bạn để hỗ trợ tính năng Lật ứng dụng

Để hỗ trợ App Flip (Lật ứng dụng), hãy thay đổi mã sau đây cho ứng dụng Android của bạn:

  1. Thêm một <intent-filter> vào tệp AndroidManifest.xml bằng một thao tác khớp với giá trị bạn đã nhập vào trường Ý định lật ứng dụng.

    <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. Xác thực chữ ký của ứng dụng gọi.

    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. Trích xuất mã ứng dụng khách từ các tham số ý định và xác minh rằng ứng dụng khách Mã nhận dạng khớp với giá trị dự kiến.

    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. Sau khi uỷ quyền thành công, hãy trả về mã uỷ quyền kết quả cho Google.

    // Successful result
    val data = Intent().apply {
        putExtra("AUTHORIZATION_CODE", authCode)
    }
    setResult(Activity.RESULT_OK, data)
    finish()
    
  5. Nếu xảy ra lỗi, hãy trả về kết quả lỗi.

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

Nội dung của ý định ra mắt

Ý định trên Android chạy ứng dụng bao gồm các trường sau:

  • CLIENT_ID (String): Google client_id đã đăng ký trong ứng dụng của bạn.
  • SCOPE (String[]): Danh sách các phạm vi được yêu cầu.
  • REDIRECT_URI (String): URL chuyển hướng.

Nội dung của dữ liệu phản hồi

Dữ liệu được trả về cho ứng dụng Google được thiết lập trong ứng dụng của bạn bằng cách gọi setResult(). Dữ liệu này bao gồm:

  • AUTHORIZATION_CODE (String): Giá trị mã uỷ quyền.
  • resultCode (int): Thông báo trạng thái thành công hay thất bại của quy trình và nhận một trong các giá trị sau:
    • Activity.RESULT_OK: Cho biết đã thành công; mã uỷ quyền sẽ được trả về.
    • Activity.RESULT_CANCELLED: Tín hiệu cho thấy người dùng đã huỷ của chúng tôi. Trong trường hợp này, ứng dụng Google sẽ cố gắng liên kết tài khoản bằng cách sử dụng URL uỷ quyền của bạn.
    • -2: Cho biết đã xảy ra lỗi. Các loại lỗi khác nhau được mô tả bên dưới.
  • ERROR_TYPE (int): Loại lỗi, xảy ra một trong các lỗi sau giá trị:
    • 1: Lỗi có thể khôi phục: Ứng dụng Google sẽ thử liên kết tài khoản bằng cách sử dụng URL uỷ quyền.
    • 2: Lỗi không thể khôi phục: Ứng dụng Google huỷ liên kết tài khoản.
    • 3: Tham số yêu cầu không hợp lệ hoặc bị thiếu.
  • ERROR_CODE (int): Một số nguyên thể hiện bản chất của lỗi. Để xem ý nghĩa của từng mã lỗi, hãy tham khảo bảng mã lỗi.
  • ERROR_DESCRIPTION (String, không bắt buộc): Thông báo trạng thái có thể đọc được mô tả lỗi.

Giá trị cho AUTHORIZATION_CODE được mong đợi khi resultCode == Activity.RESULT_OK Trong tất cả các trường hợp khác, giá trị cho Bạn cần để trống AUTHORIZATION_CODE. Nếu là resultCode == -2, thì hàm Hệ thống dự kiến sẽ điền giá trị ERROR_TYPE.

Bảng mã lỗi

Bảng dưới đây trình bày các mã lỗi khác nhau và cho biết mỗi mã là lỗi có thể khôi phục hay không thể khôi phục:

Mã lỗi Ý nghĩa Có thể khôi phục Không thể phục hồi
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

Đối với tất cả mã lỗi, bạn phải trả về kết quả lỗi qua setResult để đảm bảo phân loại dự phòng thích hợp.