دفترچه آشپزی دستگاه‌های اختصاصی

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

برنامه‌های سفارشی Home

اگر درحال توسعه برنامه‌ای برای جایگزینی صفحه اصلی و «راه‌انداز» Android هستید، این دستورالعمل‌ها مفید هستند.

برنامه صفحه اصلی باشد

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

همه برنامه‌های صفحه اصلی دسته هدف CATEGORY_HOME را مدیریت می‌کنند—این نحوه تشخیص برنامه صفحه اصلی توسط سیستم است. برای تبدیل شدن به برنامه صفحه اصلی پیش‌فرض، یکی از فعالیت‌های برنامه‌تان را به‌عنوان گرداننده هدف «صفحه اصلی» ترجیحی تنظیم کنید، با فراخوانی DevicePolicyManager.addPersistentPreferredActivity() همان‌طور که در مثال زیر نشان داده شده است:

کاتلین

// Create an intent filter to specify the Home category.
val filter = IntentFilter(Intent.ACTION_MAIN)
filter.addCategory(Intent.CATEGORY_HOME)
filter.addCategory(Intent.CATEGORY_DEFAULT)

// Set the activity as the preferred option for the device.
val activity = ComponentName(context, KioskModeActivity::class.java)
val dpm = context.getSystemService(Context.DEVICE_POLICY_SERVICE)
        as DevicePolicyManager
dpm.addPersistentPreferredActivity(adminName, filter, activity)

جاوا

// Create an intent filter to specify the Home category.
IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
filter.addCategory(Intent.CATEGORY_HOME);
filter.addCategory(Intent.CATEGORY_DEFAULT);

// Set the activity as the preferred option for the device.
ComponentName activity = new ComponentName(context, KioskModeActivity.class);
DevicePolicyManager dpm =
    (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
dpm.addPersistentPreferredActivity(adminName, filter, activity);

همچنان باید فیلتر قصد را در فایل مانیفست برنامه‌تان اعلام کنید، همان‌طور که در تکه‌کد XML زیر نشان داده شده است:

<activity
        android:name=".KioskModeActivity"
        android:label="@string/kiosk_mode"
        android:launchMode="singleInstance"
        android:excludeFromRecents="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.HOME"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

معمولاً نمی‌خواهید برنامه راه‌اندازتان در صفحه «نمای کلی» نشان داده شود. بااین‌حال، لازم نیست excludeFromRecents را به اعلام فعالیت اضافه کنید زیرا «راه‌انداز Android» فعالیت راه‌اندازی‌شده اولیه را وقتی سیستم در حالت قفل وظایف اجرا می‌شود پنهان می‌کند.

نمایش تکالیف جداگانه

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

کیوسک‌های عمومی

این دستورالعمل‌ها برای دستگاه‌های بدون مراقب در فضاهای عمومی عالی هستند، اما می‌توانند به بسیاری از کاربران دستگاه اختصاصی نیز کمک کنند تا روی کارهایشان تمرکز کنند.

قفل کردن دستگاه

برای اطمینان از اینکه دستگاه‌ها برای هدف موردنظرشان استفاده می‌شوند، می‌توانید محدودیت‌های کاربر فهرست‌شده در جدول ۱ را اضافه کنید.

جدول ۱. محدودیت‌های کاربر برای دستگاه‌های کیوسک
محدودیت کاربر شرح
DISALLOW_FACTORY_RESET از بازنشانی دستگاه به پیش‌فرض‌های کارخانه توسط کاربر دستگاه جلوگیری می‌کند. سرپرستان دستگاه‌های کاملاً مدیریت‌شده و کاربر اصلی می‌توانند این محدودیت را تنظیم کنند.
DISALLOW_SAFE_BOOT از راه‌اندازی دستگاه در حالت ایمن توسط کاربر دستگاه جلوگیری می‌کند. در این حالت، سیستم برنامه‌تان را به‌طور خودکار راه‌اندازی نمی‌کند. سرپرستان دستگاه‌های کاملاً مدیریت‌شده و کاربر اصلی می‌توانند این محدودیت را تنظیم کنند.
DISALLOW_MOUNT_PHYSICAL_MEDIA از نصب هرگونه فضای ذخیره‌سازی که ممکن است کاربر دستگاه به دستگاه متصل کند جلوگیری می‌کند. سرپرستان دستگاه‌های کاملاً مدیریت‌شده و کاربر اصلی می‌توانند این محدودیت را تنظیم کنند.
DISALLOW_ADJUST_VOLUME دستگاه را بی‌صدا می‌کند و به کاربر دستگاه اجازه نمی‌دهد تنظیمات میزان صدا و لرزش را تغییر دهد. بررسی کنید که کیوسک شما برای بازپخش رسانه یا ویژگی‌های دسترس‌پذیری به صدا نیاز نداشته باشد. سرپرستان دستگاه‌های کاملاً مدیریت‌شده، کاربر اصلی، کاربران ثانویه، و نمایه‌های کاری می‌توانند این محدودیت را تنظیم کنند.
DISALLOW_ADD_USER از افزودن کاربران جدید، مانند کاربران ثانویه یا کاربران محدودشده، توسط کاربر دستگاه جلوگیری می‌کند. سیستم به‌طور خودکار این محدودیت کاربر را به دستگاه‌های کاملاً مدیریت‌شده اضافه می‌کند اما ممکن است پاک شده باشد. سرپرستان دستگاه‌های کاملاً مدیریت‌شده و کاربر اصلی می‌توانند این محدودیت را تنظیم کنند.

قطعه کد زیر نشان می‌دهد که چگونه می‌توانید محدودیت‌ها را تنظیم کنید:

کاتلین

// If the system is running in lock task mode, set the user restrictions
// for a kiosk after launching the activity.
arrayOf(
        UserManager.DISALLOW_FACTORY_RESET,
        UserManager.DISALLOW_SAFE_BOOT,
        UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
        UserManager.DISALLOW_ADJUST_VOLUME,
        UserManager.DISALLOW_ADD_USER).forEach { dpm.addUserRestriction(adminName, it) }

جاوا

// If the system is running in lock task mode, set the user restrictions
// for a kiosk after launching the activity.
String[] restrictions = {
    UserManager.DISALLOW_FACTORY_RESET,
    UserManager.DISALLOW_SAFE_BOOT,
    UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA,
    UserManager.DISALLOW_ADJUST_VOLUME,
    UserManager.DISALLOW_ADD_USER};

for (String restriction: restrictions) dpm.addUserRestriction(adminName, restriction);

ممکن است بخواهید وقتی برنامه‌تان در حالت سرپرست است این محدودیت‌ها را بردارید تا سرپرست فناوری اطلاعات همچنان بتواند از این ویژگی‌ها برای نگهداری دستگاه استفاده کند. برای پاک کردن محدودیت، با DevicePolicyManager.clearUserRestriction() تماس بگیرید.

جلوگیری از کادرهای گفتگوی خطا

در برخی محیط‌ها، مانند نمایش‌های خرده‌فروشی یا نمایش اطلاعات عمومی، ممکن است نخواهید کادرهای گفتگوی خطا را به کاربران نشان دهید. در Android نسخه ۹.۰ (سطح API‏ ۲۸) یا بالاتر، می‌توانید با افزودن محدودیت کاربر DISALLOW_SYSTEM_ERROR_DIALOGS، کادرهای گفتگوی خطای سیستم را برای برنامه‌های خراب‌شده یا بدون پاسخ سرکوب کنید. سیستم برنامه‌های غیرپاسخگو را بازراه‌اندازی می‌کند، درست مثل اینکه کاربر دستگاه برنامه را از کادر گفتگو بسته باشد. مثال زیر نشان می‌دهد که چگونه می‌توانید این کار را انجام دهید:

کاتلین

override fun onEnabled(context: Context, intent: Intent) {
    val dpm = getManager(context)
    val adminName = getWho(context)

    dpm.addUserRestriction(adminName, UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS)
}

جاوا

public void onEnabled(Context context, Intent intent) {
  DevicePolicyManager dpm = getManager(context);
  ComponentName adminName = getWho(context);

  dpm.addUserRestriction(adminName, UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS);
}

اگر سرپرست کاربر اصلی یا ثانویه این محدودیت را تنظیم کند، سیستم کادرهای گفتگوی خطا را فقط برای آن کاربر سرکوب می‌کند. اگر سرپرست دستگاهی کاملاً مدیریت‌شده این محدودیت را تنظیم کند، سیستم کادرهای گفتگو را برای همه کاربران پنهان می‌کند.

روشن نگه داشتن صفحه‌نمایش

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

کاتلین

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    // Keep the screen on and bright while this kiosk activity is running.
    window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}

جاوا

@Override
protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  // Keep the screen on and bright while this kiosk activity is running.
  getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}

شاید بخواهید بررسی کنید که دستگاه به شارژر AC،‏ USB، یا بی‌سیم متصل است یا نه. برای همه‌فرستی‌های تغییر باتری ثبت‌نام کنید و از مقادیر BatteryManager برای کشف وضعیت شارژ استفاده کنید. حتی می‌توانید درصورت جدا شدن دستگاه از برق، هشدارهای از راه دور به سرپرست فناوری اطلاعات ارسال کنید. برای دستورالعمل‌های گام‌به‌گام، پایش سطح باتری و وضعیت شارژ را بخوانید.

همچنین می‌توانید تنظیم سراسری STAY_ON_WHILE_PLUGGED_IN را طوری تنظیم کنید که وقتی دستگاه به منبع برق متصل است، بیدار بماند. سرپرستان دستگاه‌های کاملاً مدیریت‌شده، در Android نسخه ۶.۰ (سطح میانای برنامه‌سازی کاربردی ۲۳) یا بالاتر، می‌توانند DevicePolicyManager.setGlobalSetting() را همان‌طور که در مثال زیر نشان داده شده است فراخوانی کنند:

کاتلین

val pluggedInto = BatteryManager.BATTERY_PLUGGED_AC or
        BatteryManager.BATTERY_PLUGGED_USB or
        BatteryManager.BATTERY_PLUGGED_WIRELESS
dpm.setGlobalSetting(adminName,
        Settings.Global.STAY_ON_WHILE_PLUGGED_IN, pluggedInto.toString())

جاوا

int pluggedInto = BatteryManager.BATTERY_PLUGGED_AC |
    BatteryManager.BATTERY_PLUGGED_USB |
    BatteryManager.BATTERY_PLUGGED_WIRELESS;
dpm.setGlobalSetting( adminName,
    Settings.Global.STAY_ON_WHILE_PLUGGED_IN, String.valueOf(pluggedInto));

بسته‌های برنامه

این بخش حاوی دستورالعمل‌هایی برای نصب کارآمد برنامه‌ها در دستگاه‌های اختصاصی است.

بسته‌های برنامه حافظه نهان

اگر کاربران دستگاه مشترک همگی از مجموعه مشترکی از برنامه‌ها استفاده می‌کنند، منطقی است که تا حد امکان از بارگیری برنامه‌ها اجتناب شود. برای ساده‌سازی تدارک کاربر در دستگاه‌های مشترک با مجموعه ثابتی از کاربران، مانند دستگاه‌های کارکنان شیفتی، در Android نسخه ۹.۰ (سطح API‏ ۲۸) یا بالاتر، می‌توانید بسته‌های برنامه (APK) موردنیاز برای جلسه‌های چندکاربره را ذخیره کنید.

نصب APK ذخیره‌شده در حافظه نهان (که قبلاً در دستگاه نصب شده است) در دو مرحله انجام می‌شود:

  1. مؤلفه سرپرست دستگاه کاملاً مدیریت‌شده (یا نماینده—زیر را ببینید) فهرست APKهایی را که باید در دستگاه نگهداری شود تنظیم می‌کند.
  2. مؤلفه‌های سرپرست کاربران فرعی وابسته (یا نمایندگان آن‌ها) می‌توانند APK ذخیره‌شده در حافظه نهان را ازطرف کاربر نصب کنند. سرپرستان دستگاه کاملاً مدیریت‌شده، کاربر اصلی، یا نمایه کاری وابسته (یا نمایندگان آن‌ها) نیز می‌توانند درصورت نیاز برنامه ذخیره‌شده در حافظه نهان را نصب کنند.

برای تنظیم فهرست APKهایی که باید در دستگاه نگهداری شوند، سرپرست DevicePolicyManager.setKeepUninstalledPackages() را فراخوانی می‌کند. این روش بررسی نمی‌کند که APK در دستگاه نصب شده است یا نه—اگر می‌خواهید برنامه‌ای را درست قبل‌از اینکه کاربر به آن نیاز داشته باشد نصب کنید، این روش مفید است. برای دریافت فهرست بسته‌هایی که قبلاً تنظیم شده‌اند، می‌توانید DevicePolicyManager.getKeepUninstalledPackages() را فراخوانی کنید. پس‌از اینکه setKeepUninstalledPackages() را با تغییرات فراخوانی کردید، یا وقتی کاربر ثانویه حذف شد، سیستم همه فایل‌های APK ذخیره‌شده در حافظه نهان را که دیگر به آن‌ها نیازی نیست حذف می‌کند.

برای نصب APK ذخیره‌شده در حافظه نهان، DevicePolicyManager.installExistingPackage() را فراخوانی کنید. این روش فقط می‌تواند برنامه‌ای را نصب کند که سیستم قبلاً آن را در حافظه نهان ذخیره کرده باشد—راهکار دستگاه اختصاصی شما (یا کاربر دستگاه) باید ابتدا برنامه را در دستگاه نصب کند تا بتوانید این روش را فراخوانی کنید.

نمونه زیر نشان می‌دهد که چگونه می‌توانید از این فراخوانی‌های API در سرپرست یک دستگاه کاملاً مدیریت‌شده و کاربر ثانویه استفاده کنید:

کاتلین

// Set the package to keep. This method assumes that the package is already
// installed on the device by managed Google Play.
val cachedAppPackageName = "com.example.android.myapp"
dpm.setKeepUninstalledPackages(adminName, listOf(cachedAppPackageName))

// ...

// The admin of a secondary user installs the app.
val success = dpm.installExistingPackage(adminName, cachedAppPackageName)

جاوا

// Set the package to keep. This method assumes that the package is already
// installed on the device by managed Google Play.
String cachedAppPackageName = "com.example.android.myapp";
List<String> packages = new ArrayList<String>();
packages.add(cachedAppPackageName);
dpm.setKeepUninstalledPackages(adminName, packages);

// ...

// The admin of a secondary user installs the app.
boolean success = dpm.installExistingPackage(adminName, cachedAppPackageName);

برنامه‌های نماینده

می‌توانید برنامه دیگری را برای مدیریت ذخیره کردن برنامه در حافظه نهان تعیین کنید. ممکن است این کار را برای جدا کردن ویژگی‌های راه‌حلتان یا ارائه امکان استفاده از برنامه‌های خودشان به سرپرستان فناوری اطلاعات انجام دهید. برنامه نماینده همان اجازه‌های مؤلفه سرپرست را دریافت می‌کند. برای مثال، نماینده برنامه سرپرست کاربر فرعی می‌تواند installExistingPackage() را فراخوانی کند اما نمی‌تواند setKeepUninstalledPackages() را فراخوانی کند.

برای برقراری تماس نماینده DevicePolicyManager.setDelegatedScopes() و گنجاندن DELEGATION_KEEP_UNINSTALLED_PACKAGES در آرگومان دامنه‌ها. مثال زیر نشان می‌دهد که چگونه می‌توانید برنامه دیگری را نماینده کنید:

کاتلین

var delegatePackageName = "com.example.tools.kept_app_assist"

// Check that the package is installed before delegating.
try {
    context.packageManager.getPackageInfo(delegatePackageName, 0)
    dpm.setDelegatedScopes(
            adminName,
            delegatePackageName,
            listOf(DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES))
} catch (e: PackageManager.NameNotFoundException) {
    // The delegate app isn't installed. Send a report to the IT admin ...
}

جاوا

String delegatePackageName = "com.example.tools.kept_app_assist";

// Check that the package is installed before delegating.
try {
  context.getPackageManager().getPackageInfo(delegatePackageName, 0);
  dpm.setDelegatedScopes(
      adminName,
      delegatePackageName,
      Arrays.asList(DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES));
} catch (PackageManager.NameNotFoundException e) {
  // The delegate app isn't installed. Send a report to the IT admin ...
}

اگر همه‌چیز خوب پیش برود، برنامه نماینده ACTION_APPLICATION_DELEGATION_SCOPES_CHANGED را دریافت می‌کند و نماینده می‌شود. برنامه می‌تواند روش‌های موجود در این راهنما را به‌عنوان مالک دستگاه یا مالک نمایه فراخوانی کند. هنگام فراخوانی روش‌های DevicePolicyManager، نماینده null را برای آرگومان مؤلفه سرپرست ارسال می‌کند.

نصب بسته‌های برنامه

گاهی اوقات نصب برنامه سفارشی ذخیره‌شده در حافظه پنهان محلی در دستگاه اختصاصی مفید است. برای مثال، دستگاه‌های اختصاصی اغلب در محیط‌های با پهنای باند محدود یا مناطق بدون اتصال اینترنت مستقر می‌شوند. راهکار دستگاه اختصاصی شما باید به پهنای باند مشتریانتان توجه داشته باشد. برنامه شما می‌تواند نصب بسته برنامه دیگری (APK) را بااستفاده از کلاس‌های PackageInstaller شروع کند.

درحالی‌که هر برنامه‌ای می‌تواند APK نصب کند، سرپرستان در دستگاه‌های کاملاً مدیریت‌شده می‌توانند بسته‌ها را بدون تعامل کاربر نصب (یا حذف نصب) کنند. سرپرست ممکن است دستگاه، کاربر ثانویه وابسته، یا نمایه کاری وابسته را مدیریت کند. پس‌از تکمیل نصب، سیستم اعلانی را پست می‌کند که همه کاربران دستگاه می‌بینند. این اعلان به کاربران دستگاه اطلاع می‌دهد که برنامه توسط سرپرست آن‌ها نصب (یا به‌روزرسانی) شده است.

جدول ۲. نسخه‌های Android که از نصب بسته بدون تعامل کاربر پشتیبانی می‌کنند
نسخه Android مؤلفه سرپرست برای نصب و حذف نصب
‫Android نسخه ۹.۰ (سطح میانای برنامه‌سازی کاربردی ۲۸) یا بالاتر کاربران ثانویه وابسته و نمایه‌های کاری—هر دو در دستگاه‌های کاملاً مدیریت‌شده
‫Android نسخه ۶.۰ (سطح میانای برنامه‌سازی کاربردی ۲۳) یا بالاتر دستگاه‌های کاملاً مدیریت‌شده

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

می‌توانید از PackageInstaller.Session برای ایجاد جلسه‌ای استفاده کنید که یک یا چند APK را برای نصب در صف قرار می‌دهد. در مثال زیر، بازخورد وضعیت را در فعالیتمان (حالت singleTop) دریافت می‌کنیم، اما می‌توانید از سرویس یا گیرنده رویداد ثبت‌شده استفاده کنید:

کاتلین

// First, create a package installer session.
val packageInstaller = context.packageManager.packageInstaller
val params = PackageInstaller.SessionParams(
        PackageInstaller.SessionParams.MODE_FULL_INSTALL)
val sessionId = packageInstaller.createSession(params)
val session = packageInstaller.openSession(sessionId)

// Add the APK binary to the session. The APK is included in our app binary
// and is read from res/raw but file storage is a more typical location.
// The I/O streams can't be open when installation begins.
session.openWrite("apk", 0, -1).use { output ->
    getContext().resources.openRawResource(R.raw.app).use { input ->
        input.copyTo(output, 2048)
    }
}

// Create a status receiver to report progress of the installation.
// We'll use the current activity.
// Here we're requesting status feedback to our Activity but this can be a
// service or broadcast receiver.
val intent = Intent(context, activity.javaClass)
intent.action = "com.android.example.APK_INSTALLATION_ACTION"
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
val statusReceiver = pendingIntent.intentSender

// Start the installation. Because we're an admin of a fully managed device,
// there isn't any user interaction.
session.commit(statusReceiver)

جاوا

// First, create a package installer session.
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
    PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);

// Add the APK binary to the session. The APK is included in our app binary
// and is read from res/raw but file storage is a more typical location.
try (
    // These I/O streams can't be open when installation begins.
    OutputStream output = session.openWrite("apk", 0, -1);
    InputStream input = getContext().getResources().openRawResource(R.raw.app);
) {
  byte[] buffer = new byte[2048];
  int n;
  while ((n = input.read(buffer)) >= 0) {
    output.write(buffer, 0, n);
  }
}

// Create a status receiver to report progress of the installation.
// We'll use the current activity.
// Here we're requesting status feedback to our Activity but this can be a
// service or broadcast receiver.
Intent intent = new Intent(context, getActivity().getClass());
intent.setAction("com.android.example.APK_INSTALLATION_ACTION");
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
IntentSender statusReceiver = pendingIntent.getIntentSender();

// Start the installation. Because we're an admin of a fully managed device,
// there isn't any user interaction.
session.commit(statusReceiver);

جلسه بااستفاده از مقاصد، بازخورد وضعیت درباره نصب ارسال می‌کند. برای دریافت وضعیت، فیلد EXTRA_STATUS هر قصد را بررسی کنید. به‌یاد داشته باشید که سرپرستان به‌روزرسانی وضعیت STATUS_PENDING_USER_ACTION را دریافت نمی‌کنند چون کاربر دستگاه نیازی به تأیید نصب ندارد.

برای حذف نصب برنامه‌ها، می‌توانید PackageInstaller.uninstall را فراخوانی کنید. سرپرستان دستگاه‌های کاملاً مدیریت‌شده، کاربران، و نمایه‌های کاری می‌توانند بسته‌ها را بدون تعامل کاربر در نسخه‌های پشتیبانی‌شده Android حذف نصب کنند (جدول ۲ را ببینید).

ثابت کردن به‌روزرسانی‌های سیستم

دستگاه‌های Android به‌روزرسانی‌های بی‌سیم (OTA) را برای سیستم و نرم‌افزار کاربردی دریافت می‌کنند. برای ثابت نگه داشتن نسخه سیستم‌عامل در دوره‌های بحرانی، مثل تعطیلات یا دیگر زمان‌های شلوغ، دستگاه‌های اختصاصی می‌توانند به‌روزرسانی‌های سیستم OTA را تا ۹۰ روز تعلیق کنند. برای کسب اطلاعات بیشتر، مدیریت به‌روزرسانی‌های سیستم را بخوانید.

پیکربندی از راه دور

پیکربندی‌های مدیریت‌شده Android به سرپرستان فناوری اطلاعات اجازه می‌دهد برنامه شما را از راه دور پیکربندی کنند. شاید بخواهید تنظیماتی مثل فهرست‌های مجاز، میزبان‌های شبکه، یا نشانی‌های وب محتوا را درمعرض دید قرار دهید تا برنامه‌تان برای سرپرستان فناوری اطلاعات مفیدتر شود.

اگر برنامه‌تان پیکربندی‌اش را افشا می‌کند، فراموش نکنید که تنظیمات را در اسناد خود بگنجانید. برای کسب اطلاعات بیشتر درباره نمایش پیکربندی برنامه و واکنش به تغییرات در تنظیمات، راه‌اندازی پیکربندی‌های مدیریت‌شده را بخوانید.

راه‌اندازی توسعه

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

  1. برنامه کنترل‌کننده خط‌مشی دستگاه (DPC) را در دستگاه بسازید و نصب کنید.
  2. بررسی کنید که هیچ حسابی در دستگاه وجود نداشته باشد.
  3. فرمان زیر را در پوسته پل اشکال‌زدایی Android (adb) اجرا کنید. باید com.example.dpc/.MyDeviceAdminReceiver را در مثال با نام مؤلفه سرپرست برنامه‌تان جایگزین کنید:

    adb shell dpm set-device-owner com.example.dpc/.MyDeviceAdminReceiver

برای کمک به مشتریان در استقرار راه‌حل شما، باید به روش‌های دیگر ثبت‌نام نگاه کنید. ثبت‌نام با رمزینه پاسخ‌سریع را برای دستگاه‌های اختصاصی توصیه می‌کنیم.

منابع بیشتر

برای کسب اطلاعات بیشتر درباره دستگاه‌های اختصاصی، اسناد زیر را بخوانید: