کادرهای گفتگوی اصلاحی

این صفحه نحوه رسیدگی به مشکلات مربوط به حکم‌های یکپارچگی را شرح می‌دهد.

پس‌از درخواست کردن یک توکن تمامیت، این گزینه را دارید که یک کادر گفتگوی Google Play به کاربر نمایش دهید. وقتی یک یا چند مشکل در حکم یکپارچگی وجود داشته باشد یا اگر استثنایی درطول درخواست Integrity API رخ دهد، می‌توانید کادر گفتگو را نمایش دهید. وقتی کادر گفتگو بسته شد، می‌توانید با درخواست دیگری برای دریافت یک توکن یکپارچگی، بررسی کنید که مشکل برطرف شده است یا نه. اگر درخواست‌های استاندارد ارسال می‌کنید، باید ارائه‌دهنده داده‌واحد (توکن) را دوباره گرم کنید تا حکم جدیدی دریافت کنید.

درخواست کادر گفتگوی تمامیت برای رفع مشکل حکم

وقتی کارخواه درخواست یک توکن تمامیت می‌کند، می‌توانید از روش ارائه‌شده در StandardIntegrityToken (Standard API) و IntegrityTokenResponse (Classic API) استفاده کنید: showDialog(Activity activity, int integrityDialogTypeCode).

مراحل زیر نحوه استفاده از Play Integrity API را برای نشان دادن گفتگوی اصلاح بااستفاده از کد گفتگوی GET_LICENSED نشان می‌دهد. کدهای کادر گفتگوی دیگری که برنامه‌تان می‌تواند درخواست کند بعداز این بخش فهرست شده است.

  1. از برنامه‌تان کد تمامیت درخواست کنید و کد را به سرورتان ارسال کنید. می‌توانید از درخواست «استاندارد» یا «قدیمی» استفاده کنید.

    کاتلین

    // 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())  

    جاوا

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

    بومی

    /// 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. در سرورتان، کد تمامیت را رمزگشایی کنید و فیلد appLicensingVerdict را بررسی کنید. ممکن است چیزی شبیه این باشد:

    // Licensing issue
    {
      ...
      "accountDetails": {
          "appLicensingVerdict": "UNLICENSED"
      }
    }
  3. اگر توکن حاوی appLicensingVerdict: "UNLICENSED" است، به کارخواه برنامه‌تان پاسخ دهید و از آن بخواهید کادر گفتگوی صدور پروانه را نشان دهد:

    کاتلین

    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
    }

    جاوا

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

    بومی

    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. در برنامه‌تان، showDialog را با کد درخواستی بازیابی‌شده از سرورتان فراخوانی کنید:

    کاتلین

    // 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. 

    جاوا

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

    بومی

    // 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. کادر گفتگو در بالای فعالیت ارائه‌شده نمایش داده می‌شود. وقتی کاربر کادر گفتگو را بسته باشد، «تکلیف» با کد پاسخ تکمیل می‌شود.

  6. (اختیاری) برای نمایش هرگونه کادر گفتگوی بیشتر، کد دیگری درخواست کنید. اگر درخواست‌های استاندارد ارسال می‌کنید، باید ارائه‌دهنده داده‌واحد را دوباره گرم کنید تا حکم جدیدی دریافت کنید.

درخواست کادر گفتگوی یکپارچگی برای رفع استثنای سمت کارخواه

اگر درخواست Integrity API با StandardIntegrityException (Standard API) یا IntegrityServiceException (Classic API) ناموفق باشد و استثنا قابل‌اصلاح باشد، می‌توانید از کادرهای گفتگوی GET_INTEGRITY یا GET_STRONG_INTEGRITY برای رفع خطا استفاده کنید.

مراحل زیر نحوه استفاده از کادر گفتگوی GET_INTEGRITY را برای رفع خطای قابل‌اصلاح سمت کارخواه که توسط Integrity API گزارش شده است نشان می‌دهد.

  1. بررسی کنید که استثنای برگردانده‌شده از درخواست Integrity API قابل‌اصلاح باشد.

    کاتلین

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

    جاوا

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

    بومی

    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. اگر استثنا قابل‌اصلاح است، بااستفاده از استثنای برگردانده‌شده، کادر گفتگوی GET_INTEGRITY را درخواست کنید. کادر گفتگو روی فعالیت ارائه‌شده نمایش داده می‌شود و «تکلیف» برگردانده‌شده با کد پاسخ پس‌از اینکه کاربر کادر گفتگو را می‌بندد تکمیل می‌شود.

    کاتلین

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

    جاوا

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

    بومی

    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. اگر کد پاسخ برگردانده‌شده نشان‌دهنده موفقیت باشد، درخواست بعدی برای توکن تمامیت باید بدون هیچ استثنایی موفقیت‌آمیز باشد. اگر درخواست‌های استاندارد ارسال می‌کنید، باید ارائه‌دهنده کد را دوباره گرم کنید تا حکم جدیدی دریافت کنید.

کدهای کادر گفتگوی تمامیت

GET_LICENSED (کد نوع ۱)

مشکل حکم

این کادر گفتگو برای دو مشکل مناسب است:

  • دسترسی غیرمجاز: appLicensingVerdict: "UNLICENSED". این یعنی حساب کاربری حق استفاده از برنامه شما را ندارد، که این اتفاق زمانی می‌افتد که کاربر برنامه را جانبی بار کرده باشد یا آن را از فروشگاه برنامه‌ای غیراز Google Play دریافت کرده باشد.
  • برنامه دستکاری‌شده: appRecognitionVerdict: "UNRECOGNIZED_VERSION". این یعنی دودویی برنامه‌تان اصلاح شده است یا نسخه‌ای نیست که Google Play آن را تشخیص دهد.

اصلاح

می‌توانید کادر گفتگوی GET_LICENSED را نشان دهید تا از کاربر بخواهید برنامه اصلی را از Google Play دریافت کند. این کادر گفتگوی واحد هر دو سناریو را پوشش می‌دهد:

  • برای کاربر بدون پروانه، پروانه Play به او اعطا می‌کند. این کار به کاربر امکان می‌دهد به‌روزرسانی‌های برنامه را از Google Play دریافت کند.
  • برای کاربری که نسخه برنامه دستکاری‌شده دارد، او را راهنمایی می‌کند تا برنامه تغییرنیافته را از Google Play نصب کند.

وقتی کاربر کادر گفتگو را تکمیل می‌کند، بررسی‌های تمامیت بعدی appLicensingVerdict: "LICENSED" و appRecognitionVerdict: "PLAY_RECOGNIZED" را برمی‌گرداند.

تجربه کاربری نمونه

شکل ۱. GET_LICENSED Play dialog.

CLOSE_UNKNOWN_ACCESS_RISK (کد نوع ۲)

مشکل حکم

وقتی environmentDetails.appAccessRiskVerdict.appsDetected حاوی "UNKNOWN_CAPTURING" یا "UNKNOWN_CONTROLLING" باشد، یعنی برنامه‌های دیگری (که توسط Google Play نصب نشده‌اند یا توسط سازنده دستگاه در پارتیشن سیستم پیش‌بار نشده‌اند) در دستگاه درحال اجرا هستند که ممکن است درحال ضبط صفحه‌نمایش یا کنترل دستگاه باشند.

اصلاح

می‌توانید کادر گفتگوی CLOSE_UNKNOWN_ACCESS_RISK را نشان دهید تا از کاربر خواسته شود همه برنامه‌های ناشناخته را که ممکن است درحال ضبط کردن صفحه‌نمایش یا کنترل کردن دستگاه باشند ببندد. اگر کاربر روی دکمه Close all تک‌ضرب بزند، همه این برنامه‌ها بسته می‌شوند.

تجربه کاربری نمونه

شکل ۲. کادر گفتگوی بستن خطر دسترسی ناشناخته.

CLOSE_ALL_ACCESS_RISK (کد نوع ۳)

مشکل حکم

وقتی environmentDetails.appAccessRiskVerdict.appsDetected حاوی هرکدام از "KNOWN_CAPTURING"، "KNOWN_CONTROLLING"، "UNKNOWN_CAPTURING"، یا "UNKNOWN_CONTROLLING" باشد، یعنی برنامه‌هایی در دستگاه درحال اجرا هستند که می‌توانند محتوای صفحه‌نمایش را ضبط کنند یا دستگاه را کنترل کنند.

اصلاح

می‌توانید کادر گفتگوی CLOSE_ALL_ACCESS_RISK را نشان دهید تا از کاربر بخواهید همه برنامه‌هایی را که ممکن است درحال ضبط کردن صفحه‌نمایش یا کنترل کردن دستگاه باشند ببندد. اگر کاربر روی دکمه Close all تک‌ضرب بزند، همه این برنامه‌ها در دستگاه بسته می‌شوند.

تجربه کاربری نمونه

شکل ۳. کادر گفتگوی بستن همه خطرات دسترسی.

GET_INTEGRITY (کد نوع ۴)

مشکل حکم

این کادر گفتگو برای هریک از مشکلات زیر مناسب است:

  • یکپارچگی ضعیف دستگاه: وقتی deviceRecognitionVerdict حاوی MEETS_DEVICE_INTEGRITY نباشد، ممکن است دستگاه Android اصلی و گواهی‌شده نباشد. برای مثال، اگر بوت‌لودر دستگاه باز باشد یا سیستم‌عامل Android بارشده در آن تصویر سازنده تأییدشده نباشد، ممکن است این اتفاق بیفتد.

  • دسترسی غیرمجاز: appLicensingVerdict: "UNLICENSED". این یعنی حساب کاربر حق استفاده از برنامه شما را ندارد، که این اتفاق زمانی می‌افتد که کاربر برنامه را جانبی بار کرده باشد یا آن را از فروشگاه برنامه‌ای غیراز Google Play دریافت کرده باشد.

  • برنامه دستکاری‌شده: appRecognitionVerdict: "UNRECOGNIZED_VERSION". این یعنی دودویی برنامه‌تان اصلاح شده است یا نسخه‌ای نیست که Google Play آن را تشخیص دهد.

  • استثناهای سمت کارخواه: وقتی استثنای قابل‌اصلاحی درطول درخواست Integrity API رخ می‌دهد. استثناهای قابل‌اصلاح استثناهای Integrity API با کدهای خطایی مثل PLAY_SERVICES_VERSION_OUTDATED، NETWORK_ERROR، PLAY_SERVICES_NOT_FOUND، و غیره هستند. می‌توانید از روش exception.isRemediable() برای بررسی اینکه آیا استثنا با کادر گفت‌وگو قابل‌اصلاح است یا نه استفاده کنید.

اصلاح

کادر گفتگوی GET_INTEGRITY برای ساده‌سازی تجربه کاربر ازطریق مدیریت چندین مرحله اصلاح در یک جریان واحد و پیوسته طراحی شده است. این کار مانع از این می‌شود که کاربر برای رفع مشکلات مختلف مجبور شود با چندین کادر گفتگوی جداگانه تعامل داشته باشد.

وقتی کادر گفت‌وگو را درخواست می‌کنید، به‌طور خودکار تشخیص می‌دهد که کدام‌یک از مشکلات هدف‌گذاری‌شده در رأی وجود دارد و مراحل اصلاح مناسب را ارائه می‌دهد. این یعنی یک درخواست کادر گفتگوی واحد می‌تواند چندین مشکل را به‌طور هم‌زمان برطرف کند، ازجمله:

  • تمامیت دستگاه: اگر مشکل تمامیت دستگاه شناسایی شود، کادر گفتگو کاربر را راهنمایی می‌کند تا وضعیت امنیتی دستگاه را بهبود بخشد تا الزامات حکم MEETS_DEVICE_INTEGRITY برآورده شود.
  • تمامیت برنامه: اگر مشکلاتی مانند دسترسی غیرمجاز یا دستکاری برنامه شناسایی شود، کادر گفت‌وگو کاربران را راهنمایی می‌کند تا برنامه را از «فروشگاه Play» دریافت کنند تا مشکل برطرف شود.
  • استثناهای سمت کارخواه: کادر گفت‌وگو هرگونه مشکل زمینه‌ای را که باعث استثنای Integrity API شده است بررسی می‌کند و سعی می‌کند آن را حل کند. برای مثال، ممکن است از کاربر بخواهد نسخه قدیمی «خدمات Google Play» را به‌روز کند.

تجربه کاربری نمونه

شکل ۴. جریان اصلاح خطای شبکه کادر گفتگوی GET_INTEGRITY

GET_STRONG_INTEGRITY (کد نوع ۵)

مشکل حکم

این کادر گفتگو برای رفع همه مشکلاتی طراحی شده است که GET_INTEGRITY به آن‌ها می‌پردازد، با این قابلیت اضافه که مشکلاتی را که مانع دریافت حکم MEETS_STRONG_INTEGRITY توسط دستگاه می‌شود و مشکلات مربوط به حکم «سپر ایمنی Play» را رفع می‌کند.

اصلاح

GET_STRONG_INTEGRITY برای ساده‌سازی تجربه کاربر با انجام چندین مرحله اصلاح در یک جریان پیوسته طراحی شده است. کادر گفتگو به‌طور خودکار مشکلات یکپارچگی قابل‌اعمال برای نشانی را بررسی می‌کند، ازجمله:

  • تمامیت دستگاه: اگر مشکل تمامیت دستگاه شناسایی شود، کادر گفت‌وگو کاربر را راهنمایی می‌کند تا وضعیت امنیتی دستگاه را بهبود بخشد تا الزامات حکم MEETS_STRONG_INTEGRITY برآورده شود.
  • وضعیت «سپر ایمنی Play»: اگر playProtectVerdict نشان‌دهنده مشکلی باشد، کادر گفت‌وگو کاربر را برای رفع آن راهنمایی می‌کند:

    • اگر «سپر ایمنی Play» غیرفعال باشد (playProtectVerdict == POSSIBLE_RISK)، کادر گفتگویی از کاربر می‌خواهد آن را فعال کند و همه برنامه‌های دستگاه را اسکن کند.
    • اگر برنامه‌های مضر (playProtectVerdict == MEDIUM_RISK یا HIGH_RISK) شناسایی شود، کادر گفت‌وگو کاربر را راهنمایی می‌کند تا آن‌ها را بااستفاده از «سپر ایمنی Google Play» حذف نصب کند.
  • تمامیت برنامه: اگر مشکلاتی مانند دسترسی غیرمجاز یا دستکاری برنامه شناسایی شود، کادر گفتگو از کاربر درخواست می‌کند برای رفع مشکل، برنامه را از «فروشگاه Play» دریافت کند.

  • استثناهای سمت کارخواه: این کادر گفتگو همچنین تلاش می‌کند هرگونه مشکل زمینه‌ای را که باعث ایجاد استثنای Integrity API شده است حل کند. برای مثال، اگر «خدمات Google Play» غیرفعال باشد، ممکن است از کاربر بخواهد آن را فعال کند. استثناهای قابل‌اصلاح، استثناهای Integrity API با کدهای خطایی مثل PLAY_SERVICES_VERSION_OUTDATED، NETWORK_ERROR، یا PLAY_SERVICES_NOT_FOUND هستند. می‌توانید از روش exception.isRemediable() استفاده کنید تا بررسی کنید آیا خطا توسط کادر گفتگو قابل‌رفع است یا نه.

تجربه کاربری نمونه

شکل ۵. کادر گفتگوی GET_STRONG_INTEGRITY درحال به‌روزرسانی خدمات Play.