אם אתם מפתחים אפליקציות לשוק הארגוני, יכול להיות שתצטרכו לעמוד בדרישות מסוימות שהוגדרו במדיניות של הארגון. הגדרות מנוהלות, שנקראות בעבר הגבלות על אפליקציות, מאפשרות לאדמין ה-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
. האפליקציה צריכה לבדוק את ההגדרות המנוהלות הנוכחיות במועדים הבאים:
- כשהאפליקציה מופעלת או ממשיכה לפעול, ב-method
onResume()
- כשהאפליקציה מקבלת התראה על שינוי בהגדרות, כפי שמתואר בקטע האזנה לשינויים בהגדרות המנוהלות
כדי לקבל אובייקט 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 (הסיבה לתשובה) בטופס.