إنشاء واجهات للساعات WearOS

إنشاء واجهات Watch Face لساعات WearOS بإستخدام Watch Face Format (WFF)

AbdulAlim Rajjoubمنذ يوم

 

سنتعرف في هذا المقال كيفية إنشاء واجهات Watch Face للساعات الذكية التي تعمل بنظام WearOS (Android).

 

حالياً يوجد ٣ طرق لإنشاء واجهات WearOS 

 

  1. Samsung WatchFace Studio

وهو عبارة عن برنامج ذات واجهة رسومية GUI وتستطيع إنشاء الواجهات عبر السحب والإفلات 

أبرز مزايا هذا الخيار هي عدم الحاجة لمعرفة برمجية والعناصر جاهزة للسحب والإفلات ورؤية الواجهة بشكل مباشر

عيوبها هي عدم إمكانية التخصيص الكبيرة مثل Jetpack او WFF

2. Jetpack Watch Face (Deprecated)

والذي يمكنك من إنشاء واجهات باستخدام الكود تحديداً باستخدام Canvas API

مثال مأخوذ من تطبيقي Prayer Watch Face

   override fun render(
        canvas: Canvas,
        bounds: Rect,
        zonedDateTime: ZonedDateTime,
        sharedAssets: PrayerSharedAssets
    ) {
        //Clear the canvas to prevent previous background bitmap shadow to show up.
        canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.MULTIPLY)
      

 val prayerName = getPrayerNameByLocaleUseCase.getPrayerNameByLocale(
            previousPrayer,
            locale
        )

        val prayerNameWidth = prayerNameTextPaint.measureText(prayerName)

        val centerX = width / 2f


        val x = centerX + dpToPx(12f, context)
        val textY = remainingY

        canvas.withTranslation(x = x, y = textY) {
            canvas.drawText(
                prayerName,
                0f,
                0f,
                prayerNameTextPaint
            )

        }
    }

 

للأسف قامت Google بإيقاف الدعم لهذا SDK لأسباب كثيرة أهمها التحكم بالبطارية , وعلى الرغم أن التطبيق يعمل على الساعات باستخدام هذا SDK إلا أن التطبيق لن يتم قبوله على Google Play حيث أن Google جعلت WFF الخيار الإفتراضي للساعات التي تعمل بنظام WearOS 5 فما فوق.

من أبرز مزايا هذا الخيار هو إمكانية التخصيص الكبيرة والتحكم الكامل على الواجهة , حيث أن شيئ يمكنك رسمه باستخدام Canvas يمكنك استخدامه على الواجهة مما يعطيك إمكانية تخصيص كبيرة.

 

3. Watch Face Format (WFF) 

وهو الخيار الذي تم إطلاقه حديثاً من قبل Google وهو الذي سنقوم بشرحه والتركيز عليه 

مثال:

<WatchFace
    height="450"
    width="450">
    <Metadata
        key="CLOCK_TYPE"
        value="DIGITAL" />
    <Scene>
        <DigitalClock
            height="450"
            width="450"
            x="0"
            y="0">
            <TimeText
                format="hh:mm"
                height="100"
                width="450"
                x="0"
                y="175">
                <Variant
                    mode="AMBIENT"
                    target="alpha"
                    value="0" />
                <Font
                    color="#ffffffff"
                    family="SYNC_TO_DEVICE"
                    size="128" />
            </TimeText>
            <TimeText
                alpha="0"
                format="hh:mm"
                height="100"
                width="450"
                x="0"
                y="175">
                <Variant
                    mode="AMBIENT"
                    target="alpha"
                    value="255" />
                <Font
                    color="#ffffffff"
                    family="SYNC_TO_DEVICE"
                    size="128"
                    weight="THIN" />
            </TimeText>
        </DigitalClock>
        <Group
            name="hello_world"
            height="450"
            width="450"
            x="0"
            y="0">
            <PartText
                height="50"
                width="450"
                x="0"
                y="285">
                <Variant
                    mode="AMBIENT"
                    target="alpha"
                    value="0" />
                <Text>
                    <Font
                        color="#ffffffff"
                        family="SYNC_TO_DEVICE"
                        size="36">
                        <Template>%s
                            <Parameter expression="greeting" />
                        </Template>
                    </Font>
                </Text>
            </PartText>
        </Group>
    </Scene>
</WatchFace>

 

من أبرز المزايا في هذا الخيار هو أنه الخيار المدعوم من Google , على الرغم من عدم وجود إمكانية كتابة كود برمجي في هذا الخيار, إلا أنه يتيح لك بعض التخصيص كما سنرى لاحقاً

من عيوبه أنه لا يتيح لك كامل التحكم والتخصيص مثل Jetpack Watchface 

 

إنشاء المشروع باستخدام Watch Face Format (WFF)

في Android Studio نقوم بإنشاء مشروع جديد ونختار WearOS > Basic Watch Face

ونضع إسم للمشروع

 

بعد فتح المشروع سيظهر بهذا الشكل

 

سنلاحظ أنه لا يوجد أية ملفات داخل Java فقط يوجد ملفات XML

لنشرح محتويات المشروع الحالي

داخل ملف AndroidManifest.xml سنجد التالي

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-feature android:name="android.hardware.type.watch" />
    <!-- Note: hasCode is required to be false for Watch Face Format -->
    <application
        android:hasCode="false"
        android:label="@string/watch_face_name">
        <meta-data
            android:name="com.google.android.wearable.standalone"
            android:value="true" />

        <property
            android:name="com.google.wear.watchface.format.version"
            android:value="1" />

        <!-- Optionally add details about the publisher. -->
        <!--
           <property
          android:name="com.google.wear.watchface.format.publisher"
          android:value="YourPublisherNameHere" />
        -->
    </application>

</manifest>

 

 

كما نرى فإنه يجب ان يكون 

hasCode="false"

أي أنه لا يمكن إضافة أي أكواد برمجية

 

ونستطيع أيضاً رؤية اصدار Watch Face

<property
            android:name="com.google.wear.watchface.format.version"
            android:value="1" />

حيث أن كل إصدار يحتوي على مزايا مهمة كما سنرى لاحقاً, وبعض الإصدارات لا تعمل على بعض إصدارات WearOS

لمزيد من التفاصيل

يمكنك رؤية الصورة أدناه لمزيد من المعلومات

 

داخل المجلد res سنجد

res/drawable/preview.png 

هذه الصورة التي ستظهر للمستخدم لاختيار الواجهة بين الوجهات الأخرى

 

 داخل 

res/raw/watchface.xml

هذا هو الملف الذي سنقضى كل الوقت فيه, حيث أن هذا الملف هو المسؤول عن العناصر داخل الواجهة كالألوان, النصوص, الصور, الخ..

سنعود إليه في وقت لاحق

ملف strings.xml يمكننا استخدامه لدعم عدة لغات على حسب لغة الساعة

ملف watch_face_info.xml 

<WatchFaceInfo>
    <!--
    Preview is the only required element here.

    For other elements, see:
    https://developer.android.com/training/wearables/wff/setup#declare-metadata
    -->
    <Preview value="@drawable/preview" />
</WatchFaceInfo>

حالياً الملف بهذا الشكل , يحتوي فقط على صورة العرض

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

<?xml version="1.0" encoding="utf-8"?>
<WatchFaceInfo>
    <Editable value="true" />

    <Preview value="@drawable/preview" />
</WatchFaceInfo>

 

لنجرب تشغيل التطبيق- تأكد من إضافة وتحميل Wear OS Emulator  , في حالتي قمت باستخدام WearOS Large Round Android 16.0

 

جميل جداً!

لنقم بشرح الكود خطوة بخطوة

<WatchFace
    height="450"
    width="450">
    <Metadata
        key="CLOCK_TYPE"
        value="DIGITAL" />
    <Metadata
        key="PREVIEW_TIME"
        value="06:18:00" />
</WatchFace>

 

WatchFace  هو العنصر الRoot الذي يحتوي جميع العناصر ومقاس مساحة العمل, المقاس الإفتراضي ٤٥٠ وهو مقاس مناسب لمعظم الشاشات

Metadata الذي يحتوي على معلومات الواجهة مثل نوعها Analog or Digital  ويمكننا أيضاً وضع الوقت الذي نريد للعرض على الساعة مثل 6:18

Scene والذي سيحتوي على عناصر الساعة , يمكنك أيضاً وضع backgroundColor ل scene 

من الجدير بالذكر أن Scene يمكن أن يحتوي على عنصر واحد فقط

داخل Scene يمكننا وضع الساعة. حالياً يوجد نوعين من الساعات Digital و Analog. سنقوم بالعمل على DigitalClock حالياً كونها أسهل في التعامل.

 

<DigitalClock
            height="450"
            width="450"
            x="0"
            y="0"/>

 

يمكننا تخصيص الإرتفاع والعرض, وإحداثيات الساعة الرقمية مثل x,y

يجب وضع TimeText داخل DigitalClock لعرض الوقت 

 <TimeText
                format="hh:mm"
                height="100"
                width="450"
                x="0"
                y="175">

معظم عناصر WFF تأخذ نفس البارامترات مثل الإرتفاع, العرض, x,y

بالنسبة ل TimeText يمكننا تحديد صيغة الوقت مثل 

  • hh:mm:ss renders as "12:34:56".
  • h:mm renders as "12:34"
  • hh_10 renders as "1".
  • hh_1 renders as "2".
  • m renders as "34"
  • mm_10 renders as "3".
  • mm_1 renders as "4".
  • ss renders as "56"
  • ss_10 renders as "5".
  • ss_1 renders as "6".

يمكنك تفقد الDocumentation لمعلومات أكثر عن صيغ الوقت المدعومة

يجب علينا إضافة Font للتحكم بالخط مثل نوع الخط, لونه, وحجمه.

   <Font
    color="#ffffffff"
    family="SYNC_TO_DEVICE"
    size="128" />

قمنا بوضع اللون الى اللون الأبيض

 نوع الخط "Family" SYNC_TO_DEVICE

SYNC_TO_DEVICE تعني أنه سيقوم بعرض نفس الخط الموجود بالهاتف المربوط بالساعة الذكية 

يمكننا وضع خط خاص عبر إنشاء مجلد font داخل res

 

ثم وضع family="FONT_NAME" مثل

     <Font
     color="#ffffffff"
     family="rubik"
     size="128" />

يجب أن يكون إسم الخط نفسه بدون الإمتداد

لنشغل التطبيق لنرى النتيجة

<WatchFace
    height="450"
    width="450">
    <Metadata
        key="CLOCK_TYPE"
        value="DIGITAL" />
    <Scene>
        <DigitalClock
            height="450"
            width="450"
            x="0"
            y="0">
            <TimeText
                format="hh:mm"
                height="100"
                width="450"
                x="0"
                y="175">
           
                <Font
                    color="#ffffffff"
                    family="rubik"
                    size="128" />
            </TimeText>
        </DigitalClock>
    </Scene>
</WatchFace>

 

الآن سنقوم بوضع Variant

   <Variant
   mode="AMBIENT"
   target="alpha"
   value="0" />

الVariant سيقوم بالتبديل ما بين targets في حالتنا "alpha" 

نستخدمه عادة للتبديل بين الأوضاع عندما تكون شاشة الساعة مضاءة وبين وضع AOD Always On Display
في وضع AOD يجب أن تكون الشاشة سوداء مع ألوان قريبة للأسود لتوفير البطارية.

في هذا المثال قمنا بوضع value=0 أي أنه في وضع AMBIENT سنقوم بتغيير alpha الى 0 مما يعني إخفاء هذا العنصر تماماً في وضع AOD

 

ولعرض الوقت عندما يكون AOD فعال سنقوم بإنشاء نص آخر بVairant معاكس

 <TimeText
                alpha="0" //hidden
                format="hh:mm"
                height="100"
                width="450"
                x="0"
                y="175">
                <Variant
                    mode="AMBIENT"
                    target="alpha"
                    value="255" />
                <Font
                    color="#ffffffff"
                    family="SYNC_TO_DEVICE"
                    size="128"
                    />
            </TimeText>

نلاحظ أنه TimeText Alpha هو 0 , أي أنه غير ظاهر بشكل إفتراضي

ثم وضعنا Variant alpha 255 لنعرض هذا العنصر في وضع Ambient فقط 

ليصبح لدينا نصين, واحد لوضع Ambient , والآخر للوضع العادي

 

<WatchFace
    height="450"
    width="450">
    <Metadata
        key="CLOCK_TYPE"
        value="DIGITAL" />
    <Scene>
        <DigitalClock
            height="450"
            width="450"
            x="0"
            y="0">
            <TimeText
                format="hh:mm"
                height="100"
                width="450"
                x="0"
                y="175">
                <Variant
                    mode="AMBIENT"
                    target="alpha"
                    value="0" />
                <Font
                    color="#ffffffff"
                    family="SYNC_TO_DEVICE"
                    size="128" />
            </TimeText>
            <TimeText
                alpha="0"
                format="hh:mm"
                height="100"
                width="450"
                x="0"
                y="175">
                <Variant
                    mode="AMBIENT"
                    target="alpha"
                    value="255" />
                <Font
                    color="#ffffffff"
                    family="SYNC_TO_DEVICE"
                    size="128"
                    />
            </TimeText>
        </DigitalClock>
    </Scene>
</WatchFace>

 

لتوضيح الفكرة بشكل أكبر سنقوم بتغيير النص في الوضع العادي الى الأحمر مثلا, واللون الأبيض في وضع Ambient

 

<WatchFace
    height="450"
    width="450">
    <Metadata
        key="CLOCK_TYPE"
        value="DIGITAL" />
    <Scene>
        <DigitalClock
            height="450"
            width="450"
            x="0"
            y="0">
            <TimeText
                format="hh:mm"
                height="100"
                width="450"
                x="0"
                y="175">
                <Variant
                    mode="AMBIENT"
                    target="alpha"
                    value="0" />
                <Font
                    color="#ff0000"
                    family="SYNC_TO_DEVICE"
                    size="128" />
            </TimeText>
            <TimeText
                alpha="0"
                format="hh:mm"
                height="100"
                width="450"
                x="0"
                y="175">
                <Variant
                    mode="AMBIENT"
                    target="alpha"
                    value="255" />
                <Font
                    color="#ffffffff"
                    family="SYNC_TO_DEVICE"
                    size="128"
                    />
            </TimeText>
        </DigitalClock>
    </Scene>
</WatchFace>

 

 

سنتابع الآن لنشرح كيفية إضافة نص ما(بغض النظر عن الوقت)

يمكننا إضافة Group وتستخدم عادة لتنظيم الكود, او لوضع مزايا معينة لهذا Group عند وضع معين في إعدادات Watch Face او حتى لوضع عناصر معينة ضمن X,Y معينة.

يجب أن يحتوي كل Group على إسم

  <Group
            name="hello_world"
            height="450"
            width="450"
            x="0"
            y="0">

 

ولوضع نص معين يمكننا إستخدام `PartText`

 

 <PartText
                height="50"
                width="450"
                x="0"
                y="285">

داخل PartText يجب أن نضع Text وداخله يمكننا تخصيص الخط Font

يمكننا وضع النص الذي نريده بشكل مباشر داخل Font 

أو يمكننا إستخدام Expressions كما سنرى لاحقاً

        <Group
            name="hello_world"
            height="450"
            width="450"
            x="0"
            y="0">
            <PartText
                height="50"
                width="450"
                x="0"
                y="285">

                <Text>
                    <Font
                        color="#ffffffff"
                        family="SYNC_TO_DEVICE"
                        size="30">

                        Hello 3alam Pro!

                    </Font>
                </Text>
            </PartText>
        </Group>

 

 

 

 يمكننا إستخدام strings.xml وعرض النصوص داخله عبر استخدام `Template`

        <Group
            name="hello_world"
            height="450"
            width="450"
            x="0"
            y="0">
            <PartText
                height="50"
                width="450"
                x="0"
                y="285">
                <Variant
                    mode="AMBIENT"
                    target="alpha"
                    value="0" />
                <Text>
                    <Font
                        color="#ffffffff"
                        family="SYNC_TO_DEVICE"
                        size="36">
                        <Template>%s
                            <Parameter expression="greeting" />
                        </Template>
                    </Font>
                </Text>
            </PartText>
        </Group>

 

يمكننا إستخدام Template بنفس فكرة String.format() في الأندرويد, يمكننا وضع %s لإستبدال النص strings.xml ,

يمكننا وضع اسم العنصر من strings.xml داخل expression

//strings.xml

<resources>
    <string name="watch_face_name">My Watch Face</string>
    <string name="greeting">Hello, 3alam Pro!</string>
</resources>

//watchface.xml
   <Font
   color="#ffffffff"
   family="SYNC_TO_DEVICE"
   size="36">
    <Template>%s
     <Parameter expression="greeting" />
     </Template>
    </Font>

 

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

للتأكد من أن الملف يعمل بشكل طبيعي, ولنضمن من أن التطبيق سيتم قبوله في Google Play فإنه يجب علينا استخدام wff-validator والتي ستقوم بالتحقق من صلاحية ملف xml 

يمكنك تحميل الأداة عبر رابط Github الرسمي

ويمكنك استخدامه بالشكل التالي

java -jar ~/Downloads/wff-validator.jar 2 /Users/user/AndroidStudioProjects/MyWatchFace/watchface/src/main/res/raw/watchface.xml

كل ما عليك هو تزويد الأداة ب رقم اصدار Watch Face الذي تريد التجربة عليه "٢" مثلا , وثم مسار ملف xml

 

كما نرى فإنه لاتوجد أية مشاكل في ملف xml

وللتأكد, سأقوم بتغيير داخل Font ووضع النص مباشرةً داخل Template

     <Group
            name="hello_world"
            height="450"
            width="450"
            x="0"
            y="0">
            <PartText
                height="50"
                width="450"
                x="0"
                y="285">
                <Variant
                    mode="AMBIENT"
                    target="alpha"
                    value="0" />
                <Text>
                    <Font
                        color="#ffffffff"
                        family="SYNC_TO_DEVICE"
                        size="36">
                        <Template>Hello 3alam Pro! //incorrect
                            
                        </Template>
                    </Font>
                </Text>
            </PartText>
        </Group>

 سنرى أنه يوجد خطأ مع أن التطبيق يعمل على Emulator

 

 

مصادر قد تهمك

1 2 3

كلمات دليلية: android watchface wearos wff
0
إعجاب
10
مشاهدات
0
مشاركة
1
متابع

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !