Skip to content

Most visited

Recently visited

navigation

Standalone Apps

In Android Wear 2.0, an app can work independently of a phone. Users can complete more tasks on a watch, without access to an Android or iOS phone.

Planning Your Phone and Watch Apps

A watch APK targeting Wear 2.0 should not be embedded in a phone APK. For more information, see App Distribution.

Generally, the minimum and target API level for a standalone app, and for Wear 2.0, is level 24. The minimum SDK level can be 23 only if you are using the same APK for Wear 1.0 and 2.0 (and thus have an embedded Wear 1.0 APK).

If you build a standalone Wear 2.0 APK and will continue to have a Wear 1.0 APK, please do both of the following:

Caution: For the Wear 2.0 Developer Preview, if you publish an update to your production phone APK that has removed an embedded Wear APK, production users who update the phone APK before installing your standalone Wear APK will lose their existing Wear app and its data. Therefore, it's important that you continue to embed your watch APK into your phone APK.

Run-time permissions are required for standalone apps.

Shared code and data storage

Code can be shared between a Wear app and a phone app. Optionally, code that is specific to a form factor can be in a separate module.

For example, common code for networking can be in a shared library.

You can use standard Android storage APIs to store data locally. For example, you can use the SharedPreferences APIs, SQLite, or internal storage (as you would in the case of a phone).

Detecting your app on another device

Your watch app can detect if the corresponding phone app is available and vice versa. Using the CapabilityApi, your phone app or watch app can advertise its presence to a paired device. It can do so statically and dynamically. When an app is on a node in a user's Wear network (i.e., on a phone, paired watch, or in the cloud), the CapabilityApi enables another app to detect if it is installed. For more information, see Advertise capabilities.

If one of your apps cannot detect the other, you can enable your user to open the Play Store listing on their remote device. This is a solution for watch apps that require their companion phone app's presence to function properly. A prerequisite is to check for the Play Store's presence on the remote device.

Note that not all phones support the Play Store (such as iPhones, etc.).

This section describes best practices for these scenarios:

Please review the sample that shows this functionality. For more information about the classes described below, download the Android Wear 2.0 Preview Reference and open the packages.html file. Then select, for example, com.google.android.wearable.intent. Also in that preview reference is information about the PlayStoreAvailability class, which contains a getPlayStoreAvailabilityOnPhone() method that enables your Wear app to check if a companion phone has the Play Store.

Specifying capability names for detecting your apps

For the app corresponding to each device type (watch or phone), specify a unique string for the capability name in the res/values/wear.xml file.

For example, in your mobile module, the wear.xml file could include the following:

<resources>
    <string-array name="android_wear_capabilities">
        <item>verify_remote_example_phone_app</item>
    </string-array>
</resources>

In your wear module, the wear.xml file would include a different value for the capability name, such as the following:

<resources>
    <string-array name="android_wear_capabilities">
        <item>verify_remote_example_wear_app</item>
    </string-array>
</resources>

For more information, see Advertise capabilities.

App detection starting from a watch

  1. Use the CapabilityApi to check if your phone app is installed on the paired phone. For more information, see the sample.
  2. If your phone app isn't installed on the phone, use PlayStoreAvailability.getPlayStoreAvailabilityOnPhone() to check what type of phone it is.
  3. If PlayStoreAvailability.PLAY_STORE_ON_PHONE_AVAILABLE is returned, it means the phone is an Android phone with the Play Store installed. Call RemoteIntent.startRemoteActivity() on the Wear device to open the Play Store on the phone. Use the market URI for your phone app (which may be different from your phone URI). For example, use a market URI such as: market://details?id=com.example.android.wearable.wear.finddevices
  4. If PlayStoreAvailability.PLAY_STORE_ON_PHONE_UNAVAILABLE is returned, it means the phone is likely an iOS phone (with no Play Store available). There isn't currently a way to open the App Store from a Wear device.

Details for detecting Play Store availability

Here is a snippet that uses the getPlayStoreAvailabilityOnPhone() method to determine if the paired phone has the Play Store:

int playStoreAvailabilityOnPhone =
PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(context);

The value returned by the getPlayStoreAvailabilityOnPhone() method is one of the following:

Return value Description
PLAY_STORE_ON_PHONE_AVAILABLE The Play Store is available on the companion phone.
PLAY_STORE_ON_PHONE_UNAVAILABLE The Play Store is not available on the companion phone.
PLAY_STORE_ON_PHONE_ERROR_UNKNOWN An error occurred in the check for the Play Store; another check should be made later.

App detection starting from an Android phone

  1. Using the NodeApi, find all Wear devices connected to the user's phone. For more information, see the sample.
  2. Using the CapabilityApi, check which of the user's Wear devices have your app installed.
  3. If your app isn't installed on all of the user's Wear devices (compare the results from Step 1 with the results from Step 2), allow the user to open the Play Store on the remaining Wear devices from the phone via the RemoteIntent.startRemoteActivity() method. Specifically, use the market URI for the Wear app (which may be different from your phone URI). For example, use a market URI such as: market://details?id=com.example.android.wearable.wear.finddevices

Watches paired to iPhones

After the upcoming release of the iOS companion app for Wear 2.0, developers should use the Fused Location Provider (FLP) to get location data on a watch. See Detecting Location on Android Wear.

If the companion phone is available, FLP uses the companion phone for location data. However, on iOS, FLP is only partially supported:

Obtaining only the necessary data

In most cases, when obtaining data from the internet, get only the necessary data. Otherwise, you may introduce unnecessary latency, memory use, and battery use.

When a watch is connected over a Bluetooth LE connection, your app may have access to a bandwidth of only 4 kilobytes per second, depending on the watch. Therefore, the following steps are recommended:

For cases where a high-bandwidth network is needed, see High-bandwidth Network Access.

Cloud Messaging

For sending notifications, apps can directly use Firebase Cloud Messaging (FCM), which replaces Google Cloud Messaging (GCM). FCM is supported on Wear 2.0. GCM is not supported on Wear 2.0.

No APIs for network access or FCM are specific to Android Wear. Refer to the existing documentation about connecting to a network and cloud messaging.

FCM works well with Doze.

FCM is the recommended way to send notifications to a watch.

Provide for messages from FCM by collecting a registration token for a device when your Wear app runs. Then include the token as part of the destination when your server sends messages to the FCM REST endpoint. FCM sends messages to the device identified by the token.

An FCM message is in JSON format and can include one or both of the following payloads:

For more information and examples of payloads, see About FCM Messages.

Network Access

Android Wear apps can make their own network requests. When a watch has a Bluetooth connection to a phone, the watch's network traffic generally is proxied through the phone. When a phone is unavailable, Wi-Fi and cellular networks are used, depending on the hardware. The Wear platform handles transitions between networks. A watch's network access thus does not require the Wearable Data Layer API.

You can use protocols such as HTTP, TCP, and UDP. However, the android.webkit APIs are not available. Therefore, use of cookies is available by reading and writing headers on requests and responses, but the CookieManager class is not available.

Additionally, we recommend using the following:

A Wear app can communicate with a phone app using the Wearable Data Layer API, but connecting to a network using that API is discouraged.

High-bandwidth Network Access

The Android Wear platform manages network connectivity with the goal of providing the best overall user experience. The platform chooses the default, active network by balancing two factors:

When battery preservation is prioritized, the active network may have insufficient bandwidth to do network tasks that require high bandwidth, such as transporting large files or streaming media.

This section provides guidance on using the ConnectivityManager class to ensure that requisite network bandwidth is available for your app. For general information about fine-grained control over network resources, see Managing Network Usage.

Also see the sample that illustrates practices described below.

Acquiring a High-Bandwidth Network

On Android Wear, do not assume a high-bandwidth network always is available. For use cases that require high-bandwidth network access, such as transporting large files or streaming media, we recommend the following steps:

  1. Check for an active network, and if there is one, check its bandwidth.
  2. If there isn't an active network, or its bandwidth is insufficient, request access to an unmetered Wi-Fi or cellular network.

You can use the ConnectivityManager class to check if an active network exists and has enough bandwidth:

int MIN_BANDWIDTH_KBPS = 320;
mConnectivityManager =
  (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
Network activeNetwork = mConnectivityManager.getActiveNetwork();

if (activeNetwork != null) {
  int bandwidth =
    mConnectivityManager.getNetworkCapabilities(activeNetwork).getLinkDownstreamBandwidthKbps();

  if (bandwidth < MIN_BANDWIDTH_KBPS) {
    // request high-bandwidth network
  }
} else {
  // request high-bandwidth network
}

You can request an unmetered, high-bandwidth network using the ConnectivityManager. With a single network request, you can request an unmetered Wi-Fi or cellular network. When the network is ready (e.g., the device's Wi-Fi radio connects to a saved network), the onAvailable() method of your NetworkCallback instance is called. If a suitable network is not found, the onAvailable() method is not called. Therefore, you should time-out your request manually; see Waiting for Network Availability.

mNetworkCallback = new ConnectivityManager.NetworkCallback() {
  @Override
  public void onAvailable(Network network) {
    if (bindProcessToNetwork(network)) {
      // socket connections will now use this network
    } else {
      // app doesn't have android.permission.INTERNET permission
    }
  }
};

NetworkRequest request = new NetworkRequest.Builder()
  .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
  .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
  .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED)
  .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
  .build();

mConnectivityManager.requestNetwork(request, mNetworkCallback);

Releasing the Network

When your app no longer needs the high-bandwidth network, you must release the network using the ConnectivityManager class to ensure that the platform can resume management of network access.

mConnectivityManager.bindProcessToNetwork(null);
mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);

To optimize battery consumption, a network connection should only remain registered for the duration of the activity. Therefore, you should consider releasing the network in your activity's onStop() method.

Waiting for Network Availability

Acquiring a network may not be instantaneous because a watch's Wi-Fi or cellular radio may be off to preserve battery. Additionally, if a watch cannot connect to a network, the onAvailable() method of your NetworkCallback instance is not called. Therefore, you should time-out the request after a predetermined length of time and release any associated resources.

int MESSAGE_CONNECTIVITY_TIMEOUT = 1;
long NETWORK_CONNECTIVITY_TIMEOUT_MS = 10000

mHandler = new Handler() {
  @Override
  public void handleMessage(Message msg) {
    switch (msg.what) {
      case MESSAGE_CONNECTIVITY_TIMEOUT:
        // unregister the network
        break;
    }
  }
};

mNetworkCallback = new ConnectivityManager.NetworkCallback() {
  @Override
  public void onAvailable(Network network) {
    mHandler.removeMessages(MESSAGE_CONNECTIVITY_TIMEOUT);
    ...
  }
};

mConnectivityManager.requestNetwork(request, mNetworkCallback);

mHandler.sendMessageDelayed(
  mHandler.obtainMessage(MESSAGE_CONNECTIVITY_TIMEOUT),
  NETWORK_CONNECTIVITY_TIMEOUT_MS);

Monitoring the Network State

The NetworkCallback interface has methods for monitoring state changes to the bound network, such as bandwidth changes and connectivity loss.

mNetworkCallback = ConnectivityManager.NetworkCallback {
  @Override
  public void onCapabilitiesChanged(Network network, NetworkCapabilities networkCapabilities) {
    int bandwidth =
      mConnectivityManager.getNetworkCapabilities(network).getLinkDownstreamBandwidthKbps();

      if (bandwidth < MIN_BANDWIDTH.KBPS) {
        // handle insufficient network bandwidth
      }
  }

  @Override
  public void onLost(Network network) {
    // handle network loss
  }
}

Launching the Wi-Fi Settings Activity

When requesting a Wi-Fi network, the system tries to connect to a saved network if a saved network was configured and is in range. However, if no saved Wi-Fi network is available, the onAvailable() callback method of your NetworkCallback instance is never called. If you are using a Handler to time-out the network request, you can direct the user to add a Wi-Fi network when the timeout has occurred. You can send the user directly to the activity for adding a Wi-Fi network using the following intent:

context.startActivity(new Intent("com.google.android.clockwork.settings.connectivity.wifi.ADD_NETWORK_SETTINGS"));

To launch the settings activity, your app must have the following permission: android.permission.CHANGE_WIFI_STATE

User Interface Considerations

If your app requires a user to connect to a new Wi-Fi network for a high-bandwidth operation, ensure that the reason for connecting to a new network is clear to the user, before launching the Wi-Fi settings. Only request that a user add a new Wi-Fi network when the high-bandwidth network is required, and do not block a user from accessing other app features that do not require a high-bandwidth network.

Figure 1 shows, for example, a music app. The app should allow a user to browse music and only require the user to add a new Wi-Fi network if they want to download or stream music.

Music downloading

Figure 1. A music app flow for downloading music.

If your app requires a high-bandwidth network before it can operate, you should present a clear rationale to the user before requiring the user to add a new Wi-Fi network. Also, for long-running network operations, such as downloading a user's media playlist, you should present a progress indicator with a description of what operation is being performed.

Figure 2 shows the music app in a streaming-music flow. If a user wants to stream music and a high-bandwidth network is needed, the app should clearly explain why a new Wi-Fi network is needed, before taking the user to Wi-Fi settings.

Music streaming

Figure 2. A music app flow for streaming music.

Using Background Services

To ensure that background tasks are correctly executed, they must account for Doze. In Android 6.0, Doze and App Standby resulted in significant improvements to battery life by allowing devices to enter deep sleep when idle and stationary.

Doze is enhanced in Android Nougat and Android Wear 2.0. When a screen turns off or enters ambient mode for a long enough time, a subset of Doze can occur and background tasks may be deferred for certain periods. Later, when a device is stationary for an extended time, regular Doze occurs.

You should schedule jobs with the JobScheduler API, which enables your app to register for Doze-safe code execution. When scheduling jobs, you can select constraints such as periodic execution and the need for connectivity or device charging. It is important to configure jobs in a way that does not adversely impact battery life. Jobs should use a JobInfo.Builder object to provide constraints and metadata, e.g. with one or more of the following methods for a task:

Note that some low-bandwidth networks, such as Bluetooth LE, are considered metered.

Scheduling with constraints

You can schedule a task that requires constraints. In the example below, a JobScheduler object activates MyJobService when the following constraints are met:

You can use the builder method setExtras to attach a bundle of app-specific metadata to the job request. When your job executes, this bundle is provided to your job service. Note the MY_JOB_ID value passed to the JobInfo.Builder constructor. This MY_JOB_ID value is an app-provided identifier. Subsequent calls to cancel, and subsequent jobs created with that same value, will update the existing job:

JobInfo jobInfo = new JobInfo.Builder(MY_JOB_ID,
        new ComponentName(this, MyJobService.class))
        .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
        .setRequiresCharging(true)
        .setExtras(extras)
        .build();
((JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE))
        .schedule(jobInfo);

Below is an implementation of JobService to handle the job above. When the job executes, a JobParameters object is passed into the onStartJob method. The JobParameters object enables you to get the job ID value along with any extras bundle provided when scheduling the job. The onStartJob method is called on the main application thread, and therefore any expensive logic should be run from a separate thread. In the example, an AsyncTask is used to run code in the background. When work is complete, you would call the jobFinished method to notify JobScheduler that the task is done:

public class MyJobService extends JobService {
    @Override public boolean onStartJob(JobParameters params) {
        new JobAsyncTask().execute(params);
        return true;
    }

    private class JobAsyncTask extends AsyncTask

Notifications from a Companion Phone

By default, notifications are bridged (shared) from a phone app to a watch. If you have a standalone Wear app and a corresponding phone app, duplicate notifications can occur. For example, the same notification from FCM, received by both a phone and a watch, could be displayed by both devices independently.

For information about preventing duplicate notifications, see Bridging Mode for Notifications.

This site uses cookies to store your preferences for site-specific language and display options.

Hooray!

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a one-minute survey?
Help us improve Android tools and documentation.