بيانات السلامة

توضّح هذه الصفحة كيفية تفسير نتيجة INTEGRITY المعروضة وكيفية التعامل معها. سواء أكنت تُجري طلبًا عاديًا أو كلاسيكيًا من واجهة برمجة التطبيقات، يتم عرض نتيجة السلامة بالتنسيق نفسه وبمحتوى مشابه. يعرض بيان السلامة معلومات عن صلاحية الأجهزة والتطبيقات والحسابات. يمكن لخادم تطبيقك استخدام الحمولة الناتجة في بيان سلامة مفعَّل التشفير ومُثبَّت صحته لتحديد أفضل طريقة لمتابعة إجراء معيّن أو طلب معيّن في تطبيقك.

تنسيق بيان السلامة الذي يتم إرجاعه

الحمولة هي نص JSON عادي وتحتوي على إشارات السلامة إلى جانب المعلومات التي يقدّمها المطوّر.

في ما يلي بنية الحمولة العامة:

{
  requestDetails: { ... }
  appIntegrity: { ... }
  deviceIntegrity: { ... }
  accountDetails: { ... }
  environmentDetails: { ... }
}

يجب أولاً التحقّق من أنّ القيم في حقل requestDetails تتطابق مع قيم الطلب الأصلي قبل التحقّق من كلّ قرار متعلّق بالسلامة. توضِّح الأقسام التالية كل حقل بمزيد من التفصيل.

حقل تفاصيل الطلب

يحتوي الحقل requestDetails على معلومات عن الطلب، بما في ذلك المعلومات التي يقدّمها المطوّر في requestHash للطلبات العادية وnonce للطلبات الكلاسيكية.

بالنسبة إلى طلبات البيانات العادية من واجهة برمجة التطبيقات:

requestDetails: {
  // Application package name this attestation was requested for.
  // Note that this field might be spoofed in the middle of the request.
  requestPackageName: "com.package.name"
  // Request hash provided by the developer.
  requestHash: "aGVsbG8gd29scmQgdGhlcmU"
  // The timestamp in milliseconds when the integrity token
  // was requested.
  timestampMillis: "1675655009345"
}

ويجب أن تتطابق هذه القيم مع قيم الطلب الأصلي. لذلك، تحقَّق من requestDetails جزء من الحمولة في ملف JSON من خلال التأكّد من أنّ requestPackageName وrequestHash يتطابقان مع ما تم إرساله في الطلب الأصلي، كما هو موضّح في مقتطف الرمز التالي:

Kotlin

val requestDetails = JSONObject(payload).getJSONObject("requestDetails")
val requestPackageName = requestDetails.getString("requestPackageName")
val requestHash = requestDetails.getString("requestHash")
val timestampMillis = requestDetails.getLong("timestampMillis")
val currentTimestampMillis = ...

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request
    || !requestHash.equals(expectedRequestHash)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

Java

RequestDetails requestDetails =
    decodeIntegrityTokenResponse
    .getTokenPayloadExternal()
    .getRequestDetails();
String requestPackageName = requestDetails.getRequestPackageName();
String requestHash = requestDetails.getRequestHash();
long timestampMillis = requestDetails.getTimestampMillis();
long currentTimestampMillis = ...;

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request.
    || !requestHash.equals(expectedRequestHash)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

بالنسبة إلى طلبات البيانات الكلاسيكية من واجهة برمجة التطبيقات:

requestDetails: {
  // Application package name this attestation was requested for.
  // Note that this field might be spoofed in the middle of the
  // request.
  requestPackageName: "com.package.name"
  // base64-encoded URL-safe no-wrap nonce provided by the developer.
  nonce: "aGVsbG8gd29scmQgdGhlcmU"
  // The timestamp in milliseconds when the request was made
  // (computed on the server).
  timestampMillis: "1617893780"
}

ويجب أن تتطابق هذه القيم مع قيم الطلب الأصلي. لذلك، تحقَّق من requestDetails جزء من الحمولة في ملف JSON من خلال التأكّد من أنّ requestPackageName وnonce يتطابقان مع ما تم إرساله في الطلب الأصلي، كما هو موضح في مقتطف الرمز التالي:

Kotlin

val requestDetails = JSONObject(payload).getJSONObject("requestDetails")
val requestPackageName = requestDetails.getString("requestPackageName")
val nonce = requestDetails.getString("nonce")
val timestampMillis = requestDetails.getLong("timestampMillis")
val currentTimestampMillis = ...

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request. See 'Generate a nonce'
        // section of the doc on how to store/compute the expected nonce.
    || !nonce.equals(expectedNonce)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

Java

JSONObject requestDetails =
    new JSONObject(payload).getJSONObject("requestDetails");
String requestPackageName = requestDetails.getString("requestPackageName");
String nonce = requestDetails.getString("nonce");
long timestampMillis = requestDetails.getLong("timestampMillis");
long currentTimestampMillis = ...;

// Ensure the token is from your app.
if (!requestPackageName.equals(expectedPackageName)
        // Ensure the token is for this specific request. See 'Generate a nonce'
        // section of the doc on how to store/compute the expected nonce.
    || !nonce.equals(expectedNonce)
        // Ensure the freshness of the token.
    || currentTimestampMillis - timestampMillis > ALLOWED_WINDOW_MILLIS) {
        // The token is invalid! See below for further checks.
        ...
}

حقل "سلامة التطبيق"

يحتوي الحقل appIntegrity على معلومات ذات صلة بالحزمة.

appIntegrity: {
  // PLAY_RECOGNIZED, UNRECOGNIZED_VERSION, or UNEVALUATED.
  appRecognitionVerdict: "PLAY_RECOGNIZED"
  // The package name of the app.
  // This field is populated iff appRecognitionVerdict != UNEVALUATED.
  packageName: "com.package.name"
  // The sha256 digest of app certificates (base64-encoded URL-safe).
  // This field is populated iff appRecognitionVerdict != UNEVALUATED.
  certificateSha256Digest: ["6a6a1474b5cbbb2b1aa57e0bc3"]
  // The version of the app.
  // This field is populated iff appRecognitionVerdict != UNEVALUATED.
  versionCode: "42"
}

يمكن أن يكون للمتغير appRecognitionVerdict القيم التالية:

PLAY_RECOGNIZED
يتطابق التطبيق وشهادة التطبيق مع الإصدارات التي تم توزيعها من خلال Google Play.
UNRECOGNIZED_VERSION
لا تتطابق شهادة التطبيق أو اسم الحزمة مع سجلّات Google Play.
UNEVALUATED
لم يتم تقييم سلامة التطبيق. ولم يتم استيفاء أحد المتطلّبات الضرورية، مثلاً أن يكون الجهاز غير موثوق بالقدر الكافي.

للتأكّد من أنّ الرمز المميّز قد تم إنشاؤه بواسطة تطبيق أنشأته، عليك التحقّق مما يلي: أنّ سلامة التطبيق على النحو المتوقّع، كما هو موضّح في مقتطف الرمز المميّز التالي:

Kotlin

val appIntegrity = JSONObject(payload).getJSONObject("appIntegrity")
val appRecognitionVerdict = appIntegrity.getString("appRecognitionVerdict")

if (appRecognitionVerdict == "PLAY_RECOGNIZED") {
    // Looks good!
}

Java

JSONObject appIntegrity =
    new JSONObject(payload).getJSONObject("appIntegrity");
String appRecognitionVerdict =
    appIntegrity.getString("appRecognitionVerdict");

if (appRecognitionVerdict.equals("PLAY_RECOGNIZED")) {
    // Looks good!
}

يمكنك أيضًا التحقّق من اسم حزمة التطبيق وإصداره وشهاداته يدويًا.

حقل سلامة الجهاز

يمكن أن يحتوي الحقل deviceIntegrity على قيمة واحدة، deviceRecognitionVerdict، تحتوي على تصنيف واحد أو أكثر يمثّل مدى قدرة الجهاز على فرض سلامة التطبيق. إذا لم يستوفِ الجهاز معايير أي من التصنيفات، يكون الحقل deviceIntegrity فارغًا.

deviceIntegrity: {
  // "MEETS_DEVICE_INTEGRITY" is one of several possible values.
  deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"]
}

يمكن أن يحتوي العنصر deviceRecognitionVerdict تلقائيًا على ما يلي:

MEETS_DEVICE_INTEGRITY
يعمل التطبيق على جهاز Android متوافق مع "خدمات Google Play". يجتاز الجهاز عمليات التحقّق من سلامة النظام ويستوفي متطلبات التوافق مع نظام التشغيل Android.
فارغ (قيمة فارغة)
يعمل التطبيق على جهاز يتضمّن علامات تشير إلى تعرُّضه للهجوم (مثل اعتراض طلبات البيانات من واجهة برمجة التطبيقات) أو اختراق نظامه (مثل تزويده بإذن الوصول إلى الجذر)، أو لا يعمل التطبيق على جهاز فعلي (مثل المحاكي الذي لا يجتاز عمليات التأكّد من السلامة في Google Play).

للتأكّد من أنّ الرمز المميّز مصدره جهاز موثوق، تأكَّد من أنّ deviceRecognitionVerdict كما هو متوقّع، كما هو موضّح في مقتطف الرمز التالي:

Kotlin

val deviceIntegrity =
    JSONObject(payload).getJSONObject("deviceIntegrity")
val deviceRecognitionVerdict =
    if (deviceIntegrity.has("deviceRecognitionVerdict")) {
        deviceIntegrity.getJSONArray("deviceRecognitionVerdict").toString()
    } else {
        ""
    }

if (deviceRecognitionVerdict.contains("MEETS_DEVICE_INTEGRITY")) {
    // Looks good!
}

Java

JSONObject deviceIntegrity =
    new JSONObject(payload).getJSONObject("deviceIntegrity");
String deviceRecognitionVerdict =
    deviceIntegrity.has("deviceRecognitionVerdict")
    ? deviceIntegrity.getJSONArray("deviceRecognitionVerdict").toString()
    : "";

if (deviceRecognitionVerdict.contains("MEETS_DEVICE_INTEGRITY")) {
    // Looks good!
}

إذا كنت تواجه مشاكل في جهاز الاختبار بشأن سلامة الجهاز، تأكَّد من تثبيت نظام التشغيل الثابت (ROM) من المصنع (على سبيل المثال، من خلال إعادة ضبط الجهاز) ومن قفل أداة تحميل البرامج. يمكنك أيضًا إنشاء اختبارات Play Integrity API في Play Console.

تصنيفات الأجهزة الشَرطية

إذا كنت بصدد طرح تطبيقك على "ألعاب Google Play على الكمبيوتر"، يمكن أن يحتوي ملف deviceRecognitionVerdict أيضًا على التصنيف التالي:

MEETS_VIRTUAL_INTEGRITY
يعمل التطبيق على محاكي Android متوافق مع "خدمات Google Play". يجتاز المحاكي عمليات التحقّق من سلامة النظام ويستوفي متطلبات التوافق الأساسية مع نظام Android.

معلومات اختيارية عن الجهاز

في حال الموافقة على تلقّي تصنيفات إضافية في بيان السلامة، يمكن أن يحتويdeviceRecognitionVerdict على التصنيفات الإضافية التالية:

MEETS_BASIC_INTEGRITY
يعمل التطبيق على أي جهاز يجتاز عمليات التحقق الأساسية من سلامة النظام. قد لا يستوفي الجهاز متطلبات التوافق مع نظام Android، وقد لا يحصل على موافقة لتفعيل "خدمات Google Play". على سبيل المثال، قد يعمل الجهاز بإصدار غير معروف من نظام Android، أو ربما يتضمّن برنامج إقلاع مفتوحًا، أو ربما لم تعتمده الشركة المصنِّعة.
MEETS_STRONG_INTEGRITY
يعمل التطبيق على جهاز Android متوافق مع "خدمات Google Play"، ويوفّر ضمانًا قويًا على سلامة النظام، مثل إثبات سلامة عملية التمهيد المستنِد إلى الجهاز. يجتاز الجهاز عمليات التحقّق من سلامة النظام ويستوفي متطلبات التوافق مع نظام التشغيل Android.

سيعرض جهاز واحد تصنيفات أجهزة متعددة في نتيجة تقييم سلامة الجهاز في حال استيفاء كل معايير التصنيف.

أحدث نشاط للجهاز

يمكنك أيضًا تفعيل ميزة "أحدث نشاط للجهاز" التي توضّح لك كم مرّة طلب فيها تطبيقك رمزًا مميّزًا للسلامة على جهاز معيّن خلال آخر ساعة. يمكنك استخدام ميزة "أحدث نشاط للجهاز" لحماية تطبيقك من الأجهزة التي تُجري عمليات اتصال غير متوقّعة ونشطة بشكل كبير، والتي قد تشير إلى تعرُّض تطبيقك لهجوم نشط. يمكنك تحديد مستوى الثقة في كل مستوى من مستويات "أحدث نشاط للجهاز" استنادًا إلى عدد المرات التي تتوقّع فيها أن يطلب تطبيقك المثبَّت على جهاز عادي رمزًا مميّزًا للسلامة كل ساعة.

في حال تفعيل تلقّي recentDeviceActivity، سيكون للحقل deviceIntegrity قيمتَان:

deviceIntegrity: {
  deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"]
  recentDeviceActivity: {
    // "LEVEL_2" is one of several possible values.
    deviceActivityLevel: "LEVEL_2"
  }
}

تختلف تعريفات deviceActivityLevel بين الأوضاع ويمكن أن يكون لها إحدى القيم التالية:

مستوى نشاط الجهاز الأخير طلبات الرموز المميّزة العادية لسلامة واجهة برمجة التطبيقات على هذا الجهاز في آخر ساعة لكل تطبيق طلبات الرموز المميّزة للسلامة في واجهات برمجة التطبيقات الكلاسيكية على هذا الجهاز في آخر ساعة لكل تطبيق
LEVEL_1 (أدنى) 10 أو أقل 5 أو أقل
LEVEL_2 بين 11 و25 بين 6 و10
LEVEL_3 بين 26 و50 بين 11 و15
LEVEL_4 (أعلى) أكثر من 50 أكثر من 15
UNEVALUATED لم يتم تقييم أحدث نشاط للجهاز. قد يحدث ذلك للأسباب التالية:
  • الجهاز غير موثوق بالقدر الكافي
  • لا يتعرّف Google Play على إصدار تطبيقك المثبّت على الجهاز.
  • مشاكل فنية في الجهاز

سمات الجهاز

يمكنك أيضًا تفعيل سمات الجهاز التي تُعلم إصدار حزمة تطوير البرامج (SDK) لنظام التشغيل Android بنظام التشغيل Android الذي يعمل على الجهاز. وقد تتم إضافة سمات أخرى للأجهزة في المستقبل.

قيمة إصدار حزمة SDK هي رقم إصدار حزمة SDK لنظام التشغيل Android المحدَّد في Build.VERSION_CODES. لا يتم تقييم إصدار حزمة تطوير البرامج (SDK) في حال عدم استيفاء أحد المتطلّبات الضرورية. في هذه الحالة، لم يتم ضبط الحقل sdkVersion، وبالتالي يكون الحقل deviceAttributes فارغًا. قد يرجع سبب ذلك إلى:

  • الجهاز غير موثوق بالقدر الكافي
  • لا يتعرّف Google Play على إصدار تطبيقك المثبّت على الجهاز.
  • حدثت مشاكل فنية على الجهاز.

إذا وافقت على تلقّي deviceAttributes، سيتضمّن الحقل deviceIntegrity الحقل الإضافي التالي:

deviceIntegrity: {
  deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"]
  deviceAttributes: {
    // 33 is one possible value, which represents Android 13 (Tiramisu).
    sdkVersion: 33
  }
}

في حال عدم تقييم إصدار حزمة SDK، سيتم ضبط الحقل deviceAttributes على النحو التالي:

deviceIntegrity: {
  deviceRecognitionVerdict: ["MEETS_DEVICE_INTEGRITY"]
  deviceAttributes: {}  // sdkVersion field is not set.
}

حقل تفاصيل الحساب

يحتوي الحقل accountDetails على قيمة واحدة، وهي appLicensingVerdict، تمثل حالة ترخيص التطبيق على Google Play لحساب المستخدم الذي تم تسجيل الدخول عليه على الجهاز. إذا كان حساب المستخدم يملك ترخيص Play للتطبيق، يعني ذلك أنّه نزّله أو اشتراه من Google Play.

accountDetails: {
  // This field can be LICENSED, UNLICENSED, or UNEVALUATED.
  appLicensingVerdict: "LICENSED"
}

يمكن أن يكون appLicensingVerdict إحدى القيم التالية:

LICENSED
يملك المستخدِم إذن الوصول إلى التطبيق. بمعنى آخر، ثبَّت المستخدم تطبيقك أو عدّله من Google Play على جهازه.
UNLICENSED
لا يملك المستخدِم إذنًا للوصول إلى التطبيق. ويحدث ذلك مثلاً في حال ثبَّت المستخدم تطبيقك من مصدر غير معروف أو لم يحصل عليه من Google Play. يمكنك عرض مربّع الحوار GET_LICENSED للمستخدمين لحلّ هذه المشكلة.
UNEVALUATED

لم يتم تقييم تفاصيل الترخيص بسبب عدم استيفاء أحد المتطلّبات الضرورية.

وقد يحدث ذلك لعدة أسباب، بما فيها ما يلي:

  • الجهاز غير موثوق بالقدر الكافي
  • لا يتعرّف Google Play على إصدار تطبيقك المثبَّت على الجهاز.
  • لم يسجِّل المستخدم الدخول إلى Google Play.

للتحقّق من أنّ المستخدم لديه إذن وصول إلى تطبيقك، تأكَّد من أنّ قيمة appLicensingVerdict كما هو متوقّع، كما هو موضّح في مقتطف الرمز التالي:

Kotlin

val accountDetails = JSONObject(payload).getJSONObject("accountDetails")
val appLicensingVerdict = accountDetails.getString("appLicensingVerdict")

if (appLicensingVerdict == "LICENSED") {
    // Looks good!
}

Java

JSONObject accountDetails =
    new JSONObject(payload).getJSONObject("accountDetails");
String appLicensingVerdict = accountDetails.getString("appLicensingVerdict");

if (appLicensingVerdict.equals("LICENSED")) {
    // Looks good!
}

حقل تفاصيل البيئة

يمكنك أيضًا تفعيل إشارات إضافية عن البيئة. تُعلم ميزة "احتمالية الوصول إلى التطبيق" تطبيقك إذا كانت هناك تطبيقات أخرى قيد التشغيل يمكن استخدامها لالتقاط لقطات للشاشة أو عرض محتوى على سطح الصفحة أو التحكّم في الجهاز. يوضّح بيان "Google Play للحماية" ما إذا كانت خدمة "Google Play للحماية" مفعَّلة على الجهاز وما إذا كانت قد رصدت برامج ضارة معروفة.

إذا وافقت على تلقّي بيان "مخاطر الوصول إلى التطبيق" أو بيان "Play للحماية" في Google Play Console، سيتضمّن ردّ واجهة برمجة التطبيقات الحقل environmentDetails. يمكن أن يحتوي الحقل environmentDetails على قيمتَين ، وهما appAccessRiskVerdict وplayProtectVerdict.

بيان خطورة الوصول إلى التطبيق

بعد تفعيل هذه الميزة، سيحتوي الحقل environmentDetails في حمل البيانات في Play Integrity API على بيان مدى خطورة الوصول إلى التطبيق الجديد.

{
  requestDetails: { ... }
  appIntegrity: { ... }
  deviceIntegrity: { ... }
  accountDetails: { ... }
  environmentDetails: {
      appAccessRiskVerdict: {
          // This field contains one or more responses, for example the following.
          appsDetected: ["KNOWN_INSTALLED", "UNKNOWN_INSTALLED", "UNKNOWN_CAPTURING"]
      }
 }
}

إذا تم تقييم خطر الوصول إلى التطبيق، يحتوي appAccessRiskVerdict على الحقل appsDetected مع إجابة واحدة أو أكثر. تندرج هذه الردود ضمن إحدى المجموعةَين التاليتَين استنادًا إلى مصدر تثبيت التطبيقات التي تم رصدها:

  • تطبيقات Play أو تطبيقات النظام: التطبيقات التي ثبَّتها Google Play أو حمَّلها مسبقًا المصنع على قسم نظام الجهاز (يتم تمييزها باستخدام الرمز FLAG_SYSTEM). تبدأ الردود لهذه التطبيقات بالرمز KNOWN_.

  • التطبيقات الأخرى: التطبيقات التي لم يتم تثبيتها من خلال Google Play ولا يشمل ذلك التطبيقات التي حمّلتها الشركة المصنّعة للجهاز مسبقًا على قسم النظام. تتم إضافة البادئة UNKNOWN_ إلى الردود لهذه التطبيقات.

يمكن عرض الردود التالية:

KNOWN_INSTALLED، UNKNOWN_INSTALLED
هناك تطبيقات مثبّتة تتطابق مع مصدر التثبيت المقابل.
KNOWN_CAPTURING، UNKNOWN_CAPTURING
هناك تطبيقات قيد التشغيل تم تفعيل أذونات لها يمكن استخدامها ل عرض الشاشة أثناء تشغيل تطبيقك. ولا يشمل ذلك أي خدمات تم التحقّق منها لإتاحة الاستخدام على الأجهزة والتي يعلم Google Play أنّها تعمل على الجهاز.
KNOWN_CONTROLLING، UNKNOWN_CONTROLLING
هناك تطبيقات قيد التشغيل تم تفعيل أذونات لها يمكن استخدامها للتحكّم في الجهاز والتحكّم مباشرةً في الإدخالات في تطبيقك، ويمكن استخدامها لتسجيل الإدخالات والمخرجات في تطبيقك. ويُستثنى من ذلك أي خدمات مساعدة متوفّرة ومُعتمَدة على Google Play والتي تعمل على الجهاز.
KNOWN_OVERLAYS، UNKNOWN_OVERLAYS
هناك تطبيقات قيد التشغيل تم تفعيل أذونات لها يمكن استخدامها لعرض تراكب على تطبيقك. ويُستثنى من ذلك أي خدمات تم التحقّق منها لتحسين إمكانية الاستخدام ومعلومة لدى Google Play بأنّها تعمل على الجهاز.
فارغ (قيمة فارغة)

لا يتم تقييم احتمالية اختراق التطبيق في حال عدم استيفاء أحد المتطلّبات الضرورية. في هذه الحالة، يكون حقل appAccessRiskVerdict فارغًا. وقد يحدث ذلك لعدة أسباب، بما في ذلك:

  • الجهاز غير موثوق بالقدر الكافي
  • شكل الجهاز ليس هاتفًا أو جهازًا لوحيًا أو جهازًا قابلاً للطي.
  • الجهاز لا يعمل بالإصدار 6 من نظام التشغيل Android (المستوى 23 من واجهة برمجة التطبيقات) أو إصدار أحدث.
  • لا يتعرّف Google Play على إصدار التطبيق المثبّت على الجهاز
  • إذا كان إصدار "متجر Google Play" على الجهاز قديمًا
  • الألعاب فقط: لا يملك حساب المستخدم ترخيصًا على Play للّعبة.
  • تم استخدام طلب عادي مع المَعلمة verdictOptOut.
  • تم استخدام طلب عادي مع إصدار مكتبة Play Integrity API لا يتيح إمكانية تقييم احتمالية اختراق التطبيق للطلبات العادية.

تستبعد ميزة "مخاطر الوصول إلى التطبيقات" تلقائيًا خدمات تسهيل الاستخدام التي تم التحقّق منها والتي اجتازت مراجعة محسّنة لإمكانية الاستخدام على Google Play (تم تثبيتها من خلال أي متجر تطبيقات على الجهاز). تعني الحالة "مستبعدة" أنّ خدمات تسهيل الاستخدام التي تم التحقّق منها والتي تعمل على الجهاز لن تعرِض استجابة بشأن التقاط الشاشة أو التحكّم فيها أو عرض محتوى على السطح في بيان احتمالية الوصول إلى التطبيق. لطلب إجراء مراجعة محسّنة لتطبيقك المخصّص لتحسين إمكانية الاستخدام على Google Play، عليك نشره على Google Play مع التأكّد من ضبط العلامة isAccessibilityTool على true فيملف بيان التطبيق، أو طلب إجراء مراجعة.

يقدّم الجدول التالي بعض الأمثلة على النتائج وتفسيرها (لا يسرد هذا الجدول كل النتائج المحتملة):

مثال على ردّ بشأن بيان خطورة الوصول إلى التطبيق التفسير
appsDetected:
["KNOWN_INSTALLED"]
لا تتوفّر سوى التطبيقات المثبّتة التي يتعرّف عليها Google Play أو التي حمّلتها الشركة المصنّعة للجهاز مسبقًا على قسم النظام.
لا تتوفّر أي تطبيقات قيد التشغيل يمكن أن تؤدي إلى إصدار أحكام برصد أو التحكّم أو التراكب.
appsDetected:
["KNOWN_INSTALLED",
"UNKNOWN_INSTALLED",
"UNKNOWN_CAPTURING"]
هناك تطبيقات ثبَّتها Google Play أو حمَّلها مُصنِّع الجهاز مُسبَقًا على قسم النظام.
هناك تطبيقات أخرى قيد التشغيل وتم تفعيل أذونات لها يمكن استخدامها لعرض الشاشة أو تسجيل مدخلات ومخرجات أخرى.
appsDetected:
["KNOWN_INSTALLED",
"KNOWN_CAPTURING",
"UNKNOWN_INSTALLED",
"UNKNOWN_CONTROLLING"]
هناك تطبيقات Play أو تطبيقات نظام قيد التشغيل تم تفعيل أذونات لها يمكن استخدامها لعرض الشاشة أو تسجيل مدخلات ومخرجات أخرى.
هناك أيضًا تطبيقات أخرى قيد التشغيل تم تفعيل أذونات لها يمكن استخدامها للتحكّم في الجهاز والتحكّم مباشرةً في الإدخالات في تطبيقك.
appAccessRiskVerdict: {} لم يتم تقييم مخاطر الوصول إلى التطبيق بسبب عدم استيفاء أحد المتطلّبات الضرورية. على سبيل المثال، كان الجهاز غير موثوق به بالقدر الكافي.

استنادًا إلى مستوى المخاطر، يمكنك تحديد مجموعة الأحكام المقبولة للمتابعة والأحكام التي تريد اتّخاذ إجراء بشأنها. يوضّح مقتطف الرمز البرمجي التالي مثالاً للتحقّق من عدم وجود تطبيقات قيد التشغيل يمكنها أخذ لقطات للشاشة أو التحكّم في تطبيقك:

Kotlin

val environmentDetails =
    JSONObject(payload).getJSONObject("environmentDetails")
val appAccessRiskVerdict =
    environmentDetails.getJSONObject("appAccessRiskVerdict")

if (appAccessRiskVerdict.has("appsDetected")) {
    val appsDetected = appAccessRiskVerdict.getJSONArray("appsDetected").toString()
    if (!appsDetected.contains("CAPTURING") && !appsDetected.contains("CONTROLLING")) {
        // Looks good!
    }
}

Java

JSONObject environmentDetails =
    new JSONObject(payload).getJSONObject("environmentDetails");
JSONObject appAccessRiskVerdict =
    environmentDetails.getJSONObject("appAccessRiskVerdict");

if (appAccessRiskVerdict.has("appsDetected")) {
    String appsDetected = appAccessRiskVerdict.getJSONArray("appsDetected").toString()
    if (!appsDetected.contains("CAPTURING") && !appsDetected.contains("CONTROLLING")) {
        // Looks good!
    }
}
معالجة أحكام خطورة الوصول إلى التطبيق

استنادًا إلى مستوى الخطورة، يمكنك تحديد بيانات السلامة المتعلّقة بالمخاطر في الوصول إلى التطبيق التي تريد اتخاذ إجراء بشأنها قبل السماح للمستخدم بإكمال طلب أو إجراء. هناك طلبات اختيارية من Google Play يمكنك عرضها على المستخدم بعد الاطّلاع على بيان احتمالية اختراق التطبيق. يمكنك عرض CLOSE_UNKNOWN_ACCESS_RISK لطلب إغلاق التطبيقات غير المعروفة التي تؤدي إلى إصدار بيان احتمالية اختراق التطبيق، أو يمكنك عرض CLOSE_ALL_ACCESS_RISK لطلب إغلاق المستخدم لجميع التطبيقات (المعروفة وغير المعروفة) التي تؤدي إلى إصدار بيان احتمالية اختراق التطبيق.

نتيجة فحص "Play للحماية"

بعد تفعيل هذه الميزة، سيحتوي الحقل environmentDetails في حمل البيانات في واجهة برمجة التطبيقات Play Integrity API على بيان Play Protect:

environmentDetails: {
  playProtectVerdict: "NO_ISSUES"
}

يمكن أن يكون playProtectVerdict إحدى القيم التالية:

NO_ISSUES
تم تفعيل خدمة "Play للحماية" ولم تعثر على أي مشاكل في التطبيقات على الجهاز.
NO_DATA
تم تفعيل خدمة "Play للحماية" ولكن لم يتم إجراء أي عملية فحص حتى الآن. قد تكون تمت إعادة ضبط الجهاز أو تطبيق "متجر Play" مؤخرًا.
POSSIBLE_RISK
تم إيقاف خدمة "Play للحماية":
MEDIUM_RISK
تم تفعيل خدمة "Play للحماية" وعثرت على تطبيقات قد تتسبّب بضرر مثبّتة على الجهاز.
HIGH_RISK
تكون خدمة "Play للحماية" مفعّلة وقد عثرت على تطبيقات خطيرة مثبّتة على الجهاز.
UNEVALUATED

لم يتم تقييم قرار "Google Play للحماية".

وقد يحدث ذلك لعدة أسباب، بما فيها ما يلي:

  • الجهاز غير موثوق بالقدر الكافي
  • الألعاب فقط: لا يملك حساب المستخدم ترخيصًا على Play للّعبة.

إرشادات حول استخدام قرار "Play للحماية"

يمكن لخادم الخلفية في تطبيقك أن يقرّر كيفية التصرف استنادًا إلى بيان السلامة استنادًا إلى مستوى تحملك للمخاطر. في ما يلي بعض الاقتراحات وإجراءات المستخدمين المحتمَلة:

NO_ISSUES
تم تفعيل خدمة "Google Play للحماية" ولم يتم العثور على أي مشاكل، لذا ليس على المستخدم اتّخاذ أي إجراء.
POSSIBLE_RISK وNO_DATA
عند تلقّي هذه الأحكام، اطلب من المستخدم التحقّق من تفعيل خدمة "Play للحماية" وإجراء فحص. من المفترض ألا يظهر الرمز NO_DATA إلا في حالات نادرة.
MEDIUM_RISK وHIGH_RISK
استنادًا إلى مستوى المخاطر المقبولة لديك، يمكنك أن تطلب من المستخدم تشغيل "Play الحماية" واتّخاذ إجراء بشأن تحذيرات "Play للحماية". إذا لم يتمكّن المستخدم من استيفاء هذه المتطلبات، يمكنك حظره من إجراء الخادم.