page.title=Standalone Apps meta.keywords="wear-preview" page.tags="wear-preview" page.image=images/cards/card-n-sdk_2x.png @jd:body <div id="qv-wrapper"> <div id="qv"> <h2>In this document</h2> <ul> <li><a href="#planning_apps">Planning Your Phone and Watch Apps</a></li> <li><a href="#network_access">Network Access and Cloud Messaging</a></li> <li><a href="#background_services">Using Background Services</a></li> <li><a href="#fcm">Cloud Notifications Using FCM</a></li> <li><a href="#fcm-phone">Notifications from a Companion Phone</a></li> </ul> </div> </div> <p> In Android Wear 2.0, apps can work independently of a phone. Users can complete more tasks on a watch, without access to an Android or iOS phone. </p> <h2 id="planning_apps"> Planning Your Phone and Watch Apps </h2> <p> A watch APK targeting Wear 2.0 should not be embedded in a phone APK. For more information, see <a href="{@docRoot}wear/preview/features/app-distribution.html"> App Distribution</a>. </p> <p> 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). </p> <p> 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: </p> <ul> <li>Provide a standalone version of the Wear APK, and </li> <li>Continue embedding a version of the Wear APK in your phone APK </li> </ul> <p> <strong>Caution</strong>: 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. </p> <p> <a href= "https://developer.android.com/training/articles/wear-permissions.html"> Run-time permissions</a> are required for standalone apps. </p> <h3> Shared code and data storage </h3> <p> 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. </p> <p> For example, common code for networking can be in a shared library. </p> <p> You can use standard Android storage APIs to store data locally. For example, you can use the <a href= "https://developer.android.com/reference/android/content/SharedPreferences.html"> SharedPreferences APIs</a>, SQLite, or internal storage (as you would in the case of a phone). </p> <h3> Detecting your phone app or watch app </h3> <p> If a user of your watch app needs your phone app, your watch app can detect if the phone app is available. Using the <a href= "https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi"> CapabilityApi</a>, 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 <code>CapabilityApi</code> enables another app to detect if it is installed. For more information, see <a href= "https://developer.android.com/training/wearables/data-layer/messages.html#AdvertiseCapabilities"> Advertise capabilities</a>. </p> <p> If your phone app is unavailable, your can check if the Play Store is available on the phone, as described below, before directing the user to go to the Play Store (to install your phone app). </p> <h4> Checking for Play Store availability on a phone </h4> <p> iPhones and some Android phones lack the Play Store. A standalone Wear app can check if the paired phone has the Play Store, before directing a user to go there to install your phone app. The <code>PlayStoreAvailability</code> class contains a <code>getPlayStoreAvailabilityOnPhone()</code> method that enables your Wear app to check if a companion phone has the Play Store. </p> <p> More information about the <code>PlayStoreAvailability</code> class is available when you <a href= "https://developer.android.com/wear/preview/start.html#get_the_preview_reference_documentation"> download the Android Wear 2.0 Preview Reference</a>. Here is a snippet that uses the <code>getPlayStoreAvailabilityOnPhone()</code> method to determine if the paired phone has the Play Store: </p> <pre> int playStoreAvailabilityOnPhone = PlayStoreAvailability.getPlayStoreAvailabilityOnPhone(context); </pre> <p> The value returned by the <code>getPlayStoreAvailabilityOnPhone()</code> method is one of the following: </p> <table> <tr> <th> <strong>Return value</strong> </th> <th> <strong>Description</strong> </th> </tr> <tr> <td> <code>PLAY_STORE_ON_PHONE_AVAILABLE</code> </td> <td> The Play Store is available on the companion phone. </td> </tr> <tr> <td> <code>PLAY_STORE_ON_PHONE_UNAVAILABLE</code> </td> <td> The Play Store is not available on the companion phone. </td> </tr> <tr> <td> <code>PLAY_STORE_ON_PHONE_ERROR_UNKNOWN</code> </td> <td> An error occurred in the check for the Play Store; another check should be made later. </td> </tr> </table> <h2 id="network_access"> Network Access and Cloud Messaging </h2> <p> Android Wear apps can make their own network requests. When a watch has a Bluetooth connection to a phone, the watch's network traffic 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 <a href= "https://developer.android.com/training/wearables/data-layer/index.html"> Wearable Data Layer API</a>. </p> <p> For sending notifications, apps can directly use Firebase Cloud Messaging (FCM), which replaces Google Cloud Messaging, or continue to use GCM. </p> <p> No APIs for network access or FCM are specific to Android Wear. Refer to the existing documentation about <a href= "https://developer.android.com/training/basics/network-ops/connecting.html"> connecting to a network</a> and <a href= "https://developers.google.com/cloud-messaging/">cloud messaging</a>. </p> <p> You can use protocols such as HTTP, TCP, and UDP. However, the <a href="https://developer.android.com/reference/android/webkit/package-summary.html"> android.webkit</a> APIs are not available. Therefore, use of cookies is available by reading and writing headers on requests and responses, but the <a href= "https://developer.androidcom/reference/android/webkit/CookieManager.html"> CookieManager</a> class is not available. </p> <p> FCM works well with <a href="https://developer.android.com/training/monitoring-device-state/doze-standby.html"> Doze</a>. </p> <p> Additionally, we recommend using the following: </p> <ul> <li>The <a href= "https://developer.android.com/reference/android/app/job/JobScheduler.html"> JobScheduler</a> API for asynchronous jobs, including polling at regular intervals (described below) </li> <li>Multi-networking APIs if you need to connect to specific network types; see <a href= "https://developer.android.com/about/versions/android-5.0.html#Wireless"> Multiple Network Connections</a> </li> </ul> <p> For foreground use cases, we currently recommend that you make a request for an unmetered network. Here is an example of using the multi-networking APIs to request an unmetered network: </p> <pre> ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() { @Override public void onAvailable(Network network) { // access network } }; ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); connectivityManager.requestNetwork(new NetworkRequest.Builder() .addCapability(NET_CAPABILITY_NOT_METERED) .build(), networkCallback); </pre> <p> We also recommend setting a timer for frontend scenarios to prevent a user from potentially waiting for a long time. When the network is no longer needed, or if the timer fires, the network callback needs to be unregistered: </p> <pre> connectivityManager.unregisterNetworkCallback(networkCallback): </pre> <p> A Wear app can communicate with a phone app using the <a href= "https://developer.android.com/training/wearables/data-layer/index.html">Wearable Data Layer API</a>, but connecting to a network using that API is discouraged. </p> <h3 id="necessary_data"> Obtaining only the necessary data </h3> <p> When obtaining data from the cloud, get only the necessary data. Otherwise, you may introduce unnecessary latency, memory use, and battery use. </p> <p> When a watch is connected over a Bluetooth LE connection, your app may have access to a bandwidth of only 10 kilobytes per second. Therefore, the following steps are recommended: </p> <ul> <li>Audit your network requests and responses for extra data that only is for a phone app </li> <li>Shrink large images before sending them over a network to a watch </li> </ul> <h2 id="background_services"> Using Background Services </h2> <p> To ensure that background tasks are correctly executed, they must account for <a href= "https://developer.android.com/training/monitoring-device-state/doze-standby.html"> Doze</a>. 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. </p> <p> Doze is <a href= "https://developer.android.com/preview/behavior-changes.html#doze">enhanced</a> 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. </p> <p> You should schedule jobs with the <a href= "https://developer.android.com/reference/android/app/job/JobScheduler.html"> JobScheduler</a> 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 <a href="https://developer.android.com/reference/android/app/job/JobInfo.Builder.html"> JobInfo.Builder</a> object to provide constraints and metadata, e.g. with one or more of the following methods for a task: </p> <ul> <li>To schedule a task that requires networking, use <code>setRequiredNetworkType(int networkType)</code>, specifying <code>NETWORK_TYPE_ANY</code> or <code>NETWORK_TYPE_UNMETERED</code>; note that <code>NETWORK_TYPE_UNMETERED</code> is for large data transfers while <code>NETWORK_TYPE_ANY</code> is for small transfers </li> <li>To schedule a task while charging, use <code>setRequiresCharging(boolean requiresCharging)</code> </li> <li>For specifying that a device is idle for a task, use <code>setRequiresDeviceIdle(boolean requiresDeviceIdle)</code>; this method can be useful for lower-priority background work or synchronization, especially when used with <code>setRequiresCharging</code> </li> </ul> <p> Note that some low-bandwidth networks, such as Bluetooth LE, are considered metered. </p> <h3> Scheduling with constraints </h3> <p> You can schedule a task that requires constraints. In the example below, a <code>JobScheduler</code> object activates <code>MyJobService</code> when the following constraints are met: </p> <ul> <li>Unmetered networking </li> <li>Device charging </li> </ul> <p> You can use the builder method <code>setExtras</code> 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 <code>MY_JOB_ID</code> value passed to the <code>JobInfo.Builder</code> constructor. This <code>MY_JOB_ID</code> value is an app-provided identifier. Subsequent calls to cancel, and subsequent jobs created with that same value, will update the existing job: </p> <pre> 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); </pre> <p> Below is an implementation of <a href= "https://developer.android.com/reference/android/app/job/JobService.html"> JobService</a> to handle the job above. When the job executes, a <code>JobParameters</code> object is passed into the <code>onStartJob</code> method. The <code>JobParameters</code> object enables you to get the job ID value along with any extras bundle provided when scheduling the job. The <code>onStartJob</code> method is called on the main application thread, and therefore any expensive logic should be run from a separate thread. In the example, an <code>AsyncTask</code> is used to run code in the background. When work is complete, you would call the <code>jobFinished</code> method to notify <code>JobScheduler</code> that the task is done: </p> <pre> public class MyJobService extends JobService { @Override public boolean onStartJob(JobParameters params) { new JobAsyncTask().execute(params); return true; } private class JobAsyncTask extends AsyncTask </pre> <h2 id="fcm"> Cloud Notifications Using FCM </h2> <p> FCM is the recommended way to send notifications to a watch. </p> <p> 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. </p> <p> An FCM message is in JSON format and can include one or both of the following payloads: </p> <ul> <li> <strong>Notification payload.</strong> When a notification payload is received by a watch, the data is displayed to a user directly in the notification stream. When the user taps the notification, your app is launched. </li> <li> <strong>Data payload</strong>. The payload has a set of custom key/value pairs. The payload and is delivered as data to your Wear app. </li> </ul> <p> For more information and examples of payloads, see <a href= "https://firebase.google.com/docs/cloud-messaging/concept-options">About FCM Messages</a>. </p> <h2 id="fcm-phone"> Notifications from a Companion Phone </h2> <p> 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. </p> <p> For information about preventing duplicate notifications, see <a href= "https://developer.android.com/wear/preview/features/bridger.html">Bridging Mode for Notifications</a>. </p>