تتيح لك مكتبة تطبيقات 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
: تطبيق يتيح للمستخدمين اتّخاذ إجراءات متعلقة بالأجهزة المتصلة من داخل السيارة اطّلِع على مقالة إنشاء تطبيقات إنترنت�الأشياء للسيارات.androidx.car.app.category.WEATHER
: تطبيق يتيح للمستخدمين الاطّلاع على معلومات متعلقة بالطقس في موقعهم الجغرافي الحالي أو على طول مسارهم اطّلِع على مقالة إنشاء تطبيقات الطقس للسيارات.
اطّلِع على جودة تطبيقات 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
الذي تستخدمه تطبيقات التنقّل من نقطة إلى أخرى لمشاركة البيانات الوصفية
للتنقّل وغيرها من
الأحداث المتعلقة بالتنقّل مع
المضيف.
اطّلِع على مقالة الوصول إلى نماذج التنقّل للحصول على قائمة شاملة بوظائف المكتبة المتاحة لتطبيقات التنقّل.
يوفّر 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 |
متاحة منذ مستوى Car App API |
---|---|---|
نقر | 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
باستخدام نية تتضمّن عنوان URL للبيانات:
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
في الحزمة. على سبيل المثال، إذا أرسل تطبيق نموذجَين أثناء عرض الشاشة "أ" ثم عرض الشاشة "ب"، يمكنه الآن إرسال ثلاثة نماذج أخرى. بدلاً من ذلك، إذا تم تنظيم كل شاشة
لإرسال نموذج واحد، يمكن للتطبيق دفع خمس نُسخ من الشاشة إلى حزمة
ScreenManager
.
هناك حالات خاصة لهذه القيود: عمليات إعادة تحميل النماذج وعمليات الرجوع والإعادة ضبط.
عمليات إعادة تحميل النماذج
لا يتم احتساب بعض تحديثات المحتوى ضمن الحد الأقصى المسموح به للنماذج. بشكل عام،
إذا أرسل تطبيق نموذجًا جديدًا من النوع نفسه ويحتوي
على المحتوى الرئيسي نفسه الوارد في النموذج السابق، لا يتم
احتساب النموذج الجديد ضمن الحصة. على سبيل المثال، لا يتم احتساب تعديل حالة التبديل لأحد الصفوف في جدول ListTemplate
ضمن الحصة. اطّلِع على مستندات النماذج الفردية للتعرّف على مزيد من المعلومات
حول أنواع تعديلات المحتوى التي يمكن اعتبارها إعادة تحميل.
عمليات الرجوع
لتفعيل مسارات فرعية ضمن مهمة، يرصد المضيف عندما يُخرج تطبيق
Screen
من حزمة ScreenManager
ويُعدِّل
الحصة المتبقية استنادًا إلى عدد النماذج التي يتراجع عنها التطبيق.
على سبيل المثال، إذا أرسل التطبيق نموذجَين أثناء عرض الشاشة "أ"، ثم عرض الشاشة "ب" وأرسل نموذجَين آخرين، سيتبقّى للتطبيق حصة واحدة. إذا عاد التطبيق بعد ذلك إلى الشاشة "أ"، يعيد المضيف ضبط الحصة على ثلاثة، لأنّه عاد التطبيق إلى نموذجَين سابقَين.
يُرجى العلم أنّه عند الرجوع إلى شاشة، يجب أن يرسل التطبيق نموذجًا من النوع نفسه الذي أرسلته هذه الشاشة آخر مرة. يؤدي إرسال أي نوع آخر من النماذج إلى ظهور خطأ. ومع ذلك، طالما أنّ النوع ظلّ هو نفسه أثناء عملية الرجوع، يمكن للتطبيق تعديل محتوى النموذج بحرية بدون التأثير في الحصة.
إعادة ضبط العمليات
تحتوي بعض النماذج على دلالات خاصة تشير إلى نهاية مهمة معيّنة. على سبيل المثال، يشير الرمز
NavigationTemplate
إلى عرض يُفترض أن يظل معروضًا على الشاشة وأن يتم تعديله من خلال إضافة تعليمات جديدة تتعلّق بالاتّجاهات للمستخدم. وعندما يصل إلى أحد هذين
النموذجَين، يُعيد المضيف ضبط حصة النموذج، ويتعامل مع هذا النموذج كما لو كان
هو الخطوة الأولى لمهمة جديدة. ويسمح ذلك للتطبيق ببدء مهمة جديدة.
اطّلِع على مستندات النماذج الفردية لمعرفة النماذج التي تؤدي إلى إعادة الضبط
على المضيف.
إذا تلقّى المضيف طلبًا لبدء التطبيق من إجراء إشعار أو من مشغّل التطبيقات، تتم إعادة ضبط الحصة أيضًا. تسمح هذه الآلية للتطبيق ببدء سير عمل مهام جديد من الإشعارات، ويبقى ذلك صحيحًا حتى إذا كان التطبيق مرتبطًا في المقدّمة.
اطّلِع على قسم عرض الإشعارات للحصول على مزيد من التفاصيل حول كيفية عرض إشعارات تطبيقك على شاشة السيارة. اطّلِع على القسم بدء تطبيق سيارة باستخدام نية للحصول على معلومات عن كيفية بدء تطبيقك من إجراء إشعار.
واجهة برمجة التطبيقات Connection API
يمكنك تحديد ما إذا كان تطبيقك يعمل على Android Auto أو Android
Automotive OS باستخدام واجهة برمجة التطبيقات
CarConnection
API ل retrieving retrieve information of connection at runtime.
على سبيل المثال، في 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
. تتيح "مكتبة التطبيقات" في Car App حاليًا طرق تسجيل الدخول التالية:
InputSignInMethod
لتسجيل الدخول باستخدام اسم المستخدم/كلمة المرور.PinSignInMethod
لتسجيل الدخول باستخدام رقم التعريف الشخصي، حيث يربط المستخدم حسابه من هاتفه باستخدام رقم التعريف الشخصي المعروض على وحدة التحكّم.ProviderSignInMethod
لتسجيل الدخول إلى موفِّر الخدمة، مثل تسجيل الدخول باستخدام حساب Google وOne Tap.-
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();
استخدام 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
لمزيد من المعلومات عن إنشاء هذه النطاقات. اطّلِع على مقالة
Spantastic
تنسيق النص باستخدام Spans للحصول على نظرة عامة حول آلية عمل تنسيق النص باستخدام 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 | متاحة منذ مستوى 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 والتي تعمل بواجهة برمجة التطبيقات 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
لمعرفة التفاصيل الكاملة، يُرجى الاطّلاع على مستندات الأسلوب
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. احرص على ملء جميع المعلومات المطلوبة في نموذج المشكلة.
قبل الإبلاغ عن مشكلة جديدة، يُرجى التحقّق مما إذا كانت مُدرَجة في ملاحظات الإصدار للمكتبة أو تم الإبلاغ عنها في قائمة المشاكل. يمكنك الاشتراك في المشاكل والتصويت لها من خلال النقر على النجمة الخاصة بالمشكلة في أداة التتبّع. لمزيد من المعلومات، يُرجى الاطّلاع على الاشتراك في مشكلة.