استخدام مكتبة تطبيقات Android للسيارات

مكتبة تطبيقات "Android للسيارات" يتيح لك الاستفادة من ميزات التنقّل ونقاط الاهتمام وإنترنت الأشياء (IOT) التطبيقات على السيارة. ويتم ذلك من خلال توفير مجموعة من النماذج المصمّمة لتلبية عناصر تشتيت السائق. والمعايير والاهتمام بالتفاصيل مثل مجموعة متنوعة من عوامل شاشة السيارة وأساليب الإدخال.

يقدم هذا الدليل نظرة عامة على الميزات والمفاهيم الرئيسية للمكتبة يرشدك خلال عملية إعداد تطبيق أساسي.

قبل البدء

  1. مراجعة التصميم المناسب للقيادة الصفحات التي تغطي مكتبة تطبيقات السيارات
  2. راجع المصطلحات والمفاهيم الرئيسية في ما يلي .
  3. الاطّلاع على نظام Android Auto واجهة المستخدم ونظام التشغيل Android Automotive التصميم.
  4. راجِع ملاحظات الإصدار.
  5. راجِع عيّنات.

المصطلحات والمفاهيم الرئيسية

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

مستوى واجهة برمجة تطبيقات تطبيق السيارة

تحدد مكتبة تطبيقات السيارات مستويات واجهة برمجة التطبيقات الخاصة بها حتى تتمكن من معرفة ميزات المكتبة متاحة من خلال مضيف النماذج على المركبة. لاسترداد أعلى مستوى لواجهة برمجة تطبيقات لتطبيق السيارة متاح من خلال المضيف، استخدِم getCarAppApiLevel() .

يُرجى توضيح الحد الأدنى لمستوى واجهة برمجة التطبيقات لتطبيق السيارة الذي يتيحه تطبيقك في ملف AndroidManifest.xml:

<manifest ...>
    <application ...>
        <meta-data
            android:name="androidx.car.app.minCarApiLevel"
            android:value="1"/>
    </application>
</manifest>

اطّلِع على مستندات RequiresCarApi التعليق التوضيحي للحصول على تفاصيل حول كيفية الحفاظ على التوافق مع الأنظمة القديمة وتوضيح الحد الأدنى لمستوى واجهة برمجة التطبيقات المطلوب لاستخدام إحدى الميزات. لتعريف أي واجهة برمجة تطبيقات مطلوب لاستخدام ميزة معينة في مكتبة تطبيق السيارة، فراجع وثائق مرجعية CarAppApiLevels

إنشاء CarAppService والجلسة

يحتاج تطبيقك إلى تمديد CarAppService صف وتنفيذ CANNOT TRANSLATE 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 من أجل عرض رسالة بسيطة "مرحبًا بالعالم!" string:

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 (مقدمة النموذج)

تنفيذ استدعاءات التفاعل

واجهة SurfaceCallback تتضمن العديد من طرق معاودة الاتصال التي يمكنك تنفيذها لإضافة التفاعل إلى الخرائط التي تم إنشاؤها مع القوالب الموجودة في القسم السابق:

التفاعل طريقة واحدة (SurfaceCallback) يتوفّر هذا الخيار منذ مستوى واجهة برمجة التطبيقات لتطبيق السيارة.
النقر onClick 5
استخدام إصبعين للتصغير onScale 2
السحب بلمسة واحدة onScroll 2
الانتقال بلمسة واحدة onFling 2
النقر مرتين onScale (مع عامل قياس يحدّده مضيف النموذج) 2
تحريك دوّار في وضع التحريك onScroll (مع تحديد عامل المسافة من قِبل مضيف النموذج) 2

إضافة شريط إجراءات للخريطة

يمكن أن تحتوي هذه النماذج على شريط إجراءات للخريطة من أجل الإجراءات ذات الصلة بالخريطة، مثل التكبير والتصغير، والتوسيط وعرض بوصلة، وإجراءات أخرى تختار عرضها. يمكن أن يحتوي شريط إجراءات الخريطة على ما يصل إلى أربعة أزرار للرموز فقط يمكن تحديثها دون التأثير على عمق المهمة. يختفي أثناء حالة عدم النشاط ويظهر مرة أخرى في حالة نشطة.

لتلقي استدعاءات التفاعل مع الخريطة، يمكنك يجب إضافة زر Action.PAN في شريط الإجراءات على الخريطة. عندما يجرّب عند الضغط على زر العرض الشامل، يدخل المضيف في وضع العرض الشامل، كما هو موضح في ما يلي .

إذا حذف تطبيقك Action.PAN في شريط إجراءات الخريطة، فلن يتلقى إدخالات المستخدم من SurfaceCallback، ويخرج المضيف من أي طريقة تم تفعيلها سابقًا وضع العرض الشامل.

لا يظهر زر "التحريك" على الشاشة التي تعمل باللمس.

التعرّف على "وضع العرض الشامل"

في وضع العرض الشامل، يترجم مضيف النموذج البيانات التي أدخلها المستخدم من الإدخال الذي لا يعمل باللمس. مثل وحدات التحكم الدوارة ولوحات اللمس، بالعرض المناسب SurfaceCallback طريقة الاستجابة لإجراء المستخدم للدخول في وضع العرض الشامل أو الخروج منه مع setPanModeListener في NavigationTemplate.Builder. يمكن للمضيف إخفاء واجهة مستخدم أخرى المكونات في القالب عندما يكون المستخدم في وضع التحريك.

التفاعل مع المستخدم

يمكن لتطبيقك التفاعل مع المستخدم باستخدام أنماط مشابهة لتطبيق الأجهزة الجوّالة.

التعامل مع البيانات التي أدخلها المستخدم

يمكن لتطبيقك الاستجابة لإدخال المستخدم من خلال تمرير المستمعين المناسبين إلى والنماذج التي تدعمها. يوضح المقتطف التالي كيفية إنشاء يضبط نموذج Action OnClickListener الذي بالعودة إلى طريقة يحددها رمز تطبيقك:

Kotlin

val action = Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(::onClickNavigate)
    .build()

Java

Action action = new Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(this::onClickNavigate)
    .build();

ويمكن عندئذٍ للطريقة onClickNavigate بدء التطبيق التلقائي لسيارة التنقّل باستخدام CarContext.startCarApp :

Kotlin

private fun onClickNavigate() {
    val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address))
    carContext.startCarApp(intent)
}

Java

private void onClickNavigate() {
    Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address));
    getCarContext().startCarApp(intent);
}

لمزيد من التفاصيل حول كيفية بدء تشغيل التطبيقات، بما في ذلك تنسيق ACTION_NAVIGATE intent. يمكنك الاطّلاع على بدء تطبيق سيارة بنيّة نية. .

بعض الإجراءات، مثل تلك التي تتطلب توجيه المستخدم لمتابعة بالتفاعل على أجهزتهم المحمولة، لا يُسمح إلا عند ركن السيارة. يمكنك استخدام صفحة 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 ثم دفع الشاشة ب، يمكنها الآن إرسال ثلاثة قوالب أخرى. وبدلاً من ذلك، إذا تم تنظيم كل شاشة لإرسال نموذج واحد، يمكن للتطبيق دفع خمس مثيلات للشاشة إلى حزمة 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();
}

واجهة برمجة التطبيقات للقيود

قد تسمح السيارات المختلفة بعدد مختلف من Item مثيلات سيتم عرضها المستخدم في كل مرة. يمكنك استخدام ConstraintManager للتحقق من الحد الأقصى للمحتوى في وقت التشغيل وتعيين العدد المناسب من العناصر في النماذج.

البدء بالحصول على ConstraintManager من CarContext:

Kotlin

val manager = carContext.getCarService(ConstraintManager::class.java)

Java

ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);

يمكنك بعد ذلك إرسال طلب بحث عن كائن ConstraintManager الذي تم استرداده، وذلك للعثور على ما يلي: الحد من المحتوى. على سبيل المثال، للحصول على عدد العناصر التي يمكن عرضها في شبكة، استدعاء getContentLimit مع CONTENT_LIMIT_TYPE_GRID:

Kotlin

val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)

Java

int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);

إضافة خطوات تسجيل الدخول

إذا كان تطبيقك يوفّر تجربة تسجيل الدخول للمستخدمين، يمكنك استخدام نماذج مثل SignInTemplate وLongMessageTemplate باستخدام المستوى 2 من واجهة برمجة التطبيقات Car App API أو المستويات الأعلى، لتسجيل الدخول إلى تطبيقك الوحدة الرئيسية للسيارة.

لإنشاء SignInTemplate، يجب تحديد SignInMethod. السيارة تتيح "مكتبة التطبيقات" حاليًا استخدام طرق تسجيل الدخول التالية:

  • InputSignInMethod لتسجيل الدخول باسم المستخدم/كلمة المرور.
  • PinSignInMethod لتسجيل الدخول باستخدام رقم التعريف الشخصي، حيث يربط المستخدم حسابه من هاتفه باستخدام رقم تعريف شخصي معروض في الوحدة الرئيسية.
  • ProviderSignInMethod لتسجيل الدخول إلى مقدم الخدمة، مثل تسجيل الدخول باستخدام حساب Google وانقر على نقرة واحدة.
  • QRCodeSignInMethod لتسجيل الدخول باستخدام رمز الاستجابة السريعة، حيث يمسح المستخدم ضوئيًا رمز الاستجابة السريعة لإكمال عملية تسجيل الدخول هواتفهم. تتوفّر هذه الميزة مع المستوى 4 والأعلى من واجهة برمجة تطبيقات Car API.

على سبيل المثال، لتطبيق نموذج يجمع كلمة مرور المستخدم، ابدأ جارٍ إنشاء InputCallback لمعالجة البيانات التي أدخلها المستخدم والتحقق من صحتها:

Kotlin

val callback = object : InputCallback {
    override fun onInputSubmitted(text: String) {
        // You will receive this callback when the user presses Enter on the keyboard.
    }

    override fun onInputTextChanged(text: String) {
        // You will receive this callback as the user is typing. The update
        // frequency is determined by the host.
    }
}

Java

InputCallback callback = new InputCallback() {
    @Override
    public void onInputSubmitted(@NonNull String text) {
        // You will receive this callback when the user presses Enter on the keyboard.
    }

    @Override
    public void onInputTextChanged(@NonNull String text) {
        // You will receive this callback as the user is typing. The update
        // frequency is determined by the host.
    }
};

يجب توفير InputCallback لـ InputSignInMethod Builder.

Kotlin

val passwordInput = InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build()

Java

InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build();

وأخيرًا، يمكنك استخدام InputSignInMethod الجديد لإنشاء SignInTemplate.

Kotlin

SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build()

Java

new SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build();

استخدام مدير الحساب

في التطبيقات التي تعمل بنظام التشغيل Android Automotive وتتضمّن عملية المصادقة، يجب استخدام المصادقة. AccountManager للأسباب التالية:

  • تحسين تجربة المستخدم وسهولة إدارة الحسابات: يمكن للمستخدمين إدارة جميع الحسابات بسهولة حساباتهم من قائمة الحسابات في إعدادات النظام، بما في ذلك تسجيل الدخول وتسجيل الخروج منه.
  • "الضيف" التجارب: بما أنّ السيارات هي أجهزة مشتركة، يمكن للمصنّعين الأصليين للأجهزة تفعيل تجارب الضيوف في المركبة، حيث لا يمكن إضافة حسابات.

إضافة صيغ السلسلة النصية

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

Kotlin

  
val rating = SpannableString("Rating: 4.5 stars")
rating.setSpan(
    CarIconSpan.create(
        // Create a CarIcon with an image of four and a half stars
        CarIcon.Builder(...).build(),
        // Align the CarIcon to the baseline of the text
        CarIconSpan.ALIGN_BASELINE
    ),
    // The start index of the span (index of the character '4')
    8,
    // The end index of the span (index of the last 's' in "stars")
    16,
    Spanned.SPAN_INCLUSIVE_INCLUSIVE
)

val row = Row.Builder()
    ...
    .addText(rating)
    .build()
  
  

Java

  
SpannableString rating = new SpannableString("Rating: 4.5 stars");
rating.setSpan(
        CarIconSpan.create(
                // Create a CarIcon with an image of four and a half stars
                new CarIcon.Builder(...).build(),
                // Align the CarIcon to the baseline of the text
                CarIconSpan.ALIGN_BASELINE
        ),
        // The start index of the span (index of the character '4')
        8,
        // The end index of the span (index of the last 's' in "stars")
        16,
        Spanned.SPAN_INCLUSIVE_INCLUSIVE
);
Row row = new Row.Builder()
        ...
        .addText(rating)
        .build();
  
  

واجهات برمجة تطبيقات أجهزة السيارة

بدءًا من المستوى 3 من واجهة برمجة تطبيقات Car App Library، تحتوي مكتبة تطبيقات السيارات على واجهات برمجة تطبيقات التي يمكن استخدامها للوصول إلى خصائص المركبات وأجهزة الاستشعار.

المتطلبات

لاستخدام واجهات برمجة التطبيقات مع Android Auto، ابدأ بإضافة ملف androidx.car.app:app-projected إلى ملف build.gradle لجهاز Android وحدة تلقائية. بالنسبة إلى نظام التشغيل Android Automotive، أضِف اعتمادًا على androidx.car.app:app-automotive إلى ملف build.gradle لجهاز Android نظام التشغيل Automotive.

بالإضافة إلى ذلك، في ملف AndroidManifest.xml، عليك إجراء ما يلي: الإفصاح عن الأذونات ذات الصلة اللازمة تطلب بيانات السيارة التي تريد استخدامها. لاحظ أن هذه الأذونات يجب أيضًا التي يمنحها المستخدم لك. يمكنك استخدام صفحة الرمز نفسه على كل من Android Auto وAndroid Automotive، بدلاً من من الحاجة إلى إنشاء تدفقات تعتمد على النظام الأساسي. ومع ذلك، تحتاج الأذونات المطلوبة مختلفة.

معلومات السيارة

يصف هذا الجدول السمات التي يعرضها كلّ من واجهات برمجة التطبيقات في CarInfo الأذونات التي تحتاج إلى طلب استخدامها:

الطرق الخصائص أذونات Android Auto أذونات نظام التشغيل Android Automotive يتوفّر هذا الخيار منذ مستوى واجهة برمجة التطبيقات لتطبيق السيارة.
fetchModel الماركة والطراز والسنة android.car.permission.CAR_INFO 3
fetchEnergyProfile أنواع وصلات المركبات الكهربائية وأنواع الوقود com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_INFO 3
fetchExteriorDimensions

تتوفّر هذه البيانات فقط على بعض المركبات التي تعمل بنظام التشغيل Android Automotive. تشغيل واجهة برمجة التطبيقات 30 أو أعلى

الأبعاد الخارجية لا ينطبق android.car.permission.CAR_INFO 7
addTollListener
removeTollListener
حالة بطاقة تحصيل رسوم العبور، ونوع بطاقة رسوم العبور 3
addEnergyLevelListener
removeEnergyLevelListener
مستوى البطارية، مستوى الوقود، مستوى الوقود منخفض، النطاق المتبقّي com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_ENERGY,
android.car.permission.CAR_ENERGY_PORTS,
android.car.permission.READ_CAR_DISPLAY_UNITS
3
addSpeedListener
removeSpeedListener
السرعة الأولية وسرعة العرض (يظهران على شاشة المجموعة في السيارة) com.google.android.gms.permission.CAR_SPEED android.car.permission.CAR_SPEED,
android.car.permission.READ_CAR_DISPLAY_UNITS
3
addMileageListener
removeMileageListener
مسافة عدّاد المسافات com.google.android.gms.permission.CAR_MILEAGE لا تتوفّر هذه البيانات على نظام التشغيل Android Automotive للتطبيقات المثبَّتة من "متجر Play". 3

على سبيل المثال، للحصول على النطاق المتبقي، قم بإنشاء مثيل CarInfo، ثم إنشاء OnCarDataAvailableListener وتسجيله:

Kotlin

val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo

val listener = OnCarDataAvailableListener<EnergyLevel> { data ->
    if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) {
      val rangeRemaining = data.rangeRemainingMeters.value
    } else {
      // Handle error
    }
  }

carInfo.addEnergyLevelListener(carContext.mainExecutor, listener)

// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener)

Java

CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo();

OnCarDataAvailableListener<EnergyLevel> listener = (data) -> {
  if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) {
    float rangeRemaining = data.getRangeRemainingMeters().getValue();
  } else {
    // Handle error
  }
};

carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener);

// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener);

لا تفترض أن البيانات من السيارة متاحة في جميع الأوقات. إذا ظهرت لك رسالة خطأ، تحقَّق من حالة القيمة التي طلبتها لفهم سبب إمكانية ظهور البيانات التي طلبتها التي لا يمكن استردادها. ارجع إلى المستندات المرجعية الخاصة بـ تعريف الفئة CarInfo الكامل.

أجهزة استشعار السيارات

الصف CarSensors الوصول إلى مقياس التسارع والجيروسكوب والبوصلة لبيانات الموقع. وقد يعتمد مدى توفُّر هذه القيم على المصنّع الأصلي للجهاز. ويكون تنسيق البيانات من مقياس التسارع والجيروسكوب والبوصلة نفس الشيء الذي تحصل عليه من SensorManager API. على سبيل المثال: للتحقّق من عنوان المركبة:

Kotlin

val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors

val listener = OnCarDataAvailableListener<Compass> { data ->
    if (data.orientations.status == CarValue.STATUS_SUCCESS) {
      val orientation = data.orientations.value
    } else {
      // Data not available, handle error
    }
  }

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener)

// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener)

Java

CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors();

OnCarDataAvailableListener<Compass> listener = (data) -> {
  if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) {
    List<Float> orientations = data.getOrientations().getValue();
  } else {
    // Data not available, handle error
  }
};

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(),
    listener);

// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener);

للوصول إلى بيانات الموقع الجغرافي من السيارة، عليك أيضًا الإفصاح عن إذن android.permission.ACCESS_FINE_LOCATION.

الاختبار

لمحاكاة بيانات جهاز الاستشعار عند إجراء الاختبار على Android Auto، يمكنك الاطّلاع على أجهزة الاستشعار وأدوات الاستشعار أقسام الموقع في دليل الوحدة الرئيسية لسطح المكتب لمحاكاة بيانات جهاز الاستشعار عند الاختبار على Android نظام التشغيل Automotive، راجع أجهزة المحاكاة للأجهزة State (الحالة) في Android دليل محاكي نظام التشغيل Automotive.

دورات حياة CarAppService والجلسة والشاشة

إنّ Session تنفِّذ صفوف Screen LifecycleOwner. بالنسبة يتفاعل المستخدِم مع التطبيق، وكائن Session وScreen مراحل النشاط كما هو موضح في المخططات التالية.

دورات حياة CarAppService وجلسة

الشكل 1. دورة حياة Session.

للحصول على التفاصيل الكاملة، يمكنك الاطّلاع على وثائق Session.getLifecycle .

دورة حياة الشاشة

الشكل 2. دورة حياة 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 للسيارات توفّر "المكتبة" أدوات إضافية التي يمكنك استخدامها للتحقق من سلوك تطبيقك في بيئة اختبار. على سبيل المثال، SessionController محاكاة الاتصال بالمضيف والتحقق من صحة الاتصال Screen و تم إنشاء Template عاد.

ارجع إلى عيّنات للحصول على أمثلة على الاستخدام.

الإبلاغ عن مشكلة في مكتبة تطبيقات "Android للسيارات"

إذا واجهتك مشكلة في المكتبة، يمكنك الإبلاغ عنها باستخدام أداة تتبُّع المشاكل من Google تأكَّد من ملء جميع المعلومات المطلوبة في نموذج المشكلة.

إنشاء عدد جديد

قبل تقديم أي مشكلة جديدة، يُرجى التحقق مما إذا كانت مدرجة في إصدار المكتبة. الملاحظات أو تم الإبلاغ عنها في قائمة المشكلات. يمكنك الاشتراك والتصويت على المشاكل من خلال النقر على النجمة لمشكلة في أداة التتبع. لمزيد من المعلومات، يُرجى مراجعة الاشتراك في مشكلة: