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 hộp thoại của Google Play. Bạn có thể cho người dùng thấy hộp thoại 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 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 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 sẽ trình bày cách sử dụng Play Integrity API để 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) {
       return
    }
    
    // Create dialog request
    val dialogRequest = StandardIntegrityDialogRequest.builder()
            .setActivity(activity)
            .setTypeCode(showDialogType)
            .setStandardIntegrityResponse(StandardIntegrityResponse.TokenResponse(token))
            .build()
    
    // Call showDialog, the dialog will be shown on top of the provided activity
    // and the task will complete when the dialog is closed.
    val result: Task<Int> = standardIntegrityManager.showDialog(dialogRequest)
    
    // Handle response code, call the Integrity API again to confirm that the
    // verdict issue has been resolved. 

    Java

    // Show dialog as indicated by the server
    @Nullable Integer showDialogType = yourServerResponse.integrityDialogTypeCode();
    if (showDialogType == null) {
       return;
    }
    
    // Create dialog request
    StandardIntegrityDialogRequest dialogRequest =
        StandardIntegrityDialogRequest.builder()
            .setActivity(getActivity())
            .setTypeCode(showDialogTypeCode)
            .setStandardIntegrityResponse(new StandardIntegrityResponse.TokenResponse(token))
            .build();
    
    // Call showDialog, the dialog will be shown on top of the provided activity
    // and the task will complete when the dialog is closed.
    Task<Integer> result = standardIntegrityManager.showDialog(dialogRequest);
    
    // Handle response code, call the Integrity API again to confirm that the
    // verdict issue has been resolved.

    Unity

    // Initialize the V2 manager. Requires Play Integrity Unity Plugin v2.0.0 or
    // higher.
    var standardIntegrityManager = new StandardIntegrityManagerV2();
    IEnumerator ShowDialogCoroutine() {
      int showDialogType = yourServerResponse.IntegrityDialogTypeCode();
    
      PlayAsyncOperation<IntegrityDialogResponseCode, StandardIntegrityError> showDialogTask;
    
      using (var activity = UnityPlayerHelper.GetCurrentActivity())
      {
          // Create a dialog request
          var dialogRequest = new StandardIntegrityDialogRequest(tokenResponse, activity, showDialogType);
    
          // Call showDialog with the request, the dialog will be shown on top of the
          // provided activity and complete when the dialog is closed.
          showDialogTask = standardIntegrityManager.ShowDialog(dialogRequest);
      }
    
      // Wait for PlayAsyncOperation to complete.
      yield return showDialogTask;
    
      // Handle response code, call the Integrity API again to confirm that the
      // verdict issue been resolved.
    } 

    Unreal Engine

    // .h
    void MyClass::OnShowDialogCompleted(
      EStandardIntegrityErrorCode Error,
      EIntegrityDialogResponseCode Response)
    {
      // Handle response code, call the Integrity API again to confirm that the
      // verdict issue has 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){
    return;
    }
    
    /// Create dialog request
    StandardIntegrityDialogRequest* dialog_request;
    StandardIntegrityDialogRequest_create(&dialog_request);
    StandardIntegrityDialogRequest_setTypeCode(dialog_request, show_dialog_type);
    StandardIntegrityDialogRequest_setActivity(dialog_request, activity);
    StandardIntegrityDialogRequest_setStandardIntegrityToken(dialog_request,
                                                  token_response);
    
    /// Call showDialog with the dialog request. The dialog will be shown on top
    /// of the provided activity and complete when the dialog is closed by the
    /// user.
    StandardIntegrityDialogResponse* dialog_response;
    StandardIntegrityErrorCode error_code =
      StandardIntegrityManager_showDialog(dialog_request, &dialog_response);
    
    /// Use polling to wait for the async operation to complete. Note, the polling
    /// shouldn't block the thread where the StandardIntegrityManager is running.
    IntegrityDialogResponseCode response_code = INTEGRITY_DIALOG_RESPONSE_UNKNOWN;
    while (error_code == STANDARD_INTEGRITY_NO_ERROR) {
      error_code = StandardIntegrityDialogResponse_getResponseCode(dialog_response, &response_code);
      if(response_code != INTEGRITY_DIALOG_RESPONSE_UNKNOWN){
        break;
      }
    }
    
    /// Free memory
    StandardIntegrityDialogRequest_destroy(dialog_request);
    StandardIntegrityDialogResponse_destroy(dialog_response);
    
    /// Handle response code, call the Integrity API again to confirm that the
    /// verdict issues 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 trường hợp ngoại lệ ở phía ứng dụng khách

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à trường hợp ngoại lệ đó có thể khắc phục được, thì bạn có thể sử 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 sẽ trình bày cách sử dụng GET_INTEGRITY hộp thoại để khắc phục lỗi ở phía máy khách có thể khắc phục được do Integrity API báo cáo.

  1. Kiểm tra để đảm bảo rằng trường hợp 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;
    }

    Unity

    private bool IsExceptionRemediable(StandardIntegrityError error) {
      // Check if the operation resulted in a remediable error
      if (error != null && error.ErrorCode != StandardIntegrityErrorCode.NoError && error.IsRemediable) {
          return true;
      }
      return false;
    }

    Mã gốc

    bool IsErrorRemediable(StandardIntegrityToken* token) {
      /// Check if the error associated with the token is remediable
      bool isRemediable = false;
      if(StandardIntegrityToken_getIsRemediable(response, &isRemediable) == STANDARD_INTEGRITY_NO_ERROR){
        return isRemediable;
      }
      return false;
    }
  2. Nếu trường hợp ngoại lệ có thể khắc phục được, hãy yêu cầu hộp thoại GET_INTEGRITY bằ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);
    }  

    Unity

    // Initialize the V2 manager. Requires Play Integrity Unity Plugin v2.0.0 or
    // higher.
    var standardIntegrityManager = new StandardIntegrityManagerV2();
    IEnumerator ShowDialogToFixError(StandardIntegrityError error) {
      PlayAsyncOperation<IntegrityDialogResponseCode, StandardIntegrityError> showDialogTask;
    
      using (var activity = UnityPlayerHelper.GetCurrentActivity())
      {
          // Create a dialog request using the error
          var dialogRequest = new StandardIntegrityDialogRequest(error, activity, GET_INTEGRITY_DIALOG);
    
          // Request dialog
          showDialogTask = standardIntegrityManager.ShowDialog(dialogRequest);
      }
    
      // Wait for PlayAsyncOperation to complete.
      yield return showDialogTask;
    }

    Mã gốc

    private void showDialogToFixError(StandardIntegrityToken* token) {
      /// If the token request failed, and the underlying error is not fixable
      /// then return early
      if(isErrorRemediable(token)) {
        return;
      }
    
      /// Create dialog request
      StandardIntegrityDialogRequest* dialog_request;
      StandardIntegrityDialogRequest_create(&dialog_request);
      StandardIntegrityDialogRequest_setTypeCode(dialog_request,
                                         kGetIntegrityDialogTypeCode);
      StandardIntegrityDialogRequest_setActivity(dialog_request, activity);
      StandardIntegrityDialogRequest_setStandardIntegrityToken(dialog_request,
                                                      token_response);
    
      /// Call showDialog with the dialog request. The dialog will be shown on
      /// top of the provided activity and complete when the dialog is closed by
      /// the user.
      StandardIntegrityDialogResponse* dialog_response;
      StandardIntegrityErrorCode error_code =
          StandardIntegrityManager_showDialog(dialog_request, &dialog_response);
    
      /// Use polling to wait for the async operation to complete.
      /// Note, the polling shouldn't block the thread where the
      /// StandardIntegrityManager is running.
      IntegrityDialogResponseCode response_code = INTEGRITY_DIALOG_RESPONSE_UNKNOWN;
      while (error_code == STANDARD_INTEGRITY_NO_ERROR) {
          error_code = StandardIntegrityDialogResponse_getResponseCode(response, &response_code);
          if(response_code != INTEGRITY_DIALOG_RESPONSE_UNKNOWN){
            break;
          }
      }
    
      /// Free memory
      StandardIntegrityDialogRequest_destroy(dialog_request);
      StandardIntegrityDialogResponse_destroy(dialog_response);
    
    }
  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ó trường hợp ngoại lệ nào. 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.

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. Tình trạng này có thể xảy ra nếu người dùng tải ứng dụng xuống thiết bị theo cách thủ công hoặc tải ứng dụng xuống từ một cửa hàng ứng dụng khác ngoài Google Play.
  • Ứng dụng bị can thiệp: 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 nhận dạng.

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 xuống từ Google Play. Hộp thoại duy nhất này giải quyết cả 2 trường hợp:

  • Đối với người dùng không có giấy phép, hộp thoại 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 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ị can thiệp, hộp thoại 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 lượt 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", điều này có nghĩa là có các ứng dụng khác (không phải do Google Play cài đặt hoặc không phải 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ả ứng dụng không xác định có thể ghi lại màn hình hoặc kiểm soát thiết bị. Nếu người dùng nhấn vào nút Close all (Đóng tất cả), thì tất cả các ứng dụng như vậy sẽ bị đó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ó các ứng dụ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_ALL_ACCESS_RISK để nhắc họ đóng tất cả ứng dụng có thể ghi lại màn hình hoặc kiểm soát thiết bị. Nếu người dùng nhấn vào nút Close all (Đóng tất cả), thì 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ả 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 bất kỳ vấn đề nào sau đây:

  • Tính toàn vẹn của thiết bị yếu: 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. Tình trạng này có thể xảy ra, chẳng hạn như nếu trình tải khởi động của thiết bị bị mở khoá hoặc hệ điều hành Android đã tải không phải là hình ảnh của nhà sản xuất được 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. Tình trạng này có thể xảy ra nếu người dùng tải ứng dụng xuống thiết bị theo cách thủ công hoặc tải ứng dụng xuống từ một cửa hàng ứng dụng khác ngoài Google Play.

  • Ứng dụng bị can thiệp: 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 nhận dạng.

  • Trường hợp ngoại lệ ở phía ứng dụng khách: Khi xảy ra trường hợp ngoại lệ có thể khắc phục được trong yêu cầu API Tính toàn vẹn. Trường hợp ngoại lệ có thể khắc phục được là trường hợp ngoại lệ của Integrity API có mã lỗi như PLAY_SERVICES_VERSION_OUTDATED, NETWORK_ERROR, PLAY_SERVICES_NOT_FOUND, v.v. 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.

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, hộp thoại này sẽ tự động phát hiện vấn đề nào về kết quả mục tiêu đang xảy ra và cung cấp các bước khắc phục phù hợp. Điều này có nghĩa là một yêu cầu 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 đối với kết quả MEETS_DEVICE_INTEGRITY.
  • Tính toàn vẹn của ứng dụng: Nếu phát hiện thấy 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 dẫn người dùng tải ứng dụng xuống từ Cửa hàng Play để khắc phục các vấn đề đó.
  • Trường hợp 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 trường hợp ngoại lệ của Integrity API. Ví dụ: hộp thoại này 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 của 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 đề 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 tự động kiểm tra các vấn đề về tính toàn vẹn có thể áp dụng cho đị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 đối với kết quả MEETS_STRONG_INTEGRITY.
  • Trạng thái của Play Protect: Nếu playProtectVerdict cho biết có vấn đề, hộp thoại sẽ hướng dẫn người dùng khắc phục vấn đề đó:

    • Nếu Play Protect bị tắt (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 các ứng dụng có 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 thấy 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 xuống từ Cửa hàng Play để khắc phục vấn đề.

  • Trường hợp 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 trường hợp ngoại lệ của Integrity API. Ví dụ: hộp thoại này có thể nhắc người dùng bật Dịch vụ Google Play nếu phát hiện thấy tính năng này bị tắt. Trường hợp ngoại lệ có thể khắc phục được là 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.