تتيح لك مكتبة تطبيقات Android للسيارات استخدام تطبيقات التنقّل ونقاط الاهتمام (POI) وتطبيقات إنترنت الأشياء (IOT) في السيارة. ويُجري ذلك من خلال توفير مجموعة من النماذج المصمّمة لاستيفاء معايير الإلهاء عن السائق والاهتمام بالتفاصيل، مثل التنوع في عوامل شاشة السيارة وطرق الإدخال.
يوفّر هذا الدليل نظرة عامة على الميزات والمفاهيم الرئيسية للمكتبة ويرشدك إلى عملية إعداد تطبيق أساسي.
قبل البدء
- راجِع صفحات التصميم المناسب لقيادة السيارات
التي تتناول "مكتبة تطبيقات السيارات"
- .
- نظرة عامة على فئة تطبيقات التنقل والتطبيقات الأخرى المتعلقة بالقيادة
- نظرة عامة حول إنشاء التطبيقات باستخدام النماذج
- الوحدات الأساسية التي تغطي النماذج ومكونات النماذج
- عيّنات من مسارات المستخدم التي توضّح أنماط تجربة المستخدم الشائعة
- متطلبات التطبيقات المستندة إلى النماذج
- راجِع المصطلحات والمفاهيم الرئيسية في القسم التالي.
- اطّلِع على واجهة مستخدم نظام 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 يتوافق مع المضيف، استخدِم الأسلوب
getCarAppApiLevel()
.
يُرجى توضيح الحد الأدنى لمستوى واجهة برمجة التطبيقات لتطبيق السيارة الذي يتيحه تطبيقك في
ملف AndroidManifest.xml
:
<manifest ...>
<application ...>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
</application>
</manifest>
اطّلِع على مستندات التعليق التوضيحي
RequiresCarApi
لمعرفة تفاصيل عن كيفية الحفاظ على التوافق مع الإصدارات القديمة وتحديد
الحد الأدنى لمستوى واجهة برمجة التطبيقات المطلوب لاستخدام إحدى الميزات. للاطّلاع على تعريف لمستوى IDE
المطلوب لاستخدام ميزة معيّنة من "مكتبة تطبيقات السيارات"، يُرجى الاطّلاع على مستندات IDE
المرجعية الخاصة ب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
.
تتيح ميزة "التثبيت المُسبَق" للمستخدمين الانتقال إلى الشاشات السابقة من الشاشة الأولى التي يعرضها تطبيقك.
إنشاء شاشة البدء
يمكنك إنشاء الشاشات التي يعرضها تطبيقك من خلال تحديد فئات تُوسّع فئة
Screen
وتنفيذ أسلوب
onGetTemplate
الذي يعرض مثيل
Template
الذي يمثّل
حالة واجهة المستخدم المطلوب عرضها على شاشة السيارة.
يوضّح المقتطف التالي كيفية تعريف Screen
يستخدم PaneTemplate
لكي يعرض سلسلة "مرحبًا بك" بسيطة:
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
الذي تستخدمه تطبيقات التنقّل من نقطة إلى أخرى لمشاركة مَعلمات ScreenManager
الخاصة بالتنقّل وغيرها من الأحداث المتعلقة بالتنقّل مع المضيف.
اطّلِع على الوصول إلى نماذج التنقّل للحصول على قائمة شاملة بوظائف المكتبة المتاحة لتطبيقات التنقّل.
يوفّر 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
.
رسم الخرائط
يمكن لتطبيقات التنقّل ونقاط الاهتمام التي تستخدم النماذج التالية
رسم الخرائط من خلال الوصول إلى 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 (introduction of template) |
تنفيذ طلبات معاودة الاتصال للتفاعل
تحتوي واجهة SurfaceCallback
على عدة طرق لطلبات إعادة الاتصال يمكنك تنفيذها لإضافة تفاعل إلى الخرائط التي تم إنشاؤها
باستخدام النماذج الواردة في القسم السابق:
التفاعل | طريقة SurfaceCallback |
يتوفّر هذا الخيار منذ مستوى واجهة برمجة تطبيقات تطبيق السيارة. |
---|---|---|
نقر | onClick |
5 |
استخدام إصبعين للتصغير | onScale |
2 |
السحب بنقرة واحدة | onScroll |
2 |
التمرير سريعًا بلمسة واحدة | onFling |
2 |
النقر مرتين | onScale (مع عامل تحجيم يحدّده مضيف النموذج) |
2 |
الدفع بالتناوب في وضع العرض الشامل | onScroll (مع عامل المسافة الذي يحدّده مضيف النموذج) |
2 |
إضافة شريط إجراءات الخريطة
يمكن أن تحتوي هذه النماذج على شريط إجراءات الخريطة للإجراءات ذات الصلة بالخرائط، مثل magnification/التكبير والتصغير وإعادة التوسّط وعرض بوصلة وغيرها من الإجراءات التي تريد عرضها. يمكن أن يتضمّن شريط الإجراءات على الخريطة ما يصل إلى أربعة أزرار تتضمّن رموزًا فقط يمكن إعادة تحميلها بدون التأثير في عمق المهمة. يتم إخفاء الشعار أثناء وضع السكون ويظهر مرة أخرى في وضع النشاط.
لتلقّي طلبات معاودة الاتصال بالنشاط على الخريطة، عليك إضافة زر 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
إلى عرض يُفترض أن يظل معروضًا على الشاشة وأن يتم تعديله من خلال إضافة تعليمات جديدة تتعلّق بالاتّجاهات للمستخدم. وعندما يصل إلى أحد هذين
النموذجَين، يُعيد المضيف ضبط حصة النموذج، ويتعامل مع هذا النموذج كما لو كان
هو الخطوة الأولى لمهمة جديدة. ويسمح ذلك للتطبيق ببدء مهمة جديدة.
راجع وثائق النماذج الفردية لمعرفة النماذج التي تؤدي إلى إعادة الضبط على المضيف.
إذا تلقّى المضيف طلبًا لبدء التطبيق من إجراء إشعار أو من مشغّل التطبيقات، تتم إعادة ضبط الحصة أيضًا. تسمح هذه الآلية للتطبيق ببدء مهمة جديدة من الإشعارات، وتظل صحيحة حتى إذا كان التطبيق مرتبطًا بالفعل وفي المقدمة.
اطّلِع على قسم عرض الإشعارات للحصول على مزيد من التفاصيل حول كيفية عرض إشعارات تطبيقك على شاشة السيارة. اطّلِع على القسم بدء تطبيق سيارة باستخدام نية للحصول على معلومات عن كيفية بدء تطبيقك من إجراء إشعار.
واجهة برمجة التطبيقات Connection API
يمكنك تحديد ما إذا كان تطبيقك يعمل على Android Auto أو Android
Automotive OS باستخدام واجهة برمجة التطبيقات
CarConnection
API ل retrieving
معلومات الاتصال في وقت التشغيل.
على سبيل المثال، في 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(); }
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 وOne TapQRCodeSignInMethod
لتسجيل الدخول باستخدام رمز الاستجابة السريعة، يمسح المستخدم ضوئيًا رمز الاستجابة السريعة لإكمال عملية تسجيل الدخول على هاتفه. تتوفّر هذه الميزة مع المستوى 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();
استخدام AccountManager
يجب أن تستخدم تطبيقات نظام التشغيل Android Automotive التي تتضمّن عملية مصادقة فئة برمجة التطبيقات 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
لمزيد من المعلومات عن إنشاء هذه النطاقات. يمكنك الاطّلاع على
نمط النص
السريع باستخدام 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 API، تتضمّن "مكتبة تطبيقات السيارات" واجهات برمجة تطبيقات يمكنك استخدامها للوصول إلى خصائص المركبات وأجهزة الاستشعار.
المتطلبات
لاستخدام واجهات برمجة التطبيقات مع 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
يوضّح هذا الجدول السمات التي تعرضها واجهات برمجة تطبيقات
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 أو إصدار أحدث |
الأبعاد الخارجية | لا ينطبق | 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);
لا تفترض أنّ البيانات الواردة من السيارة متاحة في جميع الأوقات.
إذا ظهرت لك رسالة خطأ، تحقَّق من
حالة
القيمة التي طلبتها لفهم سبب عدم التمكّن من retrieving
البيانات التي طلبتها. يُرجى الرجوع إلى
المستندات المرجعية للاطّلاع على
تعريف فئة 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، يُرجى الرجوع إلى قسمَي أجهزة الاستشعار وإعدادات أجهزة الاستشعار في دليل "وحدة التحكّم الرئيسية في السيارة". لمحاكاة بيانات أجهزة الاستشعار عند الاختبار على نظام التشغيل Android Automotive، يُرجى الرجوع إلى قسم محاكاة حالة الأجهزة في دليل محاكي نظام التشغيل Android Automotive.
دورات حياة CarAppService وSession وScreen
تنفِّذ فئتَا Session
و
Screen
واجهة
LifecycleOwner
. أثناء
تفاعل المستخدم مع التطبيق، يتمّ استدعاء وظائف callback الخاصة بمراحل نشاط Session
وScreen
، كما هو موضّح في المخطّطات البيانية التالية.
دورات حياة CarAppService وجلسة
لمعرفة التفاصيل الكاملة، يُرجى الاطّلاع على مستندات الأسلوب
Session.getLifecycle
.
دورة حياة الشاشة
لمعرفة التفاصيل الكاملة، اطّلِع على المستندات حول طريقة
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 للسيارات" klassen مساعدة يمكنك استخدامها للتحقّق من سلوك تطبيقك في بيئة اختبار.
على سبيل المثال، يتيح لك الإجراء
SessionController
محاكاة اتصال بالمضيف والتأكّد من إنشاء
Screen
و
Template
الصحيحَين و
إعادتهما.
راجِع القسم عيّنات للاطّلاع على أمثلة على الاستخدام.
الإبلاغ عن مشكلة في مكتبة تطبيقات "Android للسيارات"
إذا واجهت مشكلة في المكتبة، يُرجى الإبلاغ عنها باستخدام أداة تتبُّع المشاكل من Google. احرص على ملء جميع المعلومات المطلوبة في نموذج المشكلة.
قبل الإبلاغ عن مشكلة جديدة، يُرجى التحقّق مما إذا كانت مُدرَجة في ملاحظات الإصدار للمكتبة أو تم الإبلاغ عنها في قائمة المشاكل. يمكنك الاشتراك في المشاكل والتصويت لها من خلال النقر على النجمة الخاصة بالمشكلة في أداة التتبّع. لمزيد من المعلومات، يُرجى الاطّلاع على الاشتراك في مشكلة.