Apple Watch Series 3 makes it easier to stay connected, even when away from your phone. Learn how to keep your app responsive over cellular connections using URLSession. Find out how to optimize your Watch app networking code to ensure that your app is always up to date and ready for use. Discover how to leverage Core Motion data from the new barometric altimeter for displaying relative altitude changes.
Updating your watchOS 4 app for Apple Watch Series 3 makes it easier than ever to stay connected, and allows you to leverage the new barometric altimeter.
Apple Watch began with a dependence upon its connection to iPhone for all networking. However, since watchOS 2, Apple Watch has had the ability to communicate over Wi-Fi if your iPhone is off or out of range, and you are in range of a Wi-Fi hotspot your iPhone has previously connected to. Apple Watch Series 3 with cellular now allows your app to communicate directly over a cellular connection if your iPhone is out of range and Wi-Fi is not available where you are. Not only can your app update its data from anywhere, but push notifications received by your iPhone will be automatically forwarded to your Apple Watch when it is on a cellular connection. To make sure that your app works over any and all connection possibilities, it’s now even more important to use URLSession for networking requests in your watch app. URLSession is the class used for creating and managing networking connections in watchOS. Using URLSession from your watch app code, allows you to initiate network requests directly from Apple Watch. When your iPhone is in range of Apple Watch, these requests will be proxied behind the scenes through iPhone to leverage its connection. Otherwise, requests will occur directly through Wi-Fi hotspots or cell connection. When using URLSession while Apple Watch is only on a cellular connection, be aware that sessions may be handled slightly differently by the system. Let’s look at the different types of sessions and what you can expect. For default and ephemeral sessions, these type of sessions will work as they normally do when the application state is active. You can check the current application state using the applicationState property on the shared WKExtension object. However, these type of sessions are not allowed if the application state is inactive or background. There is one caveat to this, as they are allowed if your app is currently using the background navigation mode. Next, let’s look at background sessions. With background sessions, smaller transfers are preferred, and any transfer could be deferred until a point where the system has a better opportunity to make network requests. This is determined at a system level and takes into account many facets such as power level, connection strength, and tasks other apps are needing to accomplish. With background sessions, once the request has been made and a response has returned, if your app is in the frontmostapp state, your app will be woken immediately and handed the response. Outside of the frontmost app state, the system will wake your app with the response when it determines it is a good time to do so, or when the application state becomes active again.
Now let’s go over a few best practices to make sure you get the most out of your networking code on watchOS. The first is to use the new waitsForConnectivity property on your URLSessionConfiguration object. Setting this to true on a non-background session will allow the system to wait until connectivity is sufficient to make the request, instead of immediately failing. There is a delegate method to know when the connection is waiting, so you can handle the situation. We encourage using this property for all requests that are not dependent on being immediate, since they will fire immediately as long as connectivity is available. If not, the system will wait on making the request until connectivity resumes. This allows you to focus on what makes your app great instead of focusing on reachability code.
Using the applicationWillResignActive method on the WKExtensionDelegate object allows you to optimize what happens when the application state changes from active to inactive or background when you have a networking request in process. In other words, when someone puts their wrist down while using your app. By using this method, you can decide to cancel your existing request, or create it again as a background session.
Finally, it’s always best to use the shared singleton URLSession object for multiple tasks, instead of creating a session for each task. Creating and invalidating many sessions creates unnecessary overhead for the system, and it’s best to use the shared session, or as few as needed.
Let’s move on to the Watch Connectivity framework. As Apple Watch becomes more independent with its connectivity, it’s important to identify where using Watch Connectivity can help make a great watch app experience. The initial launch of an app on Apple Watch may require a token for authentication with a service. Using Watch Connectivity is a great way to pass this information that may already be established in the iPhone app. If your app is a coaching app for workouts, or something similar, you may want to initially transfer some larger audio files to Apple Watch once someone begins using your app. Watch Connectivity can handle these type of transfers, and can help your app installation remain small and supplement the app with resources later. The updateApplicationContext method on WCSession allows you to have the iPhone send over a dictionary of data that the watch app has access to the next time it activates. This is a good way to keep fresh data flowing to the watch app in case of situations where the iPhone app gets newer data and the watch app hasn’t had an opportunity to update yet. When the watch app launches, you can display this newer data while you initiate a network request for more up-to-date data. It’s very important that you build in the ability to fallback to a network request. With Apple Watch being more independent, there is less guarantee that your watch app will have up-to-date data from the iPhone.
Now let’s turn our attention to the new barometric altimeter in Apple Watch Series 3, which enables you to now add elevation gain or descent to workout summaries when someone is away from their iPhone. This also helps provide more accurate active energy burned calculations to HealthKit, and in turn, your app.
Using Core Motion, your app can now be informed about relative altitude changes from where your app begins receiving updates. Relative altitude changes means that if you begin updates while standing at an elevation of 800 meters, and move 50 meters higher in elevation, the relative altitude value will be 50 meters. If you move 80 meters lower than where you began, the relative altitude value will then be negative 80 meters. Core Motion includes the CMAltimeter class, which you will use to receive updates. CMAltimeter can determine and tell you if the device has the capabilities to give relative altitude updates. You should always check this first before asking Core Motion more about relative altitude. In watchOS 4, CMAltimeter can now provide you with the authorization status for Motion and Fitness activity. Depending on what your app is allowed to access, you may need to handle cases where authorization is denied or restricted. Finally, CMAltimeter provides the ability to start and stop relative altitude updates. These updates are delivered on a two-and-a-half second cadence on watchOS 4, due to signal filtering that we apply to the raw sensor data. When you receive an update, you will have a handler that passes you a CMAltitudeData object.
The CMAltitudeData object gives you the relative altitude change data for that update. This includes the following pieces of data: first is the timestamp. This object is a time interval and is given as the number of seconds since the reference date. To convert this value to a Date object, you can easily use the timeIntervalSinceReferenceDate initializer method on the Date class.
The next property is relative altitude. This represents the change in altitude since the last reported event. Remember that this will be a relative value, so if the device moves lower or higher in elevation, this value will represent the change in elevation and not the specific altitude. This value is given in meters. The last property is pressure. Since the altimeter onboard is a barometric altimeter, Core Motion can provide you with the recorded pressure alongside the relative altitude change. This value is given in kilopascals.
Let’s walk through an example of how to start relative altitude updates using CMAltimeter, as well as how to properly check for device capabilities and authorization status. Previous to this beginAltitudeUpdates method, I’ve imported the Core Motion framework into my class and created an instance variable called altimeter, of type CMAltimeter. That’s the object we will use to start and stop relative altitude updates later on. In our function, the first thing we should do is check to see if relative altitude is available on the device. If it’s not, we may want to alter the UI to let the person know that this data will not be available as they use the app. Next, we need to check if authorization status is denied or restricted. Here, we’re making sure authorization status isn’t denied, nor restricted. If the authorization status is authorized we can continue, and if the authorization status is not determined, the system will prompt for access, if the person has not been previously prompted. Once the app is authorized to use Motion and Fitness activity, we may ask Core Motion to start relative altitude updates. This call on a previously created CMAltimeter object has us pass in which operation queue we’d like to receive updates on, as well as provides a handler to run each time new data is handed to us by Core Motion. In this case, we’ve set the operation queue to the main queue since we will be updating UI in the handler. Moving to the handler, it passes us a CMAltitudeData object, containing the values we are interested in, or possibly an error if something went wrong in the update. After ensuring we have no error to handle, we simply grab the relativeAltitude value from the CMAltitudeData object, store its float value, and use that to update the UI. We could just as easily use the timestamp or pressure properties, as mentioned earlier. Once we no longer need to receive updates, we tell Core Motion to stop relative altitude updates, using our previously used CMAltimeter object. And that’s it! For more information about developing for Apple Watch and using URLSession and Core Motion, please view the resources links at the following page. Thank you.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.