يوضّح هذا الدليل كيفية استخدام حزمة تطوير البرامج (SDK) الخاصة بواجهة Android Management API في وحدة تحكّم مخصّصة بسياسة الجهاز (DPC) لضبط عناصر التحكّم الموحّدة في التحديثات (UUC) على الأجهزة المملوكة للشركة.
باستخدام حزمة تطوير البرامج (SDK) الخاصة بواجهة برمجة التطبيقات لإدارة Android، ترسل وحدة التحكّم في سياسة الجهاز (DPC) المخصّصة سياسة "الاستخدام غير المصنَّف" مباشرةً إلى تطبيق Android Device Policy على الجهاز. يقيّم ADP قواعد السياسة وفقًا لحالة الجهاز الحالية، ويوجّه Google Play وعميل OTA الخاص بالمصنّع الأصلي للجهاز بشأن كيفية التعامل مع التحديثات المعلّقة.
قبل البدء، يُرجى قراءة عناصر التحكّم الموحّدة في التحديثات للتعرّف على كيفية عمل القواعد والأهداف والمسندات والنتائج، والقيود التي تنطبق على جميع عمليات دمج عناصر التحكّم الموحّدة في التحديثات.
المتطلبات الأساسية
قبل دمج UUC في وحدة التحكّم في السياسات على الجهاز (DPC) المخصّصة، تأكَّد من استيفاء المتطلبات التالية:
- الجهاز مملوك للشركة، وتم ضبطه إما كـ جهاز مُدار بالكامل أو باستخدام ملف عمل على جهاز مملوك للشركة.
- تم دمج وحدة التحكّم بسياسة الجهاز (DPC) المخصّصة مع حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات لإدارة Android.
- تم تسجيل الجهاز باستخدام Google Play EMM API.
- يستوفي الجهاز الحدّ الأدنى لمتطلبات الإصدار لوضع الإدارة وكل هدف تحديث تريد التحكّم فيه:
- الأجهزة المُدارة بالكامل (مالك الجهاز): الإصدار 13 من نظام التشغيل Android (المستوى 33 لواجهة برمجة التطبيقات) أو إصدار أحدث
- الأجهزة المملوكة للشركة والتي تتضمّن ملف عمل (COPE): الإصدار 15 من نظام التشغيل Android (المستوى 35 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث
الدمج مع حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات Android Management API في وحدة التحكّم بسياسة الجهاز (DPC) المخصّصة
لضبط سياسة UUC على جهاز، يجب دمج وحدة التحكّم بسياسة الجهاز (DPC) المخصّصة مع حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات Android Management API. للحصول على تعليمات حول إضافة المكتبة وضبط ملف بيان تطبيقك، يُرجى الاطّلاع على دليل دمج حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات Android Management API.
خطوات ضبط "عناصر التحكّم الموحّدة في التحديثات"
لضبط سياسات UUC من وحدة التحكّم في سياسة الجهاز (DPC) المخصّصة، تأكَّد من أنّ بيئة العميل على الجهاز فقط جاهزة ومحدَّثة قبل إرسال طلبات السياسات إلى ADP:
التحقّق من بيئة العميل
يوضّح المثال التالي كيفية استدعاء getEnvironment (في Kotlin) أو
getEnvironmentAsync (في Java) باستخدام
Role.RoleType.DEVICE_POLICY_CONTROLLER لفحص حالة تطبيق ADP. إذا
كانت البيئة READY وUP_TO_DATE، يمكن لوحدة التحكّم بسياسة الجهاز (DPC) المخصّصة المتابعة
لضبط سياسات UUC باستخدام PolicyClient. بخلاف ذلك، يمكنك استدعاء
prepareEnvironment لتثبيت تطبيق ADP أو تحديثه (يُرجى الاطّلاع على
إعداد بيئة العميل).
Kotlin
import android.content.Context import android.util.Log import com.google.android.managementapi.common.model.Role import com.google.android.managementapi.environment.EnvironmentClientFactory import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.INSTALLED import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.NOT_INSTALLED import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE import com.google.android.managementapi.environment.model.GetEnvironmentRequest private suspend fun checkEnvironmentForUuc(context: Context): Boolean { try { val roles = listOf( Role.builder() .setRoleType(Role.RoleType.DEVICE_POLICY_CONTROLLER) .build() ) val request = GetEnvironmentRequest.builder().setRoles(roles).build() val environmentClient = EnvironmentClientFactory.create(context) val environmentResponse = environmentClient.getEnvironment(request) if (environmentResponse.hasAndroidDevicePolicyEnvironment()) { val adpEnvironment = environmentResponse.androidDevicePolicyEnvironment when (adpEnvironment.state) { READY -> { return if (adpEnvironment.version == UP_TO_DATE) { // AMAPI environment state and version are ready. true } else { prepareEnvironment(context, environmentClient) } } INSTALLED -> { // Call prepareEnvironment to silently update ADP. return prepareEnvironment(context, environmentClient) } NOT_INSTALLED -> { // Call prepareEnvironment to install ADP. return prepareEnvironment(context, environmentClient) } else -> {} } } } catch (e: Exception) { Log.e(TAG, "Exception checking environment", e) } return false }
جافا
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.INSTALLED; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.NOT_INSTALLED; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE; import android.content.Context; import android.util.Log; import com.google.android.managementapi.common.model.Role; import com.google.android.managementapi.environment.EnvironmentClient; import com.google.android.managementapi.environment.EnvironmentClientFactory; import com.google.android.managementapi.environment.model.Environment; import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment; import com.google.android.managementapi.environment.model.GetEnvironmentRequest; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; private void checkEnvironmentForUuc(Context context) { try { ImmutableListroles = new ImmutableList.Builder () .add(Role.builder() .setRoleType(Role.RoleType.DEVICE_POLICY_CONTROLLER) .build()) .build(); EnvironmentClient environmentClient = EnvironmentClientFactory.create(context); GetEnvironmentRequest getRequest = GetEnvironmentRequest.builder() .setRoles(roles) .build(); ListenableFuture getEnvironmentFuture = environmentClient.getEnvironmentAsync(getRequest); Futures.addCallback(getEnvironmentFuture, new FutureCallback () { @Override public void onSuccess(Environment environment) { if (!environment.hasAndroidDevicePolicyEnvironment()) { return; } AndroidDevicePolicyEnvironment adpEnvironment = environment.getAndroidDevicePolicyEnvironment(); AndroidDevicePolicyEnvironment.State state = adpEnvironment.getState(); AndroidDevicePolicyEnvironment.Version version = adpEnvironment.getVersion(); if (state == READY && version == UP_TO_DATE) { // AMAPI environment state and version are ready. return; } else if (state == INSTALLED || state == NOT_INSTALLED) { // Call prepareEnvironment to silently install or update ADP. prepareEnvironment(context, environmentClient); } } @Override public void onFailure(Throwable t) { Log.e(TAG, "Failed to verify environment", t); } }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.e(TAG, "Exception verifying environment", e); } }
إعداد بيئة العميل
إذا لم تكن البيئة على الجهاز جاهزة أو محدّثة، يمكنك استدعاء
prepareEnvironment قبل استخدام PolicyClient.
عند استدعاء هذه الطريقة من وحدة تحكّم بسياسة الجهاز (DPC) مخصّصة باستخدام Role.RoleType.DEVICE_POLICY_CONTROLLER
وتمرير اسم مكوّن DeviceAdminReceiver الخاص بوحدة التحكّم بسياسة الجهاز (DPC) إلى setAdmin()،
يتم تثبيت تطبيق ADP تلقائيًا من خلال prepareEnvironment (إذا لم يكن مثبّتًا من قبل)
ويتم تحديث تطبيق ADP و"متجر Google Play" بدون تفاعل المستخدم. لمزيد من المعلومات حول إعداد البيئة في مسارات "وحدة التحكّم بسياسة الجهاز" المخصّصة، يُرجى الاطّلاع على إعداد البيئة وتسجيل المستخدمين.
Kotlin
import android.content.ComponentName import android.content.Context import android.util.Log import com.google.android.managementapi.common.model.Role import com.google.android.managementapi.environment.EnvironmentClient import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE import com.google.android.managementapi.environment.model.PrepareEnvironmentRequest private suspend fun prepareEnvironment( context: Context, environmentClient: EnvironmentClient ): Boolean { try { val roles = listOf( Role.builder() .setRoleType(Role.RoleType.DEVICE_POLICY_CONTROLLER) .build() ) val request = PrepareEnvironmentRequest.builder() .setRoles(roles) .setAdmin( ComponentName( context, DeviceAdminReceiver::class.java ) ) .build() val response = environmentClient.prepareEnvironment(request, null) val environment = response.environment val adpEnvironment = environment.androidDevicePolicyEnvironment val state = adpEnvironment.state val version = adpEnvironment.version return (state == READY && version == UP_TO_DATE) } catch (e: Exception) { Log.e(TAG, "Failed to prepare environment", e) } return false }
جافا
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE; import android.content.ComponentName; import android.content.Context; import android.util.Log; import androidx.annotation.NonNull; import com.google.android.managementapi.common.model.Role; import com.google.android.managementapi.environment.EnvironmentClient; import com.google.android.managementapi.environment.model.Environment; import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment; import com.google.android.managementapi.environment.model.PrepareEnvironmentRequest; import com.google.android.managementapi.environment.model.PrepareEnvironmentResponse; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; private void prepareEnvironment(Context context, EnvironmentClient environmentClient) { try { ImmutableListroles = new ImmutableList.Builder () .add(Role.builder() .setRoleType(Role.RoleType.DEVICE_POLICY_CONTROLLER) .build()) .build(); ComponentName adminComponent = new ComponentName( context, DeviceAdminReceiver.class ); PrepareEnvironmentRequest request = PrepareEnvironmentRequest.builder() .setRoles(roles) .setAdmin(adminComponent) .build(); ListenableFuture environmentFuture = environmentClient.prepareEnvironmentAsync(request, null); Futures.addCallback(environmentFuture, new FutureCallback () { @Override public void onSuccess(PrepareEnvironmentResponse response) { Environment environment = response.getEnvironment(); AndroidDevicePolicyEnvironment adpEnvironment = environment.getAndroidDevicePolicyEnvironment(); AndroidDevicePolicyEnvironment.State state = adpEnvironment.getState(); AndroidDevicePolicyEnvironment.Version version = adpEnvironment.getVersion(); if (state == READY && version == UP_TO_DATE) { // Environment is prepared; configure UUC policy using PolicyClient. } else { Log.w( TAG, "AMAPI environment was not ready: " + state + " - " + version ); } } @Override public void onFailure(@NonNull Throwable t) { Log.e(TAG, "Failed to prepare environment", t); } }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.e(TAG, "Exception preparing environment", e); } }
ضبط سياسة التحديث واستردادها ومحوها
بعد أن تصبح البيئة جاهزة، استخدِم PolicyClient (الذي تم إنشاؤه باستخدام
PolicyClientFactory.create(context)) لتطبيق Policy يحتوي على
قواعد UnifiedUpdatePolicy، أو فحص السياسة النشطة، أو محو سياسة UUC
من الجهاز.
اقتراح استخدام PolicyClient
يؤدي إنشاء مثيل PolicyClient إلى إنشاء قناة تواصل مع تطبيق ADP. لتحسين الأداء، ننصح بإنشاء مثيل واحد من PolicyClient باستخدام PolicyClientFactory.create() وتخزينه مؤقتًا لإعادة استخدامه في جميع أنحاء تطبيقك. تجنَّب إنشاء مثيل PolicyClient جديد أثناء
نشاط مثيل آخر، لأنّ ذلك قد يؤدي إلى إغلاق قناة الاتصال
الحالية، ما يؤدي إلى زيادة النفقات العامة وقد يؤدي إلى تسرُّب الموارد.
ضبط سياسة التحديث
لتطبيق قواعد UUC، أنشئ Policy.UnifiedUpdatePolicy يحتوي على قائمة عناصر
Rule، وأرفِقه بـ Policy داخل UpdatePolicyRequest،
واستدعِ updatePolicy (في Kotlin) أو updatePolicyFuture (في Java):
Kotlin
import android.util.Log import com.google.android.managementapi.policy.PolicyClient import com.google.android.managementapi.policy.model.Policy import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.UpdatePolicyRequest suspend fun setUucPolicy( policyClient: PolicyClient, rules: Iterable): Boolean { // Build the UnifiedUpdatePolicy and attach it to the overall Policy. val unifiedUpdatePolicy = Policy.UnifiedUpdatePolicy.builder() .setRules(rules) .build() val policy = Policy.builder() .setUnifiedUpdatePolicy(unifiedUpdatePolicy) .build() // Create the UpdatePolicyRequest. val updateRequest = UpdatePolicyRequest.builder() .setPolicy(policy) .build() // Apply the policy using PolicyClient within a CoroutineScope. return try { val updatedPolicy = policyClient.updatePolicy(updateRequest) Log.d(TAG, "Policy updated successfully: $updatedPolicy") true } catch (e: Exception) { Log.e(TAG, "Error updating policy: ${e.message}", e) false } }
جافا
import android.util.Log; import com.google.android.managementapi.policy.PolicyClient; import com.google.android.managementapi.policy.model.Policy; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.UpdatePolicyRequest; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.stream.Collectors; import java.util.stream.StreamSupport; ListenableFuturesetUucPolicy( PolicyClient policyClient, Iterable rules ) { // Build the UnifiedUpdatePolicy and attach it to the overall Policy. UnifiedUpdatePolicy unifiedUpdatePolicy = UnifiedUpdatePolicy.builder() .setRules( StreamSupport.stream(rules.spliterator(), false) .collect(Collectors.toList()) ) .build(); Policy policy = Policy.builder() .setUnifiedUpdatePolicy(unifiedUpdatePolicy) .build(); // Create the UpdatePolicyRequest. UpdatePolicyRequest updateRequest = UpdatePolicyRequest.builder() .setPolicy(policy) .build(); // Apply the policy using PolicyClient. try { ListenableFuture updateFuture = policyClient.updatePolicyFuture(updateRequest); return Futures.transform(updateFuture, updatedPolicy -> { Log.d(TAG, "Policy updated successfully: " + updatedPolicy); return true; }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.e(TAG, "Error updating policy: " + e.getMessage(), e); return Futures.immediateFuture(false); } }
استرداد سياسة التحديث النشطة
لفحص سياسة UUC النشطة على الجهاز، أنشئ GetPolicyRequest واستدعِ getPolicy (في Kotlin) أو getPolicyFuture (في Java). استخدِم
hasUnifiedUpdatePolicy() في Policy الذي تم عرضه للتحقّق مما إذا تم ضبط سياسة
UUC:
Kotlin
import android.util.Log import com.google.android.managementapi.policy.PolicyClient import com.google.android.managementapi.policy.model.GetPolicyRequest import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule suspend fun getActiveUucPolicy(policyClient: PolicyClient) { try { val getPolicyRequest = GetPolicyRequest.builder().build() val activePolicy = policyClient.getPolicy(getPolicyRequest) Log.i(TAG, "Policy version: ${activePolicy.version}") if (!activePolicy.hasUnifiedUpdatePolicy()) { Log.i(TAG, "No Unified Update Policy set.") return } val activeUucPolicy = activePolicy.unifiedUpdatePolicy val rules: List= activeUucPolicy.rules.toList() rules.forEachIndexed { index, rule -> val outcome = if (rule.hasOutcome()) rule.outcome.toString() else "[no outcome]" val predicate = if (rule.hasPredicate()) rule.predicate.toString() else "[no predicate]" Log.i(TAG, "Rule [$index] targets: ${rule.targets}") Log.i(TAG, "Rule [$index] outcome: $outcome") Log.i(TAG, "Rule [$index] predicate: $predicate") } } catch (e: Exception) { Log.e(TAG, "Error retrieving policy: ${e.message}", e) } }
جافا
import android.util.Log; import com.google.android.managementapi.policy.PolicyClient; import com.google.android.managementapi.policy.model.GetPolicyRequest; import com.google.android.managementapi.policy.model.Policy; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.List; import java.util.stream.Collectors; import java.util.stream.StreamSupport; void getActiveUucPolicy(PolicyClient policyClient) { try { GetPolicyRequest getPolicyRequest = GetPolicyRequest.builder().build(); ListenableFuturegetActivePolicy = policyClient.getPolicyFuture(getPolicyRequest); Futures.addCallback(getActivePolicy, new FutureCallback () { @Override public void onSuccess(Policy result) { if (!result.hasUnifiedUpdatePolicy()) { Log.i(TAG, "No Unified Update Policy set."); return; } UnifiedUpdatePolicy activeUucPolicy = result.getUnifiedUpdatePolicy(); List uucRules = StreamSupport.stream( activeUucPolicy.getRules().spliterator(), false) .collect(Collectors.toList()); for (int i = 0; i < uucRules.size(); i++) { Rule rule = uucRules.get(i); String outcome = rule.hasOutcome() ? rule.getOutcome().toString() : "[no outcome]"; String predicate = rule.hasPredicate() ? rule.getPredicate().toString() : "[no predicate]"; Log.i(TAG, "Rule [" + i + "] targets: " + rule.getTargets()); Log.i(TAG, "Rule [" + i + "] outcome: " + outcome); Log.i(TAG, "Rule [" + i + "] predicate: " + predicate); } } @Override public void onFailure(Throwable t) { Log.e(TAG, "Error retrieving policy", t); } }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.e(TAG, "Exception retrieving policy", e); } }
محو سياسة التحديث
لإزالة UnifiedUpdatePolicy من الجهاز بدون محو الحقول الأخرى في Policy، يمكنك استرداد Policy الحالي باستخدام getPolicy، واستدعاء currentPolicy.toBuilder().clearUnifiedUpdatePolicy().build()، وتطبيق Policy المعدَّل:
Kotlin
import android.util.Log import com.google.android.managementapi.policy.PolicyClient import com.google.android.managementapi.policy.model.GetPolicyRequest import com.google.android.managementapi.policy.model.UpdatePolicyRequest suspend fun clearUucPolicy(policyClient: PolicyClient): Boolean { try { // 1. Retrieve the current policy. val currentPolicy = policyClient.getPolicy( GetPolicyRequest.builder().build() ) if (!currentPolicy.hasUnifiedUpdatePolicy()) { Log.i(TAG, "Policy does not have a UnifiedUpdatePolicy to clear.") return true } // 2. Convert to a builder and clear the UnifiedUpdatePolicy field. val policyWithUucCleared = currentPolicy.toBuilder() .clearUnifiedUpdatePolicy() .build() // 3. Apply the modified Policy object. val updateRequest = UpdatePolicyRequest.builder() .setPolicy(policyWithUucCleared) .build() val updatedPolicy = policyClient.updatePolicy(updateRequest) return !updatedPolicy.hasUnifiedUpdatePolicy() } catch (e: Exception) { Log.e(TAG, "Error clearing policy: ${e.message}", e) return false } }
جافا
import android.util.Log; import com.google.android.managementapi.policy.PolicyClient; import com.google.android.managementapi.policy.model.GetPolicyRequest; import com.google.android.managementapi.policy.model.Policy; import com.google.android.managementapi.policy.model.UpdatePolicyRequest; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; ListenableFutureclearUucPolicy(PolicyClient policyClient) { try { ListenableFuture currentPolicyFuture = policyClient.getPolicyFuture(GetPolicyRequest.builder().build()); return Futures.transformAsync(currentPolicyFuture, currentPolicy -> { if (!currentPolicy.hasUnifiedUpdatePolicy()) { Log.i(TAG, "Policy does not have a UnifiedUpdatePolicy to clear."); return Futures.immediateFuture(true); } Policy policyWithUucCleared = currentPolicy.toBuilder() .clearUnifiedUpdatePolicy() .build(); UpdatePolicyRequest updateRequest = UpdatePolicyRequest.builder() .setPolicy(policyWithUucCleared) .build(); ListenableFuture updateFuture = policyClient.updatePolicyFuture(updateRequest); return Futures.transform( updateFuture, updatedPolicy -> !updatedPolicy.hasUnifiedUpdatePolicy(), MoreExecutors.directExecutor() ); }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.e(TAG, "Error clearing policy: " + e.getMessage(), e); return Futures.immediateFuture(false); } }
أولوية SystemUpdatePolicy في نظام التشغيل Android مفتوح المصدر (AOSP)
في وحدة التحكّم بسياسة الجهاز (DPC) المخصّصة، يتطلّب مستند تعريف معايير التوافق (CDD) مع Android من الأجهزة الالتزام بإعدادات SystemUpdatePolicy في مشروع Android المفتوح المصدر (AOSP) من خلال DevicePolicyManager.setSystemUpdatePolicy.
نتيجةً لذلك، يعتمد سلوك تحديثات OTA من المصنّع الأصلي للجهاز على ما إذا كان
SystemUpdatePolicy من مشروع Android المفتوح المصدر (AOSP) نشطًا على الجهاز:
- في حال ضبط كل من سياسة UUC وAOSP
SystemUpdatePolicy: تكون الأولوية لـ AOSPSystemUpdatePolicyفي ما يتعلّق بالتحديثات عبر اتصال لاسلكي التي يجريها المصنّع الأصلي للجهاز، ويتم تجاهل استهدافات UUCOS_UPDATE_WITH_API_LEVEL_CHANGEوOS_UPDATE_WITHOUT_API_LEVEL_CHANGE. يجب محو إعدادات AOSPSystemUpdatePolicyفي وحدة التحكّم بسياسة الجهاز المخصّصة إذا أردت أن تدير وحدة التحكّم في التحديثات تحديثات المصنّع الأصلي للجهاز عبر اتصال لاسلكي. - ضبط سياسة UUC فقط (تم محو سياسة
SystemUpdatePolicyفي مشروع Android المفتوح المصدر): يطبّق وكيل التحديثات عبر اتصال لاسلكي من المصنّع الأصلي للجهاز سياسة UUC على التحديثات عبر اتصال لاسلكي من المصنّع الأصلي للجهاز على الأجهزة المتوافقة. - الأجهزة التي لا تتيح بعد استخدام UUC لتحديثات OTA من المصنّع الأصلي للجهاز: على الأجهزة التي يتطلّب فيها تحديث OTA من المصنّع الأصلي للجهاز استخدام Android 17 (المستوى 37 من واجهة برمجة التطبيقات)، يمكنك استخدام UUC للتحكّم في تحديثات نظام Google Play (
GOOGLE_PLAY_SYSTEM_UPDATE) وخدمات نظام Google (GOOGLE_SYSTEM_SERVICESوSINGLE_APP) مع مواصلة استخدام AOSPSystemUpdatePolicyلتحديثات OTA من المصنّع الأصلي للجهاز.
يمكنك التحقّق مما إذا كان ملف شخصي SystemUpdatePolicy في نظام Android المفتوح المصدر (AOSP) نشطًا على الجهاز باستخدام
DevicePolicyManager:
Kotlin
import android.app.admin.DevicePolicyManager import android.content.Context fun Context.isSystemUpdatePolicyActive(): Boolean { val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as? DevicePolicyManager return dpm?.systemUpdatePolicy != null }
جافا
import android.app.admin.DevicePolicyManager; import android.content.Context; boolean isSystemUpdatePolicyActive(Context context) { DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); return dpm != null && dpm.getSystemUpdatePolicy() != null; }
أمثلة على ضبط السياسات
توضّح الأمثلة التالية كيفية إنشاء قواعد UUC في Kotlin وJava وتطبيقها
باستخدام دالة المساعدة setUucPolicy المحدّدة في
ضبط سياسة التحديث واستردادها ومحوها. لمعرفة معنى كل حقل، يُرجى الاطّلاع على فهم سياسات UUC. تتوفّر السيناريوهات نفسها بتنسيق JSON في عناصر التحكّم الموحّدة في التحديثات.
حظر تحديثات نظام التشغيل الرئيسية خلال ساعات العمل
تحظر القاعدة التالية تحديثات نظام التشغيل الرئيسية (OS_UPDATE_WITH_API_LEVEL_CHANGE)
من الساعة 09:00 إلى الساعة 17:00، من الاثنين إلى الجمعة:
Kotlin
import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE import java.time.DayOfWeek import java.time.LocalTime // 1. Define the target (OS update with API level change). val target = Target.builder() .setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE) .build() // 2. Define the predicate (Monday through Friday, 09:00 to 17:00). val predicate = Predicate.builder() .setDaysOfWeek( listOf( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build() // 3. Define the outcome (BLOCK). val outcome = Outcome.builder() .setOutcomeType(BLOCK) .build() // 4. Assemble and apply the rule. val rule = Rule.builder() .setTargets(listOf(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Block Policy") .build() setUucPolicy(policyClient, listOf(rule))
جافا
import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target; import java.time.DayOfWeek; import java.time.LocalTime; import java.util.List; // 1. Define the target (OS update with API level change). Target target = Target.builder() .setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE) .build(); // 2. Define the predicate (Monday through Friday, 09:00 to 17:00). Predicate predicate = Predicate.builder() .setDaysOfWeek( List.of( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build(); // 3. Define the outcome (BLOCK). Outcome outcome = Outcome.builder() .setOutcomeType(BLOCK) .build(); // 4. Assemble and apply the rule. Rule rule = Rule.builder() .setTargets(List.of(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Block Policy") .build(); setUucPolicy(policyClient, List.of(rule));
فرض تحديثات نظام التشغيل حسب عمر التحديث
تفرض القاعدة التالية تحديثات نظام التشغيل الرئيسية (OS_UPDATE_WITH_API_LEVEL_CHANGE)
مع حد أقصى لعمر التحديث يبلغ 7 أيام:
Kotlin
import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.FORCE import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE import java.time.Duration val target = Target.builder() .setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE) .build() val predicate = Predicate.builder() .setUpdateAgeUpperBound(Duration.ofDays(7)) .build() val outcome = Outcome.builder() .setOutcomeType(FORCE) .build() val rule = Rule.builder() .setTargets(listOf(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Force Policy") .build() setUucPolicy(policyClient, listOf(rule))
جافا
import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.FORCE; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target; import java.time.Duration; import java.util.List; Target target = Target.builder() .setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE) .build(); Predicate predicate = Predicate.builder() .setUpdateAgeUpperBound(Duration.ofDays(7)) .build(); Outcome outcome = Outcome.builder() .setOutcomeType(FORCE) .build(); Rule rule = Rule.builder() .setTargets(List.of(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Force Policy") .build(); setUucPolicy(policyClient, List.of(rule));
حظر تحديثات تطبيق واحد من تطبيقات الخدمات التابعة لنظام التشغيل من Google
للتحكّم في حزمة معيّنة تشكّل جزءًا من خدمات نظام Google، مثل
Android System WebView (com.google.android.webview)، يجب ضبط نوع الاستهداف على
SINGLE_APP وتقديم عنصر SingleApp يتضمّن اسم الحزمة:
Kotlin
import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.SingleApp import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.SINGLE_APP import java.time.DayOfWeek import java.time.LocalTime val target = Target.builder() .setTargetType(SINGLE_APP) .setSingleApp( SingleApp.builder() .setPackageName("com.google.android.webview") .build() ) .build() val predicate = Predicate.builder() .setDaysOfWeek( listOf( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build() val outcome = Outcome.builder() .setOutcomeType(BLOCK) .build() val rule = Rule.builder() .setTargets(listOf(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Block Webview Policy") .build() setUucPolicy(policyClient, listOf(rule))
جافا
import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.SINGLE_APP; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.SingleApp; import java.time.DayOfWeek; import java.time.LocalTime; import java.util.List; Target target = Target.builder() .setTargetType(SINGLE_APP) .setSingleApp( SingleApp.builder() .setPackageName("com.google.android.webview") .build() ) .build(); Predicate predicate = Predicate.builder() .setDaysOfWeek( List.of( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build(); Outcome outcome = Outcome.builder() .setOutcomeType(BLOCK) .build(); Rule rule = Rule.builder() .setTargets(List.of(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Block Webview Policy") .build(); setUucPolicy(policyClient, List.of(rule));
دمج قواعد متعددة في جميع أهداف التعديل
بما أنّه يتم تقييم القواعد بالترتيب، يمكنك دمج قواعد متعددة لحظر التحديثات خلال فترات زمنية محدّدة (مثل ساعات العمل أو قبل تاريخ مستهدف في التقويم) وفرض التحديثات خارج هذه الفترات الزمنية.
يطبّق المثال التالي قاعدتَين متتاليتَين على جميع الفئات المستهدَفة الأربع (OS_UPDATE_WITH_API_LEVEL_CHANGE وOS_UPDATE_WITHOUT_API_LEVEL_CHANGE وGOOGLE_SYSTEM_SERVICES وGOOGLE_PLAY_SYSTEM_UPDATE):
- حظر جميع التحديثات خلال ساعات العمل (من الاثنين إلى الجمعة، من الساعة 09:00 إلى الساعة 17:00)
- خارج ساعات العمل، يمكنك فرض التحديثات التي كانت متاحة لمدة تصل إلى 7 أيام.
Kotlin
import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.FORCE import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.GOOGLE_PLAY_SYSTEM_UPDATE import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.GOOGLE_SYSTEM_SERVICES import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITHOUT_API_LEVEL_CHANGE import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE import java.time.DayOfWeek import java.time.Duration import java.time.LocalTime // 1. Define the targets to reuse across both rules. val allTargets = listOf( Target.builder().setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE).build(), Target.builder().setTargetType(OS_UPDATE_WITHOUT_API_LEVEL_CHANGE).build(), Target.builder().setTargetType(GOOGLE_SYSTEM_SERVICES).build(), Target.builder().setTargetType(GOOGLE_PLAY_SYSTEM_UPDATE).build() ) // 2. Rule 1: Block updates during business hours. val blockPredicate = Predicate.builder() .setDaysOfWeek( listOf( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build() val blockOutcome = Outcome.builder() .setOutcomeType(BLOCK) .build() val rule1 = Rule.builder() .setTargets(allTargets) .setPredicate(blockPredicate) .setOutcome(blockOutcome) .setId("Block Policy - rule1") .build() // 3. Rule 2: Force updates within 7 days of availability. val forcePredicate = Predicate.builder() .setUpdateAgeUpperBound(Duration.ofDays(7)) .build() val forceOutcome = Outcome.builder() .setOutcomeType(FORCE) .build() val rule2 = Rule.builder() .setTargets(allTargets) .setPredicate(forcePredicate) .setOutcome(forceOutcome) .setId("Force Policy - rule2") .build() setUucPolicy(policyClient, listOf(rule1, rule2))
جافا
import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.FORCE; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.GOOGLE_PLAY_SYSTEM_UPDATE; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.GOOGLE_SYSTEM_SERVICES; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITHOUT_API_LEVEL_CHANGE; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target; import java.time.DayOfWeek; import java.time.Duration; import java.time.LocalTime; import java.util.List; // 1. Define the targets to reuse across both rules. ListallTargets = List.of( Target.builder().setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE).build(), Target.builder().setTargetType(OS_UPDATE_WITHOUT_API_LEVEL_CHANGE).build(), Target.builder().setTargetType(GOOGLE_SYSTEM_SERVICES).build(), Target.builder().setTargetType(GOOGLE_PLAY_SYSTEM_UPDATE).build() ); // 2. Rule 1: Block updates during business hours. Predicate blockPredicate = Predicate.builder() .setDaysOfWeek( List.of( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build(); Outcome blockOutcome = Outcome.builder() .setOutcomeType(BLOCK) .build(); Rule rule1 = Rule.builder() .setTargets(allTargets) .setPredicate(blockPredicate) .setOutcome(blockOutcome) .setId("Block Policy - rule1") .build(); // 3. Rule 2: Force updates within 7 days of availability. Predicate forcePredicate = Predicate.builder() .setUpdateAgeUpperBound(Duration.ofDays(7)) .build(); Outcome forceOutcome = Outcome.builder() .setOutcomeType(FORCE) .build(); Rule rule2 = Rule.builder() .setTargets(allTargets) .setPredicate(forcePredicate) .setOutcome(forceOutcome) .setId("Force Policy - rule2") .build(); setUucPolicy(policyClient, List.of(rule1, rule2));
حظر التحديثات حتى تاريخ معيّن في التقويم
يمكنك استخدام setDateLowerBound وsetDateUpperBound على Predicate.Builder
لتقييد التحديثات أو السماح بها ضمن نطاق زمني محدّد في التقويم في
المنطقة الزمنية المحلية للجهاز:
Kotlin
import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate import java.time.LocalDate val blockUntilDateRule = Rule.builder() .setId("block_until_date") .setTargets(allTargets) .setPredicate( Predicate.builder() .setDateUpperBound(LocalDate.of(2026, 3, 14)) .build() ) .setOutcome(Outcome.builder().setOutcomeType(BLOCK).build()) .build() setUucPolicy(policyClient, listOf(blockUntilDateRule))
جافا
import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate; import java.time.LocalDate; import java.util.List; Rule blockUntilDateRule = Rule.builder() .setId("block_until_date") .setTargets(allTargets) .setPredicate( Predicate.builder() .setDateUpperBound(LocalDate.of(2026, 3, 14)) .build() ) .setOutcome(Outcome.builder().setOutcomeType(BLOCK).build()) .build(); setUucPolicy(policyClient, List.of(blockUntilDateRule));
معالجة الأخطاء
في حال تعذّر إجراء طلب PolicyClient، تتلقّى وحدة التحكّم في سياسة الجهاز (DPC) المخصّصة استثناءً (يتم طرحه
مباشرةً من خلال طريقتَي Kotlin suspend getPolicy وupdatePolicy، أو
يتم تضمينه كسبب لـ ExecutionException في getPolicyFuture و
updatePolicyFuture). تشمل الاستثناءات الشائعة ما يلي:
-
ApiLevelException: يعمل الجهاز بإصدار Android أقدم من Android 13 (المستوى 33 لواجهة برمجة التطبيقات). -
DeviceNotManagedException: لا تتم إدارة الجهاز كجهاز مُدار بالكامل (مالك الجهاز) أو كجهاز مملوك للشركة يتضمّن ملف عمل (COPE). -
AndroidDevicePolicyAppNotInstalledExceptionأوAndroidDevicePolicyAppDisabledExceptionأوAndroidDevicePolicyAppNotUpdatedException: تطبيق ADP غير مثبَّت أو تم إيقافه أو يشغّل إصدارًا قديمًا لا يتوافق معPolicyClient. اتصل بالرقمprepareEnvironmentلتثبيت تطبيق ADP أو تحديثه. InvalidArgumentException: الطلب غير صالح أو يحتوي على قواعد سياسة غير صالحة (على سبيل المثال، حذف قاعدةidأو استخدام قاعدةidمكرّرة أو ضبط الدقائق أو الثواني على حدّ زمني معيّن أو تحديد مدة عمر التحديث التي لا تكون من مضاعفات 24 ساعة، بما في ذلك الأهداف المكرّرة أو ضبطOutcomeType.DEFAULTبشكل صريح في قاعدة).SecurityException: لا يُسمح للتطبيق الذي يرسل الطلب بإدارة سياسة الجهاز.-
TimeoutException(java.util.concurrent.TimeoutException) أوInternalExceptionأو فئة فرعية أخرى منAmapiSdkException: حدث خطأ مؤقت في الاتصال بين العمليات (IPC) أو خطأ داخلي أثناء الاتصال بتطبيق ADP. أعِد محاولة الاتصال باستخدام استراتيجية التراجع الأسي.
استراتيجيات إعادة المحاولة
بالنسبة إلى الاستثناءات الناتجة عن حالة عابرة (مثل TimeoutException أو
InternalException)، يمكنك تنفيذ استراتيجية إعادة المحاولة باستخدام خوارزمية الرقود الأسي الثنائي:
- بعد حدوث الخطأ الأول، انتظِر لمدة 5 ثوانٍ قبل إعادة المحاولة.
- يمكنك زيادة مدة التأخير بشكل كبير في كل محاولة لاحقة (10 ثوانٍ، 20 ثانية، وما إلى ذلك) حتى الوصول إلى الحد الأقصى لعدد المحاولات.