Hộp thoại khắc phục

Trang này mô tả cách xử lý các vấn đề liên quan đến kết quả về tính toàn vẹn.

Sau khi yêu cầu mã thông báo về tính toàn vẹn, bạn có thể cho người dùng thấy một hộp thoại của Google Play. Bạn có thể cho người dùng thấy hộp thoại này khi gặp phải một hoặc nhiều vấn đề liên quan đến kết quả về tính toàn vẹn hoặc nếu xảy ra một trường hợp ngoại lệ trong yêu cầu API Tính toàn vẹn. Sau khi đóng hộp thoại, bạn có thể xác minh xem vấn đề đã được khắc phục hay chưa bằng cách gửi một yêu cầu khác về mã thông báo về tính toàn vẹn. Nếu thực hiện yêu cầu chuẩn, bạn cần khởi động lại trình cung cấp mã thông báo để nhận kết quả mới.

Yêu cầu hộp thoại về tính toàn vẹn để khắc phục vấn đề về kết quả

Khi ứng dụng khách yêu cầu mã thông báo về tính toàn vẹn, bạn có thể sử dụng phương thức mà chúng tôi cung cấp trong StandardIntegrityToken (API Chuẩn) và IntegrityTokenResponse (API Kiểu cũ): showDialog(Activity activity, int integrityDialogTypeCode).

Các bước sau đây trình bày cách sử dụng API Tính toàn vẹn của Play để hiện hộp thoại khắc phục bằng mã hộp thoại GET_LICENSED. Các mã hộp thoại khác mà ứng dụng của bạn có thể yêu cầu được liệt kê sau phần này.

  1. Yêu cầu mã thông báo về tính toàn vẹn từ ứng dụng rồi gửi mã thông báo này đến máy chủ của bạn. Bạn có thể sử dụng yêu cầu Chuẩn hoặc Kiểu cũ.

    Kotlin

    // Request an integrity token
    val tokenResponse: StandardIntegrityToken = requestIntegrityToken()
    // Send token to app server and get response on what to do next
    val yourServerResponse: YourServerResponse = sendToServer(tokenResponse.token())  

    Java

    // Request an integrity token
    StandardIntegrityToken tokenResponse = requestIntegrityToken();
    // Send token to app server and get response on what to do next
    YourServerResponse yourServerResponse = sendToServer(tokenResponse.token());  

    Unity

    // Request an integrity token
    StandardIntegrityToken tokenResponse = RequestIntegrityToken();
    // Send token to app server and get response on what to do next
    YourServerResponse yourServerResponse = sendToServer(tokenResponse.Token); 

    Unreal Engine

    // Request an integrity token
    StandardIntegrityToken* Response = RequestIntegrityToken();
    // Send token to app server and get response on what to do next
    YourServerResponse YourServerResponse = SendToServer(Response->Token); 

    Mã gốc

    /// Request an integrity token
    StandardIntegrityToken* response = requestIntegrityToken();
    /// Send token to app server and get response on what to do next
    YourServerResponse yourServerResponse = sendToServer(StandardIntegrityToken_getToken(response));
  2. Trên máy chủ của bạn, hãy giải mã mã thông báo về tính toàn vẹn rồi kiểm tra trường appLicensingVerdict. Mã sẽ có dạng như sau:

    // Licensing issue
    {
      ...
      "accountDetails": {
          "appLicensingVerdict": "UNLICENSED"
      }
    }
  3. Nếu mã thông báo chứa appLicensingVerdict: "UNLICENSED", hãy phản hồi ứng dụng khách của bạn và yêu cầu hiện hộp thoại cấp phép:

    Kotlin

    private fun getDialogTypeCode(integrityToken: String): Int{
      // Get licensing verdict from decrypted and verified integritytoken
      val licensingVerdict: String = getLicensingVerdictFromDecryptedToken(integrityToken)
    
      return if (licensingVerdict == "UNLICENSED") {
              1 // GET_LICENSED
          } else 0
    }

    Java

    private int getDialogTypeCode(String integrityToken) {
      // Get licensing verdict from decrypted and verified integrityToken
      String licensingVerdict = getLicensingVerdictFromDecryptedToken(integrityToken);
    
      if (licensingVerdict.equals("UNLICENSED")) {
        return 1; // GET_LICENSED
      }
      return 0;
    }

    Unity

    private int GetDialogTypeCode(string IntegrityToken) {
      // Get licensing verdict from decrypted and verified integrityToken
      string licensingVerdict = GetLicensingVerdictFromDecryptedToken(IntegrityToken);
    
      if (licensingVerdict == "UNLICENSED") {
        return 1; // GET_LICENSED
      }
      return 0;
    } 

    Unreal Engine

    private int GetDialogTypeCode(FString IntegrityToken) {
      // Get licensing verdict from decrypted and verified integrityToken
      FString LicensingVerdict = GetLicensingVerdictFromDecryptedToken(IntegrityToken);
    
      if (LicensingVerdict == "UNLICENSED") {
        return 1; // GET_LICENSED
      }
      return 0;
    } 

    Mã gốc

    private int getDialogTypeCode(string integrity_token) {
      /// Get licensing verdict from decrypted and verified integrityToken
      string licensing_verdict = getLicensingVerdictFromDecryptedToken(integrity_token);
    
      if (licensing_verdict == "UNLICENSED") {
        return 1; // GET_LICENSED
      }
      return 0;
    }
  4. Trên ứng dụng, hãy gọi showDialog bằng mã bắt buộc được truy xuất từ máy chủ:

    Kotlin

    // Show dialog as indicated by the server
    val showDialogType: Int? = yourServerResponse.integrityDialogTypeCode()
    if (showDialogType != null) {
      // Call showDialog with type code, the dialog will be shown on top of the
      // provided activity and complete when the dialog is closed.
      val integrityDialogResponseCode: Task<Int> =
      tokenResponse.showDialog(activity, showDialogType)
      // Handle response code, call the Integrity API again to confirm that
      // verdicts have been resolved.
    } 

    Java

    // Show dialog as indicated by the server
    @Nullable Integer showDialogType = yourServerResponse.integrityDialogTypeCode();
    if (showDialogType != null) {
      // Call showDialog with type code, the dialog will be shown on top of the
      // provided activity and complete when the dialog is closed.
      Task<Integer> integrityDialogResponseCode =
          tokenResponse.showDialog(activity, showDialogType);
      // Handle response code, call the Integrity API again to confirm that
      // verdicts have been resolved.
    }

    Unity

    IEnumerator ShowDialogCoroutine() {
      int showDialogType = yourServerResponse.IntegrityDialogTypeCode();
    
      // Call showDialog with type code, the dialog will be shown on top of the
      // provided activity and complete when the dialog is closed.
      var showDialogTask = tokenResponse.ShowDialog(showDialogType);
    
      // Wait for PlayAsyncOperation to complete.
      yield return showDialogTask;
    
      // Handle response code, call the Integrity API again to confirm that
      // verdicts have been resolved.
    } 

    Unreal Engine

    // .h
    void MyClass::OnShowDialogCompleted(
      EStandardIntegrityErrorCode Error,
      EIntegrityDialogResponseCode Response)
    {
      // Handle response code, call the Integrity API again to confirm that
      // verdicts have been resolved.
    }
    
    // .cpp
    void MyClass::RequestIntegrityToken()
    {
      UStandardIntegrityToken* Response = ...
      int TypeCode = YourServerResponse.integrityDialogTypeCode();
    
      // Create a delegate to bind the callback function.
      FShowDialogStandardOperationCompletedDelegate Delegate;
    
      // Bind the completion handler (OnShowDialogCompleted) to the delegate.
      Delegate.BindDynamic(this, &MyClass::OnShowDialogCompleted);
    
      // Call ShowDialog with TypeCode which completes when the dialog is closed.
      Response->ShowDialog(TypeCode, Delegate);
    }

    Mã gốc

    // Show dialog as indicated by the server
    int show_dialog_type = yourServerResponse.integrityDialogTypeCode();
    if (show_dialog_type != 0) {
      /// Call showDialog with type code, the dialog will be shown on top of the
      /// provided activity and complete when the dialog is closed.
      StandardIntegrityErrorCode error_code =
          IntegrityTokenResponse_showDialog(response, activity, show_dialog_type);
    
      /// Proceed to polling iff error_code == STANDARD_INTEGRITY_NO_ERROR
      if (error_code != STANDARD_INTEGRITY_NO_ERROR)
      {
          /// Remember to call the *_destroy() functions.
          return;
      }
    
      /// Use polling to wait for the async operation to complete.
      /// Note, the polling shouldn't block the thread where the IntegrityManager
      /// is running.
    
      IntegrityDialogResponseCode* response_code;
      error_code = StandardIntegrityToken_getDialogResponseCode(response, response_code);
    
      if (error_code != STANDARD_INTEGRITY_NO_ERROR)
      {
          /// Remember to call the *_destroy() functions.
          return;
      }
    
      /// Handle response code, call the Integrity API again to confirm that
      /// verdicts have been resolved.
    }
  5. Hộp thoại sẽ xuất hiện bên trên hoạt động được cung cấp. Khi người dùng đóng hộp thoại, Tác vụ sẽ hoàn tất bằng một mã phản hồi.

  6. (Không bắt buộc) Hãy yêu cầu mã thông báo khác để hiện thêm hộp thoại. Nếu thực hiện yêu cầu chuẩn, bạn cần khởi động lại trình cung cấp mã thông báo để nhận kết quả mới.

Yêu cầu hộp thoại về tính toàn vẹn để khắc phục một ngoại lệ phía ứng dụng

Nếu yêu cầu API Tính toàn vẹn không thành công với StandardIntegrityException (API Chuẩn) hoặc IntegrityServiceException (API Kiểu cũ) và bạn có thể khắc phục ngoại lệ, thì bạn có thể dùng hộp thoại GET_INTEGRITY hoặc GET_STRONG_INTEGRITY để khắc phục lỗi.

Các bước sau đây trình bày cách bạn có thể sử dụng hộp thoại GET_INTEGRITY để khắc phục lỗi có thể khắc phục ở phía máy khách do API Tính toàn vẹn báo cáo.

  1. Kiểm tra để đảm bảo rằng ngoại lệ được trả về từ yêu cầu API Tính toàn vẹn có thể khắc phục được.

    Kotlin

    private fun isExceptionRemediable(exception: ExecutionException): Boolean {
      val cause = exception.cause
      if (cause is StandardIntegrityException && cause.isRemediable) {
          return true
      }
      return false
    }
     

    Java

    private boolean isExceptionRemediable(ExecutionException exception) {
      Throwable cause = exception.getCause();
      if (cause instanceof StandardIntegrityException integrityException
    && integrityException.isRemediable()) {
          return true;
      }
      return false;
    }
     
  2. Nếu có thể khắc phục trường hợp ngoại lệ, hãy yêu cầu hộp thoại GET_INTEGRITY bằng cách sử dụng trường hợp ngoại lệ được trả về. Hộp thoại sẽ xuất hiện trên hoạt động được cung cấp và Tác vụ được trả về sẽ hoàn tất bằng một mã phản hồi sau khi người dùng đóng hộp thoại.

    Kotlin

    private fun showDialog(exception: StandardIntegrityException) {
      // Create a dialog request
      val standardIntegrityDialogRequest =
          StandardIntegrityDialogRequest.builder()
              .setActivity(activity)
              .setType(IntegrityDialogTypeCode.GET_INTEGRITY)
              .setStandardIntegrityResponse(ExceptionDetails(exception))
              .build()
    
      // Request dialog
      val responseCode: Task<Int> =
            standardIntegrityManager.showDialog(standardIntegrityDialogRequest)
    }
     

    Java

    private void showDialog(StandardIntegrityException exception) {
      // Create a dialog request
      StandardIntegrityDialogRequest standardIntegrityDialogRequest =
          StandardIntegrityDialogRequest.builder()
              .setActivity(this.activity)
              .setType(IntegrityDialogTypeCode.GET_INTEGRITY)
              .setStandardIntegrityResponse(new ExceptionDetails(exception))
              .build();
    
      // Request dialog
      Task<Integer> responseCode =
            standardIntegrityManager.showDialog(standardIntegrityDialogRequest);
    }  
  3. Nếu mã phản hồi được trả về cho biết thành công, thì yêu cầu tiếp theo về mã thông báo về tính toàn vẹn sẽ thành công mà không có bất kỳ trường hợp ngoại lệ nào. Nếu thực hiện các yêu cầu chuẩn, bạn cần khởi động lại trình cung cấp mã thông báo để nhận kết quả mới.

Mã hộp thoại về tính toàn vẹn

GET_LICENSED (Mã loại 1)

Vấn đề về kết quả kiểm tra

Hộp thoại này phù hợp với 2 vấn đề:

  • Truy cập trái phép: appLicensingVerdict: "UNLICENSED". Điều này có nghĩa là tài khoản người dùng không có quyền đối với ứng dụng của bạn. Điều này có thể xảy ra nếu người dùng cài đặt ứng dụng bên ngoài hoặc mua ứng dụng đó từ một cửa hàng ứng dụng khác ngoài Google Play.
  • Ứng dụng bị giả mạo: appRecognitionVerdict: "UNRECOGNIZED_VERSION". Điều này có nghĩa là tệp nhị phân của ứng dụng đã bị sửa đổi hoặc không phải là phiên bản được Google Play công nhận.

Cách khắc phục

Bạn có thể cho người dùng thấy hộp thoại GET_LICENSED để nhắc họ tải ứng dụng chính hãng qua Google Play. Một hộp thoại duy nhất này giải quyết cả hai trường hợp:

  • Đối với người dùng chưa được cấp phép, phương thức này sẽ cấp cho họ giấy phép Play. Điều này cho phép người dùng nhận được bản cập nhật ứng dụng từ Google Play.
  • Đối với người dùng có phiên bản ứng dụng bị giả mạo, thông báo này sẽ hướng dẫn họ cài đặt ứng dụng chưa bị sửa đổi từ Google Play.

Khi người dùng hoàn tất hộp thoại, các quy trình kiểm tra tính toàn vẹn tiếp theo sẽ trả về appLicensingVerdict: "LICENSED"appRecognitionVerdict: "PLAY_RECOGNIZED".

Ví dụ về trải nghiệm người dùng

Hình 1. Hộp thoại GET_LICENSED của Play.

CLOSE_UNKNOWN_ACCESS_RISK (Mã loại 2)

Vấn đề về kết quả kiểm tra

Khi environmentDetails.appAccessRiskVerdict.appsDetected chứa "UNKNOWN_CAPTURING" hoặc "UNKNOWN_CONTROLLING", tức là có những ứng dụng khác (không phải do Google Play cài đặt hoặc do nhà sản xuất thiết bị tải trước lên phân vùng hệ thống) đang chạy trên thiết bị có thể ghi lại màn hình hoặc kiểm soát thiết bị.

Cách khắc phục

Bạn có thể cho người dùng thấy hộp thoại CLOSE_UNKNOWN_ACCESS_RISK để nhắc họ đóng tất cả các ứng dụng không xác định có thể đang chụp màn hình hoặc điều khiển thiết bị. Nếu người dùng nhấn vào nút Close all, tất cả các ứng dụng như vậy sẽ đóng.

Ví dụ về trải nghiệm người dùng

Hình 2. Hộp thoại đóng rủi ro truy cập không xác định.

CLOSE_ALL_ACCESS_RISK (Mã loại 3)

Vấn đề về kết quả kiểm tra

Khi environmentDetails.appAccessRiskVerdict.appsDetected chứa bất kỳ giá trị nào trong số "KNOWN_CAPTURING", "KNOWN_CONTROLLING","UNKNOWN_CAPTURING" hoặc "UNKNOWN_CONTROLLING", điều này có nghĩa là có những ứng dụng đang chạy trên thiết bị có thể chụp màn hình hoặc điều khiển thiết bị.

Cách khắc phục

Bạn có thể cho người dùng thấy hộp thoại CLOSE_ALL_ACCESS_RISK để nhắc họ đóng tất cả các ứng dụng có thể đang chụp màn hình hoặc điều khiển thiết bị. Nếu người dùng nhấn vào nút Close all, tất cả các ứng dụng như vậy sẽ bị đóng trên thiết bị.

Ví dụ về trải nghiệm người dùng

Hình 3. Hộp thoại đóng tất cả các rủi ro truy cập.

GET_INTEGRITY (Mã loại 4)

Vấn đề về kết quả kiểm tra

Hộp thoại này phù hợp với mọi vấn đề sau:

  • Tính toàn vẹn yếu của thiết bị: Khi deviceRecognitionVerdict không chứa MEETS_DEVICE_INTEGRITY, thiết bị có thể không phải là thiết bị Android chính hãng và được chứng nhận. Ví dụ: điều này có thể xảy ra nếu trình tải khởi động của thiết bị được mở khoá hoặc hệ điều hành Android đã tải không phải là hình ảnh được nhà sản xuất chứng nhận.

  • Truy cập trái phép: appLicensingVerdict: "UNLICENSED". Điều này có nghĩa là tài khoản người dùng không có quyền đối với ứng dụng của bạn. Điều này có thể xảy ra nếu người dùng tải ứng dụng xuống thiết bị mà không qua Cửa hàng Play hoặc tải ứng dụng từ một cửa hàng ứng dụng khác ngoài Google Play.

  • Ứng dụng bị giả mạo: appRecognitionVerdict: "UNRECOGNIZED_VERSION". Điều này có nghĩa là tệp nhị phân của ứng dụng đã bị sửa đổi hoặc không phải là phiên bản được Google Play công nhận.

  • Ngoại lệ phía máy khách: Khi một ngoại lệ có thể khắc phục xảy ra trong yêu cầu API Tính toàn vẹn. Ngoại lệ có thể khắc phục là ngoại lệ API Tính toàn vẹn có mã lỗi như PLAY_SERVICES_VERSION_OUTDATED, NETWORK_ERROR, PLAY_SERVICES_NOT_FOUND, v.v. Bạn có thể dùng phương thức exception.isRemediable() để kiểm tra xem hộp thoại có thể khắc phục một ngoại lệ hay không.

Cách khắc phục

Hộp thoại GET_INTEGRITY được thiết kế để đơn giản hoá trải nghiệm của người dùng bằng cách xử lý nhiều bước khắc phục trong một quy trình liên tục duy nhất. Điều này giúp người dùng không phải tương tác với nhiều hộp thoại riêng biệt để khắc phục các vấn đề khác nhau.

Khi bạn yêu cầu hộp thoại này, hộp thoại sẽ tự động phát hiện những vấn đề về kết quả nhắm đến hiện có và cung cấp các bước khắc phục thích hợp. Điều này có nghĩa là một yêu cầu duy nhất cho hộp thoại có thể giải quyết nhiều vấn đề cùng một lúc, bao gồm:

  • Tính toàn vẹn của thiết bị: Nếu phát hiện thấy vấn đề về tính toàn vẹn của thiết bị, hộp thoại sẽ hướng dẫn người dùng cải thiện trạng thái bảo mật của thiết bị để đáp ứng các yêu cầu cho kết quả MEETS_DEVICE_INTEGRITY.
  • Tính toàn vẹn của ứng dụng: Nếu phát hiện các vấn đề như truy cập trái phép hoặc can thiệp vào ứng dụng, hộp thoại sẽ hướng người dùng tải ứng dụng từ Cửa hàng Play để khắc phục các vấn đề đó.
  • Ngoại lệ phía máy khách: Hộp thoại này kiểm tra và cố gắng giải quyết mọi vấn đề cơ bản gây ra ngoại lệ API Tính toàn vẹn. Ví dụ: có thể nhắc người dùng cập nhật phiên bản Dịch vụ Google Play đã lỗi thời.

Ví dụ về trải nghiệm người dùng

Hình 4. Quy trình khắc phục lỗi mạng trong hộp thoại GET_INTEGRITY

GET_STRONG_INTEGRITY (Mã loại 5)

Vấn đề về kết quả kiểm tra

Hộp thoại này được thiết kế để khắc phục tất cả các vấn đề tương tự mà GET_INTEGRITY giải quyết, đồng thời có thêm khả năng khắc phục các vấn đề khiến thiết bị không nhận được kết quả MEETS_STRONG_INTEGRITY và khắc phục các vấn đề về kết quả của Play Protect.

Cách khắc phục

GET_STRONG_INTEGRITY được thiết kế để đơn giản hoá trải nghiệm của người dùng bằng cách xử lý nhiều bước khắc phục trong một quy trình liên tục duy nhất. Hộp thoại này sẽ tự động kiểm tra các vấn đề về tính toàn vẹn có thể xảy ra đối với một địa chỉ, bao gồm:

  • Tính toàn vẹn của thiết bị: Nếu phát hiện thấy vấn đề về tính toàn vẹn của thiết bị, hộp thoại sẽ hướng dẫn người dùng cải thiện trạng thái bảo mật của thiết bị để đáp ứng các yêu cầu cho kết quả MEETS_STRONG_INTEGRITY.
  • Trạng thái Play Protect: Nếu playProtectVerdict cho biết có vấn đề, hộp thoại sẽ hướng dẫn người dùng cách khắc phục:

    • Nếu Play Protect bị vô hiệu hoá (playProtectVerdict == POSSIBLE_RISK), hộp thoại sẽ nhắc người dùng bật tính năng này và quét tất cả ứng dụng trên thiết bị.
    • Nếu phát hiện thấy ứng dụng gây hại (playProtectVerdict == MEDIUM_RISK hoặc HIGH_RISK), hộp thoại sẽ hướng dẫn người dùng gỡ cài đặt các ứng dụng đó bằng Google Play Protect.
  • Tính toàn vẹn của ứng dụng: Nếu phát hiện các vấn đề như truy cập trái phép hoặc can thiệp vào ứng dụng, hộp thoại sẽ nhắc người dùng tải ứng dụng qua Cửa hàng Play để khắc phục vấn đề.

  • Ngoại lệ phía máy khách: Hộp thoại này cũng cố gắng giải quyết mọi vấn đề cơ bản gây ra ngoại lệ API Tính toàn vẹn. Ví dụ: ứng dụng có thể nhắc người dùng bật Dịch vụ Google Play nếu phát hiện thấy dịch vụ này đang bị tắt. Các trường hợp ngoại lệ có thể khắc phục là các trường hợp ngoại lệ của Integrity API có mã lỗi như PLAY_SERVICES_VERSION_OUTDATED, NETWORK_ERROR hoặc PLAY_SERVICES_NOT_FOUND. Bạn có thể sử dụng phương thức exception.isRemediable() để kiểm tra xem hộp thoại có thể khắc phục lỗi hay không.

Ví dụ về trải nghiệm người dùng

Hình 5. Hộp thoại GET_STRONG_INTEGRITY cập nhật Dịch vụ Play.