Okna działań naprawczych

Na tej stronie opisujemy, jak rozwiązywać problemy z wynikami weryfikacji integralności.

Gdy zostanie wysłane żądanie tokena integralności, możesz wyświetlić użytkownikowi okno Google Play. Możesz wyświetlać okno dialogowe, gdy wystąpi co najmniej 1 problem z wynikiem oceny integralności. Okno dialogowe jest wyświetlane na wierzchu aplikacji i zachęca użytkowników do rozwiązania problemu. Po zamknięciu okna możesz sprawdzić, czy problem został rozwiązany, wysyłając kolejne żądanie do interfejsu Integrity API.

Wysyłanie prośby o wyświetlenie okna integralności

Gdy klient zażąda tokena integralności, możesz użyć metody oferowanej w StandardIntegrityToken (standardowy interfejs API) i IntegrityTokenResponse (klasyczny interfejs API):showDialog(Activity activity, int integrityDialogTypeCode).

Poniżej znajdziesz instrukcje, jak za pomocą interfejsu Play Integrity API wyświetlić okno na temat działań naprawczych, używając kodu okna GET_LICENSED. Inne kody okien, o które może poprosić Twoja aplikacja, są wymienione po tej sekcji.

  1. Wyślij z aplikacji prośbę o token integralności i prześlij go na serwer. Możesz użyć żądania standardowego lub klasycznego.

    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); 

    Rodzimy użytkownik

    /// 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. Odszyfruj token integralności na serwerze i sprawdź pole appLicensingVerdict. Może to wyglądać mniej więcej tak:

    // Licensing issue
    {
      ...
      accountDetails: {
          appLicensingVerdict: "UNLICENSED"
      }
    }
  3. Jeśli token zawiera znak appLicensingVerdict: "UNLICENSED", odpowiedz klientowi aplikacji, prosząc go o wyświetlenie okna licencji:

    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;
    } 

    Rodzimy użytkownik

    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. W aplikacji wywołaj funkcję showDialog z kodem pobranym z serwera:

    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);
    }

    Rodzimy użytkownik

    // 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. Okno dialogowe jest wyświetlane nad podaną aktywnością. Gdy użytkownik zamknie okno, zadanie zostanie ukończone z kodem odpowiedzi.

  6. (Opcjonalnie) Poproś o kolejny token, aby wyświetlić kolejne okna. Jeśli wysyłasz standardowe żądania, musisz ponownie rozgrzać dostawcę tokenów, aby uzyskać nową decyzję.

Kody okna integralności

GET_LICENSED (typ kodu 1)

Problem z oceną

To okno dialogowe jest odpowiednie w przypadku 2 problemów:

  • Nieautoryzowany dostęp: appLicensingVerdict: "UNLICENSED" Oznacza to, że konto użytkownika nie ma uprawnień do korzystania z aplikacji. Może się tak zdarzyć, jeśli użytkownik zainstalował ją z innego urządzenia lub pozyskał ją z innego sklepu z aplikacjami niż Google Play.
  • Zmodyfikowana aplikacja: appRecognitionVerdict: "UNRECOGNIZED_VERSION". Oznacza to, że plik binarny aplikacji został zmodyfikowany lub nie jest wersją rozpoznawaną przez Google Play.

Działania naprawcze

Możesz wyświetlić okno GET_LICENSED, aby poprosić użytkownika o pobranie oryginalnej aplikacji z Google Play. To okno dialogowe obejmuje oba scenariusze:

  • W przypadku użytkownika bez licencji przyznaje mu licencję Google Play. Dzięki temu użytkownik będzie otrzymywać aktualizacje aplikacji z Google Play.
  • W przypadku użytkownika, który ma zmodyfikowaną wersję aplikacji, wyświetla instrukcje instalacji niezmodyfikowanej aplikacji z Google Play.

Gdy użytkownik zamknie okno, kolejne weryfikacje integralności zwrócą wartości appLicensingVerdict: "LICENSED"appRecognitionVerdict: "PLAY_RECOGNIZED".

Przykładowy UX

Rysunek 1. Okno GET_LICENSED w Google Play.

CLOSE_UNKNOWN_ACCESS_RISK (kod typu 2)

Problem z oceną

Gdy environmentDetails.appAccessRiskVerdict.appsDetected zawiera"UNKNOWN_CAPTURING" lub "UNKNOWN_CONTROLLING", oznacza to, że na urządzeniu są uruchomione nieznane aplikacje, które mogą rejestrować to, co widać na ekranie, lub kontrolować urządzenie.

Działania naprawcze

Możesz wyświetlić okno CLOSE_UNKNOWN_ACCESS_RISK, aby poprosić użytkownika o zamknięcie wszystkich nieznanych aplikacji, które mogą przechwytywać ekran lub sterować urządzeniem. Jeśli użytkownik kliknie przycisk Close all, wszystkie takie aplikacje zostaną zamknięte.

Przykładowy UX

Rysunek 2. Okno zamykania nieznanego ryzyka dostępu.

CLOSE_ALL_ACCESS_RISK (Type Code 3)

Problem z oceną

Gdy environmentDetails.appAccessRiskVerdict.appsDetected zawiera dowolny z tych elementów: "KNOWN_CAPTURING", "KNOWN_CONTROLLING", "UNKNOWN_CAPTURING" lub "UNKNOWN_CONTROLLING", oznacza to, że na urządzeniu są uruchomione aplikacje, które mogą przechwytywać ekran lub sterować urządzeniem.

Działania naprawcze

Możesz wyświetlić CLOSE_ALL_ACCESS_RISK, aby poprosić użytkownika o zamknięcie wszystkich aplikacji, które mogą przechwytywać ekran lub sterować urządzeniem. Jeśli użytkownik kliknie przycisk Close all, wszystkie takie aplikacje zostaną zamknięte na urządzeniu.

Przykładowy UX

Rysunek 3. Okno zamykania wszystkich ryzyk związanych z dostępem.