ספריית האפליקציות של Android לרכב מאפשרת להוסיף לרכב אפליקציות ניווט, נקודות עניין (POI), האינטרנט של הדברים (IoT) או מזג אוויר. הוא עושה זאת באמצעות סט של תבניות שנועדו לעמוד בתקנים למניעת הסחת דעת של הנהג, וטיפול בפרטים כמו מגוון הגורמים במסך הרכב ואופני הקלט.
במדריך הזה מוסבר על התכונות והמושגים העיקריים של הספרייה, ומוצג תהליך ההגדרה של אפליקציה בסיסית.
לפני שמתחילים
- כדאי לעיין בדפים בנושא עיצוב לנהיגה שכוללים מידע על ספריית האפליקציות לרכב
- סקירות כלליות של הקטגוריות אפליקציות לניווט ואפליקציות אחרות שקשורות לנהיגה
- סקירה כללית על פיתוח אפליקציות באמצעות תבניות
- אבני בניין שכוללות תבניות ורכיבי תבניות
- זרימות לדוגמה שמציגות דפוסי UX נפוצים
- דרישות לגבי אפליקציות שמבוססות על תבניות
- כדאי לעיין במושגים מרכזיים בקטע הבא.
- מומלץ לקרוא את המאמרים בנושא ממשק המשתמש של מערכת Android Auto ועיצוב של Android Automotive OS.
- כדאי לעיין בנתוני הגרסה.
- מעיינים בדוגמאות.
מונחים ומושגים מרכזיים
- מודלים ותבניות
- ממשק המשתמש מיוצג על ידי תרשים של אובייקטים של מודלים שאפשר לסדר יחד בדרכים שונות, בהתאם לתבנית שאליה הם שייכים. תבניות הן קבוצת משנה של המודלים שיכולים לשמש כבסיס בתרשימים האלה. המודלים כוללים את המידע שיוצג למשתמש בצורה של טקסט ותמונות, וגם מאפיינים להגדרת היבטים של המראה החזותי של המידע הזה – לדוגמה, צבעי טקסט או גדלי תמונות. המארח ממיר את המודלים לתצוגות שנועדו לעמוד בתקנים למניעת הסחת דעת של הנהג, ומטפל בפרטים כמו מגוון הגורמים במסך המכונית ואופני הקלט.
- מארח
- המארח הוא רכיב הקצה העורפי שמטמיע את הפונקציונליות שממשקי ה-API של הספרייה מציעים, כדי שהאפליקציה תוכל לפעול ברכב. האחריות של המארח כוללת גילוי האפליקציה שלכם וניהול מחזור החיים שלה, המרת המודלים לתצוגות והודעה לאפליקציה על אינטראקציות של משתמשים. במכשירים ניידים, המארח הזה מיושם על ידי Android Auto. ב-Android Automotive OS, האפליקציה המארחת הזו מותקנת כאפליקציית מערכת.
- מגבלות על תבניות
- תבניות שונות אוכפות הגבלות בתוכן של המודלים שלהן. לדוגמה, בתבניות של רשימות יש מגבלות על מספר הפריטים שאפשר להציג למשתמש. יש גם הגבלות על האופן שבו אפשר לקשר בין תבניות כדי ליצור את רצף הפעולות של משימה. לדוגמה, האפליקציה יכולה להציג עד חמש תבניות במצבור המסכים. פרטים נוספים זמינים במאמר הגבלות על תבניות.
Screen
Screen
היא מחלקה שסופקה על ידי הספרייה, ואפליקציות מטמיעות אותה כדי לנהל את ממשק המשתמש שמוצג למשתמש. ל-Screen
יש מחזור חיים והוא מספק את המנגנון לשליחת התבנית על ידי האפליקציה כדי להציג אותה כשהמסך גלוי. אפשר גם להוסיף ולהסיר מופעים שלScreen
ממחסנית שלScreen
, כדי לוודא שהם עומדים בהגבלות של תהליך התבנית.CarAppService
CarAppService
הוא מחלקה מופשטת שלService
שהאפליקציה שלכם צריכה להטמיע ולייצא כדי שהמארח יוכל לגלות אותה ולנהל אותה. ה-CarAppService
של האפליקציה אחראי לאימות של חיבור מארח באמצעותcreateHostValidator
, ולאחר מכן לספק מופעים שלSession
לכל חיבור באמצעותonCreateSession
.Session
Session
היא מחלקה מופשטת שהאפליקציה צריכה להטמיע ולהחזיר באמצעותCarAppService.onCreateSession
. הוא משמש כנקודת הכניסה להצגת מידע במסך המכונית. יש לו מחזור חיים שמציין את המצב הנוכחי של האפליקציה במסך הרכב, למשל אם האפליקציה גלויה או מוסתרת.כשמתחילים
Session
, למשל כשמפעילים את האפליקציה בפעם הראשונה, המארח מבקש להציג אתScreen
הראשוני באמצעות השיטהonCreateScreen
.
התקנת ספריית האפליקציות לרכב
הוראות להוספת הספרייה לאפליקציה זמינות בדף הגרסה של ספריית Jetpack.
הגדרת קובצי המניפסט של האפליקציה
לפני שיוצרים את האפליקציה לרכב, צריך להגדיר את קבצי המניפסט של האפליקציה באופן הבא.
הצהרה על CarAppService
המארח מתחבר לאפליקציה שלכם דרך ההטמעה של CarAppService
. מצהירים על השירות הזה במניפסט כדי שהמארח יוכל לגלות את האפליקציה שלכם ולהתחבר אליה.
בנוסף, צריך להצהיר על הקטגוריה של האפליקציה ברכיב
<category>
של מסנן ה-Intent של האפליקציה. במאמר קטגוריות אפליקציות נתמכות מפורטים הערכים המותרים לרכיב הזה.
קטע הקוד הבא מראה איך להצהיר על שירות אפליקציית רכב לאפליקציה של נקודות עניין במניפסט:
<application>
...
<service
...
android:name=".MyCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService"/>
<category android:name="androidx.car.app.category.POI"/>
</intent-filter>
</service>
...
<application>
קטגוריות אפליקציות נתמכות
מצהירים על הקטגוריה של האפליקציה על ידי הוספה של ערך קטגוריה אחד או יותר מהערכים הבאים למסנן Intent כשמצהירים על CarAppService
, כמו שמתואר בקטע הקודם:
-
androidx.car.app.category.NAVIGATION
: אפליקציה שמספקת הוראות ניווט מפורטות. איך מפתחים אפליקציות ניווט לרכב -
androidx.car.app.category.POI
: אפליקציה שמספקת פונקציונליות שרלוונטית למציאת נקודות עניין כמו מקומות חנייה, תחנות טעינה ותחנות דלק. מידע נוסף זמין במאמר בנושא פיתוח אפליקציות של נקודות עניין לרכב. -
androidx.car.app.category.IOT
: אפליקציה שמאפשרת למשתמשים לבצע פעולות רלוונטיות במכשירים מחוברים מתוך הרכב. מידע נוסף זמין במאמר בנושא בניית אפליקציות של האינטרנט של הדברים לרכבים. -
androidx.car.app.category.WEATHER
: אפליקציה שמאפשרת למשתמשים לראות מידע רלוונטי על מזג האוויר שקשור למיקום הנוכחי שלהם או למסלול הנסיעה שלהם. אפשר לקרוא מידע נוסף במאמר בנושא בניית אפליקציות מזג אוויר לרכבים. -
androidx.car.app.category.MEDIA
: אפליקציה שמאפשרת למשתמשים לעיין במוזיקה, בתחנות רדיו, בספרי אודיו ובתוכן אודיו אחר ולהפעיל אותם ברכב. מידע נוסף זמין במאמר בנושא בניית אפליקציות מדיה מבוססות-תבניות לרכבים. -
androidx.car.app.category.MESSAGING
: אפליקציה שמאפשרת למשתמשים לתקשר באמצעות הודעות טקסט קצרות. אפשר לעיין במאמר בנושא יצירת חוויות הודעות מבוססות-תבניות ל-Android Auto. -
androidx.car.app.category.CALLING
: אפליקציה שמאפשרת למשתמשים לתקשר באמצעות שיחות קוליות. אפשר לקרוא מידע נוסף במאמר בנושא יצירת חוויות שיחה ל-Android Auto.
במאמר איכות אפליקציות ל-Android לרכב מפורטים תיאורים של כל קטגוריה וקריטריונים להכללת אפליקציות בקטגוריות האלה.
שמשמשת כדי לעזור למשתמשים לגלות את האפליקציות הרלוונטיות ביותר בחנות Play.ציון השם והסמל של האפליקציה
צריך לציין שם וסמל לאפליקציה, שהמארח יוכל להשתמש בהם כדי לייצג את האפליקציה בממשק המשתמש של המערכת.
אתם יכולים לציין את שם האפליקציה ואת הסמל שמשמש לייצוג האפליקציה באמצעות המאפיינים label
ו-icon
של CarAppService
:
...
<service
android:name=".MyCarAppService"
android:exported="true"
android:label="@string/my_app_name"
android:icon="@drawable/my_app_icon">
...
</service>
...
אם התווית או הסמל לא מוצהרים ברכיב <service>
, המארח חוזר לערכים שצוינו ברכיב <application>
.
הגדרת עיצוב מותאם אישית
כדי להגדיר עיצוב בהתאמה אישית לאפליקציה לרכב, מוסיפים רכיב <meta-data>
לקובץ המניפסט, באופן הבא:
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
לאחר מכן, מצהירים על משאב הסגנון כדי להגדיר את המאפיינים הבאים לנושא של אפליקציית הרכב בהתאמה אישית:
<resources> <style name="MyCarAppTheme"> <item name="carColorPrimary">@layout/my_primary_car_color</item> <item name="carColorPrimaryDark">@layout/my_primary_dark_car_color</item> <item name="carColorSecondary">@layout/my_secondary_car_color</item> <item name="carColorSecondaryDark">@layout/my_secondary_dark_car_color</item> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
רמת ה-API של אפליקציות לרכב
ספריית האפליקציות לרכב מגדירה רמות API משלה, כדי שתוכלו לדעת אילו תכונות בספרייה נתמכות על ידי מארח התבניות ברכב.
כדי לאחזר את רמת ה-API הגבוהה ביותר של אפליקציות לרכב שנתמכת על ידי מארח, משתמשים ב-method getCarAppApiLevel()
.
מצהירים על רמת ה-API המינימלית של אפליקציית הרכב שהאפליקציה תומכת בה בקובץ AndroidManifest.xml
:
<manifest ...>
<application ...>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
</application>
</manifest>
במסמכי התיעוד של ההערה RequiresCarApi
מוסבר איך לשמור על תאימות לאחור ואיך להצהיר על רמת ה-API המינימלית שנדרשת לשימוש בתכונה. כדי לדעת באיזה רמת API נדרשת כדי להשתמש בתכונה מסוימת של ספריית האפליקציות לרכב, אפשר לעיין במסמכי העיון של CarAppApiLevels
.
יצירת CarAppService ו-Session
האפליקציה צריכה להרחיב את המחלקה CarAppService
ולהטמיע את השיטה onCreateSession
שלה, שמחזירה מופע Session
שמתאים לחיבור הנוכחי למארח:
Kotlin
class HelloWorldService : CarAppService() { ... override fun onCreateSession(): Session { return HelloWorldSession() } ... }
Java
public final class HelloWorldService extends CarAppService { ... @Override @NonNull public Session onCreateSession() { return new HelloWorldSession(); } ... }
המופע Session
אחראי להחזרת המופע Screen
לשימוש בפעם הראשונה שהאפליקציה מופעלת:
Kotlin
class HelloWorldSession : Session() { ... override fun onCreateScreen(intent: Intent): Screen { return HelloWorldScreen(carContext) } ... }
Java
public final class HelloWorldSession extends Session { ... @Override @NonNull public Screen onCreateScreen(@NonNull Intent intent) { return new HelloWorldScreen(getCarContext()); } ... }
כדי לטפל בתרחישים שבהם אפליקציית הרכב צריכה להתחיל ממסך שהוא לא מסך הבית או מסך הנחיתה של האפליקציה, כמו טיפול בקישורי עומק, אפשר להגדיר מראש מחסנית של מסכים באמצעות ScreenManager.push
לפני החזרה מ-onCreateScreen
.
הטכנולוגיה Pre-seeding מאפשרת למשתמשים לחזור למסכים קודמים מהמסך הראשון שמוצג באפליקציה.
יצירת מסך הפתיחה
כדי ליצור את המסכים שמוצגים באפליקציה, מגדירים מחלקות שמרחיבות את המחלקה Screen
ומיישמים את השיטה onGetTemplate
שלה, שמחזירה את המופע Template
שמייצג את מצב ממשק המשתמש שיוצג במסך המכונית.
בדוגמה הבאה מוצג קטע קוד להצהרה על Screen
שמשתמש בתבנית PaneTemplate
כדי להציג את המחרוזת הפשוטה Hello world!:
Kotlin
class HelloWorldScreen(carContext: CarContext) : Screen(carContext) { override fun onGetTemplate(): Template { val row = Row.Builder().setTitle("Hello world!").build() val pane = Pane.Builder().addRow(row).build() return PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build() } }
Java
public class HelloWorldScreen extends Screen { @NonNull @Override public Template onGetTemplate() { Row row = new Row.Builder().setTitle("Hello world!").build(); Pane pane = new Pane.Builder().addRow(row).build(); return new PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build(); } }
המחלקות CarContext
המחלקה CarContext
היא מחלקת משנה ContextWrapper
שאפשר לגשת אליה במופעים Session
ו-Screen
. היא מספקת גישה לשירותי רכב, כמו ScreenManager
לניהול ערימת המסכים, AppManager
לפונקציונליות כללית שקשורה לאפליקציות, כמו גישה לאובייקט Surface
לצורך ציור מפות, ו-NavigationManager
שמשמש אפליקציות של ניווט מפורט כדי לתקשר מטא-נתונים של ניווט ואירועים אחרים שקשורים לניווט עם המארח.
כאן אפשר לראות רשימה מלאה של הפונקציות בספרייה שזמינות באפליקציות לניווט.
CarContext
מציע גם פונקציות אחרות, כמו טעינת משאבים של ציורים באמצעות ההגדרה ממסך הרכב, הפעלת אפליקציה ברכב באמצעות כוונות וציון אם האפליקציה צריכה להציג את המפה שלה בעיצוב כהה.
הטמעה של ניווט במסך
באפליקציות מוצגים בדרך כלל כמה מסכים שונים, וכל אחד מהם יכול להשתמש בתבניות שונות שהמשתמש יכול לנווט ביניהן כשהוא מקיים אינטראקציה עם הממשק שמוצג במסך.
המחלקות ScreenManager
מספקות מחסנית מסכים שאפשר להשתמש בה כדי להוסיף מסכים שאפשר להסיר באופן אוטומטי כשהמשתמש בוחר בכפתור 'חזרה' במסך המכונית או משתמש בכפתור החזרה הפיזי שזמין בחלק מהמכוניות.
קטע הקוד הבא מראה איך להוסיף פעולת חזרה לתבנית של הודעה, וגם פעולה שמעבירה למסך חדש כשהמשתמש בוחר בה:
Kotlin
val template = MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( Action.Builder() .setTitle("Next screen") .setOnClickListener { screenManager.push(NextScreen(carContext)) } .build()) .build()
Java
MessageTemplate template = new MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( new Action.Builder() .setTitle("Next screen") .setOnClickListener( () -> getScreenManager().push(new NextScreen(getCarContext()))) .build()) .build();
האובייקט Action.BACK
הוא Action
רגיל שמפעיל באופן אוטומטי את ScreenManager.pop
.
אפשר לשנות את ההתנהגות הזו באמצעות המופע OnBackPressedDispatcher
שזמין מ-CarContext
.
כדי לוודא שהאפליקציה בטוחה לשימוש בזמן נהיגה, עומק מחסנית המסכים יכול להיות עד חמישה מסכים. פרטים נוספים זמינים בקטע הגבלות על תבניות.
רענון התוכן של תבנית
האפליקציה יכולה לשלוח בקשה לביטול התוקף של התוכן של Screen
באמצעות קריאה לשיטה Screen.invalidate
.
המארח מתקשר לאחר מכן חזרה לשיטה Screen.onGetTemplate
של האפליקציה כדי לאחזר את התבנית עם התוכן החדש.
כשמרעננים תבנית Screen
, חשוב להבין את התוכן הספציפי בתבנית שאפשר לעדכן, כדי שהמארח לא יספור את התבנית החדשה במסגרת מכסת התבניות.
פרטים נוספים זמינים בקטע הגבלות על תבניות.
מומלץ לעצב את המסכים כך שתהיה מיפוי אחד לאחד בין Screen
לסוג התבנית שהוא מחזיר באמצעות ההטמעה של onGetTemplate
.
ציור מפות
אפליקציות ניווט, אפליקציות של נקודות עניין (POI) ואפליקציות מזג אוויר שמשתמשות בתבניות הבאות יכולות לצייר מפות על ידי גישה אל Surface
.
כדי להשתמש בתבניות הבאות, צריך להצהיר על אחת מההרשאות המתאימות באלמנט <uses-permission>
בקובץ AndroidManifest.xml
של האפליקציה.
תבנית | הרשאה לתבנית | הנחיות לגבי קטגוריות |
---|---|---|
NavigationTemplate |
androidx.car.app.NAVIGATION_TEMPLATES |
ניווט |
MapWithContentTemplate |
androidx.car.app.NAVIGATION_TEMPLATES או androidx.car.app.MAP_TEMPLATES |
ניווט, נקודות עניין, מזג אוויר |
MapTemplate (הוצא משימוש) |
androidx.car.app.NAVIGATION_TEMPLATES |
ניווט |
PlaceListNavigationTemplate (הוצא משימוש) |
androidx.car.app.NAVIGATION_TEMPLATES |
ניווט |
RoutePreviewNavigationTemplate (הוצא משימוש) |
androidx.car.app.NAVIGATION_TEMPLATES |
ניווט |
הצהרה על הרשאת המשטח
בנוסף להרשאה שנדרשת לתבנית שבה האפליקציה משתמשת, האפליקציה צריכה להצהיר על ההרשאה androidx.car.app.ACCESS_SURFACE
בקובץ AndroidManifest.xml
שלה כדי לקבל גישה למשטח:
<manifest ...>
...
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
...
</manifest>
גישה לפלטפורמה
כדי לגשת אל Surface
שהמארח מספק, צריך להטמיע SurfaceCallback
ולספק את ההטמעה הזו לשירות הרכב AppManager
. הערך הנוכחי של Surface
מועבר אל SurfaceCallback
בפרמטר SurfaceContainer
של הקריאות החוזרות onSurfaceAvailable()
ו-onSurfaceDestroyed()
.
Kotlin
carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)
Java
carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);
הסבר על האזור הגלוי של המשטח
המארח יכול לצייר רכיבים של ממשק משתמש לתבניות מעל המפה. המארח מעביר את השטח של הממשק שמוצג למשתמש ללא הפרעות ובאופן מלא על ידי קריאה לשיטה SurfaceCallback.onVisibleAreaChanged
. בנוסף, כדי למזער את מספר השינויים, המארח קורא לשיטה
SurfaceCallback.onStableAreaChanged
עם המלבן הקטן ביותר, שתמיד גלוי על סמך התבנית הנוכחית.
לדוגמה, כשמשתמשים ב-NavigationTemplate
באפליקציית ניווט עם סרגל פעולות בחלק העליון, סרגל הפעולות יכול להיעלם אם המשתמש לא מקיים אינטראקציה עם המסך במשך זמן מה, כדי לפנות יותר מקום למפה. במקרה הזה, יש קריאה חוזרת אל onStableAreaChanged
ואל onVisibleAreaChanged
עם אותו מלבן. כשסרגל הפעולות מוסתר,
רק onVisibleAreaChanged
מופעל עם האזור הגדול יותר. אם המשתמש מקיים אינטראקציה עם המסך, רק onVisibleAreaChanged
נקרא שוב עם המלבן הראשון.
תמיכה בעיצוב כהה
כשהמארח קובע שהתנאים מצדיקים זאת, האפליקציות צריכות לצייר מחדש את המפה במופע Surface
עם הצבעים הכהים המתאימים, כמו שמתואר במאמר איכות אפליקציות ל-Android Auto.
כדי להחליט אם לשרטט מפה כהה, אפשר להשתמש בשיטה
CarContext.isDarkMode
. בכל פעם שהסטטוס של העיצוב הכהה משתנה, מתקבלת שיחה אל
Session.onCarConfigurationChanged
.
ציור מפות בלוח המחוונים
בנוסף לציור מפות במסך הראשי, אפליקציות ניווט יכולות גם לתמוך בציור מפות במסך של לוח המחוונים שמאחורי ההגה. הנחיות נוספות מפורטות במאמר בנושא ציור בתצוגת האשכול.
איך מאפשרים למשתמשים לבצע אינטראקציה עם המפה
כשמשתמשים בתבניות הבאות, אפשר להוסיף תמיכה באינטראקציה של משתמשים עם המפות שאתם מציירים, למשל לאפשר להם לראות חלקים שונים במפה באמצעות שינוי קנה המידה והזזה.
תבנית | האינטראקטיביות נתמכת מאז Car App API Level |
---|---|
NavigationTemplate |
2 |
PlaceListNavigationTemplate (הוצא משימוש) |
4 |
RoutePreviewNavigationTemplate (הוצא משימוש) |
4 |
MapTemplate (הוצא משימוש) |
5 (מבוא לתבנית) |
MapWithContentTemplate |
7 (introduction of template) |
הטמעה של התקשרות חזרה לאינטראקטיביות
לממשק SurfaceCallback
יש כמה שיטות של קריאה חוזרת שאפשר להטמיע כדי להוסיף אינטראקטיביות למפות שנוצרו באמצעות התבניות שבקטע הקודם:
אינטראקציה | SurfaceCallback method |
נתמך מגרסת Car App API |
---|---|---|
לחיצה | onClick |
5 |
אפשר לפתוח או לסגור אצבעות כדי לשנות את מרחק התצוגה | onScale |
2 |
גרירה בנגיעה אחת | onScroll |
2 |
הזזה בנגיעה אחת | onFling |
2 |
לחיצה פעמיים | onScale (עם גורם קנה מידה שנקבע על ידי מארח התבנית) |
2 |
הזזה סיבובית במצב הזזה | onScroll (עם גורם מרחק שנקבע על ידי מארח התבנית) |
2 |
הוספה של סרגל פעולות במפה
בתבניות האלה יכולה להיות רצועת פעולות במפה, לפעולות שקשורות למפה כמו הגדלה והקטנה, מרכוז מחדש, הצגת מצפן ופעולות אחרות שאתם בוחרים להציג. בסרגל הפעולות של המפה יכולים להיות עד ארבעה לחצנים עם סמלים בלבד שאפשר לרענן בלי להשפיע על עומק המשימה. הוא מוסתר במצב לא פעיל ומופיע שוב במצב פעיל.
כדי לקבל קריאות חוזרות (callback) של אינטראקטיביות במפה, חובה להוסיף לחצן Action.PAN
בשורת הפעולות במפה. כשהמשתמש לוחץ על כפתור ההזזה, המארח עובר למצב הזזה, כמו שמתואר בקטע הבא.
אם האפליקציה לא כוללת את לחצן Action.PAN
בסרגל הפעולות של המפה, היא לא מקבלת קלט משתמש מהשיטות SurfaceCallback
, והמארח יוצא מכל מצב הזזה שהופעל קודם.
במסך מגע, לחצן ההזזה לא מוצג.
הסבר על מצב הזזה
במצב הזזה, המארח של התבנית מתרגם קלט משתמש ממכשירי קלט שאינם מבוססי מגע, כמו בקרי חוגה ומשטחי מגע, לשיטות SurfaceCallback
המתאימות. תגובה לפעולת המשתמש להפעלת מצב ההזזה או ליציאה ממנו באמצעות השיטה setPanModeListener
ב-NavigationTemplate.Builder
. המארח יכול להסתיר רכיבי ממשק משתמש אחרים בתבנית בזמן שהמשתמש נמצא במצב פנורמה.
אינטראקציה עם המשתמש
האפליקציה יכולה ליצור אינטראקציה עם המשתמש באמצעות דפוסים שדומים לאלה של אפליקציה לנייד.
טיפול בקלט של משתמשים
האפליקציה יכולה להגיב לקלט של המשתמשים על ידי העברת מאזינים מתאימים למודלים שתומכים בהם. בדוגמה הבאה אפשר לראות איך ליצור מודל Action
שמגדיר OnClickListener
שקורא חזרה לשיטה שמוגדרת על ידי קוד האפליקציה:
Kotlin
val action = Action.Builder() .setTitle("Navigate") .setOnClickListener(::onClickNavigate) .build()
Java
Action action = new Action.Builder() .setTitle("Navigate") .setOnClickListener(this::onClickNavigate) .build();
אחרי כן, אפשר להשתמש בשיטה onClickNavigate
כדי להפעיל את אפליקציית הניווט שמוגדרת כברירת מחדל לרכב באמצעות השיטה CarContext.startCarApp
:
Kotlin
private fun onClickNavigate() { val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address)) carContext.startCarApp(intent) }
Java
private void onClickNavigate() { Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address)); getCarContext().startCarApp(intent); }
לפרטים נוספים על הפורמט של ACTION_NAVIGATE
intent ועל דרכים נוספות להפעלת אפליקציות, אפשר לעיין בקטע הפעלת אפליקציה לרכב באמצעות intent.
חלק מהפעולות, כמו אלה שמחייבות להפנות את המשתמש להמשך האינטראקציה במכשיר הנייד שלו, מותרות רק כשהמכונית חונה.
אפשר להשתמש בלחצן
ParkedOnlyOnClickListener
כדי לבצע את הפעולות האלה. אם הרכב לא חונה, המארח מציג למשתמש אינדיקציה לכך שהפעולה לא מותרת במקרה הזה. אם המכונית חונה, הקוד מופעל כרגיל. בקטע הקוד הבא מוצג אופן השימוש ב-ParkedOnlyOnClickListener
כדי לפתוח מסך הגדרות במכשיר הנייד:
Kotlin
val row = Row.Builder() .setTitle("Open Settings") .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone)) .build()
Java
Row row = new Row.Builder() .setTitle("Open Settings") .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone)) .build();
הצגת התראות
ההתראות שנשלחות לנייד מוצגות במסך הרכב רק אם הן מורחבות באמצעות CarAppExtender
.
אפשר להגדיר חלק מהמאפיינים של ההתראה, כמו כותרת התוכן, הטקסט, הסמל והפעולות, ב-CarAppExtender
. ההגדרות האלה יחליפו את המאפיינים של ההתראה כשהיא תופיע במסך הרכב.
בקטע הקוד הבא מוצג אופן שליחת התראה למסך ברכב, עם כותרת שונה מזו שמוצגת במכשיר הנייד:
Kotlin
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle(titleOnThePhone) .extend( CarAppExtender.Builder() .setContentTitle(titleOnTheCar) ... .build()) .build()
Java
Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle(titleOnThePhone) .extend( new CarAppExtender.Builder() .setContentTitle(titleOnTheCar) ... .build()) .build();
ההתראות יכולות להשפיע על החלקים הבאים בממשק המשתמש:
- יכול להיות שתוצג למשתמש התראה קופצת.
- יכול להיות שתווסף רשומה למרכז ההתראות, ואפשרות נוספת היא שתוצג תגית בסרגל הצד.
- באפליקציות ניווט, יכול להיות שההתראה תוצג בווידג'ט של פס הניווט, כמו שמתואר במאמר התראות על פניות.
אתם יכולים להגדיר את ההתראות של האפליקציה כך שישפיעו על כל אחד מרכיבי ממשק המשתמש האלה באמצעות העדיפות של ההתראה, כפי שמתואר במסמכי התיעוד של CarAppExtender
.
אם הפונקציה
NotificationCompat.Builder.setOnlyAlertOnce
מופעלת עם הערך true
, התראה בעדיפות גבוהה מוצגת כ-HUN רק פעם אחת.
מידע נוסף על עיצוב ההתראות באפליקציית הרכב זמין במדריך Google Design for Driving בנושא התראות.
הצגת הודעות קופצות
האפליקציה יכולה להציג הודעה קצרה באמצעות CarToast
כמו בקטע הקוד הבא:
Kotlin
CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()
Java
CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();
בקשת הרשאות
אם האפליקציה שלכם צריכה גישה לנתונים או לפעולות מוגבלים – למשל, מיקום – חלים עליה הכללים הרגילים של הרשאות Android. כדי לבקש הרשאה, אפשר להשתמש בשיטה CarContext.requestPermissions()
.
היתרון בשימוש ב-CarContext.requestPermissions()
, לעומת שימוש בממשקי API רגילים של Android, הוא שלא צריך להפעיל Activity
משלכם כדי ליצור את תיבת הדו-שיח של ההרשאות. בנוסף, אפשר להשתמש באותו קוד גם ב-Android Auto וגם ב-Android Automotive OS, במקום ליצור תהליכים שמותנים בפלטפורמה.
שינוי הסגנון של תיבת הדו-שיח של ההרשאות ב-Android Auto
ב-Android Auto, תיבת הדו-שיח של ההרשאות למשתמש תופיע בטלפון.
כברירת מחדל, לא יהיה רקע מאחורי תיבת הדו-שיח. כדי להגדיר רקע מותאם אישית, צריך להצהיר על עיצוב של אפליקציה לרכב בקובץ AndroidManifest.xml
ולהגדיר את מאפיין carPermissionActivityLayout
של העיצוב של האפליקציה לרכב.
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
לאחר מכן, מגדירים את מאפיין carPermissionActivityLayout
של העיצוב של אפליקציית הרכב:
<resources> <style name="MyCarAppTheme"> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
הפעלת אפליקציה לרכב באמצעות Intent
אפשר להפעיל את השיטה
CarContext.startCarApp
כדי לבצע אחת מהפעולות הבאות:
- פותחים את החייגן כדי להתקשר.
- התחלת מסלול מפורט למיקום מסוים באמצעות אפליקציית הניווט שמוגדרת כברירת המחדל.
- התחלת אפליקציה משלכם באמצעות כוונה.
בדוגמה הבאה מוצג איך ליצור התראה עם פעולה שפותחת את האפליקציה במסך שבו מוצגים פרטי הזמנת חנייה.
מרחיבים את מופע ההתראה באמצעות כוונת תוכן שמכילה PendingIntent
שעוטף כוונה מפורשת לפעולה של האפליקציה:
Kotlin
val notification = notificationBuilder ... .extend( CarAppExtender.Builder() .setContentIntent( PendingIntent.getBroadcast( context, ACTION_VIEW_PARKING_RESERVATION.hashCode(), Intent(ACTION_VIEW_PARKING_RESERVATION) .setComponent(ComponentName(context, MyNotificationReceiver::class.java)), 0)) .build())
Java
Notification notification = notificationBuilder ... .extend( new CarAppExtender.Builder() .setContentIntent( PendingIntent.getBroadcast( context, ACTION_VIEW_PARKING_RESERVATION.hashCode(), new Intent(ACTION_VIEW_PARKING_RESERVATION) .setComponent(new ComponentName(context, MyNotificationReceiver.class)), 0)) .build());
בנוסף, באפליקציה צריך להיות מוצהר על BroadcastReceiver
שמופעל כדי לעבד את הכוונה כשהמשתמש בוחר את הפעולה בממשק ההתראות ומפעיל את CarContext.startCarApp
עם כוונה שכוללת את ה-URI של הנתונים:
Kotlin
class MyNotificationReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val intentAction = intent.action if (ACTION_VIEW_PARKING_RESERVATION == intentAction) { CarContext.startCarApp( intent, Intent(Intent.ACTION_VIEW) .setComponent(ComponentName(context, MyCarAppService::class.java)) .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction))) } } }
Java
public class MyNotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String intentAction = intent.getAction(); if (ACTION_VIEW_PARKING_RESERVATION.equals(intentAction)) { CarContext.startCarApp( intent, new Intent(Intent.ACTION_VIEW) .setComponent(new ComponentName(context, MyCarAppService.class)) .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction))); } } }
לבסוף, השיטה
Session.onNewIntent
באפליקציה מטפלת ב-Intent הזה על ידי העברת מסך הזמנת החנייה
לראש המחסנית, אם הוא לא כבר בראש:
Kotlin
override fun onNewIntent(intent: Intent) { val screenManager = carContext.getCarService(ScreenManager::class.java) val uri = intent.data if (uri != null && MY_URI_SCHEME == uri.scheme && MY_URI_HOST == uri.schemeSpecificPart && ACTION_VIEW_PARKING_RESERVATION == uri.fragment ) { val top = screenManager.top if (top !is ParkingReservationScreen) { screenManager.push(ParkingReservationScreen(carContext)) } } }
Java
@Override public void onNewIntent(@NonNull Intent intent) { ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class); Uri uri = intent.getData(); if (uri != null && MY_URI_SCHEME.equals(uri.getScheme()) && MY_URI_HOST.equals(uri.getSchemeSpecificPart()) && ACTION_VIEW_PARKING_RESERVATION.equals(uri.getFragment()) ) { Screen top = screenManager.getTop(); if (!(top instanceof ParkingReservationScreen)) { screenManager.push(new ParkingReservationScreen(getCarContext())); } } }
מידע נוסף על טיפול בהתראות באפליקציה לרכב זמין בקטע הצגת התראות.
מגבלות על תבניות
המארח מגביל את מספר התבניות שיוצגו למשימה מסוימת לחמש לכל היותר, והתבנית האחרונה חייבת להיות אחת מהסוגים הבאים:
NavigationTemplate
PaneTemplate
MessageTemplate
MediaPlaybackTemplate
SignInTemplate
LongMessageTemplate
שימו לב שהמגבלה הזו חלה על מספר התבניות ולא על מספר המופעים של Screen
במערך. לדוגמה, אם אפליקציה שולחת שני תבניות כשהיא במסך א' ואז מעבירה למסך ב', היא יכולה עכשיו לשלוח עוד שלוש תבניות. לחלופין, אם כל מסך בנוי כך שהוא שולח תבנית אחת, האפליקציה יכולה להעביר חמישה מופעים של מסכים אל מחסנית ScreenManager
.
יש מקרים מיוחדים שבהם ההגבלות האלה לא חלות: רענון תבניות ופעולות של חזרה אחורה ואיפוס.
רענון תבניות
עדכוני תוכן מסוימים לא נספרים במסגרת מגבלת התבניות. באופן כללי,
אם אפליקציה שולחת תבנית חדשה מאותו סוג שמכילה את אותו תוכן ראשי כמו התבנית הקודמת, התבנית החדשה לא נספרת במכסת השימוש. לדוגמה, עדכון מצב המתג של שורה ב-ListTemplate
לא נספר במכסה. כדי לקבל מידע נוסף על סוגי עדכוני התוכן שאפשר להגדיר כרענון, אפשר לעיין במסמכי התיעוד של התבניות השונות.
פעולות חזרה
כדי להפעיל תת-תהליכים במשימה, המארח מזהה מתי אפליקציה שולפת Screen
ממחסנית ScreenManager
ומעדכן את המכסה שנותרה על סמך מספר התבניות שהאפליקציה חוזרת אליהן.
לדוגמה, אם האפליקציה שולחת שתי תבניות כשהיא במסך א', ואז מעבירה למסך ב' ושולחת עוד שתי תבניות, נשאר לאפליקציה מכסת שימוש אחת. אם האפליקציה חוזרת למסך א', המארח מאפס את המכסה לשלוש, כי האפליקציה חזרה אחורה בשני תבניות.
הערה: כשחוזרים למסך, האפליקציה צריכה לשלוח תבנית מאותו סוג של התבנית האחרונה שנשלחה מהמסך הזה. שליחה של כל סוג אחר של תבנית גורמת לשגיאה. עם זאת, כל עוד הסוג נשאר זהה במהלך פעולת חזרה, אפליקציה יכולה לשנות את התוכן של התבנית באופן חופשי בלי להשפיע על המכסה.
איפוס פעולות
לחלק מהתבניות יש סמנטיקה מיוחדת שמציינת את סוף המשימה. לדוגמה, NavigationTemplate
הוא תצוגה שצפויה להישאר על המסך ולהתעדכן בהוראות חדשות שלב אחר שלב לצריכת המשתמש. כשהמארח מגיע לאחת מהתבניות האלה, הוא מאפס את מכסת התבניות, ומתייחס לתבנית כאילו היא השלב הראשון במשימה חדשה. ההרשאה הזו מאפשרת לאפליקציה להתחיל משימה חדשה.
כדי לדעת אילו תבניות מפעילות איפוס במארח, אפשר לעיין במסמכי התיעוד של התבניות השונות.
אם המארח מקבל כוונה להפעיל את האפליקציה מפעולת התראה או ממרכז האפליקציות, המכסה מאופסת גם כן. המנגנון הזה מאפשר לאפליקציה להתחיל תהליך חדש של משימות מתוך ההתראות, והוא תקף גם אם האפליקציה כבר מקושרת ופועלת בחזית.
מידע נוסף על הצגת ההתראות מהאפליקציה במסך הרכב מופיע בקטע הצגת התראות. בקטע הפעלת אפליקציה לרכב באמצעות Intent מוסבר איך להפעיל את האפליקציה מפעולת התראה.
Connection API
כדי לדעת אם האפליקציה פועלת ב-Android Auto או ב-Android Automotive OS, אפשר להשתמש ב-CarConnection
API כדי לאחזר מידע על החיבור בזמן הריצה.
לדוגמה, באפליקציית הרכב Session
, מאתחלים CarConnection
ונרשמים לעדכונים של LiveData
:
Kotlin
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)
Java
new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);
ב-observer, אפשר להגיב לשינויים בסטטוס החיבור:
Kotlin
fun onConnectionStateUpdated(connectionState: Int) { val message = when(connectionState) { CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "Not connected to a head unit" CarConnection.CONNECTION_TYPE_NATIVE -> "Connected to Android Automotive OS" CarConnection.CONNECTION_TYPE_PROJECTION -> "Connected to Android Auto" else -> "Unknown car connection type" } CarToast.makeText(carContext, message, CarToast.LENGTH_SHORT).show() }
Java
private void onConnectionStateUpdated(int connectionState) { String message; switch(connectionState) { case CarConnection.CONNECTION_TYPE_NOT_CONNECTED: message = "Not connected to a head unit"; break; case CarConnection.CONNECTION_TYPE_NATIVE: message = "Connected to Android Automotive OS"; break; case CarConnection.CONNECTION_TYPE_PROJECTION: message = "Connected to Android Auto"; break; default: message = "Unknown car connection type"; break; } CarToast.makeText(getCarContext(), message, CarToast.LENGTH_SHORT).show(); }
Constraints API
במכוניות שונות יכול להיות שיוצג למשתמש מספר שונה של מופעים של Item
בכל פעם. כדי לבדוק את מגבלת התוכן בזמן הריצה ולהגדיר את מספר הפריטים המתאים בתבניות, צריך להשתמש בתג
ConstraintManager
.
כדי להתחיל, צריך לקבל ConstraintManager
מ-CarContext
:
Kotlin
val manager = carContext.getCarService(ConstraintManager::class.java)
Java
ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);
אחר כך אפשר לשלוח שאילתה לאובייקט ConstraintManager
שאוחזר כדי לקבל את מגבלת התוכן הרלוונטית. לדוגמה, כדי לקבל את מספר הפריטים שאפשר להציג ברשת, קוראים ל-getContentLimit
עם CONTENT_LIMIT_TYPE_GRID
:
Kotlin
val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)
Java
int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);
הוספת תהליך כניסה
אם האפליקציה שלכם מציעה למשתמשים חוויה של כניסה לחשבון, אתם יכולים להשתמש בתבניות כמו SignInTemplate
ו-LongMessageTemplate
עם רמת Car App API 2 ומעלה כדי לטפל בכניסה לחשבון באפליקציה במערכת המידע והבידור של הרכב.
כדי ליצור SignInTemplate
, מגדירים SignInMethod
. בשלב הזה, בספריית אפליקציות לרכב יש תמיכה בשיטות ההתחברות הבאות:
InputSignInMethod
לכניסה באמצעות שם משתמש וסיסמה.-
PinSignInMethod
לכניסה באמצעות קוד אימות, שבה המשתמש מקשר את החשבון שלו מהטלפון באמצעות קוד אימות שמוצג ביחידה הראשית. -
ProviderSignInMethod
לכניסה דרך ספק, כמו כניסה באמצעות חשבון Google ולחיצה אחת. QRCodeSignInMethod
לכניסה באמצעות קוד QR, שבה המשתמש סורק קוד QR כדי להשלים את הכניסה בטלפון שלו. האפשרות הזו זמינה ב-Car API מגרסה 4 ואילך.
לדוגמה, כדי להטמיע תבנית שאוספת את הסיסמה של המשתמש, מתחילים ביצירת InputCallback
כדי לעבד ולאמת את קלט המשתמש:
Kotlin
val callback = object : InputCallback { override fun onInputSubmitted(text: String) { // You will receive this callback when the user presses Enter on the keyboard. } override fun onInputTextChanged(text: String) { // You will receive this callback as the user is typing. The update // frequency is determined by the host. } }
Java
InputCallback callback = new InputCallback() { @Override public void onInputSubmitted(@NonNull String text) { // You will receive this callback when the user presses Enter on the keyboard. } @Override public void onInputTextChanged(@NonNull String text) { // You will receive this callback as the user is typing. The update // frequency is determined by the host. } };
נדרש InputCallback
בשביל InputSignInMethod
Builder
.
Kotlin
val passwordInput = InputSignInMethod.Builder(callback) .setHint("Password") .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD) ... .build()
Java
InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback) .setHint("Password") .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD) ... .build();
לבסוף, משתמשים בInputSignInMethod
החדש כדי ליצור SignInTemplate
.
Kotlin
SignInTemplate.Builder(passwordInput) .setTitle("Sign in with username and password") .setInstructions("Enter your password") .setHeaderAction(Action.BACK) ... .build()
Java
new SignInTemplate.Builder(passwordInput) .setTitle("Sign in with username and password") .setInstructions("Enter your password") .setHeaderAction(Action.BACK) ... .build();
שימוש ב-AccountManager
אפליקציות ל-Android Automotive OS שכוללות אימות צריכות להשתמש ב-AccountManager מהסיבות הבאות:
- חוויית משתמש משופרת וניהול חשבונות קל יותר: המשתמשים יכולים לנהל בקלות את כל החשבונות שלהם דרך תפריט החשבונות בהגדרות המערכת, כולל כניסה ויציאה.
- חוויות של 'אורח': מכיוון שמכוניות הן מכשירים משותפים, יצרני ציוד מקורי יכולים להפעיל חוויות של 'אורח' ברכב, שבהן אי אפשר להוסיף חשבונות.
הוספת וריאציות של מחרוזות טקסט
במסכים שונים ברכב יכולות להופיע כמויות שונות של טקסט. ב-Car App API ברמה 2 ומעלה, אפשר לציין כמה וריאציות של מחרוזת טקסט כדי להתאים אותה בצורה הכי טובה למסך. כדי לראות איפה מתקבלים וריאציות של טקסט, מחפשים תבניות ורכיבים שמקבלים CarText
.
אפשר להוסיף וריאציות של מחרוזות טקסט ל-CarText
באמצעות השיטה
CarText.Builder.addVariant()
:
Kotlin
val itemTitle = CarText.Builder("This is a very long string") .addVariant("Shorter string") ... .build()
Java
CarText itemTitle = new CarText.Builder("This is a very long string") .addVariant("Shorter string") ... .build();
אחר כך אפשר להשתמש ב-CarText
, למשל כטקסט הראשי של GridItem
.
Kotlin
GridItem.Builder() .addTitle(itemTitle) ... .build()
Java
new GridItem.Builder() .addTitle(itemTitle) ... build();
מוסיפים מחרוזות בסדר יורד של העדפה – למשל, מהארוכה ביותר לקצרה ביותר. המארח בוחר את המחרוזת באורך המתאים בהתאם לכמות המקום שזמין במסך המכונית.
הוספת CarIcons מוטבעים לשורות
אתם יכולים להוסיף סמלים בתוך הטקסט כדי לשפר את המראה של האפליקציה באמצעות התג CarIconSpan
.
מידע נוסף על יצירת טווחים כאלה זמין במסמכי התיעוד של CarIconSpan.create
. במאמר Spantastic text styling with Spans מוסבר איך פועל עיצוב טקסט באמצעות תגי span.
Kotlin
val rating = SpannableString("Rating: 4.5 stars") rating.setSpan( CarIconSpan.create( // Create a CarIcon with an image of four and a half stars CarIcon.Builder(...).build(), // Align the CarIcon to the baseline of the text CarIconSpan.ALIGN_BASELINE ), // The start index of the span (index of the character '4') 8, // The end index of the span (index of the last 's' in "stars") 16, Spanned.SPAN_INCLUSIVE_INCLUSIVE ) val row = Row.Builder() ... .addText(rating) .build()
Java
SpannableString rating = new SpannableString("Rating: 4.5 stars"); rating.setSpan( CarIconSpan.create( // Create a CarIcon with an image of four and a half stars new CarIcon.Builder(...).build(), // Align the CarIcon to the baseline of the text CarIconSpan.ALIGN_BASELINE ), // The start index of the span (index of the character '4') 8, // The end index of the span (index of the last 's' in "stars") 16, Spanned.SPAN_INCLUSIVE_INCLUSIVE ); Row row = new Row.Builder() ... .addText(rating) .build();
Car Hardware APIs
החל מרמת Car App API 3, בספריית Car App יש ממשקי API שאפשר להשתמש בהם כדי לגשת למאפיינים ולחיישנים של הרכב.
דרישות
כדי להשתמש בממשקי ה-API עם Android Auto, צריך קודם להוסיף תלות ב-androidx.car.app:app-projected
לקובץ build.gradle
של מודול Android Auto. ב-Android Automotive OS, מוסיפים תלות ב-androidx.car.app:app-automotive
לקובץ build.gradle
של מודול Android Automotive OS.
בנוסף, בקובץ AndroidManifest.xml
צריך להצהיר על ההרשאות הרלוונטיות שנדרשות כדי לבקש את נתוני הרכב שבהם רוצים להשתמש. חשוב לזכור שהמשתמש צריך גם להעניק לכם את ההרשאות האלה. אפשר להשתמש באותו קוד גם ב-Android Auto וגם ב-Android Automotive OS, במקום ליצור תהליכים שתלויים בפלטפורמה. עם זאת, ההרשאות הנדרשות שונות.
CarInfo
בטבלה הזו מתוארות התכונות שמוצגות על ידי ממשקי ה-API CarInfo
וההרשאות שצריך לבקש כדי להשתמש בהן:
שיטות | מאפיינים | הרשאות ב-Android Auto | הרשאות ב-Android Automotive OS | נתמך מגרסת Car App API |
---|---|---|---|---|
fetchModel |
יצרן, דגם, שנת ייצור | android.car.permission.CAR_INFO |
3 | |
fetchEnergyProfile |
סוגי מחברים של רכב חשמלי, סוגי דלק | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_INFO |
3 |
fetchExteriorDimensions
הנתונים האלה זמינים רק בחלק מהרכבים עם Android Automotive OS שפועלת בהם גרסה API 30 ומעלה |
מידות חיצוניות | לא רלוונטי | android.car.permission.CAR_INFO |
7 |
addTollListener
removeTollListener |
מצב כרטיס האגרה, סוג כרטיס האגרה | 3 | ||
addEnergyLevelListener
removeEnergyLevelListener |
רמת הטעינה של הסוללה, רמת הדלק, רמת הדלק נמוכה, הטווח שנותר | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_ENERGY ,android.car.permission.CAR_ENERGY_PORTS ,android.car.permission.READ_CAR_DISPLAY_UNITS
|
3 |
addSpeedListener
removeSpeedListener |
מהירות גולמית, מהירות מוצגת (מוצגת בלוח המחוונים של הרכב) | com.google.android.gms.permission.CAR_SPEED |
android.car.permission.CAR_SPEED ,android.car.permission.READ_CAR_DISPLAY_UNITS |
3 |
addMileageListener
removeMileageListener
אזהרה: השם של ה-method |
מרחק במד המרחק | com.google.android.gms.permission.CAR_MILEAGE |
הנתונים האלה לא זמינים ב-Android Automotive OS לאפליקציות שהותקנו מחנות Play. | 3 |
לדוגמה, כדי לקבל את הטווח שנותר, יוצרים מופע של אובייקט CarInfo
, ואז יוצרים ומลงים OnCarDataAvailableListener
:
Kotlin
val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo val listener = OnCarDataAvailableListener<EnergyLevel> { data -> if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) { val rangeRemaining = data.rangeRemainingMeters.value } else { // Handle error } } carInfo.addEnergyLevelListener(carContext.mainExecutor, listener) … // Unregister the listener when you no longer need updates carInfo.removeEnergyLevelListener(listener)
Java
CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo(); OnCarDataAvailableListener<EnergyLevel> listener = (data) -> { if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) { float rangeRemaining = data.getRangeRemainingMeters().getValue(); } else { // Handle error } }; carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener); … // Unregister the listener when you no longer need updates carInfo.removeEnergyLevelListener(listener);
אל תניחו שהנתונים מהרכב זמינים בכל רגע.
אם מופיעה שגיאה, כדאי לבדוק את הסטטוס של הערך שביקשתם כדי להבין טוב יותר למה לא ניתן לאחזר את הנתונים שביקשתם. במאמרי העזרה מופיעה ההגדרה המלאה של המחלקה CarInfo
.
CarSensors
הסיווג CarSensors
מאפשר גישה למד התאוצה, לג'ירוסקופ, למצפן ולנתוני המיקום של הרכב. יכול להיות שהזמינות של הערכים האלה תהיה תלויה ביצרן הציוד המקורי. הפורמט של הנתונים ממד התאוצה, מהג'ירוסקופ ומהמצפן זהה לפורמט שמתקבל מ-SensorManager
API. לדוגמה, כדי לבדוק את כיוון הנסיעה של הרכב:
Kotlin
val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors val listener = OnCarDataAvailableListener<Compass> { data -> if (data.orientations.status == CarValue.STATUS_SUCCESS) { val orientation = data.orientations.value } else { // Data not available, handle error } } carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener) … // Unregister the listener when you no longer need updates carSensors.removeCompassListener(listener)
Java
CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors(); OnCarDataAvailableListener<Compass> listener = (data) -> { if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) { List<Float> orientations = data.getOrientations().getValue(); } else { // Data not available, handle error } }; carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(), listener); … // Unregister the listener when you no longer need updates carSensors.removeCompassListener(listener);
כדי לגשת לנתוני מיקום מהרכב, צריך גם להצהיר על ההרשאה android.permission.ACCESS_FINE_LOCATION
ולבקש אותה.
בדיקה
כדי לדמות נתוני חיישנים כשבודקים ב-Android Auto, אפשר לעיין בקטעים Sensors (חיישנים) ו-Sensor configuration (הגדרת חיישנים) במדריך Desktop Head Unit (יחידה ראשית למחשב). כדי לדמות נתוני חיישנים כשבודקים ב-Android Automotive OS, אפשר לעיין בקטע הדמיה של מצב החומרה במדריך לאמולטור של Android Automotive OS.
מחזורי החיים של CarAppService, Session ו-Screen
הממשק LifecycleOwner
מוטמע במחלקות Session
ו-Screen
. במהלך האינטראקציה של המשתמש עם האפליקציה, מופעלים קריאות חוזרות (callbacks) של מחזור החיים של האובייקטים Session
ו-Screen
, כפי שמתואר בתרשימים הבאים.
מחזור החיים של CarAppService ושל סשן

Session
מחזור החייםפרטים מלאים זמינים במסמכי התיעוד של השיטה Session.getLifecycle
.
מחזור החיים של מסך

Screen
מחזור החייםפרטים מלאים זמינים במסמכי התיעוד של השיטה Screen.getLifecycle
.
הקלטה מהמיקרופון של הרכב
באמצעות CarAppService
של האפליקציה ו-API CarAudioRecord
, אפשר להעניק לאפליקציה גישה למיקרופון של הרכב של המשתמש. המשתמשים צריכים לתת לאפליקציה שלכם הרשאה לגשת למיקרופון של הרכב. האפליקציה יכולה להקליט ולעבד את הקלט של המשתמש בתוך האפליקציה.
הרשאה להקלטה
לפני שמקליטים אודיו, צריך קודם להצהיר על ההרשאה להקלטה בקובץ AndroidManifest.xml
ולבקש מהמשתמש להעניק אותה.
<manifest ...>
...
<uses-permission android:name="android.permission.RECORD_AUDIO" />
...
</manifest>
צריך לבקש את ההרשאה להקלטה בזמן הריצה. בקטע בקשת הרשאות מוסבר איך לבקש הרשאה באפליקציה לרכב.
הקלטת אודיו
אחרי שהמשתמש נותן הרשאה להקלטה, אפשר להקליט את האודיו ולעבד את ההקלטה.
Kotlin
val carAudioRecord = CarAudioRecord.create(carContext) carAudioRecord.startRecording() val data = ByteArray(CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) while(carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) { // Use data array // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech } carAudioRecord.stopRecording()
Java
CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext()); carAudioRecord.startRecording(); byte[] data = new byte[CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE]; while (carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) { // Use data array // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech } carAudioRecord.stopRecording();
מיקוד אודיו
כשמקליטים באמצעות המיקרופון של הרכב, צריך קודם להשיג מיקוד אודיו כדי לוודא שהמדיה שפועלת תופסק. אם מאבדים את המיקוד באודיו, צריך להפסיק את ההקלטה.
דוגמה לאופן ההשגה של פוקוס אודיו:
Kotlin
val carAudioRecord = CarAudioRecord.create(carContext) // Take audio focus so that user's media is not recorded val audioAttributes = AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // Use the most appropriate usage type for your use case .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) .build() val audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener { state: Int -> if (state == AudioManager.AUDIOFOCUS_LOSS) { // Stop recording if audio focus is lost carAudioRecord.stopRecording() } } .build() if (carContext.getSystemService(AudioManager::class.java) .requestAudioFocus(audioFocusRequest) != AudioManager.AUDIOFOCUS_REQUEST_GRANTED ) { // Don't record if the focus isn't granted return } carAudioRecord.startRecording() // Process the audio and abandon the AudioFocusRequest when done
Java
CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext()); // Take audio focus so that user's media is not recorded AudioAttributes audioAttributes = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // Use the most appropriate usage type for your use case .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) .build(); AudioFocusRequest audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener(state -> { if (state == AudioManager.AUDIOFOCUS_LOSS) { // Stop recording if audio focus is lost carAudioRecord.stopRecording(); } }) .build(); if (getCarContext().getSystemService(AudioManager.class).requestAudioFocus(audioFocusRequest) != AUDIOFOCUS_REQUEST_GRANTED) { // Don't record if the focus isn't granted return; } carAudioRecord.startRecording(); // Process the audio and abandon the AudioFocusRequest when done
Testing Library
ספריית הבדיקה של Android for Cars מספקת מחלקות עזר שאפשר להשתמש בהן כדי לאמת את התנהגות האפליקציה בסביבת בדיקה.
לדוגמה, הפקודה
SessionController
מאפשרת לדמות חיבור למארח ולאמת שנוצרו והוחזרו
Screen
ו-Template
הנכונים.
דוגמאות לשימוש מופיעות בדוגמאות.
דיווח על בעיה בספריית האפליקציות של Android למכוניות
אם נתקלתם בבעיה בספרייה, אתם יכולים לדווח עליה באמצעות כלי המעקב אחר בעיות של Google. חשוב למלא את כל הפרטים הנדרשים בתבנית הבעיה.
לפני שפותחים בעיה חדשה, כדאי לבדוק אם היא מופיעה בהערות על הגרסה של הספרייה או ברשימת הבעיות. כדי להירשם לעדכונים על בעיות ולהצביע עליהן, לוחצים על הכוכב של הבעיה בכלי למעקב. מידע נוסף זמין במאמר בנושא הרשמה לבעיה.