Maps API для Wear OS

Карта на носимом устройстве

С помощью Maps SDK для Android можно добавить поддержку карт в приложение для носимых устройств с операционной системой Wear OS by Google. Это позволит пользователям определять свое местоположение, просто взглянув на экран. Им будут доступны такие функции карт, как определение своего местоположения, изменение масштаба, просмотр информации об объектах и т. п.

На этой странице описываются функциональные возможности API, доступные для носимых устройств, и приводятся рекомендации, которые помогут вам начать разработку приложения.

Начало работы с Wear OS

Приложения для носимых устройств с использованием Maps SDK для Android разрабатываются в целом так же, как и для любых других устройств Android. Различия обусловлены меньшими размерами носимых устройств и необходимостью оптимизировать интерфейс приложения и его производительность.

Инструмент Android Studio является рекомендуемой средой разработки приложений для Wear OS. Он поддерживает настройку проектов, включение библиотек и средства создания пакета приложения.

Мы подготовили рекомендации по разработке приложений для Wear OS и советы, которые помогут вам при создании вашего первого приложения для носимых устройств.

Создание приложения для работы с картами на Wear OS

В этом кратком руководстве предполагается следующее: вы знакомы с Maps SDK для Android; вы создали в своем приложении модуль для носимых устройств, следуя рекомендациям из руководства по разработке для Wear OS; вы хотите добавить поддержку карт в этот модуль.

Добавление зависимостей в модуль для носимых устройств

Убедитесь, что в файл 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 в своем объекте activity добавьте обратный вызов и задайте для него выполнение необходимого действия закрытия приложения, как показано ниже.

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

      

Включение спящего режима

Maps SDK для Android поддерживает спящий режим в приложениях для носимых устройств. Приложения, поддерживающие спящий режим, называются всегда включенными. Спящий режим активируется, если пользователь не выполнял никаких действий в приложении в течение некоторого времени. Приложение в этом режиме остается видимым на экране носимого устройства.

Maps SDK для Android поддерживает упрощенную прорисовку карты с приглушенными цветами в спящем режиме. Стиль карты автоматически изменяется, когда приложение переходит из интерактивного режима в спящий. В спящем режиме не отображаются маркеры, объекты и элементы интерфейса. Это позволяет сократить энергопотребление и сделать стиль интерфейса похожим на стиль других всегда включенных приложений, таких как циферблаты часов.

Чтобы обеспечить поддержку спящего режима карты в вашем приложении, выполните следующие действия:

  1. Обновите Android SDK, включив в него платформу Android 6.0 (API уровня 23) или более поздней версии с API для поддержки перехода приложения в спящий режим. Подробнее о том, как обновить SDK, рассказывается в документации Android по добавлению пакетов SDK.
  2. В качестве целевой платформы своего приложения укажите Android версии 6.0 или более поздней, указав для параметра targetSdkVersion в манифесте приложения значение 23 или выше.
  3. Добавьте в файл build.gradle своего приложения зависимости для поддержки носимых устройств. См. пример.
  4. Укажите в манифесте своего приложения общую библиотеку для поддержки носимых устройств согласно инструкциям в этом уроке.
  5. Добавьте разрешение WAKE_LOCK в манифесты приложений для носимых и мобильных устройств согласно инструкциям в этом уроке.
  6. В методе onCreate() своего класса activity вызовите метод AmbientModeSupport.attach(). Это сообщит операционной системе о том, что приложение должно быть всегда включено. Тогда при переходе устройства в энергосберегающий режим приложение перейдет в спящий, а не вернется к интерфейсу часов.
  7. Добавьте интерфейс AmbientModeSupport.AmbientCallbackProvider для класса Activity, чтобы он получал данные об изменении статуса спящего режима.
  8. Настройте для своей карты поддержку спящего режима. Для этого задайте атрибут map:ambientEnabled="true" в XML-файле макета вашего объекта activity. Также можно сделать это программными средствами с помощью GoogleMapOptions.ambientEnabled(true). Так API получит информацию о том, что требуется предварительно загрузить необходимые фрагменты карты, которые будут использоваться в спящем режиме.
  9. Когда объект activity переключается в спящий режим, система вызывает метод 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(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 могут узнать, как сделать приложение постоянно видимым.

Использование Просмотра улиц на Wear OS

Просмотр улиц полностью поддерживается на носимых устройствах.

Чтобы разрешить пользователям выходить из приложения при просмотре панорам в Просмотре улиц, используйте интерфейс StreetViewPanorama.OnStreetViewPanoramaLongClickListener, отслеживающий долгие нажатия. Если пользователь нажмет на любую область изображения Просмотра улиц и будет удерживать палец на экране, вы получите событие onStreetViewPanoramaLongClick(StreetViewPanoramaOrientation). Вызовите метод DismissOverlayView.show(), чтобы показать кнопку выхода.

Пример кода

На сайте GitHub приведен пример, который поможет вам начать разработку. В нем показано, как добавлять базовую карту в приложение для Wear OS.

Поддерживаемые функции в Maps API для Wear OS

В этом разделе описываются различия поддерживаемых функций для карт на носимых устройствах в сравнении с мобильными устройствами (телефонами и планшетами). Все функции API, не указанные ниже, должны работать так, как описано в документации к полноценному интерфейсу API.

Функции
Полностью интерактивный режим и упрощенный режим

Maps SDK для Android можно использовать как в полностью интерактивном, так и в упрощенном режиме. Упрощенный режим позволяет оптимизировать производительность на носимом устройстве и может использоваться, если приложению не нужно поддерживать различные варианты взаимодействия, такие как жесты, панорамирование или масштабирование карты.

В упрощенном режиме на носимых устройствах отключена функция запуска мобильного приложения "Google Карты" при нажатии на карту, показанную на экране. Включить эту функцию нельзя.

Полный список различий между полностью интерактивным и упрощенным режимами приведен в документации упрощенного режима.

Панель инструментов на карте Панель инструментов на карте отключена на носимых устройствах, и включить ее нельзя.
Элементы управления пользовательского интерфейса По умолчанию элементы управления пользовательского интерфейса отключены на носимых устройствах. Это относится к кнопкам масштабирования, компасу и кнопке "Мое местоположение". Их можно включить с помощью класса UiSettings.
Жесты Жесты с одним касанием работают обычным образом. Примеры жестов с одним касанием: перетаскивание прокручивает карту, двойное касание увеличивает масштаб, касание двумя пальцами уменьшает масштаб. Поддержка жестов с несколькими касаниями зависит от устройства. Примеры жестов с несколькими касаниями: нажатие двумя пальцами для наклона карты, сведение или разведение двух пальцев для масштабирования, вращение карты двумя пальцами.
Схемы зданий и строения Схемы зданий по умолчанию отключены на носимых устройствах. Их можно включить с помощью метода GoogleMap.setIndoorEnabled(true). Если схемы зданий включены, то на карте будет отображаться уровень этажа, выбираемый по умолчанию. Элемент интерфейса для выбора этажа не поддерживается на носимых устройствах.
Наложения фрагментов карты Наложения фрагментов карты не поддерживаются на носимых устройствах.

Рекомендации по разработке приложений с интеграцией API Карт для Wear OS

Для создания максимально удобного пользовательского интерфейса в вашем приложении соблюдайте следующие принципы:

  • Карта должна занимать значительную часть экрана. Это необходимо для того, чтобы карту было удобно использовать на носимом устройстве малого размера.
  • Дизайн приложения нужно продумать с учетом небольшой емкости аккумуляторов носимых устройств. Постоянно включенный экран и непрерывное отображение карты значительно сократят время работы устройства от аккумулятора.