הצגת פעילויות מתמשכות

מכשירי Wear OS משמשים לעיתים קרובות לחוויות שימוש ממושכות, כמו מעקב אחר אימון. הדבר הזה יוצר בעיה בחוויית המשתמש: אם משתמש מתחיל משימה ואז עובר לתצוגת השעון, איך הוא יכול לחזור למשימה? יכול להיות שיהיה קשה לחזור לאפליקציה באמצעות מרכז האפליקציות, במיוחד כשנמצאים בתנועה, וזה יוצר חיכוך מיותר.

הפתרון הוא לשייך התראה מתמשכת לOngoingActivity. ההרשאה הזו מאפשרת למכשיר להציג מידע על פעילות שמתבצעת לאורך זמן בממשק המשתמש, ומאפשרת להשתמש בתכונות כמו הסמל שאפשר להקיש עליו בחלק התחתון של תצוגת השעון. כך המשתמשים יודעים על המשימה שפועלת ברקע, ויכולים לחזור לאפליקציה בלחיצה אחת.

פעילות מתמשכת גם מאפשרת לאפליקציה להישאר גלויה למשך זמן ארוך יותר, ומונעת מהמערכת לחזור לתצוגת השעון אחרי תקופה של חוסר פעילות. מידע נוסף מופיע במאמר שמירה על נראות האפליקציה ב-Wear.

לדוגמה, באפליקציית אימון הכושר הזו, המידע יכול להופיע בתצוגת השעון של המשתמש כסמל ריצה שאפשר להקיש עליו:

running-icon

איור 1. אינדיקטור של פעילות.

התראה מתמשכת מציגה גם מידע בקטע האפליקציות שהיו בשימוש בזמן האחרון במרכז האפליקציות הגלובלי. כך המשתמשים יכולים לראות את סטטוס המשימה שלהם במקום נוח נוסף ולחזור לאפליקציה:

מרכז האפליקציות

איור 2. מרכז האפליקציות הגלובלי.

אלה מצבים שבהם כדאי להשתמש בהתראה מתמשכת שקשורה לפעילות מתמשכת:

טיימר

איור 3. טיימר: סופר לאחור את הזמן ומסתיים כשהטיימר מושהה או מופסק.

מפה

איור 4. מסלול מפורט: הכרזה על הוראות הגעה ליעד. השיתוף מסתיים כשהמשתמש מגיע ליעד או מפסיק את הניווט.

מוזיקה

איור 5. מדיה: השמעת מוזיקה לאורך כל הסשן. הסשן מסתיים מיד אחרי שהמשתמש משהה אותו.

מערכת Wear יוצרת באופן אוטומטי פעילויות מתמשכות לאפליקציות מדיה.

בדף Ongoing Activity codelab יש דוגמה מפורטת ליצירת פעילויות מתמשכות לסוגים אחרים של אפליקציות.

הגדרה

כדי להתחיל להשתמש ב-Ongoing Activity API באפליקציה, מוסיפים את התלויות הבאות לקובץ build.gradle של האפליקציה:

dependencies {
  implementation "androidx.wear:wear-ongoing:1.1.0"
  implementation "androidx.core:core:1.18.0"
}

יצירת פעילות מתמשכת

התהליך כולל שלושה שלבים:

  1. יוצרים NotificationCompat.Builder רגיל ומגדירים אותו כמתמשך.
  2. יוצרים ומגדירים אובייקט OngoingActivity ומעבירים אליו את builder ההתראות.
  3. מחילים את הפעילות המתמשכת על כלי ליצירת התראות ומפרסמים את ההתראה שנוצרת.

יצירה והגדרה של ההתראה

קודם כול יוצרים NotificationCompat.Builder. השלב העיקרי הוא לקרוא ל-setOngoing(true) כדי לסמן אותה כהתראה מתמשכת. בשלב הזה אפשר גם להגדיר מאפיינים אחרים של ההתראה, כמו הסמל הקטן והקטגוריה.

// Create a PendingIntent to pass to the notification builder
val pendingIntent =
    PendingIntent.getActivity(
        this,
        0,
        Intent(this, AlwaysOnActivity::class.java).apply {
            flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
        },
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
    )

val notificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID)
    .setContentTitle("Always On Service")
    .setContentText("Service is running in background")
    .setSmallIcon(R.drawable.animated_walk)
    // Category helps the system prioritize the ongoing activity
    .setCategory(NotificationCompat.CATEGORY_WORKOUT)
    .setContentIntent(pendingIntent)
    .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
    .setOngoing(true) // Important!

יצירת OngoingActivity

לאחר מכן, יוצרים מופע של OngoingActivity באמצעות כלי הבנייה שלו. הפונקציה OngoingActivity.Builder דורשת Context, מזהה התראה ו-NotificationCompat.Builder שיצרתם בשלב הקודם.

מגדירים את מאפייני המפתח שיוצגו בממשק המשתמש החדש:

  • סמלים עם אנימציה וסמלים סטטיים: צריך לספק סמלים שיוצגו בתצוגת השעון במצבים פעילים ובמצבי אווירה.
  • הקשה על סמל הפעילות המתמשכת: PendingIntent שמחזיר את המשתמש לאפליקציה שלכם כשהוא מקיש על סמל הפעילות המתמשכת. אפשר להשתמש שוב ב-pendingIndent שנוצר בשלב הקודם.

val ongoingActivity =
    OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder)
        // Sets the icon that appears on the watch face in active mode.
        .setAnimatedIcon(R.drawable.animated_walk)
        // Sets the icon that appears on the watch face in ambient mode.
        .setStaticIcon(R.drawable.ic_walk)
        // Sets the tap target to bring the user back to the app.
        .setTouchIntent(pendingIntent)
        .build()

החלת ההגדרה על ההתראה ועל הפוסט

השלב האחרון הוא לקשר את OngoingActivity להתראה ואז לפרסם אותה. השיטה ongoingActivity.apply() משנה את כלי בניית ההודעות המקורי, ומוסיפה את הנתונים הנדרשים כדי שהמערכת תוכל להציג אותם בממשקים הנוספים. אחרי שמחילים את ההמלצה, אפשר ליצור ולפרסם את ההתראה כרגיל.

// This call modifies notificationBuilder to include the ongoing activity data.
ongoingActivity.apply(applicationContext)

// Post the notification.
startForeground(NOTIFICATION_ID, notificationBuilder.build())

הוספת טקסט סטטוס דינמי למרכז האפליקציות

הקוד שלמעלה מוסיף את הסמל שאפשר להקיש עליו לתצוגת השעון. כדי לספק עדכונים עשירים יותר בזמן אמת בקטע האחרונים במרכז האפליקציות, צריך ליצור אובייקט Status ולצרף אותו ל-OngoingActivity. אם לא מציינים Status מותאם אישית, המערכת משתמשת כברירת מחדל בטקסט התוכן של ההתראה (שמוגדר באמצעות setContentText()). כדי להציג טקסט דינמי, צריך להשתמש ב-Status.Builder. אפשר להגדיר מחרוזת תבנית עם placeholders ולספק אובייקטים של Status.Part כדי למלא את ה-placeholders האלה. הערך של Status.Part יכול להיות דינמי, כמו שעון עצר או טיימר.

בדוגמה הבאה מוצג אופן היצירה של סטטוס עם הכיתוב 'פועל במשך [טיימר שעון עצר]':

// Define a template with placeholders for the activity type and the timer.
val statusTemplate = "#type# for #time#"

// Set the start time for a stopwatch.
// Use SystemClock.elapsedRealtime() for time-based parts.
val runStartTime = SystemClock.elapsedRealtime()

val ongoingActivityStatus = Status.Builder()
    // Sets the template string.
    .addTemplate(statusTemplate)
    // Fills the #type# placeholder with a static text part.
    .addPart("type", Status.TextPart("Run"))
    // Fills the #time# placeholder with a stopwatch part.
    .addPart("time", Status.StopwatchPart(runStartTime))
    .build()

לבסוף, כדי לקשר את Status אל OngoingActivity, צריך להתקשר אל setStatus() ב-OngoingActivity.Builder.

val ongoingActivity =
    OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder)
        // ...
        // Add the status to the OngoingActivity.
        .setStatus(ongoingActivityStatus)
        .build()

התאמות אישיות נוספות

בנוסף לStatus, יש כמה דרכים להתאים אישית את הפעילות המתמשכת או את ההתראות. עם זאת, יכול להיות שההתאמות האישיות האלה לא ישמשו אתכם, בהתאם להטמעה של יצרן הציוד המקורי.

התראה מתמשכת

  • הקטגוריה שמוגדרת קובעת את העדיפות של הפעילות המתמשכת.
    • CATEGORY_CALL: שיחת וידאו או שיחה קולית נכנסת או בקשה דומה לתקשורת סינכרונית
    • CATEGORY_NAVIGATION: מפה או מסלול מפורט
    • CATEGORY_TRANSPORT: שליטה בהעברת מדיה להפעלה
    • CATEGORY_ALARM: שעון מעורר או טיימר
    • CATEGORY_WORKOUT: אימון כושר
    • CATEGORY_LOCATION_SHARING: קטגוריה של שיתוף מיקום זמני
    • CATEGORY_STOPWATCH: שעון עצר

פעילות שוטפת

  • סמל מונפש: וקטור בשחור-לבן, רצוי עם רקע שקוף. הוא מוצג בתצוגת השעון במצב פעיל. אם לא מספקים סמל אנימציה, המערכת משתמשת בסמל ברירת המחדל של ההתראה. סמל ברירת המחדל של ההתראה שונה בכל אפליקציה.

  • סמל סטטי: סמל וקטורי עם רקע שקוף. מוצג בתצוגת השעון במצב אווירה. אם לא מוגדר סמל עם אנימציה, הסמל הסטטי מוצג בתצוגת השעון במצב פעיל. אם לא מציינים סמל, המערכת משתמשת בסמל של ההתראה. אם לא מוגדר אף אחד מהם, נוצרת חריגה. (מרכז האפליקציות עדיין משתמש בסמל האפליקציה).

  • OngoingActivityStatus: טקסט פשוט או Chronometer. מוצג בקטע האחרונות במרכז האפליקציות. אם לא מספקים את הטקסט הזה, המערכת משתמשת ב"טקסט ההקשר" של ההתראה.

  • Touch Intent:PendingIntent משמש כדי לחזור לאפליקציה אם המשתמש מקיש על סמל הפעילות המתמשכת. האפליקציה מוצגת בתצוגת השעון או בפריט של מרכז האפליקציות. יכול להיות שהמטרה הזו שונה מהמטרה המקורית ששימשה להפעלת האפליקציה. אם לא מציינים מטרה, נעשה שימוש במטרה של תוכן ההתראה. אם אף אחד מהם לא מוגדר, נוצרת חריגה.

  • LocusId: מזהה שמקצה את קיצור הדרך במרכז האפליקציות שאליו משויכת הפעילות המתמשכת. הפעילות מוצגת במרכז האפליקציות בקטע מהזמן האחרון בזמן שהיא מתבצעת. אם לא מספקים את המזהה, מרכז האפליקציות מסתיר את כל פריטי האפליקציות בקטע הפעולות האחרונות מאותו חבילה, ומציג רק את הפעילות המתמשכת.

  • Ongoing Activity ID: מזהה שמשמש להבחנה בין קריאות ל-fromExistingOngoingActivity() כשיש לאפליקציה יותר מפעילות מתמשכת אחת.

עדכון פעילות מתמשכת

אם רוצים לשנות את הסטטוס, צריך לעדכן את הפעילות המתמשכת של ההתראה הקיימת, ולא ליצור התראה חדשה ופעילות מתמשכת חדשה. כדי לעדכן את הפעילות הרציפה ואת ההתראה שפורסמה, משתמשים באובייקט שיצרתם קודם ומפעילים את update(), כמו בדוגמה הבאה:

ongoingActivity.update(context, newStatus)

במקרים שבהם אי אפשר לשמור הפניה לפעילות המתמשכת, יש שיטה סטטית לשחזור הפעילות המתמשכת. עם זאת, האפשרות הזו פחות מועדפת:

OngoingActivity.recoverOngoingActivity(context)
    ?.update(context, newStatus)

הפסקת פעילות מתמשכת

כשהאפליקציה מסיימת לפעול כפעילות מתמשכת, היא צריכה רק לבטל את ההתראה המתמשכת.

אפשר גם לבטל את ההתראה או את הפעילות המתמשכת כשהן עוברות לחזית, ואז ליצור אותן מחדש כשחוזרים לרקע, אבל זה לא חובה.

השהיית פעילות מתמשכת

אם באפליקציה יש פעולת עצירה מפורשת, צריך להמשיך את הפעילות המתמשכת אחרי שההשהיה שלה מבוטלת. אם לאפליקציה אין פעולת עצירה מפורשת, הפעילות מסתיימת כשהיא מושהית.

שיקולים עיקריים

כשעובדים עם Ongoing Activity API, חשוב לזכור את הדברים הבאים:

  • מגדירים סמל סטטי לפעילות המתמשכת, באופן מפורש או כגיבוי באמצעות ההתראה. אם לא, תקבלו הודעה על כך IllegalArgumentException.

  • שימוש בסמלי וקטור בשחור-לבן עם רקע שקוף.

  • מגדירים כוונת מגע לפעילות המתמשכת, באופן מפורש או כגיבוי באמצעות ההתראה. אם לא, תקבלו הודעה על כך IllegalArgumentException.

  • אם באפליקציה שלכם מוצהרת יותר מפעילות אחת MAIN LAUNCHER במניפסט, פרסמו קיצור דרך דינמי וקשרו אותו לפעילות המתמשכת באמצעות LocusId.

פרסום התראות על מדיה כשמפעילים מדיה במכשירי Wear OS

אם תוכן מדיה מופעל במכשיר Wear OS, מפרסמים התראה על מדיה. כך המערכת יכולה ליצור את הפעילות המתאימה שמתבצעת באופן שוטף.

אם אתם משתמשים ב-Media3, ההתראה מתפרסמת באופן אוטומטי. אם יוצרים את ההתראה באופן ידני, צריך להשתמש ב-MediaStyleNotificationHelper.MediaStyle, וב-MediaSession המתאים צריך להיות מאוכלס session activity.