Maps API ב-Wear OS

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

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

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

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

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

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

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

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

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

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

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

dependencies {
    // ...
    // Modern Android projects use version catalogs to manage dependencies.  To include the necessary dependencies,
    // first add the following to your libs.versions.toml file:
    //
    // [versions]
    // playServicesMaps = "20.0.0"
    // wear = "1.4.0"
    // wearable = "2.9.0"
    //
    // [libraries]
    // play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesMaps" }
    // wear = { group = "androidx.wear", name = "wear", version.ref = "wear" }
    // wearable-compile = { group = "com.google.android.wearable", name = "wearable", version.ref = "wearable" }
    // wearable-support = { group = "com.google.android.support", name = "wearable", version.ref = "wearable" }

    compileOnly(libs.wearable.compile)
    implementation(libs.wearable.support)
    implementation(libs.play.services.maps)

    // This dependency is necessary for ambient mode
    implementation(libs.wear)

    // Android Test Dependencies
    androidTestImplementation(libs.ext.junit)
    androidTestImplementation(libs.espresso.core)
    androidTestImplementation(libs.uiautomator)
    androidTestImplementation(libs.truth)
    androidTestImplementation(libs.junit)
    
    // If your project does not use a version catalog, you can use the following dependencies instead:
    //
    //    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:20.0.0")
    //    implementation("androidx.wear:wear:1.4.0")
    //    androidTestImplementation("androidx.test.ext:junit:1.3.0")
    //    androidTestImplementation("androidx.test.espresso:espresso-core:3.7.0")
    //    androidTestImplementation("androidx.test.uiautomator:uiautomator:2.3.0")
    //    androidTestImplementation("com.google.truth:truth:1.4.5")
    //    androidTestImplementation("junit:junit:4.13.2")
}

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

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.
        try {
            val controller = AmbientModeSupport.attach(this)
            Log.d(MainActivity::class.java.simpleName, "Is ambient enabled: " + controller.isAmbient)
        } catch (e: Exception) {
            Log.w(MainActivity::class.java.simpleName, "Ambient mode unavailable on this device: ${e.message}")
        }

        // 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.
        try {
            AmbientModeSupport.AmbientController controller = AmbientModeSupport.attach(this);
            Log.d(MainActivity.class.getSimpleName(), "Is ambient enabled: " + controller.isAmbient());
        } catch (Exception e) {
            Log.w(MainActivity.class.getSimpleName(), "Ambient mode unavailable on this device: " + e.getMessage());
        }

        // 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 של מפות ל-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. ב-method‏ onCreate() של הפעילות, מבצעים קריאה ל-method‏ AmbientModeSupport.attach(). כך מערכת ההפעלה יודעת שהאפליקציה פועלת תמיד, וכשהמכשיר נכבה, הוא נכנס למצב רגיש לסביבה במקום לחזור לתצוגת השעון.
  7. מטמיעים את הממשק AmbientModeSupport.AmbientCallbackProvider בפעילות כדי שהיא תוכל לקבל שינויים במצב האווירה.
  8. מגדירים את המפה כך שתתמוך במצב רגיש לסביבה. כדי לעשות את זה, אפשר להגדיר את המאפיין map:ambientEnabled="true" בקובץ הפריסה של ה-XML של הפעילות, או לעשות את זה באופן פרוגרמטי על ידי הגדרת GoogleMapOptions.ambientEnabled(true). ההגדרה הזו מודיעה ל-API שהוא צריך לטעון מראש את משבצות המפה הנדרשות לשימוש במצב אווירה.
  9. כשהפעילות עוברת למצב תאורת אווירה, המערכת קוראת ל-method‏ 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.
        try {
            val controller = AmbientModeSupport.attach(this)
            Log.d(AmbientActivity::class.java.simpleName, "Is ambient enabled: " + controller.isAmbient)
        } catch (e: Exception) {
            Log.w(AmbientActivity::class.java.simpleName, "Ambient mode unavailable on this device: ${e.message}")
        }

        // 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.
        try {
            AmbientModeSupport.AmbientController controller = AmbientModeSupport.attach(this);
            Log.d(AmbientActivity.class.getSimpleName(), "Is ambient enabled: " + controller.isAmbient());
        } catch (Exception e) {
            Log.w(AmbientActivity.class.getSimpleName(), "Ambient mode unavailable on this device: " + e.getMessage());
        }

        // 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.

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

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

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

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

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

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

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

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

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

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