ספר המתכונים הזה עוזר למפתחים ולמטמיעי מערכות לשפר את במכשיר. כדאי לעקוב אחר המתכונים שלנו כדי למצוא פתרונות למכשיר ייעודי והתנהגויות. ספר המתכונים הזה מתאים במיוחד למפתחים שכבר יש להם אפליקציה לניהול מכשיר משני – אם רק התחלתם להשתמש באפליקציה, מומלץ לקרוא את המאמר מכשירים ייעודיים סקירה כללית.
אפליקציות דף בית בהתאמה אישית
המתכונים האלה שימושיים אם אתם מפתחים אפליקציה שתחליף את Android Home במסך ובמרכז האפליקציות.
אפליקציית דף הבית
ניתן להגדיר את האפליקציה כאפליקציית דף הבית של המכשיר כדי שהיא תושק באופן אוטומטי כשהמכשיר מופעל. אפשר גם להפעיל את דף הבית לחצן שמוביל את האפליקציה שברשימת ההיתרים לחזית במסך הנעילה במצב משימה.
כל אפליקציות הבית מתייחסות לקטגוריית ה-Intent CATEGORY_HOME
– זו
הוא האופן שבו המערכת מזהה אפליקציית דף בית. כדי להפוך לאפליקציית ברירת המחדל לדף הבית, צריך להגדיר אחת
של הפעילויות של האפליקציה בתור ה-handler המועדף של Intent Home, על ידי קריאה
DevicePolicyManager.addPersistentPreferredActivity()
כפי שאפשר לראות בדוגמה הבאה:
Kotlin
// 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)
Java
// 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
יכול להיות סימון מועיל עבור
באפליקציות מסוג מרכז אפליקציות מפני שכל משימה חדשה מופיעה כפריט נפרד
מסך סקירה כללית. למידע נוסף על משימות במסך הסקירה הכללית אפשר לקרוא לאחרונה
מסך.
קיוסקים ציבוריים
המתכונים האלה מעולים למכשירים שאפשר להשתמש בהם במקומות ציבוריים, אבל הם יכולים גם עוזרים למשתמשים ייעודיים רבים להתמקד במשימות שלהם.
נעילת המכשיר
כדי לוודא שהמכשירים משמשים למטרה שלשמה נועדו, אפשר להוסיף הגבלות המשתמשים המפורטות בטבלה 1.
הגבלת משתמשים | תיאור |
---|---|
DISALLOW_FACTORY_RESET |
מונע ממשתמש לאפס את המכשיר להגדרות ברירת המחדל של היצרן. אדמינים של מכשירים מנוהלים והמשתמשים הראשיים יכולים להגדיר את האפשרות הזו המוגבלות של המשאבים. |
DISALLOW_SAFE_BOOT |
מונע ממשתמש במכשיר להפעיל את המכשיר מצב בטוח שבו המערכת לא תפעיל את האפליקציה באופן אוטומטי. אדמינים של כל במכשירים מנוהלים והמשתמש הראשי יכולים להגדיר את ההגבלה הזאת. |
DISALLOW_MOUNT_PHYSICAL_MEDIA |
מונע ממשתמשי המכשיר לטעון נפחי אחסון שעשויים להיות זמינים מחוברים למכשיר. אדמינים של מכשירים מנוהלים והמשתמש הראשי יכולים להגדיר את ההגבלה הזו. |
DISALLOW_ADJUST_VOLUME |
השתקת המכשיר ומניעת שינוי הצליל של המשתמש במכשיר הגדרות של עוצמת קול ורטט. בודקים שאין צורך באודיו במכשיר הקיוסק להפעלת מדיה או לתכונות נגישות. אדמינים של חשבונות מנוהלים המשתמשים הראשיים, המשתמשים הראשיים, המשתמשים המשניים ופרופילים של העבודה יכולים להגדיר את האפשרות הזו המוגבלות של המשאבים. |
DISALLOW_ADD_USER |
מונע ממשתמשים חדשים להוסיף משתמשים במכשיר, כמו משתמשים משניים או למשתמשים מוגבלים. המערכת מוסיפה באופן אוטומטי את הגבלת המשתמש הזו במכשירים מנוהלים, אבל יכול להיות שהוא הוסר. אדמינים של כל במכשירים מנוהלים והמשתמש הראשי יכולים להגדיר את ההגבלה הזאת. |
בקטע הקוד הבא מוסבר איך להגדיר את ההגבלות:
Kotlin
// 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) }
Java
// 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);
מומלץ להסיר את ההגבלות האלה כשהאפליקציה במצב אדמין,
שאדמין ב-IT עדיין יכול להשתמש בתכונות האלה לתחזוקת מכשירים. כדי לנקות
ההגבלה, שיחה
DevicePolicyManager.clearUserRestriction()
הסתרה של תיבות דו-שיח של שגיאות
בסביבות מסוימות, למשל הדגמות קמעונאות או מידע ציבורי
יכול להיות שלא תרצו להציג למשתמשים תיבות דו-שיח של שגיאות. ב-Android 9.0 (API)
ברמה 28) ומעלה, אפשר להסתיר תיבות דו-שיח של שגיאות מערכת במקרים של קריסות או
אפליקציות שלא מגיבות על ידי הוספת
משתמש ב-DISALLOW_SYSTEM_ERROR_DIALOGS
המוגבלות של המשאבים. המערכת מפעילה מחדש אפליקציות שלא מגיבות, כאילו המשתמש במכשיר נסגר
את האפליקציה בתיבת הדו-שיח. הדוגמה הבאה מראה איך לעשות זאת:
Kotlin
override fun onEnabled(context: Context, intent: Intent) { val dpm = getManager(context) val adminName = getWho(context) dpm.addUserRestriction(adminName, UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS) }
Java
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
חלון כמו שמוצג בדוגמה הבאה:
Kotlin
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) }
Java
@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
כדי לגלות את מצב הטעינה. אפשר אפילו לשלוח התראות מרחוק ל-IT
אם המכשיר מנותק. לקבלת הוראות מפורטות, אפשר לקרוא את
מעקב אחר רמת הטעינה של הסוללה והטעינה
מדינה (State).
אפשר גם להגדיר את STAY_ON_WHILE_PLUGGED_IN
הגדרה גלובלית שנועדה למנוע מהמכשיר להיכנס למצב שינה בזמן שהוא מחובר למקור חשמל.
אדמינים של מכשירים מנוהלים, ב-Android 6.0 (רמת API 23) ואילך, יכולים
התקשרות אל DevicePolicyManager.setGlobalSetting()
כפי שמוצג
בדוגמה הבאה:
Kotlin
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())
Java
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));
חבילות אפליקציה
הקטע הזה כולל מתכונים להתקנה יעילה של אפליקציות במכשירים ייעודיים.
חבילות אפליקציה לשמירה במטמון
אם המשתמשים במכשיר משותף חולקים קבוצה משותפת של אפליקציות, יכול להיות להימנע מהורדת אפליקציות ככל האפשר. כדי לייעל את השימוש ניהול הקצאות ידני במכשירים משותפים עם קבוצת משתמשים קבועה, כמו מכשירים עבור shift Worker, ב-Android 9.0 (רמת API 28) ואילך, ניתן לשמור אפליקציה במטמון חבילות (APK) שנחוצות לסשנים של משתמשים מרובים.
התקנת APK שנשמר במטמון (שכבר מותקן במכשיר) מתבצעת שני שלבים:
- רכיב הניהול של מכשיר מנוהל באופן מלא (או משתמש עם הרשאות גישה לחשבון) – למידע נוסף הבא) מגדיר את רשימת חבילות ה-APK שיש לשמור במכשיר.
- רכיבי אדמין של משתמשים משניים משויכים (או המשתמשים שקיבלו הרשאה) להתקין את ה-APK שנשמר במטמון בשם המשתמש. אדמינים של החשבון המנוהל במלואו במכשיר, המשתמש הראשי או פרופיל עבודה משויך (או בעלי גישה) יכולים גם להתקין את האפליקציה שנשמרה במטמון במקרה הצורך.
כדי להגדיר את רשימת חבילות ה-APK שיישמרו במכשיר, האדמין מתקשר
DevicePolicyManager.setKeepUninstalledPackages()
השיטה הזו לא בודקת שה-APK מותקן במכשיר – מועיל אם
כשרוצים להתקין אפליקציה ממש לפני שהמשתמש צריך אותה. כדי לקבל רשימה של
חבילות שכבר הוגדרו, אפשר להתקשר
DevicePolicyManager.getKeepUninstalledPackages()
אחרי קריאה אל setKeepUninstalledPackages()
עם שינויים, או
המשתמש נמחק, המערכת מוחקת את כל חבילות ה-APK שנשמרו במטמון שאינן נחוצות יותר.
כדי להתקין APK שנשמר במטמון, התקשר
DevicePolicyManager.installExistingPackage()
השיטה הזו יכולה להתקין רק אפליקציה שהמערכת כבר שמרה במטמון –
על פתרון ייעודי למכשיר (או המשתמש במכשיר) להתקין קודם את האפליקציה
במכשיר, לפני שאפשר לקרוא לשיטה הזו.
הדוגמה הבאה ממחישה איך אפשר להשתמש בקריאות האלה ל-API במנהל המערכת של מכשיר מנוהל ומשתמש משני:
Kotlin
// 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)
Java
// 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);
הענקת גישה לאפליקציות
אתם יכולים להעניק גישה לאפליקציה אחרת לניהול שמירת האפליקציות במטמון. תוכל לעשות זאת כדי
להפריד את התכונות של הפתרון שלך או להציע למנהלי IT את היכולת להשתמש
אפליקציות משלהם. האפליקציה שהענקתם לה גישה מקבלת את אותן הרשאות שיש לאדמין
לרכיב הזה. לדוגמה, אדמין של משתמש משני יכול להתקשר אל האפליקציה
installExistingPackage()
אבל לא ניתן להתקשר אל setKeepUninstalledPackages()
.
כדי לתת למשתמש אחר גישה אליו
DevicePolicyManager.setDelegatedScopes()
וכוללות
DELEGATION_KEEP_UNINSTALLED_PACKAGES
בארגומנט 'היקפים'. הדוגמה הבאה מראה איך יוצרים אפליקציה נוספת
בעל הגישה:
Kotlin
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 ... }
Java
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 9.0 (רמת API 28) ואילך | משתמשים משניים משויכים ופרופילים של עבודה – שניהם בחשבונות מנוהלים מכשירים |
Android 6.0 (רמת API 23) ואילך | מכשירים מנוהלים |
אופן ההפצה של עותק אחד או יותר של ה-APK למכשירים ייעודיים יגרום תלויים במרחק בין המכשירים, ולפעמים גם המרחק ביניהם בין המכשירים הם ביחד. הפתרון צריך לפעול בהתאם לשיטות המומלצות בנושא אבטחה לפני שמתקינים חבילות APK במכשירים ייעודיים.
אפשר להשתמש ב-PackageInstaller.Session
כדי ליצור סשן בתור
חבילות APK או יותר להתקנה. בדוגמה הבאה אנחנו מקבלים סטטוס
בפעילות שלנו (במצב singleTop), אבל אפשר להשתמש
שירות או מקלט שידורים:
Kotlin
// 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)
Java
// 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);
בסשן נשלח משוב סטטוס לגבי ההתקנה באמצעות Intent. לבדיקה
השדה EXTRA_STATUS
של כל Intent כדי לקבל
סטטוס. חשוב לזכור שהאדמינים לא מקבלים את
עדכון הסטטוס של STATUS_PENDING_USER_ACTION
כי המשתמש במכשיר לא צריך לאשר את ההתקנה.
כדי להסיר אפליקציות, אפשר להתקשר למספר PackageInstaller.uninstall
.
אדמינים של מכשירים מנוהלים, משתמשים ופרופילים של עבודה יכולים להסיר חבילות
ללא אינטראקציה של המשתמש שפועלות בו גרסאות Android נתמכות (ראו
טבלה 2).
הקפאת עדכוני המערכת
מכשירי Android מקבלים עדכוני OTA למערכת ולאפליקציה תוכנה. כדי להקפיא את גרסת מערכת ההפעלה על פני תקופות קריטיות, כמו חגים או בזמנים עמוסים אחרים, מכשירים ייעודיים יכולים להשעות עדכוני מערכת OTA למשך עד 90 ימים. מידע נוסף זמין במאמר בנושא ניהול עדכוני מערכת.
הגדרת תצורה מרחוק
ההגדרות המנוהלות של Android מאפשרות לאדמינים ב-IT להגדיר מרחוק את האפליקציה. יכול להיות שתרצו לחשוף הגדרות כמו רשימות היתרים, מארחי רשתות או כתובות URL של התוכן כדי שהאפליקציה תהיה שימושית יותר ל-IT ב-Google Workspace for Education.
אם האפליקציה חושפת את ההגדרות שלה, חשוב לכלול את ההגדרות התיעוד. למידע נוסף על חשיפת הגדרות האפליקציה והתגובה אליהן שינויים בהגדרות, קראו את המאמר הגדרת הגדרות מנוהלות.
הגדרת פיתוח
כשאתם מפתחים את הפתרון שלכם למכשירים ייעודיים, לפעמים שימושי אם רוצים להגדיר את האפליקציה כאדמין של מכשיר מנוהל ללא צורך במפעל לאתחל. כדי להגדיר את האדמין של מכשיר מנוהל, צריך לפעול לפי השלבים הבאים:
- יוצרים ומתקינים במכשיר את אפליקציית בקר מדיניות המכשיר (DPC).
- צריך לבדוק שאין חשבונות במכשיר.
מריצים את הפקודה הבאה במעטפת Android Debug Bridge (adb). שלך צריך להחליף את
com.example.dpc/.MyDeviceAdminReceiver
בדוגמה עם השם של רכיב האדמין של האפליקציה:adb shell dpm set-device-owner com.example.dpc/.MyDeviceAdminReceiver
כדי לעזור ללקוחות לפרוס את הפתרון שלך, עליך לבדוק מקורות מידע אחרים שיטות. אנחנו ממליצים על הרשמה באמצעות קוד QR למכשירים ייעודיים.
מקורות מידע נוספים
כדי לקבל מידע נוסף על מכשירים ייעודיים, כדאי לקרוא את המסמכים הבאים: