Maps API ב-Wear OS

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

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

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

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

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

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

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

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

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

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

חשוב לוודא שהתלויות הבאות כלולות בקובץ build.gradle.kts של מודול 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:19.0.0")

    // This dependency is necessary for ambient mode
    implementation("androidx.wear:wear:1.3.0")
}

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

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

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

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

מוסיפים את הרכיבים 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 בפעילות, מוסיפים קריאה חוזרת ומגדירים את ההתנהגות של הקריאה החוזרת לביצוע פעולת הסגירה הנדרשת, כמו שמוצג בהמשך:

Kotlin

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


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

        // 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));
}

      

הפעלת מצב אווירה

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

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

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

  1. צריך לעדכן את Android SDK כך שיכלול את פלטפורמת Android 6.0 ‏ (API 23) ואילך, שמספקת את ממשקי ה-API שמאפשרים להעביר פעילויות למצב סביבתי. מידע על עדכון ה-SDK זמין במסמכי התיעוד של Android בנושא הוספה של חבילות SDK.
  2. מוודאים שהפרויקט מטרגט ל-Android 6.0 ומעלה, על ידי הגדרת הערך של targetSdkVersion ל-23 ומעלה במניפסט האפליקציה.
  3. מוסיפים את יחסי התלות של המכשיר הלביש לקובץ build.gradle.kts של האפליקציה. אפשר לראות דוגמה בדף הזה.
  4. מוסיפים את הרשומה של הספרייה המשותפת למכשירים לבישים למניפסט של האפליקציה למכשירים לבישים, כמו שמתואר בשיעור ההדרכה בנושא Android בנושא שמירה על נראות האפליקציה.
  5. מוסיפים את ההרשאה WAKE_LOCK למניפסטים של האפליקציות לנייד ולמכשירים לבישים, כמו שמתואר בשיעור ההדרכה בנושא Android על שמירה על נראות האפליקציה.
  6. בשיטה onCreate() של הפעילות, קוראים לשיטה 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(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 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). ‫Call DismissOverlayView.show() כדי להציג לחצן יציאה.

קוד לדוגמה

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

פונקציות נתמכות ב-Maps API ב-Wear OS

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

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

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

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

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

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

שיטות מומלצות לפיתוח באמצעות Maps API ב-Wear OS

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

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