تتيح ميزة أدوار التطبيقات لمشرف تكنولوجيا المعلومات منح امتيازات خاصة لتطبيق مُدار على جهاز Android. من خلال منح دور محدّد، يمكن إعفاء التطبيق من قيود الطاقة والتشغيل في الخلفية والتعليق والإيقاف المؤقت (على Android 14 والإصدارات الأحدث) وإيقاف عناصر تحكّم المستخدم (أي الإجراءات التي يتّخذها المستخدم مثل الإيقاف الإجباري ومحو بيانات التطبيق) (على Android 11 والإصدارات الأحدث)، ما يسمح له بأداء وظيفته الأساسية بدون انقطاع. بالإضافة إلى ذلك، يمكن إشعار التطبيق بالأدوار المخصّصة له، ما يسمح له ببدء التشغيل بدون تدخّل المستخدم.
للاطّلاع على قائمة بأدوار التطبيقات المتاحة والامتيازات الخاصة الممنوحة لكل دور، يُرجى الانتقال إلى RoleType.
المتطلبات الأساسية
تتم إدارة الجهاز من خلال إدارة الخدمات الجوّالة للمؤسسات (EMM) المستندة إلى AMAPI (لا تتوفّر إدارة الخدمات الجوّالة للمؤسسات التي تستخدم وحدة التحكّم بسياسة الجهاز المخصّصة).
تجهيز تطبيقك لاستخدام الميزة
لا يلزم التكامل مع حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات لإدارة Android إلا إذا كان التطبيق يريد أن يتم إبلاغه بأدواره المخصّصة التي تسمح له بتشغيل نفسه (أي التشغيل التلقائي بدون تفاعل المستخدم).
الدمج مع حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات AMAPI في تطبيقك
يمكنك العثور على مزيد من المعلومات حول حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات AMAPI وكيفية إضافتها إلى تطبيقك في دليل دمج حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات AMAPI.
إضافة البيانات الوصفية المطلوبة إلى ملف بيان التطبيق
يحتاج تطبيق Android Device Policy (ADP) إلى معرفة ComponentName لفئتك
التي تنفّذ NotificationReceiverService لإعلام تطبيقك
بالأدوار المخصّصة له. يجب وضع علامة على خدمتك في AndroidManifest.xml بشكل مناسب حتى
يتمكّن ADP من اكتشافها تلقائيًا.
- يجب أن يتضمّن تطبيقك خدمة واحدة فقط هي
enabledوأن يحتوي علىmeta-dataمعandroid:nameيساويcom.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES - يجب ضبط السمة
android:exportedعلىtrueفي هذه الخدمة - يجب ضبط السمة
android:valueلـmeta-dataعلى سلسلة فارغة
<service
android:name=".MyNotificationReceiverService"
android:exported="true">
<meta-data android:name="com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_APP_ROLES" android:value="" />
</service>
إذا كنت تختبر دور COMPANION_APP، عليك أيضًا إضافة meta-data التالي إلى خدمتك حتى يتمكّن تطبيق سياسة جهاز Android من إرسال تحديثات حالة الأوامر المحلية إلى تطبيقك:
<meta-data android:name="com.google.android.managementapi.notification.NotificationReceiverService.SERVICE_COMMAND_STATUS" android:value="" />
أنشئ خدمة تمدّد NotificationReceiverService (أو عدِّل الخدمة الحالية)
أنشئ NotificationReceiverService الحالي أو حدِّثه ونفِّذ
AppRolesListener للاستماع إلى الأدوار المخصّصة لتطبيقك. لا يلزم سوى
getAppRolesListener() للاستماع إلى الأدوار المخصّصة لتطبيقك. إذا تم تخصيص دور COMPANION_APP لتطبيقك، عليك أيضًا تنفيذ
getCommandListener():
import android.util.Log
import com.google.android.managementapi.approles.AppRolesListener
import com.google.android.managementapi.approles.model.AppRolesSetRequest
import com.google.android.managementapi.approles.model.AppRolesSetResponse
import com.google.android.managementapi.commands.CommandListener
import com.google.android.managementapi.commands.model.Command
import com.google.android.managementapi.notification.NotificationReceiverService
class MyNotificationReceiverService : NotificationReceiverService() {
// If your app wants to listen for roles assigned
override fun getAppRolesListener(): AppRolesListener =
object : AppRolesListener {
override fun onAppRolesSet(request: AppRolesSetRequest): AppRolesSetResponse {
val roleTypes = request.roles.map { role -> role.roleType }
Log.i(TAG, "onAppRolesSet: $roleTypes")
return AppRolesSetResponse.getDefaultInstance()
}
}
// If your app wants to listen for local command status updates
// Only relevant for COMPANION_APP role
override fun getCommandListener(): CommandListener {
return object : CommandListener {
override fun onCommandStatusChanged(command: Command) {
Log.i(TAG, "onCommandStatusChanged")
}
}
}
private companion object {
const val TAG = "MyNotificationReceiverService"
}
}
يمكن إرسال إشعارات إلى تطبيقك عدة مرات في حال تغيّر أدواره عدة مرات. في حال إزالة جميع الأدوار، سيستمر إرسال إشعار إلى تطبيقك يتضمّن قائمة فارغة بالأدوار. سيؤدي هذا الإشعار إلى إخراج تطبيقك من حالة الإيقاف، بالإضافة إلى
الإعفاءات الممنوحة لتطبيقك، يمكن لتطبيقك تشغيل نفسه بدون أي
تفاعل من المستخدم. بفضل إشعار أدوار التطبيق والإعفاءات، يمكن لتطبيقك
الاستماع إلى عمليات بث ACTION_BOOT_COMPLETED. إذا كان تطبيقك يعتمد على
إعداداته المُدارة لتشغيل نفسه، يُرجى الاطّلاع على
إعداد الإعدادات المُدارة لمعرفة كيفية قراءة التغييرات
والاستماع إليها.
بدءًا من الإصدار 1.9.0 من حزمة تطوير البرامج (SDK) لواجهة برمجة التطبيقات AMAPI، يتضمّن كل دور في
AppRolesSetRequest أيضًا Role.ExtraCapabilities التي منحها مشرف تكنولوجيا المعلومات
في السياسة. على سبيل المثال، يمكن للتطبيق المصاحب التحقّق مما إذا كان مسموحًا له بإصدار أمر محو البيانات على الجهاز:
import com.google.android.managementapi.approles.model.AppRolesSetRequest
import com.google.android.managementapi.approles.model.AppRolesSetResponse
import com.google.android.managementapi.common.model.Role
...
override fun onAppRolesSet(request: AppRolesSetRequest): AppRolesSetResponse {
val canWipeLocally =
request.roles.any { role ->
role.roleType == Role.RoleType.COMPANION_APP &&
role.extraCapabilities.localDeviceWipeCommand ==
Role.ExtraCapabilities.LocalDeviceWipeCommand.LOCAL_DEVICE_WIPE_COMMAND_ALLOWED
}
Log.i(TAG, "onAppRolesSet: canWipeLocally=$canWipeLocally")
return AppRolesSetResponse.getDefaultInstance()
}
يمكن لمشرف تكنولوجيا المعلومات فقط منح إمكانات إضافية. إذا ضبطت extraCapabilities
على دور تم تمريره إلى EnvironmentClient، سيتعذّر تنفيذ الطلب مع ظهور
InvalidArgumentException.
إعداد الجهاز باستخدام سياسات أدوار التطبيقات
يمكن لمطوّري التطبيقات اختبار تعيين أدوار التطبيقات لتطبيقاتهم باستخدام حلّ "إدارة الخدمات الجوّالة للمؤسسات" (EMM) أو اتّباع دليل البدء السريع لواجهة Android Management API. تتيح لك ورقة ملاحظات Colab في AMAPI تسجيل مؤسسة وإنشاء سياسة وإعداد جهاز.
ضبط السياسة لتطبيقك باستخدام أدوار التطبيق
اضبط policy باستخدام أدوار التطبيق التي من المفترض أن يتضمّنها تطبيقك باستخدام
ApplicationPolicy.roles.
يوضّح المثال التالي كيفية ضبط الدور لتطبيقات MTD:
{
"applications": [
{
"packageName": "com.example.mtd",
"installType": "FORCE_INSTALLED",
"roles": [
{ "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
]
}
]
}
يتيح الدور COMPANION_APP فقط استخدام
extraCapabilities. للسماح للتطبيق المصاحب
بحجب بيانات الجهاز أو ملف العمل على الجهاز، اضبط
extraCapabilities.localDeviceWipeCommand على
LOCAL_DEVICE_WIPE_COMMAND_ALLOWED لهذا الدور.
قبل منح الأدوار على النحو المحدّد في السياسة، سيتحقّق النظام من تطابق الملف المرجعي لشهادة مفتاح توقيع التطبيق على الجهاز مع الملف المرجعي من "متجر Google Play".
إذا كانت البصمة مختلفة، لن يتم منح الأدوار إلى التطبيق وسيتم إبلاغ إدارة الخدمات الجوّالة للمؤسسات (EMM) بعدم امتثال NonComplianceReason.APP_SIGNING_CERT_MISMATCH.
{
"applications": [
{
"packageName": "com.example.mtd",
"installType": "FORCE_INSTALLED",
"signingKeyCerts": [
{ "signingKeyCertFingerprintSha256": "base64-encoded-sha256" }
],
"roles": [
{ "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
]
}
]
}
إذا كان تطبيقك يتضمّن إعدادات مُدارة، يمكن لمشرف تكنولوجيا المعلومات ضبط إعدادات أولية
لـ restriction ذات الصلة في سياسة التطبيق:
{
"applications": [
{
"packageName": "com.example.mtd",
"installType": "FORCE_INSTALLED",
"roles": [
{ "roleType": "MOBILE_THREAT_DEFENSE_ENDPOINT_DETECTION_RESPONSE" }
],
"managedConfiguration": {
"<key>": "<value>"
}
}
]
}
التحقّق من حالة الإعفاء من متطلبات البطارية
يتم تلقائيًا إعفاء التطبيقات التي تؤدي دور "الحماية من التهديدات على الأجهزة الجوّالة" (MTD) من القيود العادية المفروضة على استهلاك الطاقة في الخلفية. ومع ذلك، يتم تنفيذ هذا الإعفاء من خلال "مجموعة تطبيقات وضع الاستعداد" بدلاً من "القائمة المسموح بها لتوفير الطاقة" في النظام.
للتحقّق مما إذا كان إعفاء التطبيق نشطًا:
import android.app.usage.UsageStatsManager
import android.content.Context
// UsageStatsManager.STANDBY_BUCKET_EXEMPTED is annotated as a @SystemApi. We can redefine it for clarity.
// Define this at the top level of your file, or inside a companion object
private const val STANDBY_BUCKET_EXEMPTED = 5
private fun isAppExemptedFromAppStandbyBucket(): Boolean =
(getSystemService(Context.USAGE_STATS_SERVICE) as? UsageStatsManager)
?.appStandbyBucket == STANDBY_BUCKET_EXEMPTED