| 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> |