{"id":123,"date":"2025-07-30T19:39:58","date_gmt":"2025-07-31T00:39:58","guid":{"rendered":"https:\/\/blog.alangaelrojas.com\/?p=123"},"modified":"2025-07-30T19:39:58","modified_gmt":"2025-07-31T00:39:58","slug":"developing-a-wear-os-app","status":"publish","type":"post","link":"https:\/\/blog.alangaelrojas.com\/index.php\/2025\/07\/30\/developing-a-wear-os-app\/","title":{"rendered":"Developing a Wear OS app"},"content":{"rendered":"\n<p>Continuing with the topic of Wear OS development, in a previous article, we discussed the fundamentals of Wear OS development. If you haven&#8217;t seen it, I suggest you check that <a href=\"https:\/\/blog.alangaelrojas.com\/index.php\/2025\/07\/19\/introduction-to-wear-os\/\" title=\"\">article<\/a> out and then come back here.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"359\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Compose_hero_m3-1024x359.png\" alt=\"\" class=\"wp-image-162\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Compose_hero_m3-1024x359.png 1024w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Compose_hero_m3-300x105.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Compose_hero_m3-768x269.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Compose_hero_m3-1536x538.png 1536w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Compose_hero_m3-2048x717.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">\ud83d\udcf2 Building a Connected Wear OS App: Overview<\/h3>\n\n\n\n<p>In this blog, we explore how to build a Wear OS app that communicates effectively with its companion Android app. Seamless communication is key to keeping both apps in sync, and Android provides us with three main tools to achieve this\u2014such as <code>DataClient<\/code>, <code>MessageClient<\/code>, and <code>CapabilityClient<\/code>.<\/p>\n\n\n\n<p>We cover the two main ways of receiving data with <code>DataClient<\/code>:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Using <code>WearableListenerService<\/code><\/strong>: This allows you to listen for messages globally, even if the app is closed. By overriding methods like <code>onMessageReceived()<\/code> and registering the service in the <code>AndroidManifest.xml<\/code>, your app can handle incoming messages automatically.<\/li>\n\n\n\n<li><strong>Adding Listeners Locally<\/strong>: Alternatively, you can set up listeners directly in classes like <code>Activity<\/code>, <code>Fragment<\/code>, <code>Service<\/code>, or <code>ViewModel<\/code>, giving you more scoped and flexible control over communication.<\/li>\n<\/ol>\n\n\n\n<p>We demonstrate this with an example in the <code>RunningViewModel<\/code>, where we listen for both <code>onDataChanged()<\/code> and <code>onMessageReceived()<\/code> events, keeping the app reactive and synchronized.<\/p>\n\n\n\n<p>To send messages from the Wear app to the phone, we use the <code>MessageClient<\/code> and its <code>sendMessage()<\/code> method, which takes three parameters: the node ID, a path (like <code>\"\/start_stop\"<\/code>), and the message data. For example, sending the <code>\"\/start_stop\"<\/code> command triggers the simulator to start or stop tracking data.<\/p>\n\n\n\n<p>We also introduce the <code>RunningActivity.kt<\/code>, which features a <code>HorizontalPager<\/code> UI to provide a smooth, scrollable interface for navigating between views.<\/p>\n\n\n\n<p>By combining all these tools, we demonstrate how to build a simple but fully connected Wear OS app that syncs effectively with its Android phone counterpart.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Project structure<\/h2>\n\n\n\n<p>To start developing Wear, the initial setup in Android Studio doesn&#8217;t change much. In the New Project &gt; Wear OS section, we can find these main options [Wear App + Tile or Empty Wear App].<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"776\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/image-2-1024x776.png\" alt=\"\" class=\"wp-image-131\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/image-2-1024x776.png 1024w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/image-2-300x227.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/image-2-768x582.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/image-2-1536x1164.png 1536w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/image-2.png 1802w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>By selecting one of these two options, we will have the initial configurations of the application or the project itself. This step is crucial, depending on whether our app will work standalone or in conjunction with the companion and wear app. We also explained this in the previous article.<\/p>\n\n\n\n<p>\u26a0\ufe0f For standalone mode, we will not have any limitation for the package name, we will have total freedom to choose any package name, however if our app will work in companion + wear app mode, the package name of our wear app must match the package name of our android app, this is important because later we will see how the internal communication between wear app and companion app is.<\/p>\n\n\n\n<figure class=\"wp-block-table aligncenter\"><table class=\"has-fixed-layout\"><tbody><tr><td class=\"has-text-align-center\" data-align=\"center\"><strong>standalone<\/strong><\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>companion + wear app<\/strong><\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\">Does not matter<\/td><td class=\"has-text-align-center\" data-align=\"center\"><strong>package name<\/strong> for both projects &#8220;com.wizeline.myapp&#8221;<\/td><\/tr><tr><td class=\"has-text-align-center\" data-align=\"center\"><img decoding=\"async\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/image-6-1024x352.png\" alt=\"\"><\/td><td class=\"has-text-align-center\" data-align=\"center\"><img decoding=\"async\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/image-5-1024x459.png\" alt=\"\"><\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p><img decoding=\"async\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/image-3-1024x773.png\" alt=\"\"><\/p>\n\n\n\n<p>Having said that, we can click on &#8220;Finish&#8221; and our IDE will open as if it were an Android project.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udc68\u200d\ud83d\udcbb Start developing<\/h2>\n\n\n\n<p>Once the project is properly configured, we&#8217;ll have an empty activity with the traditional Android Studio composable <strong>Greeting <\/strong>template.<br>We&#8217;ll notice that our class inherits\/extends ComponentActivity, which tells us our app is ready for Jetpack Compose, the declarative UI supported by <strong>androidx.wear.compose.<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"788\" height=\"1024\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/composable-wear-788x1024.png\" alt=\"\" class=\"wp-image-149\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/composable-wear-788x1024.png 788w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/composable-wear-231x300.png 231w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/composable-wear-768x998.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/composable-wear-1182x1536.png 1182w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/composable-wear-1576x2048.png 1576w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/composable-wear.png 1976w\" sizes=\"auto, (max-width: 788px) 100vw, 788px\" \/><figcaption class=\"wp-element-caption\">A composable for a Fitness app example that shows a list of items<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"224\" height=\"224\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screen_recording_20250729_231728.gif\" alt=\"\" class=\"wp-image-150\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">\ud83d\udce1 Communication with the companion app<\/h2>\n\n\n\n<p>A fundamental part of building our app, along with the phone app, is enabling good communication between these two components, allowing us to keep their states in sync. For this, Android provides us with three main agents:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><code>DataClient<\/code> <\/strong>(for persistent data sync)<\/li>\n\n\n\n<li><strong><code>MessageClient<\/code> <\/strong>(real-time one-shot messages)<\/li>\n\n\n\n<li><strong><code>CapabilityClient<\/code> <\/strong>(feature discovery)<\/li>\n<\/ul>\n\n\n\n<p><strong>DataClient<\/strong>\/<strong>MessageClient<\/strong><br>Provides an API for reading and writing data items and assets across devices in an Android Wear network (commonly Bluetooth).<br><br>Follows a <strong>producer-consumer <\/strong>pattern<strong>:<\/strong> one node is responsible for creating a data item, and a second node is responsible for deleting it once it has been processed. Data items should have unique IDs when using this pattern, and data items should not be modified once created.<\/p>\n\n\n\n<p>There are two ways to send and receive information using <code><strong>DataClient<\/strong><\/code>. We can listen to events globally throughout the entire application by creating a class that extends <strong><code>WearableListenerService<\/code> <\/strong>and registering it in our <code><strong>AndroidManifest.xml<\/strong><\/code> file.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"724\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-message-example-1024x724.png\" alt=\"\" class=\"wp-image-141\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-message-example-1024x724.png 1024w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-message-example-300x212.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-message-example-768x543.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-message-example-1536x1086.png 1536w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-message-example.png 1632w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"453\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/manifest-service-1024x453.png\" alt=\"\" class=\"wp-image-140\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/manifest-service-1024x453.png 1024w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/manifest-service-300x133.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/manifest-service-768x340.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/manifest-service-1536x679.png 1536w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/manifest-service.png 1682w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">AndroidManifest.xml<\/figcaption><\/figure>\n\n\n\n<p>In this way, the service automatically listens for messages that may be sent from a sender through the <code><strong>onMessageReceived(event: MessageEvent)<\/strong><\/code> method. This method will receive any message coming from a valid sender (a Wear app with the same package name as the phone app), and it can even launch the app if it&#8217;s not currently running.<\/p>\n\n\n\n<p>Another way to listen for messages is without setting up a service, by creating a listener in a specific class\u2014this can be an <code><strong>Activity<\/strong><\/code>, <code><strong>Fragment<\/strong><\/code>, <code><strong>Service<\/strong><\/code>, <code><strong>ViewModel<\/strong><\/code>, etc., as we\u2019ll see below:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1011\" height=\"1024\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-implementation-for-listeners-1-1011x1024.png\" alt=\"\" class=\"wp-image-143\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-implementation-for-listeners-1-1011x1024.png 1011w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-implementation-for-listeners-1-296x300.png 296w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-implementation-for-listeners-1-768x778.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-implementation-for-listeners-1-1516x1536.png 1516w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/wear-implementation-for-listeners-1.png 1948w\" sizes=\"auto, (max-width: 1011px) 100vw, 1011px\" \/><\/figure>\n\n\n\n<p>In this example, we are listening for messages and data items in the <code><strong>ViewModel<\/strong><\/code>, which allows us to maintain a reactive state based on the changes received from the app\u2014delivered, in this case, to the <strong><code>ViewModel<\/code> <\/strong>on the watch.<\/p>\n\n\n\n<p><br>We can notice a couple of things. The <strong><code>onDataChanged<\/code> <\/strong>method is designed to receive a data buffer composed as follows:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>DataItem<\/strong>: class that contains:\n<ul class=\"wp-block-list\">\n<li><strong>Uri<\/strong> is most commonly used to define a listening path to identify the producer.<\/li>\n\n\n\n<li><strong>byte[]<\/strong> as DataItem itself, which contains <strong>DataMap<\/strong>; this DataMap is used as a table to pass all parameters needed from producer, such as Int, String, Double, Float, Parcelable, etc. <\/li>\n\n\n\n<li><strong>Map&lt;String, DataItemAsset&gt;<\/strong> to send larger objects, such as images and music.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Type<\/strong> = <br>int <em>TYPE_CHANGED <\/em>= 1 notifies a data update from the producer.<br>int <em>TYPE_DELETED <\/em>= 2 notifies a data deletion from the producer.<\/li>\n<\/ul>\n\n\n\n<p>In the case of <code><strong>onMessageReceived<\/strong><\/code>, we receive an object like this:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Path<\/strong>: String object to define a listening path to identify the producer.<\/li>\n\n\n\n<li><strong>SourceNodeId<\/strong>: Returns a non-null unique ID for the device that sent the message in a Wear OS network.<\/li>\n\n\n\n<li><strong>Data<\/strong>: Byte array to pass serialized objects.<\/li>\n<\/ul>\n\n\n\n<p>Below, you can see different scenarios for producer-consumer pattern:<\/p>\n\n\n\n<div class=\"wp-block-media-text is-stacked-on-mobile\"><figure class=\"wp-block-media-text__media\"><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"788\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/2.png\" alt=\"\" class=\"wp-image-137 size-full\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/2.png 940w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/2-300x251.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/2-768x644.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><div class=\"wp-block-media-text__content\">\n<p>In this scenario, the watch is listening to the established route or path<\/p>\n<\/div><\/div>\n\n\n\n<p>A second scenario, as we will see below, is when&#8230; <\/p>\n\n\n\n<div class=\"wp-block-media-text has-media-on-the-right is-stacked-on-mobile\"><div class=\"wp-block-media-text__content\">\n<p>Having a two-way communication, where both subjects can act at the same time as consumers\/producers whether messages or data.<\/p>\n<\/div><figure class=\"wp-block-media-text__media\"><img loading=\"lazy\" decoding=\"async\" width=\"940\" height=\"788\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/3.png\" alt=\"\" class=\"wp-image-138 size-full\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/3.png 940w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/3-300x251.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/3-768x644.png 768w\" sizes=\"auto, (max-width: 940px) 100vw, 940px\" \/><\/figure><\/div>\n\n\n\n<p><\/p>\n\n\n\n<p>Having explained this, let\u2019s look at an example from the Fitness app where we\u2019ll show how data is synchronized from the companion app to the Wear app.<\/p>\n\n\n\n<p>We create the <code><strong>RunningActivity<\/strong>.kt<\/code>, where we build the following UI. On one side, we see a <code><strong>HorizontalPager<\/strong><\/code>, a component that allows us to handle pages within an activity, enabling horizontal scrolling, as if it were navigation.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"540\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/horizontal-pager-1024x540.png\" alt=\"\" class=\"wp-image-151\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/horizontal-pager-1024x540.png 1024w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/horizontal-pager-300x158.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/horizontal-pager-768x405.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/horizontal-pager-1536x810.png 1536w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/horizontal-pager.png 1976w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Within this, we have two more composables: <strong>RunningStatsView <\/strong>y <strong>RunningControlVie<\/strong>w<\/p>\n\n\n\n<p><strong>RunningControlVie<\/strong>w<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized is-style-rounded\"><img loading=\"lazy\" decoding=\"async\" width=\"539\" height=\"539\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot_20250729_233612.png\" alt=\"\" class=\"wp-image-153\" style=\"width:179px;height:auto\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot_20250729_233612.png 539w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot_20250729_233612-300x300.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot_20250729_233612-150x150.png 150w\" sizes=\"auto, (max-width: 539px) 100vw, 539px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"787\" height=\"1024\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/control-view-787x1024.png\" alt=\"\" class=\"wp-image-156\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/control-view-787x1024.png 787w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/control-view-231x300.png 231w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/control-view-768x999.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/control-view-1181x1536.png 1181w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/control-view-1575x2048.png 1575w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/control-view.png 1976w\" sizes=\"auto, (max-width: 787px) 100vw, 787px\" \/><\/figure>\n\n\n\n<p><strong>RunningStatsView <\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full is-resized is-style-rounded\"><img loading=\"lazy\" decoding=\"async\" width=\"539\" height=\"539\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot_20250729_233621.png\" alt=\"\" class=\"wp-image-154\" style=\"width:187px;height:auto\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot_20250729_233621.png 539w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot_20250729_233621-300x300.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot_20250729_233621-150x150.png 150w\" sizes=\"auto, (max-width: 539px) 100vw, 539px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"744\" height=\"1024\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/stats-view-744x1024.png\" alt=\"\" class=\"wp-image-155\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/stats-view-744x1024.png 744w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/stats-view-218x300.png 218w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/stats-view-768x1056.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/stats-view-1117x1536.png 1117w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/stats-view-1489x2048.png 1489w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/stats-view.png 1976w\" sizes=\"auto, (max-width: 744px) 100vw, 744px\" \/><\/figure>\n\n\n\n<p>Here you can see the <code><strong>ViewModel<\/strong><\/code> attached to <code><strong>RunningActivity<\/strong><\/code>, called <code><strong>RunningViewModel<\/strong><\/code>. As you can see, it implements <code><strong>DataClient<\/strong><\/code> in order to listen for data from the test app, Fitness app.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1015\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-29-at-11.41.28\u202fp.m-1024x1015.png\" alt=\"\" class=\"wp-image-158\" style=\"width:552px;height:auto\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-29-at-11.41.28\u202fp.m-1024x1015.png 1024w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-29-at-11.41.28\u202fp.m-300x297.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-29-at-11.41.28\u202fp.m-150x150.png 150w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-29-at-11.41.28\u202fp.m-768x761.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-29-at-11.41.28\u202fp.m-1536x1523.png 1536w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-29-at-11.41.28\u202fp.m.png 1616w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Left: RunningActivity for Wear app; Right: RunningActivity for companion app<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"725\" height=\"1024\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/viewmodel-1-725x1024.png\" alt=\"\" class=\"wp-image-159\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/viewmodel-1-725x1024.png 725w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/viewmodel-1-212x300.png 212w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/viewmodel-1-768x1085.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/viewmodel-1-1087x1536.png 1087w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/viewmodel-1-1449x2048.png 1449w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/viewmodel-1.png 1976w\" sizes=\"auto, (max-width: 725px) 100vw, 725px\" \/><figcaption class=\"wp-element-caption\">RunningViewModel.kt<\/figcaption><\/figure>\n\n\n\n<p>Here\u2019s the translation:<\/p>\n\n\n\n<p>Likewise, we\u2019ve created the variable <code><strong>messageClient<\/strong><\/code>, which holds the instance of <code><a href=\"https:\/\/developer.android.com\/training\/wearables\/data\/messages\" title=\"\">MessageClient<\/a><\/code>. This allows us to send messages in the form of commands from the Wear app to our companion app. We achieve this by calling the <code><strong>sendMessage<\/strong><\/code> method on <code><strong>messageClient<\/strong><\/code>, which takes three parameters:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>nodeId<\/strong> = node identifier (as we saw before, the node is the active connection to a companion phone).<\/li>\n\n\n\n<li><strong>String<\/strong>: where we will send our value in a text string.<\/li>\n\n\n\n<li><strong>byte[]<\/strong>: where you can send data in the form of a bytearray.<\/li>\n<\/ul>\n\n\n\n<p>So, as we can see, I send the node id of my current companion device, and I send it the following message &#8220;\/start_stop&#8221;.<\/p>\n\n\n\n<p>Next, we&#8217;ll see how the app on the companion device is listening to our MessageClient:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"329\" src=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/listening-messageclient-1024x329.png\" alt=\"\" class=\"wp-image-161\" srcset=\"https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/listening-messageclient-1024x329.png 1024w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/listening-messageclient-300x96.png 300w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/listening-messageclient-768x247.png 768w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/listening-messageclient-1536x493.png 1536w, https:\/\/blog.alangaelrojas.com\/wp-content\/uploads\/2025\/07\/listening-messageclient.png 1968w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">listener on companion app -> RunningActivity.kt<\/figcaption><\/figure>\n\n\n\n<p>Here\u2019s the translation:<\/p>\n\n\n\n<p>As you can see, by listening for the message path <code>\"<strong>\/start_stop<\/strong>\"<\/code>, we are calling the <code><strong>onStartStopClick<\/strong>()<\/code> method, which we use to start or stop the running data simulator.<\/p>\n\n\n\n<p>In this way, we can create a simple Wear OS app synchronized with an Android app on the phone.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">References\/Links<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/developer.android.com\/training\/wearables\/data\/messages\">https:\/\/developer.android.com\/training\/wearables\/data\/messages<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.android.com\/training\/wearables\">https:\/\/developer.android.com\/training\/wearables<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.android.com\/training\/wearables\/data\/sync\">https:\/\/developer.android.com\/training\/wearables\/data\/sync<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.android.com\/training\/wearables\/apps\/standalone-apps\">https:\/\/developer.android.com\/training\/wearables\/apps\/standalone-apps<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/developer.android.com\/training\/wearables\/compose\">https:\/\/developer.android.com\/training\/wearables\/compose<\/a><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p>\ud83d\udcac <strong>Your thoughts?<\/strong><br>Building a Wear OS app too? Share your experience or questions in the comments \u2014 let\u2019s connect! \ud83d\udc47<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Continuing with the topic of Wear OS development, in a previous article, we discussed the fundamentals of Wear OS development. If you haven&#8217;t seen it, I suggest you check that article out and then come back here. \ud83d\udcf2 Building a Connected Wear OS App: Overview In this blog, we explore how to build a Wear&#8230;<\/p>\n","protected":false},"author":1,"featured_media":163,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[3,4,30],"tags":[27,28,29,31],"class_list":["post-123","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-android","category-programming","category-wear","tag-android","tag-kotlin","tag-programming","tag-wear"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/posts\/123","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/comments?post=123"}],"version-history":[{"count":7,"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/posts\/123\/revisions"}],"predecessor-version":[{"id":164,"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/posts\/123\/revisions\/164"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/media\/163"}],"wp:attachment":[{"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/media?parent=123"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/categories?post=123"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.alangaelrojas.com\/index.php\/wp-json\/wp\/v2\/tags?post=123"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}