הגדרה של הגדרות מנוהלות

אם אתם מפתחים אפליקציות לשוק הארגוני, יכול להיות שתצטרכו לעמוד בדרישות מסוימות שהוגדרו במדיניות של הארגון. הגדרות מנוהלות, שנקראות בעבר הגבלות על אפליקציות, מאפשרות לאדמין ה-IT של הארגון לציין הגדרות לאפליקציות מרחוק. היכולת הזו שימושית במיוחד לאפליקציות שאושרו על ידי הארגון ופורסמו בפרופיל העבודה.

לדוגמה, יכול להיות שארגון מחייב שאפליקציות שאושרו יאפשרו לאדמין ב-IT:

  • אישור או חסימה של כתובות URL בדפדפן אינטרנט
  • לקבוע אם אפליקציה מסוימת תוכל לסנכרן תוכן דרך הרשת הסלולרית או רק דרך Wi-Fi
  • הגדרת הגדרות האימייל של האפליקציה

במדריך הזה מוסבר איך להטמיע הגדרות של תצורה מנוהלת באפליקציה. כדי לראות אפליקציות לדוגמה עם תצורה מנוהלת, אפשר לעיין במאמר ManagedConfigurations. אם אתם מפתחים של ניהול מכשירים ושירותי מובייל בארגון (EMM), כדאי לעיין במדריך ל-Android Management API.

הערה: מסיבות היסטוריות, הגדרות התצורה האלה נקראות הגבלות,והן מיושמות באמצעות קבצים וכיתות שמשתמשים במונח הזה (כמו RestrictionsManager). עם זאת, ההגבלות האלה יכולות למעשה ליישם מגוון רחב של אפשרויות תצורה, ולא רק הגבלות על הפונקציונליות של האפליקציה.

סקירה כללית על הגדרה מרחוק

האפליקציות מגדירות את אפשרויות ההגדרה המנוהלות שאפשר להגדיר מרחוק על ידי אדמין IT. אלה הגדרות שרירותיות שספק ההגדרות המנוהלות יכול לשנות. אם האפליקציה פועלת בפרופיל עבודה, אדמין ה-IT יכול לשנות את ההגדרות המנוהלות של האפליקציה.

ספק ההגדרות האישיות המנוהלות הוא אפליקציה אחרת שפועלת באותו מכשיר. האפליקציה הזו בדרך כלל בשליטת האדמין ב-IT. האדמין ב-IT מעביר את השינויים בהגדרות לאפליקציה של ספק ההגדרות המנוהלות. האפליקציה הזו, בתורה, משנה את ההגדרות באפליקציה שלכם.

כדי לספק הגדרות מנוהלות באופן חיצוני:

  • מגדירים את ההגדרות המנוהלות במניפסט של האפליקציה. כך האדמין ב-IT יוכל לקרוא את הגדרות האפליקציה דרך ממשקי ה-API של Google Play.
  • בכל פעם שהאפליקציה תמשיך לפעול, תוכלו להשתמש באובייקט RestrictionsManager כדי לבדוק את ההגדרות המנוהלות הנוכחיות ולשנות את ממשק המשתמש וההתנהגות של האפליקציה בהתאם להגדרות האלה.
  • מקשיבים לכוונה ACTION_APPLICATION_RESTRICTIONS_CHANGED. כשמקבלים את השידור הזה, בודקים את RestrictionsManager כדי לראות מהן ההגדרות המנוהלות הנוכחיות, ומבצעים את השינויים הנדרשים בהתנהגות האפליקציה.

הגדרת תצורות מנוהלות

האפליקציה יכולה לתמוך בכל הגדרה מנוהלת שתרצו להגדיר. מגדירים את ההגדרות המנוהלות של האפליקציה בקובץ תצורות מנוהל, ומגדירים את קובץ התצורות במניפסט. יצירת קובץ תצורה מאפשרת לאפליקציות אחרות לבדוק את ההגדרות המנוהלות שהאפליקציה מספקת. שותפי EMM יכולים לקרוא את הגדרות האפליקציה באמצעות ממשקי ה-API של Google Play.

כדי להגדיר את אפשרויות התצורה מרחוק של האפליקציה, מוסיפים את הרכיב הבא לרכיב <application> במניפסט:

<meta-data android:name="android.content.APP_RESTRICTIONS"
    android:resource="@xml/app_restrictions" />

יוצרים קובץ בשם app_restrictions.xml בתיקייה res/xml של האפליקציה. המבנה של הקובץ הזה מתואר במאמר העזר בנושא RestrictionsManager. הקובץ מכיל רכיב <restrictions> יחיד ברמה העליונה, שמכיל רכיב צאצא <restriction> אחד לכל אפשרות הגדרה שיש לאפליקציה.

הערה: אין ליצור גרסאות מותאמות לשוק המקומי של קובץ התצורה המנוהל. מותר לאפליקציה לכלול רק קובץ תצורה מנוהל אחד, כך שההגדרות יהיו עקביות באפליקציה בכל אזורי הזמן.

בסביבת הארגון, מערכת EMM בדרך כלל משתמשת בסכימת ההגדרה המנוהלת כדי ליצור מסוף מרוחק לאדמינים ב-IT, כדי שהאדמינים יוכלו להגדיר את האפליקציה מרחוק.

ספק ההגדרות המנוהלות יכול לשלוח לאפליקציה שאילתה כדי למצוא פרטים על ההגדרות הזמינות של האפליקציה, כולל טקסט התיאור שלהן. ספק ההגדרות ואדמין ה-IT יכולים לשנות את ההגדרות המנוהלות של האפליקציה בכל שלב, גם כשהאפליקציה לא פועלת.

לדוגמה, נניח שאפשר להגדיר מרחוק את האפליקציה כך שתאפשר או שתאסור להוריד נתונים דרך חיבור סלולרי. יכול להיות באפליקציה שלכם רכיב <restriction> כזה:

<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android">

  <restriction
    android:key="downloadOnCellular"
    android:title="@string/download_on_cell_title"
    android:restrictionType="bool"
    android:description="@string/download_on_cell_description"
    android:defaultValue="true" />

</restrictions>

אתם משתמשים במאפיין android:key של כל הגדרה כדי לקרוא את הערך שלה מחבילת הגדרות מנוהלת. לכן, לכל הגדרה צריכה להיות מחרוזת מפתח ייחודית, והיא לא יכולה להיות מותאמת לשוק המקומי. צריך לציין אותו באמצעות מחרוזת ליסטרית.

הערה: באפליקציה בסביבת הייצור, צריך להשתמש ב-android:title וב-android:description מקובץ משאבים מותאם לשוק המקומי, כפי שמתואר בקטע התאמה לשוק המקומי באמצעות משאבים.

אפליקציה מגדירה הגבלות באמצעות חבילות בתוך bundle_array. לדוגמה, אפליקציה עם כמה אפשרויות חיבור ל-VPN יכולה להגדיר כל הגדרה של שרת VPN ב-bundle, עם כמה חבילות מקובצות יחד במערך חבילות:

<?xml version="1.0" encoding="utf-8"?>
<restrictions xmlns:android="http://schemas.android.com/apk/res/android" >

  <restriction
    android:key="vpn_configuration_list"
    android:restrictionType="bundle_array">
    <restriction
      android:key="vpn_configuration"
      android:restrictionType="bundle">
      <restriction
        android:key="vpn_server"
        android:restrictionType="string"/>
      <restriction
        android:key="vpn_username"
        android:restrictionType="string"/>
      <restriction
        android:key="vpn_password"
        android:restrictionType="string"/>
    </restriction>
  </restriction>

</restrictions>

סוגי הרכיבים הנתמכים של android:restrictionType מפורטים בטבלה 1 ומופיעים במסמכי העזרה של RestrictionsManager ושל RestrictionEntry.

טבלה 1. סוגי הרשומות של ההגבלות והשימוש בהן.

סוג android:restrictionType שימוש רגיל
TYPE_BOOLEAN "bool" ערך בוליאני, true או false.
TYPE_STRING "string" ערך מחרוזת, כמו שם.
TYPE_INTEGER "integer" מספר שלם עם ערך בין MIN_VALUE ל-MAX_VALUE.
TYPE_CHOICE "choice" ערך מחרוזת שנבחר מ-android:entryValues, בדרך כלל מוצג כרשימה לבחירה יחידה.
TYPE_MULTI_SELECT "multi-select" מערך מחרוזות עם ערכים שנבחרו מ-android:entryValues. משתמשים באפשרות הזו כדי להציג רשימה עם מספר בחירות, שבה אפשר לבחור יותר מרשומה אחת, למשל כדי לבחור כותרים ספציפיים להוספה לרשימת ההיתרים.
TYPE_NULL "hidden" סוג ההגבלה מוסתר. כדאי להשתמש בסוג הזה למידע שצריך להעביר אבל לא להציג למשתמש בממשק המשתמש. אחסון של ערך מחרוזת יחיד.
TYPE_BUNDLE_ARRAY "bundle_array" משתמשים בו לאחסון מערכי הגבלות של bundles. התכונה זמינה ב-Android 6.0 (רמת API‏ 23).

הערה: android:entryValues הם קריאים למכונה ואי אפשר לבצע להם לוקליזציה. משתמשים ב-android:entries כדי להציג ערכים שקריאים לבני אדם וניתנים ללוקליזציה. לכל רשומה צריך להיות אינדקס תואם ב-android:entryValues.

בדיקת ההגדרות המנוהלות

האפליקציה לא מקבלת התראה אוטומטית כשאפליקציות אחרות משנות את הגדרות ההגדרה שלה. במקום זאת, צריך לבדוק מהן ההגדרות המנוהלות כשהאפליקציה מתחילה או ממשיכה לפעול, ולהקשיב לכוונה של המערכת כדי לבדוק אם ההגדרות משתנות בזמן שהאפליקציה פועלת.

כדי לבדוק את הגדרות התצורה הנוכחיות, האפליקציה משתמשת באובייקט RestrictionsManager. האפליקציה צריכה לבדוק את ההגדרות המנוהלות הנוכחיות במועדים הבאים:

כדי לקבל אובייקט RestrictionsManager, מקבלים את הפעילות הנוכחית באמצעות getActivity() ואז קוראים ל-method‏ Activity.getSystemService() של הפעילות הזו:

Kotlin

var myRestrictionsMgr =
        activity?.getSystemService(Context.RESTRICTIONS_SERVICE) as RestrictionsManager

Java

RestrictionsManager myRestrictionsMgr =
    (RestrictionsManager) getActivity()
        .getSystemService(Context.RESTRICTIONS_SERVICE);

אחרי שיוצרים RestrictionsManager, אפשר לקבל את הגדרות התצורה הנוכחיות על ידי קריאה לשיטה getApplicationRestrictions():

Kotlin

var appRestrictions: Bundle = myRestrictionsMgr.applicationRestrictions

Java

Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

הערה: לנוחות, אפשר גם לאחזר את ההגדרות הנוכחיות באמצעות UserManager, על ידי קריאה ל-UserManager.getApplicationRestrictions(). השיטה הזו פועלת בדיוק כמו RestrictionsManager.getApplicationRestrictions().

השיטה getApplicationRestrictions() דורשת קריאה מאחסון הנתונים, ולכן צריך להשתמש בה במשורה. אין להפעיל את השיטה הזו בכל פעם שרוצים לדעת מהי ההגדרה הנוכחית. במקום זאת, צריך להפעיל אותו פעם אחת כשהאפליקציה מתחילה או ממשיכה לפעול, ולאחסן במטמון את חבילת ההגדרות המנוהלות שאוחזרה. לאחר מכן, צריך להאזין לכוונה ACTION_APPLICATION_RESTRICTIONS_CHANGED כדי לבדוק אם ההגדרות השתנו בזמן שהאפליקציה פעילה, כפי שמתואר בקטע האזנה לשינויים בהגדרות המנוהלות.

קריאה והחלה של הגדרות מנוהלות

השיטה getApplicationRestrictions() מחזירה Bundle שמכיל זוג מפתח/ערך לכל הגדרה שהוגדרה. כל הערכים הם מסוג Boolean,‏ int,‏ String ו-String[]. אחרי שתקבלו את ההגדרות המנוהלות Bundle, תוכלו לבדוק את הגדרות ההגדרה הנוכחיות באמצעות השיטות הסטנדרטיות של Bundle לסוגי הנתונים האלה, כמו getBoolean() או getString().

הערה: השדה Bundle של ההגדרות המנוהלות מכיל פריט אחד לכל הגדרה שהוגדרה במפורש על ידי ספק של הגדרות מנוהלות. עם זאת, אי אפשר להניח שהגדרה מסוימת תופיע בחבילה רק בגלל שהגדרתם ערך ברירת מחדל בקובץ ה-XML של ההגדרות המנוהלות.

האפליקציה צריכה לבצע את הפעולה המתאימה על סמך ההגדרות הנוכחיות של ההגדרות המנוהלות. לדוגמה, אם באפליקציה יש הגדרה שמציינת אם היא יכולה להוריד נתונים בחיבור סלולרי, ואתם מגלים שההגדרה מוגדרת ל-false, תצטרכו להשבית את הורדת הנתונים, מלבד במקרים שבהם המכשיר מחובר לרשת Wi-Fi, כפי שמתואר בקוד לדוגמה הבא:

Kotlin

val appCanUseCellular: Boolean =
        if (appRestrictions.containsKey("downloadOnCellular")) {
            appRestrictions.getBoolean("downloadOnCellular")
        } else {
            // cellularDefault is a boolean using the restriction's default value
            cellularDefault
        }

if (!appCanUseCellular) {
    // ...turn off app's cellular-download functionality
    // ...show appropriate notices to user
}

Java

boolean appCanUseCellular;

if (appRestrictions.containsKey("downloadOnCellular")) {
    appCanUseCellular = appRestrictions.getBoolean("downloadOnCellular");
} else {
    // cellularDefault is a boolean using the restriction's default value
    appCanUseCellular = cellularDefault;
}

if (!appCanUseCellular) {
    // ...turn off app's cellular-download functionality
    // ...show appropriate notices to user
}

כדי להחיל כמה הגבלות בתצוגת עץ, קוראים את רשומת ההגבלה bundle_array כקבוצה של אובייקטים מסוג Parcelable ומבצעים הטמעה (cast) כ-Bundle. בדוגמה הזו, נתוני התצורה של כל VPN מנותחים ומשמשים ליצירת רשימה של אפשרויות חיבור לשרת:

Kotlin

// VpnConfig is a sample class used store config data, not defined
val vpnConfigs = mutableListOf<VpnConfig>()

val parcelables: Array<out Parcelable>? =
        appRestrictions.getParcelableArray("vpn_configuration_list")

if (parcelables?.isNotEmpty() == true) {
    // iterate parcelables and cast as bundle
    parcelables.map { it as Bundle }.forEach { vpnConfigBundle ->
        // parse bundle data and store in VpnConfig array
        vpnConfigs.add(VpnConfig()
                .setServer(vpnConfigBundle.getString("vpn_server"))
                .setUsername(vpnConfigBundle.getString("vpn_username"))
                .setPassword(vpnConfigBundle.getString("vpn_password")))
    }
}

if (vpnConfigs.isNotEmpty()) {
    // ...choose a VPN configuration or prompt user to select from list
}

Java

// VpnConfig is a sample class used store config data, not defined
List<VpnConfig> vpnConfigs = new ArrayList<>();

Parcelable[] parcelables =
    appRestrictions.getParcelableArray("vpn_configuration_list");

if (parcelables != null && parcelables.length > 0) {
    // iterate parcelables and cast as bundle
    for (int i = 0; i < parcelables.length; i++) {
        Bundle vpnConfigBundle = (Bundle) parcelables[i];
        // parse bundle data and store in VpnConfig array
        vpnConfigs.add(new VpnConfig()
            .setServer(vpnConfigBundle.getString("vpn_server"))
            .setUsername(vpnConfigBundle.getString("vpn_username"))
            .setPassword(vpnConfigBundle.getString("vpn_password")));
    }
}

if (!vpnConfigs.isEmpty()) {
    // ...choose a VPN configuration or prompt user to select from list
}

האזנה לשינויים בהגדרות המנוהלות

בכל פעם שמשתנות ההגדרות המנוהלות של אפליקציה, המערכת מפעילה את ה-intent‏ ACTION_APPLICATION_RESTRICTIONS_CHANGED. האפליקציה צריכה להאזין לכוונה הזו כדי שתוכלו לשנות את התנהגות האפליקציה כשהגדרות התצורה משתנות.

הערה: הכוונה ACTION_APPLICATION_RESTRICTIONS_CHANGED נשלחת רק למאזינים שנרשמו באופן דינמי, ולא למאזינים שהוגדרו במניפסט של האפליקציה.

הקוד הבא מראה איך לרשום באופן דינמי מקלט שידור ל-intent הזה:

Kotlin

val restrictionsFilter = IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED)

val restrictionsReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {

        // Get the current configuration bundle
        val appRestrictions = myRestrictionsMgr.applicationRestrictions

        // Check current configuration settings, change your app's UI and
        // functionality as necessary.
    }
}

registerReceiver(restrictionsReceiver, restrictionsFilter)

Java

IntentFilter restrictionsFilter =
    new IntentFilter(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);

BroadcastReceiver restrictionsReceiver = new BroadcastReceiver() {
  @Override public void onReceive(Context context, Intent intent) {

    // Get the current configuration bundle
    Bundle appRestrictions = myRestrictionsMgr.getApplicationRestrictions();

    // Check current configuration settings, change your app's UI and
    // functionality as necessary.
  }
};

registerReceiver(restrictionsReceiver, restrictionsFilter);

הערה: בדרך כלל, אין צורך לשלוח לאפליקציה התראות על שינויים בהגדרות כשהיא מושהית. במקום זאת, צריך לבטל את הרישום של מקלט השידור כשהאפליקציה מושהית. כשהאפליקציה ממשיכה לפעול, קודם צריך לבדוק את ההגדרות המנוהלות הנוכחיות (כפי שמתואר בקטע בדיקת ההגדרות המנוהלות), ואז לרשום את מקלט השידור כדי לוודא שתקבלו התראות על שינויים בהגדרות שמתרחשים בזמן שהאפליקציה פעילה.

שליחת משוב על הגדרות מנוהלות ל-EMMs

אחרי שמחילים שינויים בהגדרות המנוהלות באפליקציה, מומלץ להודיע ל-EMMs על סטטוס השינוי. Android תומך בתכונה שנקראת מצב אפליקציה עם מפתח, שבאמצעותה אפשר לשלוח משוב בכל פעם שהאפליקציה מנסה להחיל שינויים בהגדרות המנוהלות. המשוב הזה יכול לשמש כהוכחה שהאפליקציה הגדרה את ההגדרות המנוהלות בהצלחה, או לכלול הודעת שגיאה אם האפליקציה לא הצליחה להחיל את השינויים שצוינו.

ספקי EMM יכולים לאחזר את המשוב הזה ולהציג אותו במסופים שלהם כדי שאדמינים ב-IT יוכלו לראות אותו. למידע נוסף בנושא, כולל מדריך מפורט להוספת תמיכה במשוב לאפליקציה, אפשר לעיין במאמר שליחת משוב על אפליקציות ל-EMM.

דוגמאות קוד נוספות

הדוגמה ManagedConfigurations מדגימה את השימוש בממשקי ה-API שמפורטים בדף הזה.

הוספה של אפליקציות לרשימת ההיתרים או לרשימת החסימות בפרופיל האישי

חנויות אפליקציות של צד שלישי עשויות להביע עניין בשימוש בהגדרות מנוהלות כדי שתהיה להן דרך מהימנה להחיל רשימת אפליקציות חסרות או רשימת אפליקציות מותרות גם בפרופיל האישי וגם בתכונה של מרחב פרטי, שהיא מרחב אישי נוסף שבו המשתמשים יכולים לשמור את האפליקציות הרגישות שלהם. אם אתם מפתחים חנות אפליקציות לשימוש בארגון ואתם רוצים להשתמש בתכונה הזו, תוכלו לשלוח את הטופס הזה כדי להביע עניין, ולבחור באפשרות Interest in 3P app store allowlisting (עניין בהוספה לרשימת ההיתרים של חנות אפליקציות של צד שלישי) בתור Reason for Response (הסיבה לתשובה) בטופס.