Maps API ב-Wear OS

מפה במכשיר לביש

באמצעות ה-SDK של מפות Google ל-Android, אפשר ליצור אפליקציה לבישה מבוססת מפה שפועלת ישירות במכשירי Wear OS by Google. משתמשי האפליקציה יכולים לראות את המיקום שלהם במפה פשוט על ידי מבט אל פרקי כף היד שלהם. הם יכולים להציב את המיקום שלהם במסלול, לדוגמה, ואז להגדיל את התצוגה כדי לראות פרטים או להקיש על סמן כדי לראות חלון מידע שהאפליקציה מספקת.

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

תחילת העבודה עם Wear OS

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

Android Studio הוא הכלי המומלץ לפיתוח ל-Wear OS, כי הוא מאפשר להגדיר את הפרויקט, לכלול את הספרייה ולהשתמש בנוחות האריזה.

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

פיתוח אפליקציית המפות הראשונה שלך ב-Wear OS

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

הוספת יחסי תלות למודול Wear

מוודאים שיחסי התלות הבאים כלולים בקובץ build.gradle של מודול Wear OS של האפליקציה:

dependencies {
    // ...
    compileOnly 'com.google.android.wearable:wearable:2.9.0'
    implementation 'com.google.android.support:wearable:2.9.0'
    implementation 'com.google.android.gms:play-services-maps:18.2.0'

    // This dependency is necessary for ambient mode
    implementation 'androidx.wear:wear:1.3.0'
}

מידע נוסף על יחסי התלות זמין במדריך להוספת מודול Wear OS לפרויקט הקיים.

להטמיע תנועת החלקה לסגירה ולהגדיר את צבע הרקע הראשוני

מומלץ להשתמש ב-SwipeDismissFrameLayout כדי להציג את המפה במכשיר הלביש. באמצעות המחלקה SwipeDismissFrameLayout אפשר להטמיע את תנועת החלקה לכיווץ, שמאפשרת למשתמשים לצאת מהאפליקציה על ידי החלקה מהקצה השמאלי ביותר של המסך.

כדי להגדיר צבע רקע ראשוני בהתאמה אישית, תוכלו להשתמש במאפיין ה-XML של map:backgroundColor כדי להגדיר את הצבע שיוצג עד שמשבצות המפה ייטענו בפועל.

מוסיפים את הרכיבים SwipeDismissFrameLayout ו-backgroundColor להגדרת הפריסה כקונטיינר של SupportMapFragment:

  <androidx.wear.widget.SwipeDismissFrameLayout
      android:id="@+id/map_container"
      android:layout_width="match_parent"
      android:layout_height="match_parent">
    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        map:backgroundColor="#fff0b2dd" />
  </androidx.wear.widget.SwipeDismissFrameLayout>

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

Kotlin



class MainActivity : AppCompatActivity(), OnMapReadyCallback,
                     AmbientModeSupport.AmbientCallbackProvider {


    public override fun onCreate(savedState: Bundle?) {
        super.onCreate(savedState)

        // Set the layout. It only contains a SupportMapFragment and a DismissOverlay.
        setContentView(R.layout.activity_main)

        // Enable ambient support, so the map remains visible in simplified, low-color display
        // when the user is no longer actively using the app but the app is still visible on the
        // watch face.
        val controller = AmbientModeSupport.attach(this)
        Log.d(MainActivity::class.java.simpleName, "Is ambient enabled: " + controller.isAmbient)

        // Retrieve the containers for the root of the layout and the map. Margins will need to be
        // set on them to account for the system window insets.
        val mapFrameLayout = findViewById<SwipeDismissFrameLayout>(R.id.map_container)
        mapFrameLayout.addCallback(object : SwipeDismissFrameLayout.Callback() {
            override fun onDismissed(layout: SwipeDismissFrameLayout) {
                onBackPressed()
            }
        })

        // Obtain the MapFragment and set the async listener to be notified when the map is ready.
        mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

    // ...
}

      

Java


public class MainActivity extends AppCompatActivity implements OnMapReadyCallback,
    AmbientModeSupport.AmbientCallbackProvider {


    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);

        // Set the layout. It only contains a SupportMapFragment and a DismissOverlay.
        setContentView(R.layout.activity_main);

        // Enable ambient support, so the map remains visible in simplified, low-color display
        // when the user is no longer actively using the app but the app is still visible on the
        // watch face.
        AmbientModeSupport.AmbientController controller = AmbientModeSupport.attach(this);
        Log.d(MainActivity.class.getSimpleName(), "Is ambient enabled: " + controller.isAmbient());

        // Retrieve the containers for the root of the layout and the map. Margins will need to be
        // set on them to account for the system window insets.
        final SwipeDismissFrameLayout mapFrameLayout = (SwipeDismissFrameLayout) findViewById(
            R.id.map_container);
        mapFrameLayout.addCallback(new SwipeDismissFrameLayout.Callback() {
            @Override
            public void onDismissed(SwipeDismissFrameLayout layout) {
                onBackPressed();
            }
        });

        // Obtain the MapFragment and set the async listener to be notified when the map is ready.
        mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    // ...
}

      

הוספת מפה

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

Kotlin



private val sydney = LatLng(-33.85704, 151.21522)

override fun onMapReady(googleMap: GoogleMap) {
    // Add a marker with a title that is shown in its info window.
    googleMap.addMarker(
        MarkerOptions().position(sydney)
            .title("Sydney Opera House")
    )

    // Move the camera to show the marker.
    googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(sydney, 10f))
}

      

Java


private static final LatLng SYDNEY = new LatLng(-33.85704, 151.21522);

@Override
public void onMapReady(@NonNull GoogleMap googleMap) {
    // Add a marker with a title that is shown in its info window.
    googleMap.addMarker(new MarkerOptions().position(SYDNEY)
        .title("Sydney Opera House"));

    // Move the camera to show the marker.
    googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(SYDNEY, 10));
}

      

הפעלת תאורת אווירה

ה-SDK של מפות Google ל-Android תומך במצב רגישות לאפליקציות לבישות. לפעמים, אפליקציות שתומכות במצב רגישות לסביבה נקראות אפליקציות מופעלות תמיד. תאורת האווירה מופעלת כשהמשתמש לא משתמש יותר באפליקציה באופן פעיל, ומאפשר לאפליקציה להישאר גלויה במכשיר הלביש.

ה-SDK של מפות Google ל-Android מספק עיבוד פשוט של המפה בצבע נמוך לשימוש במצב רגישות לסביבה, וסגנון המפה מותאם באופן אוטומטי כשהמכשיר עובר ממצב אינטראקטיבי למצב רגישות לסביבה. כל הסמנים, האובייקטים והפקדים בממשק המשתמש נעלמים במצב רגישות לסביבה. כך תפחיתו את צריכת החשמל של האפליקציה ותבטיחו מראה וסגנון עקביים באפליקציות אווירה אחרות, כמו תצוגות שעון.

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

  1. מעדכנים את Android SDK כך שיכלול את Android 6.0 (API 23) ואילך, שמספקת את ממשקי ה-API שמאפשרים לפעילויות לעבור למצב רגישות לסביבה. רוצים לדעת איך לעדכן את ה-SDK? עיינו במאמרי העזרה של Android בנושא הוספת חבילות SDK.
  2. חשוב לוודא שהפרויקט מטרגט את Android 6.0 ואילך, על ידי הגדרת הערך של targetSdkVersion לערך 23 ואילך במניפסט האפליקציה.
  3. צריך להוסיף את יחסי התלות הלבישים לקובץ build.gradle של האפליקציה. ראו דוגמה בדף הזה.
  4. מוסיפים את הרשומה של הספרייה המשותפת הלבישת לקובץ המניפסט של האפליקציה הלבישת, כפי שמתואר בשיעור ההדרכה של Android בנושא שמירה על חשיפה של האפליקציה.
  5. מוסיפים את ההרשאה WAKE_LOCK למניפסטים של אפליקציות לבישים ולמכשירים ניידים, כפי שמתואר בשיעור ההדרכה של Android בנושא שמירת האפליקציה גלויה.
  6. ב-method onCreate() של הפעילות, קוראים ל-method AmbientModeSupport.attach(). הפקודה הזו מנחה את מערכת ההפעלה שהאפליקציה פועלת תמיד. לכן, כשהמכשיר ייכבה, עליו לעבור למצב רגישות לסביבה במקום לחזור לתצוגת השעון.
  7. חשוב להטמיע את הממשק AmbientModeSupport.AmbientCallbackProvider בפעילות כדי שהוא יוכל לקבל שינויים במצב האווירה.
  8. יש להגדיר את המפה כך שתתמוך במצב רגישות לסביבה. אפשר לעשות זאת על ידי הגדרת המאפיין map:ambientEnabled="true" בקובץ פריסת ה-XML של הפעילות, או על ידי הגדרה של GoogleMapOptions.ambientEnabled(true) באופן פרוגרמטי. ההגדרה הזו מודיעה ל-API שעליו לטעון מראש את אריחי המפה הנחוצים לשימוש במצב רגישות לסביבה.
  9. כשהפעילות עוברת למצב רגישות לסביבה, המערכת מפעילה את השיטה onEnterAmbient() ב-AmbientCallback שסיפקתם. שינוי onEnterAmbient() וקריאה ל-SupportMapFragment.onEnterAmbient(ambientDetails) או ל-MapView.onEnterAmbient(ambientDetails). ה-API מחליף את התצוגה של המפה לרינדור לא אינטראקטיבי ובצבע נמוך.
  10. באופן דומה, ב-onExitAmbient() קוראים ל-SupportMapFragment.onExitAmbient() או ל-MapView.onExitAmbient(). ה-API מחליף לרינדור הרגיל של המפה.

דוגמת הקוד הבאה מפעילה את מצב האווירה בפעילות:

Kotlin



class AmbientActivity : AppCompatActivity(), AmbientModeSupport.AmbientCallbackProvider {

    private lateinit var mapFragment: SupportMapFragment

    public override fun onCreate(savedState: Bundle?) {
        super.onCreate(savedState)

        // Set the layout. It only contains a SupportMapFragment and a DismissOverlay.
        setContentView(R.layout.activity_main)

        // Enable ambient support, so the map remains visible in simplified, low-color display
        // when the user is no longer actively using the app but the app is still visible on the
        // watch face.
        val controller = AmbientModeSupport.attach(this)
        Log.d(AmbientActivity::class.java.simpleName, "Is ambient enabled: " + controller.isAmbient)

        // Obtain the MapFragment and set the async listener to be notified when the map is ready.
        mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
    }

    override fun getAmbientCallback(): AmbientModeSupport.AmbientCallback {
        return object : AmbientModeSupport.AmbientCallback() {
            /**
             * Starts ambient mode on the map.
             * The API swaps to a non-interactive and low-color rendering of the map when the user is no
             * longer actively using the app.
             */
            override fun onEnterAmbient(ambientDetails: Bundle) {
                super.onEnterAmbient(ambientDetails)
                mapFragment.onEnterAmbient(ambientDetails)
            }

            /**
             * Exits ambient mode on the map.
             * The API swaps to the normal rendering of the map when the user starts actively using the app.
             */
            override fun onExitAmbient() {
                super.onExitAmbient()
                mapFragment.onExitAmbient()
            }
        }
    }
}

      

Java


public class AmbientActivity extends AppCompatActivity implements
    AmbientModeSupport.AmbientCallbackProvider {

    private SupportMapFragment mapFragment;

    public void onCreate(Bundle savedState) {
        super.onCreate(savedState);

        // Set the layout. It only contains a SupportMapFragment and a DismissOverlay.
        setContentView(R.layout.activity_main);

        // Enable ambient support, so the map remains visible in simplified, low-color display
        // when the user is no longer actively using the app but the app is still visible on the
        // watch face.
        AmbientModeSupport.AmbientController controller = AmbientModeSupport.attach(this);
        Log.d(AmbientActivity.class.getSimpleName(), "Is ambient enabled: " + controller.isAmbient());

        // Obtain the MapFragment and set the async listener to be notified when the map is ready.
        mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map);
    }

    @Override
    public AmbientCallback getAmbientCallback() {
        return new AmbientCallback() {
            /**
             * Starts ambient mode on the map.
             * The API swaps to a non-interactive and low-color rendering of the map when the user is no
             * longer actively using the app.
             */
            @Override
            public void onEnterAmbient(Bundle ambientDetails) {
                super.onEnterAmbient(ambientDetails);
                mapFragment.onEnterAmbient(ambientDetails);
            }

            /**
             * Exits ambient mode on the map.
             * The API swaps to the normal rendering of the map when the user starts actively using the app.
             */
            @Override
            public void onExitAmbient() {
                super.onExitAmbient();
                mapFragment.onExitAmbient();
            }
        };
    }
}

      

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

שימוש ב-Street View ב-Wear OS

יש תמיכה מלאה ב-Street View במכשירים לבישים.

כדי לאפשר למשתמשים לצאת מהאפליקציה כשהם צופים בפנורמה של Street View, צריך להשתמש בממשק StreetViewPanorama.OnStreetViewPanoramaLongClickListener כדי להאזין לתנועה של לחיצה ארוכה. כשמשתמש ילחץ לחיצה ארוכה במקום כלשהו בתמונת Street View, תקבלו אירוע onStreetViewPanoramaLongClick(StreetViewPanoramaOrientation). קוראים לפונקציה DismissOverlayView.show() כדי להציג לחצן יציאה.

קוד לדוגמה

ב-GitHub יש אפליקציה לדוגמה, ואפשר להשתמש בה כנקודת התחלה של האפליקציה. בדוגמה אפשר לראות איך מגדירים מפת Google בסיסית ב-Wear OS.

פונקציונליות נתמכת ב-API של מפות Google ב-Wear OS

בקטע הזה מפורטים ההבדלים בפונקציונליות הנתמכת של מפות במכשירים לבישים, בהשוואה למכשירים ניידים (טלפונים וטאבלטים). כל תכונות ה-API שלא צוינו למטה אמורות לפעול לפי התיעוד המלא של ה-API.

פונקציונליות
מצב אינטראקטיבי מלא ומצב Lite

אפשר להשתמש ב-SDK של מפות ל-Android במצב אינטראקטיבי מלא או במצב Lite. כדאי להשתמש במצב Lite אם רוצים לשפר את הביצועים במכשיר הלביש והאפליקציה לא צריכה לתמוך באינטראקציות כמו תנועות או הזזה או שינוי מרחק התצוגה של המפה.

במצב Lite, הכוונה להפעיל את האפליקציה לנייד של מפות Google כשהמשתמש מקיש על המפה מושבתת ולא ניתן להפעיל אותה במכשיר לביש.

במאמר בנושא מצב Lite אפשר למצוא רשימה מלאה של ההבדלים בין מצב Lite לבין מצב אינטראקטיבי מלא.

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

שיטות מומלצות לפיתוח עם ה-API של מפות Google ב-Wear OS

איך לספק את חוויית המשתמש הטובה ביותר באפליקציה:

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