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

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

‫SDK של מפות ל-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. כשהפעילות עוברת למצב תאורת אווירה, המערכת קוראת ל-method‏ onEnterAmbient() ב-AmbientCallback שסיפקתם. תתקשר ל-onEnterAmbient() ותחליף את SupportMapFragment.onEnterAmbient(ambientDetails) או את MapView.onEnterAmbient(ambientDetails). ה-API עובר לרינדור לא אינטראקטיבי של המפה עם מספר מצומצם של צבעים.
  10. באופן דומה, בשיחה onExitAmbient() אפשר להשתמש ב-SupportMapFragment.onExitAmbient() או ב-MapView.onExitAmbient(). ה-API עובר לרינדור רגיל של המפה.

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

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

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

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

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

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

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

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