تتيح لك مكتبة تطبيقات Android للسيارات استخدام تطبيقات التنقّل ونقاط الاهتمام (POI) وإنترنت الأشياء (IOT) في السيارة. ويتم ذلك من خلال توفير مجموعة من القوالب المصمَّمة لتلبية معايير منع تشتيت السائق والاهتمام بالتفاصيل مثل مجموعة متنوعة من عوامل شاشة السيارة وطُرق الإدخال.
يقدم هذا الدليل نظرة عامة على الميزات والمفاهيم الرئيسية للمكتبة ويرشدك خلال عملية إعداد تطبيق أساسي.
قبل البدء
- مراجعة صفحات Design for Drive
التي تغطي مكتبة تطبيقات السيارات
- نظرة عامة على فئة تطبيقات التنقل والتطبيقات الأخرى المتعلقة بالقيادة
- نظرة عامة على إنشاء التطبيقات باستخدام النماذج
- وحدات أساسية تشمل النماذج ومكوّنات النماذج
- نموذج تدفقات توضح أنماط تجربة المستخدم الشائعة
- متطلبات التطبيقات المستندة إلى نموذج
- راجع المصطلحات والمفاهيم الرئيسية في القسم التالي.
- تعرَّف على واجهة مستخدم نظام Android Auto وتصميم نظام التشغيل Android Automotive.
- راجِع ملاحظات الإصدار.
- راجِع عيّنات.
المصطلحات والمفاهيم الرئيسية
- النماذج والنماذج
- يتم تمثيل واجهة المستخدم برسم بياني لعناصر النموذج التي يمكن ترتيبها معًا بطرق مختلفة على النحو الذي يسمح به النموذج الذي تنتمي إليه. النماذج هي مجموعة فرعية من النماذج التي يمكن أن تعمل كجذر في تلك الرسوم البيانية. وتتضمّن النماذج المعلومات التي سيتم عرضها للمستخدم في شكل نص وصور بالإضافة إلى سمات لضبط جوانب المظهر المرئي لهذه المعلومات، مثل ألوان النص أو أحجام الصور. يحوّل المضيف النماذج إلى طرق عرض مصمّمة لتلبية معايير تشتيت السائق، ويهتم بالتفاصيل مثل مجموعة متنوعة من عوامل شاشة السيارة وطُرق الإدخال.
- المضيف
- المضيف هو مكوّن الخلفية الذي ينفّذ الوظائف التي توفّرها واجهات برمجة التطبيقات للمكتبة كي يتسنى تشغيل التطبيق في السيارة. وتتراوح مسؤوليات المضيف من اكتشاف تطبيقك وإدارة مراحل نشاطه وتحويل نماذجك إلى مشاهدات وإشعار التطبيق بتفاعلات المستخدمين. على الأجهزة الجوّالة، يتم تنفيذ هذا المضيف من خلال Android Auto. على نظام التشغيل Android Automotive، يتم تثبيت هذا المضيف كتطبيق نظام.
- القيود على النماذج
- تفرض النماذج المختلفة قيودًا في محتوى نماذجها. على سبيل المثال، تفرض قوالب القوائم حدودًا على عدد العناصر التي يمكن تقديمها للمستخدم. تحتوي القوالب أيضًا على قيود في الطريقة التي يمكن ربطها بها لتشكيل تدفق المهمة. على سبيل المثال، يمكن للتطبيق دفع ما يصل إلى خمسة قوالب فقط إلى مكدس الشاشة. يمكنك الاطّلاع على قيود النماذج لمعرفة مزيد من التفاصيل.
Screen
Screen
هي فئة توفّرها المكتبة التي تنفّذها التطبيقات لإدارة واجهة المستخدم المقدَّمة للمستخدم. تشملScreen
دورة حياة وتوفر آلية للتطبيق لإرسال النموذج عندما تكون الشاشة مرئية. يمكن أيضًا فرض مثيلاتScreen
وتمييزها من حزمةScreen
وإليها، ما يضمن التقيّد بقيود تدفق النموذج.CarAppService
CarAppService
هي فئةService
مجردة يجب أن ينفّذها تطبيقك ويصدّرها حتى يتمكن المضيف من اكتشافه وإدارته. إنّCarAppService
في تطبيقك مسؤول عن التحقّق من إمكانية الوثوق في اتصال مضيف باستخدامcreateHostValidator
وبالتالي توفيرSession
مثيلات لكل اتصال باستخدامonCreateSession
.Session
Session
هي فئة مجردة يجب أن ينفّذها تطبيقك ويعيد عرضها باستخدامCarAppService.onCreateSession
. وهو بمثابة نقطة دخول لعرض المعلومات على شاشة السيارة. وله دورة حياة تحدد الحالة الحالية لتطبيقك على شاشة السيارة، على سبيل المثال عندما يكون تطبيقك مرئيًا أو مخفيًا.عند بدء
Session
، مثلاً عند إطلاق التطبيق لأول مرة، يطلب المضيف عرض علامةScreen
الأولى باستخدام الطريقةonCreateScreen
.
تثبيت مكتبة تطبيقات السيارة
انتقِل إلى صفحة إصدار مكتبة Jetpack للحصول على تعليمات حول كيفية إضافة المكتبة إلى تطبيقك.
ضبط ملفات بيان تطبيقك
قبل أن تتمكّن من إنشاء تطبيق السيارة، عليك ضبط ملفات البيان في تطبيقك على النحو التالي.
الإفصاح عن CarAppService
يتصل المضيف بتطبيقك من خلال تنفيذ CarAppService
. لقد أفصحت عن هذه الخدمة في ملف البيان للسماح للمضيف باكتشاف تطبيقك والاتصال به.
يجب أيضًا توضيح فئة تطبيقك في العنصر <category>
ضِمن فلتر الأهداف في تطبيقك. راجِع قائمة فئات التطبيقات المتوافقة لمعرفة القيم المسموح بها لهذا العنصر.
يعرض مقتطف الرمز التالي في البيان كيفية الإشارة إلى خدمة تطبيق خاص بالسيارات لنقطة اهتمام في البيان:
<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>
فئات التطبيقات المتوافقة
يُرجى تعريف فئة تطبيقك عن طريق إضافة قيمة واحدة أو أكثر من قيم الفئات التالية في فلتر الأهداف عند تعريف CarAppService
كما هو موضّح في القسم السابق:
androidx.car.app.category.NAVIGATION
: تطبيق يوفّر اتجاهات التنقّل المفصّلة. اطلع على إنشاء تطبيقات التنقل للسيارات للحصول على وثائق إضافية حول هذه الفئة.androidx.car.app.category.POI
: تطبيق يوفر وظائف ذات صلة بالعثور على نقاط الاهتمام مثل مواقف السيارات ومحطات الشحن ومحطات الوقود راجع إنشاء تطبيقات نقاط الاهتمام للسيارات للحصول على وثائق إضافية حول هذه الفئة.androidx.car.app.category.IOT
: تطبيق يتيح للمستخدمين اتخاذ الإجراءات ذات الصلة على الأجهزة المتصلة من داخل السيارة. راجع إنشاء تطبيقات إنترنت من الأشياء للسيارات للحصول على وثائق إضافية حول هذه الفئة.
راجع جودة تطبيقات Android للسيارات للحصول على أوصاف تفصيلية لكل فئة والمعايير التي يجب أن تنتمي إليها التطبيقات.
تحديد اسم التطبيق ورمزه
يجب تحديد اسم تطبيق ورمز يمكن للمضيف استخدامهما لتمثيل تطبيقك في واجهة مستخدِم النظام.
يمكنك تحديد اسم التطبيق ورمزه المُستخدَمان لتمثيل تطبيقك باستخدام السمتَين 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>
مستوى واجهة برمجة تطبيقات تطبيق السيارة
تحدد مكتبة تطبيقات السيارات مستويات واجهة برمجة التطبيقات الخاصة بها حتى تتمكن من معرفة ميزات المكتبة التي يدعمها مضيف النموذج في السيارة.
لاسترداد أعلى مستوى لواجهة برمجة تطبيقات Car App API يتيحه المضيف، استخدِم الطريقة
getCarAppApiLevel()
.
يُرجى توضيح الحد الأدنى لمستوى واجهة برمجة التطبيقات لتطبيق السيارة الذي يتيحه تطبيقك في
ملف AndroidManifest.xml
:
<manifest ...>
<application ...>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
</application>
</manifest>
للاطّلاع على تفاصيل حول كيفية الحفاظ على التوافق مع الأنظمة القديمة وتقديم حدّ أدنى لمستوى واجهة برمجة التطبيقات المطلوب لاستخدام إحدى الميزات، يُرجى الاطّلاع على المستندات الخاصة بالتعليق التوضيحي الخاص RequiresCarApi
. للتعرّف على مستوى واجهة برمجة التطبيقات المطلوب لاستخدام ميزة معيّنة في "مكتبة تطبيقات السيارة"، يُرجى الاطّلاع على المستندات المرجعية الخاصة بالسمة CarAppApiLevels
.
إنشاء CarAppService والجلسة
يحتاج تطبيقك إلى توسيع فئة
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
.
تسمح البهلة المسبقة للمستخدمين بالرجوع إلى الشاشات السابقة من الشاشة الأولى التي يعرضها تطبيقك.
إنشاء شاشة البدء
يمكنك إنشاء الشاشات التي يعرضها تطبيقك من خلال تحديد الفئات التي توسّع
فئة 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
" أيضًا وظائف أخرى، مثل السماح لك بتحميل الموارد القابلة للرسم باستخدام الإعدادات التي ضبطتها من شاشة السيارة، وتشغيل تطبيق في السيارة باستخدام عناصر intent، والإشارة إلى ما إذا كان يجب أن يعرض تطبيقك خريطته في المظهر الداكن.
تنفيذ التنقل على الشاشة
غالبًا ما تقدم التطبيقات عددًا من الشاشات المختلفة، وربما يستخدم كل منها قوالب مختلفة يمكن للمستخدم التنقل خلالها أثناء تفاعله مع الواجهة المعروضة في الشاشة.
توفّر الفئة 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
.
رسم الخرائط
يمكن لتطبيقات نقاط الاهتمام التي تستخدم النماذج التالية رسم خرائط من خلال الوصول إلى Surface
:
النموذج | إذن النموذج | إرشادات متعلّقة بالفئة |
---|---|---|
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 للسيارات.
لتحديد ما إذا كنت تريد رسم خريطة مظلمة، يمكنك استخدام الطريقة
CarContext.isDarkMode
. كلما تغيّرت حالة المظهر الداكن، ستتلقّى مكالمة
Session.onCarConfigurationChanged
.
السماح للمستخدمين بالتفاعل مع خريطتك
عند استخدام النماذج التالية، يمكنك إضافة دعم للمستخدمين للتفاعل مع الخرائط التي ترسمها، مثل السماح لهم بمشاهدة أجزاء مختلفة من الخريطة عن طريق التكبير والتصغير والتدوير.
النموذج | ميزة التفاعل متاحة منذ مستوى واجهة برمجة تطبيقات تطبيق السيارة |
---|---|
NavigationTemplate |
2 |
PlaceListNavigationTemplate (متوقّفة نهائيًا) |
4 |
RoutePreviewNavigationTemplate (متوقّفة نهائيًا) |
4 |
MapTemplate (متوقّفة نهائيًا) |
5 (مقدمة النموذج) |
MapWithContentTemplate |
7 (مقدمة النموذج) |
تنفيذ استدعاءات التفاعل
تحتوي واجهة SurfaceCallback
على العديد من طرق معاودة الاتصال التي يمكنك تنفيذها لإضافة التفاعل إلى الخرائط التي تم إنشاؤها
باستخدام النماذج الواردة في القسم السابق:
التفاعل | طريقة واحدة (SurfaceCallback ) |
يتوفّر هذا الخيار منذ مستوى واجهة برمجة التطبيقات لتطبيق السيارة. |
---|---|---|
النقر | onClick |
5 |
التكبير/التصغير بإصبعَين | onScale |
2 |
السحب بلمسة واحدة | onScroll |
2 |
الانتقال بلمسة واحدة | onFling |
2 |
النقر مرتين | onScale (مع عامل قياس يحدّده مضيف النموذج) |
2 |
تحريك دوّار في وضع التحريك | onScroll (مع تحديد عامل المسافة من قِبل مضيف النموذج) |
2 |
إضافة شريط إجراءات للخريطة
يمكن أن تحتوي هذه النماذج على شريط إجراءات للخريطة لتنفيذ الإجراءات المتعلقة بالخريطة مثل التكبير والتصغير وإعادة التوسيط وعرض بوصلة وغيرها من الإجراءات التي تختار عرضها. يمكن أن يحتوي شريط إجراءات الخريطة على ما يصل إلى أربعة أزرار للرموز فقط يمكن تحديثها دون التأثير على عمق المهمة. ويختفي أثناء حالة الخمول ويظهر مرة أخرى في حالة النشاط.
لتلقّي طلبات معاودة الاتصال بالنشاط على الخريطة، عليك إضافة زر 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();
يمكن أن تؤثر الإشعارات في الأجزاء التالية من واجهة المستخدم:
- قد يظهر إشعار تنبيه (HUN) للمستخدم.
- يمكنك إضافة إدخال في مركز الإشعارات، ويمكنك بشكل اختياري إضافة شارة تظهر في السكة الحديدية.
- بالنسبة إلى تطبيقات التنقّل، قد يتم عرض الإشعار في التطبيق المصغّر للسكك الحديدية كما هو موضّح في الإشعارات المفصّلة.
يمكنك اختيار طريقة ضبط إشعارات التطبيق للتأثير في كل عنصر من عناصر واجهة المستخدم هذه باستخدام أولوية الإشعار كما هو موضّح
في مستندات
CarAppExtender
.
إذا تم استدعاء
NotificationCompat.Builder.setOnlyAlertOnce
والقيمة true
، سيظهر الإشعار
ذو الأولوية العالية كـ HUN مرة واحدة فقط.
للحصول على مزيد من المعلومات حول كيفية تصميم إشعارات تطبيق السيارة، اطّلع على دليل "تصميم Google للقيادة" حول الإشعارات.
عرض الخبز المحمص
يمكن لتطبيقك عرض إشعار منبثق باستخدام CarToast
كما هو موضّح في هذا المقتطف:
Kotlin
CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()
Java
CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();
طلب الأذونات
إذا كان تطبيقك يحتاج إلى الوصول إلى بيانات أو إجراءات مشروطة، مثل الموقع الجغرافي، تسري القواعد العادية لأذونات Android. لطلب إذن، يمكنك استخدام
الطريقة
CarContext.requestPermissions()
.
إنّ فائدة استخدام
CarContext.requestPermissions()
على عكس استخدام
واجهات برمجة تطبيقات Android العادية
أنّك لست بحاجة إلى تشغيل Activity
الخاص بك لإنشاء مربّع حوار الأذونات. علاوةً على ذلك، يمكنك استخدام الرمز نفسه على كل من
Android Auto وAndroid Automotive، بدلاً من الحاجة إلى إنشاء مسارات تعتمد على النظام الأساسي.
ضبط نمط مربّع حوار الأذونات على 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>
شغِّل تطبيق سيارة هادفة.
يمكنك استدعاء الطريقة
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
في تطبيقك هذا الهدف من خلال دفع شاشة حجز موقف السيارات
على الحزمة إذا لم تكن موجودة في الأعلى:
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())); } } }
يمكنك الانتقال إلى قسم عرض الإشعارات للحصول على مزيد من المعلومات حول كيفية التعامل مع الإشعارات الخاصة بتطبيق السيارة.
القيود على النماذج
يحدد المضيف عدد النماذج التي يتم عرضها لمهمة معينة بحد أقصى خمسة نماذج، يجب أن يكون النموذج الأخير أحد الأنواع التالية:
يُرجى العِلم أنّ هذا الحد الأقصى ينطبق على عدد النماذج وليس على عدد مثيلات
Screen
في الحزمة. على سبيل المثال، إذا أرسل أحد التطبيقات نموذجين أثناء وجوده في الشاشة A، ثم دفع الشاشة B، فيمكنه الآن إرسال ثلاثة نماذج أخرى. بدلاً من ذلك، إذا تم تنظيم كل شاشة لإرسال نموذج واحد، يمكن للتطبيق إرسال خمس مثيلات للشاشة إلى حزمة ScreenManager
.
هناك حالات خاصة لهذه القيود: عمليات إعادة تحميل النموذج وعمليات الرجوع وإعادة الضبط.
عمليات إعادة تحميل النموذج
لا يتم احتساب بعض تعديلات المحتوى ضمن الحدّ الأقصى لعدد النماذج. وبشكل عام، إذا فرض أحد التطبيقات نموذجًا جديدًا من النوع نفسه ويحتوي على المحتوى الرئيسي نفسه مثل النموذج السابق، لن يُحتسب النموذج الجديد ضمن الحصة. على سبيل المثال، لا يُحتسب تعديل حالة الإيقاف لصف في ListTemplate
ضمن الحصة. راجِع وثائق النماذج الفردية لمعرفة المزيد من المعلومات
حول أنواع تحديثات المحتوى التي يمكن اعتبارها تحديثًا.
عمليات الرجوع
لتفعيل التدفقات الفرعية ضمن إحدى المهام، يرصد المضيف عندما يعرض التطبيق Screen
من حزمة ScreenManager
ويعدّل الحصة المتبقية استنادًا إلى عدد النماذج التي يتنقل فيها التطبيق إلى الخلف.
على سبيل المثال، إذا كان التطبيق يرسل نموذجين أثناء وجوده في الشاشة "أ"، ثم يدفع الشاشة "ب" ويرسل نموذجين آخرين، فإن التطبيق يحتوي على حصة واحدة متبقية. إذا عاد التطبيق بعد ذلك إلى الشاشة "أ"، يعيد المضيف ضبط الحصة إلى ثلاث، لأن التطبيق تراجع بنموذجين.
لاحظ أنه عند العودة إلى الشاشة، يجب أن يرسل التطبيق نموذجًا من نفس النوع مثل آخر نموذج تم إرساله بواسطة تلك الشاشة. يؤدي إرسال أي نوع قالب آخر إلى حدوث خطأ. ومع ذلك، طالما أن النوع يظل كما هو أثناء عملية الرجوع، يمكن للتطبيق تعديل محتوى النموذج بحرية بدون التأثير في الحصة.
إعادة ضبط العمليات
تحتوي بعض القوالب على دلالات خاصة تشير إلى نهاية المهمة. على سبيل المثال،
NavigationTemplate
هي ملف شخصي من المتوقّع أن يظل معروضًا على الشاشة وتتم إعادة تحميله مع إضافة تعليمات مفصّلة
جديدة حول استهلاك المستخدم. عندما يصل المضيف إلى أحد هذه القوالب، يعيد المضيف تعيين حصة النموذج، ويتعامل مع هذا النموذج كما لو أنه الخطوة الأولى في مهمة جديدة. يسمح هذا الإجراء للتطبيق ببدء مهمة جديدة.
راجع وثائق النماذج الفردية لمعرفة النماذج التي تؤدي إلى إعادة الضبط على المضيف.
وإذا تلقى المضيف نية بدء تشغيل التطبيق من خلال إجراء إشعار أو من مشغّل التطبيقات، تتم أيضًا إعادة ضبط الحصة. تسمح هذه الآلية للتطبيق ببدء مهمة جديدة من الإشعارات، وتظل صحيحة حتى إذا كان التطبيق مرتبطًا بالفعل وفي المقدمة.
يمكنك الانتقال إلى قسم عرض الإشعارات للحصول على مزيد من التفاصيل حول طريقة عرض إشعارات تطبيقك على شاشة السيارة. يمكنك الاطّلاع على قسم تشغيل تطبيق للسيارة من خلال هدف للحصول على معلومات عن طريقة بدء تشغيل تطبيقك من خلال إشعار.
واجهة برمجة تطبيقات الاتصال
يمكنك تحديد ما إذا كان تطبيقك يعمل على Android Auto أو Android Automotive من خلال استخدام واجهة برمجة تطبيقات CarConnection
لاسترداد معلومات الاتصال في وقت التشغيل.
على سبيل المثال، في Session
لتطبيق السيارة، يمكنك إعداد CarConnection
والاشتراك في تحديثات LiveData
:
Kotlin
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)
Java
new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);
في المراقب، يمكنك بعد ذلك التفاعل مع التغييرات في حالة الاتصال:
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(); }
واجهة برمجة التطبيقات للقيود
قد تتيح السيارات المختلفة عرض عدد مختلف من مثيلات
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
مع المستوى 2 والأعلى من واجهة برمجة تطبيقات Car App API لتسجيل الدخول إلى تطبيقك على
وحدة السيارة الرئيسية.
لإنشاء SignInTemplate
، يجب تحديد SignInMethod
. تتيح مكتبة تطبيقات
سيارة السيارة حاليًا طرق تسجيل الدخول التالية:
InputSignInMethod
لتسجيل الدخول باسم المستخدم أو كلمة المرورPinSignInMethod
لتسجيل الدخول باستخدام رقم التعريف الشخصي، حيث يربط المستخدم حسابه من هاتفه باستخدام رقم تعريف شخصي يظهر على الوحدة الرئيسية.ProviderSignInMethod
لتسجيل الدخول إلى مقدّم الخدمة، مثل تسجيل الدخول بحساب Google ونقرة واحدةQRCodeSignInMethod
لتسجيل الدخول باستخدام رمز الاستجابة السريعة، يمسح المستخدم ضوئيًا رمز الاستجابة السريعة لإكمال عملية تسجيل الدخول على هاتفه. تتوفّر هذه الميزة مع المستوى 4 والأعلى من واجهة برمجة تطبيقات Car API.
على سبيل المثال، لتنفيذ نموذج يجمع كلمة مرور المستخدم، ابدأ
بإنشاء 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();
استخدام مدير الحساب
إنّ التطبيقات التي تعمل بنظام التشغيل Android Automotive وتتضمّن مصادقة يجب أن تستخدم أداة AccountManager للأسباب التالية:
- تجربة أفضل وسهولة في إدارة الحسابات: يمكن للمستخدمين إدارة جميع حساباتهم بسهولة من قائمة الحسابات في إعدادات النظام، بما في ذلك معلومات تسجيل الدخول وتسجيل الخروج.
- تجارب"الضيف": بما أنّ السيارات هي أجهزة مشتركة، يمكن للمصنّعين الأصليين للأجهزة تفعيل تجارب الضيوف في المركبة، حيث لا يمكن إضافة حسابات.
إضافة صيغ السلسلة النصية
قد تعرض أحجام شاشات السيارة المختلفة كميات مختلفة من النص. من خلال المستوى 2 والأعلى من واجهة برمجة تطبيقات Car App API، يمكنك تحديد صيغ متعددة لسلسلة نصية لتناسب الشاشة على أفضل نحو. للتعرّف على الأماكن التي تقبل فيها خيارات المنتجات النصية، ابحث عن النماذج
والمكوّنات التي تحمل رمز 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
لمزيد من المعلومات حول إنشاء هذه النطاقات. يمكنك الاطّلاع على
نمط النص
السريع باستخدام Spans للحصول على نظرة عامة حول طريقة عمل نمط النص باستخدام الامتدادات.
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();
واجهات برمجة تطبيقات أجهزة السيارة
بدءًا من المستوى 3 من واجهة برمجة تطبيقات Car App Library، تحتوي "مكتبة تطبيقات السيارة" على واجهات برمجة تطبيقات يمكنك استخدامها للوصول إلى خصائص المركبة وأدوات الاستشعار.
المتطلبات الأساسية
لاستخدام واجهات برمجة التطبيقات مع Android Auto، عليك البدء بإضافة ملف يعتمد على androidx.car.app:app-projected
إلى ملف build.gradle
الخاص بوحدة Android Auto. بالنسبة إلى نظام التشغيل Android Automotive، أضِف اعتمادية على androidx.car.app:app-automotive
إلى ملف build.gradle
في وحدة نظام التشغيل Android Automotive.
بالإضافة إلى ذلك، في ملف AndroidManifest.xml
، يجب توضيح
الأذونات ذات الصلة اللازمة
لطلب بيانات السيارة التي تريد استخدامها. يُرجى العِلم بأنّ هذه الأذونات يجب أن يمنحكها المستخدم أيضًا. يمكنك استخدام الرمز نفسه على كل من Android Auto وAndroid Automotive، بدلاً من إنشاء مسارات تعتمد على النظام الأساسي. ومع ذلك، تختلف الأذونات
المطلوبة.
معلومات السيارة
يوضّح هذا الجدول السمات التي تعرضها واجهات برمجة تطبيقات
CarInfo
والأذونات التي تحتاج إلى طلب استخدامها:
الطرق | الخصائص | أذونات Android Auto | أذونات نظام التشغيل Android Automotive | يتوفّر هذا الخيار منذ مستوى واجهة برمجة التطبيقات لتطبيق السيارة. |
---|---|---|---|---|
fetchModel |
الماركة والطراز والسنة | android.car.permission.CAR_INFO |
3 | |
fetchEnergyProfile |
أنواع وصلات المركبات الكهربائية وأنواع الوقود | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_INFO |
3 |
fetchExteriorDimensions
تتوفّر هذه البيانات فقط على بعض المركبات التي تعمل بنظام التشغيل Android Automotive والتي تعمل بالإصدار 30 من واجهة برمجة التطبيقات (API) أو الإصدارات الأحدث. |
الأبعاد الخارجية | لا ينطبق | 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 |
مسافة عدّاد المسافات | com.google.android.gms.permission.CAR_MILEAGE |
لا تتوفّر هذه البيانات على نظام التشغيل Android Automotive للتطبيقات المثبَّتة من "متجر 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
إمكانية الوصول إلى مقياس التسارع والجيروسكوب والبوصلة وبيانات الموقع الجغرافي للمركبة. وقد يعتمد مدى توفُّر هذه القيم على المصنّع الأصلي للجهاز. إنّ تنسيق البيانات من مقياس التسارع والجيروسكوب والبوصلة هو نفسه الذي تستخدمه في 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، يمكنك الاطّلاع على قسمَي أجهزة الاستشعار وضبط أجهزة الاستشعار في دليل الوحدة الرئيسية للكمبيوتر المكتبي. لمحاكاة بيانات جهاز الاستشعار عند إجراء اختبار على نظام التشغيل Android Automotive، يمكنك الرجوع إلى قسم محاكاة حالة الجهاز في دليل محاكي نظام التشغيل Android Automotive.
دورات حياة CarAppService والجلسة والشاشة
تستخدم الفئتان Session
وScreen
الواجهة LifecycleOwner
. أثناء تفاعل المستخدم مع التطبيق، يتم استدعاء عمليات الاستدعاء للكائنَين Session
وScreen
على النحو الموضّح في الرسوم البيانية التالية.
دورات حياة CarAppService وجلسة
![](https://developer.android.com/static/images/training/cars/carappservice-session-lifecycle.png?authuser=5&hl=ar)
Session
.لمعرفة التفاصيل الكاملة، راجِع المستندات الخاصة بالطريقة
Session.getLifecycle
.
دورة حياة الشاشة
![](https://developer.android.com/static/images/training/cars/screen-lifecycle.png?authuser=5&hl=ar)
Screen
.لمعرفة التفاصيل الكاملة، اطّلِع على المستندات حول طريقة
Screen.getLifecycle
.
التسجيل من ميكروفون السيارة
باستخدام CarAppService
في تطبيقك وواجهة برمجة تطبيقات 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
مكتبة الاختبار
توفّر مكتبة
اختبار Android for Cars فئات إضافية
يمكنك استخدامها للتحقّق من سلوك تطبيقك في بيئة اختبار.
على سبيل المثال، تتيح لك العلامة
SessionController
محاكاة الاتصال بالمضيف والتحقّق من إنشاء
Screen
و
Template
وإرجاعهما بشكل صحيح.
راجِع مقالة عيّنات للاطّلاع على أمثلة على الاستخدام.
الإبلاغ عن مشكلة في مكتبة تطبيقات "Android للسيارات"
إذا واجهتك مشكلة في المكتبة، يمكنك الإبلاغ عنها باستخدام أداة تتبُّع المشاكل من Google. تأكَّد من ملء جميع المعلومات المطلوبة في نموذج المشكلة.
قبل تقديم أي مشكلة جديدة، يُرجى التحقق مما إذا كانت مدرجة ضمن ملاحظات إصدار المكتبة أو تم الإبلاغ عنها في قائمة المشاكل. يمكنك الاشتراك والتصويت للمشكلات من خلال النقر فوق النجمة لمشكلة في أداة التتبع. لمزيد من المعلومات، يُرجى الاطّلاع على الاشتراك في مشكلة.