این راهنما توضیح میدهد که چگونه از کیت توسعه نرمافزار Android Management API (AMAPI) در «کنترلکننده خطمشی دستگاه» (DPC) سفارشی برای پیکربندی کنترلهای بهروزرسانی یکپارچه (UUC) در دستگاههای متعلق به شرکت استفاده کنید.
بااستفاده از کیت توسعه نرمافزار AMAPI، DPC سفارشی شما خطمشی UUC را مستقیماً به برنامه Android Device Policy (ADP) در دستگاه ارسال میکند. ADP قوانین خطمشی را دربرابر وضعیت فعلی دستگاه ارزیابی میکند و به Google Play و کارخواه OEM OTA دستور میدهد که چگونه بهروزرسانیهای معلقه را مدیریت کنند.
قبلاز شروع، کنترلهای بهروزرسانی یکپارچه را بخوانید تا با نحوه عملکرد قوانین، اهداف، گزارهها، و نتایج و محدودیتهای اعمالشده بر همه ادغامهای UUC آشنا شوید.
پیشنیازها
قبلاز ادغام UUC در DPC سفارشیتان، الزامات زیر را تأیید کنید:
- دستگاه متعلق به شرکت است و بهعنوان دستگاه کاملاً مدیریتشده یا با نمایه کاری در دستگاه متعلق به شرکت پیکربندی شده است.
- «کنترلکننده خطمشی دستگاه» سفارشی شما با کیت توسعه نرمافزار AMAPI ادغام شده است.
- دستگاه بااستفاده از Google Play EMM API ثبت شده است.
- دستگاه حداقل ملزومات نسخه را برای
حالت مدیریت خود و هر هدف بهروزرسانی که میخواهید کنترل کنید برآورده میکند:
- دستگاههای کاملاً مدیریتشده (مالک دستگاه): Android 13 (سطح میانای برنامهسازی کاربردی ۳۳) یا بالاتر.
- دستگاههای تحت مالکیت شرکت با نمایه کاری (COPE): Android 15 (سطح API ۳۵) یا بالاتر.
ادغام با کیت توسعه نرمافزار AMAPI در «کنترلکننده خطمشی دستگاه» سفارشی شما
برای پیکربندی خطمشی UUC در دستگاه، DPC سفارشی شما باید با AMAPI SDK ادغام شود. برای دستورالعملهای مربوط به افزودن کتابخانه و پیکربندی مانیفست برنامهتان، راهنمای ادغام AMAPI SDK را ببینید.
مراحل پیکربندی «کنترلهای بهروزرسانی یکپارچه»
برای پیکربندی خطمشیهای UUC از «کنترلکننده خطمشی دستگاه» سفارشی، مطمئن شوید که محیط کارخواه دروندستگاهی قبلاز ارسال درخواستهای خطمشی به 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); } }
آمادهسازی محیط کارخواه
اگر محیط دستگاه آماده یا بهروز نیست، قبلاز استفاده از PolicyClient،
prepareEnvironment را فراخوانی کنید.
وقتی از DPC سفارشی با Role.RoleType.DEVICE_POLICY_CONTROLLER فراخوانی شود و
نام مؤلفه DeviceAdminReceiver DPC شما به setAdmin() ارسال شود،
prepareEnvironment برنامه ADP را بیصدا نصب میکند (اگر قبلاً نصب نشده باشد)
و برنامه ADP و «فروشگاه Google Play» را بدون تعامل کاربر بهروز میکند. برای اطلاعات بیشتر درباره آمادهسازی محیط در جریانهای DPC سفارشی، به آمادهسازی محیط و ثبتنام کاربر مراجعه کنید.
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); } }
تقدم AOSP SystemUpdatePolicy
در «کنترلکننده خطمشی دستگاه» سفارشی، «سند تعریف سازگاری Android» (CDD)
دستگاهها را ملزم میکند که از AOSP SystemUpdatePolicy تنظیمشده ازطریق
DevicePolicyManager.setSystemUpdatePolicy پیروی کنند.
درنتیجه، رفتار بهروزرسانی OTA سازنده اصلی تجهیزات به این بستگی دارد که آیا AOSP
SystemUpdatePolicy در دستگاه فعال است یا نه:
- هم خطمشی UUC و هم AOSP
SystemUpdatePolicyتنظیم شدهاند: AOSPSystemUpdatePolicyبرای بهروزرسانیهای OTA سازنده اصلی سختافزار اولویت دارد و هدفهایOS_UPDATE_WITH_API_LEVEL_CHANGEوOS_UPDATE_WITHOUT_API_LEVEL_CHANGEUUC نادیده گرفته میشوند. اگر میخواهید UUC بهروزرسانیهای OEM OTA را مدیریت کند،SystemUpdatePolicyAOSP را در DPC سفارشیتان پاک کنید. - فقط خطمشی UUC تنظیم شده است (AOSP
SystemUpdatePolicyپاک شده است): عامل OTA سازنده اصلی تجهیزات خطمشی UUC را برای بهروزرسانیهای OTA سازنده اصلی تجهیزات در دستگاههای پشتیبانیشده اعمال میکند. - دستگاههایی که هنوز از UUC برای بهروزرسانیهای OTA سازنده تجهیزات اصلی پشتیبانی نمیکنند: در دستگاههایی که
پشتیبانی OTA سازنده تجهیزات اصلی به Android 17 (سطح API ۳۷) نیاز دارد، میتوانید از UUC برای
کنترل بهروزرسانیهای سیستم Google Play (
GOOGLE_PLAY_SYSTEM_UPDATE) و سرویسهای سیستم Google (GOOGLE_SYSTEM_SERVICESوSINGLE_APP) استفاده کنید و درعینحال به استفاده از AOSPSystemUpdatePolicyبرای بهروزرسانیهای OTA سازنده تجهیزات اصلی ادامه دهید.
بااستفاده از DevicePolicyManager میتوانید بررسی کنید که آیا AOSP SystemUpdatePolicy در دستگاه فعال است یا نه:
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 تعریفشده در تنظیم، بازیابی، و پاک کردن خطمشی بهروزرسانی را نشان میدهد. برای
معنی هر فیلد، به آشنایی با خطمشیهای «تبلیغات نصب برنامه» مراجعه کنید. همین سناریوها بهصورت JSON در
کنترلهای بهروزرسانی یکپارچه دردسترس است.
مسدود کردن بهروزرسانیهای اصلی سیستمعامل درطول ساعت کاری
قانون زیر بهروزرسانیهای اصلی سیستمعامل (OS_UPDATE_WITH_API_LEVEL_CHANGE)
را از ساعت ۹:۰۰ تا ۱۷:۰۰، از دوشنبه تا جمعه مسدود میکند:
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) را
با حد بالای سن بهروزرسانی ۷ روز اجباری میکند:
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) اعمال میکند:
- مسدود کردن همه بهروزرسانیها درطول ساعت کاری (دوشنبه تا جمعه، ۹:۰۰ تا ۱۷:۰۰).
- خارج از ساعت کاری، بهروزرسانیهایی را که تا ۷ روز دردسترس بودهاند اجباری کنید.
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 (سطح میانای برنامهسازی کاربردی ۳۳) را اجرا میکند.DeviceNotManagedException: دستگاه بهعنوان دستگاه کاملاً مدیریتشده (مالک دستگاه) یا دستگاه تحت مالکیت شرکت با نمایه کاری (COPE) مدیریت نمیشود.AndroidDevicePolicyAppNotInstalledException،AndroidDevicePolicyAppDisabledException، یاAndroidDevicePolicyAppNotUpdatedException: برنامه ADP نصب نشده است، غیرفعال است، یا نسخه قدیمیتری را اجرا میکند که ازPolicyClientپشتیبانی نمیکند. برای نصب یا بهروزرسانی برنامه ADP، باprepareEnvironmentتماس بگیرید.InvalidArgumentException: درخواست بدشکل است یا حاوی قوانین خطمشی نامعتبر است (برای مثال، حذف قانونidیا استفاده ازidتکراری، تنظیم دقیقه یا ثانیه در محدوده زمان روز، مشخص کردن مدت زمان سن بهروزرسانی که مضربی از ۲۴ ساعت نیست، ازجمله هدفهای تکراری، یا تنظیم صریحOutcomeType.DEFAULTدر قانون).SecurityException: برنامه برقراری تماس برای مدیریت خطمشی دستگاه مجاز نیست.-
TimeoutException(java.util.concurrent.TimeoutException)،InternalException، یا زیرکلاس دیگری ازAmapiSdkException: خطای داخلی یا IPC گذرا هنگام برقراری ارتباط با برنامه ADP رخ داده است. تماس را بااستفاده از استراتژی عقبنشینی نمایی تکرار کنید.
استراتژیهای امتحان مجدد
برای استثناهای ناشی از شرایط گذرا (مانند TimeoutException یا
InternalException)، راهبرد تکرار مجدد با عقبگرد نمایی را اجرا کنید:
- پساز اولین شکست، ۵ ثانیه صبر کنید و سپس دوباره امتحان کنید.
- در هر تلاش بعدی، تأخیر را بهصورت تصاعدی (۱۰ ثانیه، ۲۰ ثانیه، و غیره) تا حداکثر تعداد تلاشها افزایش دهید.