تتيح لك مكتبة تطبيقات Android للسيارات إمكانية استخدام تطبيقات التنقل ونقاط الاهتمام وإنترنت الأشياء (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
تحدِّد "مكتبة تطبيقات السيارة" مستويات واجهة برمجة التطبيقات الخاصة بها حتى تتمكّن من معرفة ميزات المكتبة التي يوفّرها مضيف النماذج على أي مركبة.
لاسترداد أعلى مستوى لواجهة برمجة تطبيقات Car App API الذي يوفّره المضيف، استخدِم الطريقة
getCarAppApiLevel()
.
يُرجى تحديد الحدّ الأدنى لمستوى واجهة برمجة تطبيقات Car App API الذي يتيحه تطبيقك في
ملف AndroidManifest.xml
:
<manifest ...>
<application ...>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
</application>
</manifest>
راجِع مستندات
تعليق توضيحي على RequiresCarApi
للحصول على تفاصيل عن كيفية الحفاظ على التوافق مع الأنظمة القديمة وتوضيح الحد الأدنى من مستوى واجهة برمجة التطبيقات المطلوب لاستخدام الميزة. للحصول على تعريف لمستوى واجهة برمجة التطبيقات المطلوب لاستخدام ميزة معيّنة في "مكتبة تطبيقات السيارة"، يُرجى الاطّلاع على المستندات المرجعية بخصوص 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
لعرض سلسلة "Hello world!" بسيطة:
Kotlin
class HelloWorldScreen(carContext: CarContext) : Screen(carContext) { override fun onGetTemplate(): Template { val row = Row.Builder().setTitle("Hello world!").build() val pane = Pane.Builder().addRow(row).build() return PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build() } }
Java
public class HelloWorldScreen extends Screen { @NonNull @Override public Template onGetTemplate() { Row row = new Row.Builder().setTitle("Hello world!").build(); Pane pane = new Pane.Builder().addRow(row).build(); return new PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build(); } }
فئة CarContext
فئة CarContext
هي فئة فرعية
ContextWrapper
يمكن
الوصول إليها من خلال مثيلَي Session
وScreen
. وتوفّر هذه الخدمة إمكانية الوصول
إلى خدمات السيارات، مثل
ScreenManager
لإدارة
حِزم الشاشة،
وAppManager
الوظائف العامة المتعلّقة
بالتطبيقات، مثل الوصول إلى الكائن Surface
من أجل رسم
خريطة
تطبيق التنقّل الخاص بك،
وNavigationManager
التي تستخدمها تطبيقات التنقّل باتّجاهات مفصّلة لإعلام
المضيف
والبيانات الوصفية الأخرىبالأحداث
التنقّل والبيانات الوصفية الأخرى
انظر الوصول إلى نماذج التنقل للحصول على قائمة شاملة بوظائف المكتبة المتاحة لتطبيقات التنقل.
وتوفّر CarContext
أيضًا وظائف أخرى، مثل السماح لك بتحميل موارد قابلة للرسم من خلال الإعدادات من شاشة السيارة، وتشغيل تطبيق في السيارة باستخدام الأغراض، والإشارة إلى ما إذا كان يجب على تطبيق التنقّل عرض خريطته في الوضع الداكن.
تنفيذ التنقّل على الشاشة
غالبًا ما تقدم التطبيقات عددًا من الشاشات المختلفة، ويمكن لكل منها استخدام نماذج مختلفة يمكن للمستخدم التنقل من خلالها أثناء تفاعله مع الواجهة المعروضة على الشاشة.
توفّر فئة ScreenManager
حزمة شاشة يمكنك استخدامها لدفع الشاشات التي يمكن أن تنبثق تلقائيًا عندما ينقر المستخدم على زر الرجوع في شاشة السيارة أو يستخدم زر الرجوع في الجهاز المتوفّر في بعض السيارات.
ويوضّح المقتطف التالي كيفية إضافة إجراء الرجوع إلى نموذج الرسالة، بالإضافة إلى إجراء يدفع شاشة جديدة عند اختيار المستخدم:
Kotlin
val template = MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( Action.Builder() .setTitle("Next screen") .setOnClickListener { screenManager.push(NextScreen(carContext)) } .build()) .build()
Java
MessageTemplate template = new MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( new Action.Builder() .setTitle("Next screen") .setOnClickListener( () -> getScreenManager().push(new NextScreen(getCarContext()))) .build()) .build();
الكائن Action.BACK
هو
Action
عادي
يستدعي ScreenManager.pop
تلقائيًا.
يمكن إلغاء هذا السلوك باستخدام مثيل OnBackPressedDispatcher
المتوفّر في CarContext
.
للمساعدة في ضمان أمان التطبيق للاستخدام أثناء القيادة، يمكن أن تتضمن حزمة الشاشة خمس شاشات بحد أقصى. يمكن الاطّلاع على قسم قيود النموذج للحصول على المزيد من التفاصيل.
إعادة تحميل محتوى نموذج
يمكن لتطبيقك طلب إلغاء صلاحية محتوى
Screen
من خلال طلب الإجراء
Screen.invalidate
.
بعد ذلك، يستدعي المضيف مرة أخرى طريقة
Screen.onGetTemplate
في تطبيقك لاسترداد النموذج بالعناصر الجديدة.
عند إعادة تحميل Screen
، من المهم فهم المحتوى المحدّد في النموذج الذي يمكن تعديله حتى لا يحتسب المضيف النموذج الجديد ضمن حصة النموذج.
يمكن الاطّلاع على قسم قيود النموذج للحصول على مزيد من التفاصيل.
ننصحك بتنظيم بنية الشاشات بحيث يتم الربط بين Screen
ونوع النموذج الذي يعرضه استنادًا إلى السمة onGetTemplate
.
التفاعل مع المستخدم
يمكن لتطبيقك التفاعل مع المستخدم باستخدام أنماط مشابهة لتطبيق متوافق مع الأجهزة الجوّالة.
التعامل مع البيانات التي أدخلها المستخدم
يمكن لتطبيقك الاستجابة لإدخالات المستخدمين من خلال تمرير المستمعين المناسبين إلى النماذج التي تدعمهم. يوضِّح المقتطف التالي كيفية إنشاء نموذج 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
الغرض، يُرجى الاطّلاع على قسم بدء تشغيل تطبيق سيارة يتضمّن هدفاً.
لا يُسمح ببعض الإجراءات، مثل تلك التي تتطلب توجيه المستخدم لمواصلة التفاعل على أجهزته، إلا عند ركن السيارة.
يمكنك استخدام
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()
.
في 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.requestPermissions()
، على عكس واجهات برمجة تطبيقات Android العادية، في أنّك لن تحتاج إلى تشغيل Activity
الخاص بك لإنشاء مربّع حوار الأذونات. علاوة على ذلك، يمكنك استخدام الرمز نفسه على كل من Android Auto ونظام التشغيل Android Automotive، بدلاً من الاضطرار إلى إنشاء مسارات تعتمد على النظام الأساسي.
تشغيل تطبيق سيارة هدف
يمكنك استدعاء الطريقة
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
بهدف تضمين معرّف الموارد المنتظم للبيانات:
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
طريقة عرض من المتوقّع أن تبقى معروضة على الشاشة وأن تتم إعادة تحميلها مع تعليمات جديدة مفصّلة حول استهلاك المستخدم. عندما يصل إلى أحد هذه النماذج، يعيد المضيف ضبط حصة النموذج، ويتعامل مع هذا النموذج كما لو كان الخطوة الأولى في مهمة جديدة. يسمح هذا الإذن للتطبيق ببدء مهمة جديدة.
يمكنك مراجعة وثائق النماذج الفردية لمعرفة النماذج التي تؤدي إلى إعادة الضبط على المضيف.
إذا تلقّى المضيف هدفًا لبدء تشغيل التطبيق من خلال إجراء إشعار أو من مشغّل التطبيقات، تتم أيضًا إعادة ضبط الحصة. تتيح هذه الآلية للتطبيق بدء تدفق مهمة جديدة من الإشعارات، وتكون صحيحة حتى إذا كان التطبيق مرتبطًا بالفعل وفي المقدمة.
راجع قسم عرض الإشعارات لمزيد من التفاصيل حول كيفية عرض إشعارات تطبيقك في شاشة السيارة. راجع قسم تشغيل تطبيق سيارة مخصص للحصول على معلومات عن طريقة تشغيل تطبيقك من خلال إجراء إشعار.
واجهة برمجة تطبيقات الاتصال
يمكنك تحديد ما إذا كان تطبيقك يعمل على نظام التشغيل Android Auto أو Android Automotive،
وذلك باستخدام
CarConnection
API
لاسترداد معلومات الاتصال أثناء وقت التشغيل.
على سبيل المثال، في 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
قد تسمح السيارات المختلفة بعرض عدد مختلف من مثيلات
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();
استخدام AccountManager
على تطبيقات نظام التشغيل 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();
أضِف السلاسل بالترتيب من الأكثر إلى الأقل تفضيلاً، مثل من الأطول إلى الأقصر. يختار المضيف السلسلة ذات الطول المناسب اعتمادًا على مساحة المساحة المتاحة على شاشة السيارة.
إضافة رموز CarIcon مُضمَّنة للصفوف
يمكنك استخدام
CarIconSpan
لإضافة رموز مضمّنة مع النص لتعزيز جاذبية تطبيقك المرئي.
راجِع مستندات CarIconSpan.create
للحصول على مزيد من المعلومات عن إنشاء هذه النطاقات. راجِع
نمط النص
الشامل باستخدام المسافات للحصول على نظرة عامة حول طريقة عمل نمط النص باستخدام المسافات.
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 من واجهة برمجة تطبيقات السيارة.
الشروط
لاستخدام واجهات برمجة التطبيقات مع 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 |
|
fetchEnergyProfile |
أنواع وصلات المركبات الكهربائية وأنواع الوقود | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_INFO |
addTollListener
removeTollListener |
حالة بطاقة تحصيل رسوم العبور، ونوع بطاقة تحصيل رسوم العبور | ||
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 |
addSpeedListener
removeSpeedListener |
السرعة الأولية، سرعة العرض (تظهر على شاشة المجموعة العنقودية في السيارة) | com.google.android.gms.permission.CAR_SPEED |
android.car.permission.CAR_SPEED ،android.car.permission.READ_CAR_DISPLAY_UNITS |
addMileageListener
removeMileageListener |
مسافة عدّاد المسافة | com.google.android.gms.permission.CAR_MILEAGE |
لا تتوفّر هذه البيانات على نظام التشغيل Android Automotive للتطبيقات المثبّتة من "متجر Play". |
على سبيل المثال، للحصول على النطاق المتبقي، أنشئ مثيلاً لكائن
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
. على سبيل المثال،
للتحقق من عنوان المركبة:
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
. أثناء تفاعل المستخدم مع التطبيق، يتم استدعاء استدعاءات مراحل نشاط الكائنات Session
وScreen
، كما هو موضّح في المخطّطات البيانية التالية.
دورات حياة CarAppService والجلسة

Session
للحصول على التفاصيل الكاملة، راجِع مستندات
طريقة Session.getLifecycle
.
دورة حياة الشاشة

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. احرص على ملء جميع المعلومات المطلوبة في نموذج المشكلة.
قبل تقديم عدد جديد، يُرجى التحقق مما إذا كان قد تم إدراجه في ملاحظات إصدار المكتبة أو تم الإبلاغ عنه في قائمة المشكلات. يمكنك الاشتراك والتصويت للمشكلات من خلال النقر فوق النجمة الخاصة بمشكلة في أداة التتبع. لمزيد من المعلومات، راجِع الاشتراك في مشكلة.