Introducing Watch Connectivity-713 译文

来源:互联网 发布:iphone库存软件 编辑:程序博客网 时间:2024/05/22 17:25

最近在看watchOS2与iPhone的通信,视频地址为

https://developer.apple.com/videos/play/wwdc2015-713/?time=113

视频译文部分如下。

CHRIS JENSEN: Good morning. Welcome to Introducing WatchConnectivity.


My name is Chris. Today I'm joined by my coworker Alex, who will join me on stage later.

//今天我会和我的同事Alex合作,他等会上来


We are excited to show you what we have been working on for both watchOS 2 and iOS 9. We think what we are going to talk about today is going to help you make more responsive and better user experiences for your Watch apps. To do a brief recap of where we are coming from, let's look at what the world looked like in watchOS 1. Your iOS app and your WatchKit extension were both living on the iPhone, and we were taking care of the communication to the WatchKit app, and they could both share a data store. In watchOS 2, we've moved the WatchKit extension over to the Watch, and now your app is running natively on the Watch. This has a lot of benefits, but it also means they now each have their own data store.

//我们会介绍WatchOS2IOS9的新特点。这些将会帮助你们的应用有更好的体验。watchOS1IOSwatch extention都存储在iPhone上,他们可以通过Group来共享数据。在WatchOS2中,我们将extension转移到了watch上,这意味着watchiOS分别有了他们自己的存储区域。


The obvious next question is going to be: How do we get data over to the Apple Watch? That's what we will discuss today.

//那么问题来了:怎样将数据转移到watch


So we are going to show you two main ways to deal with this problem, of getting the data to the Watch. There's the new WatchConnectivity framework, which we are introducing in watchOS 2 and iOS 9. And then there's the NSURLSession APIs available in Foundation.

//有两个方法。一:WatchConnectivity框架二:NSURLSession接口


These are still available to your WatchKit extension, and it's now available native on watchOS 2. We think the topics we are going to discuss today apply to most Watch apps, and we think it's going to apply to most of you. This is exemplified by the amount of examples that we will be using in our presentation today. You can see there's a wide range here, and we hope that every one of you will be able to identify with at least one of these.

//今天将会举大量的例子来说明这些方法,希望你们至少会一种方法。


So let's get started with discussing WatchConnectivity. So this is the new framework we introduced in watchOS 2 and iOS 9.

//先介绍WatchConnectivity框架


It's available in both platforms, and pretty much all of the APIs are available in both sides. There are couple of iPhone-specific APIs that we will get into. The first thing you want to do when you are starting to adopt WatchConnectivity is you want to go through the setup. We recommend that you set this up very early in your app's life cycle on both sides, both on the WatchKit extension, running on the Watch and in your iOS 9 apps. You want to make sure you do this setup in a code path that will be executed even if you are being background launched. So, don't put it inside, like, a view controller's View Did Load, because when you're being launched in the background, those won't get called. So the first thing you want to do in your iOS app is you will check to see if the WCSession is supported. You might have a universal iOS app.

//WatchConnectionvity在两种平台上都可以使用,并且大多数的接口都可以在两台设备上通用,iPhone上有一些特有的接口。开始要setup,建议你在程序一运行的时候就建立这个框架的使用,然后再判断当前这个平台是否支持WCSession,因为只有iPhone才可以支持,iPad不支持


Which means this code may be executing on an iPad, where WatchConnectivity is not available. So check this up front before you do any Watch-specific work because we don't want you to waste a bunch of CPU doing work that won't be used anywhere. The next thing you want to do is create an instance of our object, and you do that by calling Default Session. And then you want to set a delegate on the session object, and then finally you want to call Activate.

//接着创建一个WCSession的实例,最后激活这个session对象


This will go and set up the WCSession object, initialize all the properties, and once this call returns, all the properties will be updated with the correct initialization values. And also at this point, any delegate callbacks, any cued-up content can start coming in.


That's another reason why you want to do this very early and always. There might be content waiting to be delivered to your app.


So make sure you do these steps up front. The next thing is you are going to want to do, once you completed that step, is look at the session states.

//建立成功之后,检查session对象的状态


This will inform your app about what the current relationship between the iOS app and the Watch is. So these properties are only available on the iPhone app.

//这个会告诉我们当前的IOS appwatch上的app连接情况。这写属性只在iPhone上有用,watch上不支持检查


It's informing the iOS app what its relationship with the Watch is. So you don't need to use this in your Watch app, and they are mostly not available. So for this example, we will use a news app. Something that pulls down the most recent interesting articles. And it's going to first go through the setup process that we just discussed.

//以新闻类应用举个例子,这个新闻app下载最新的文章到watch


It will do this early in its life cycle. Next, it will want to check, is this device paired with a Watch? If it's not paired, then it's almost as if this is running on an iPad, there's nothing more to do. There's no one else to talk to. So at that point you might as well stop doing any Watch-specific work. But the user will go out and buy a new Watch, and he will go through the pairing process.

//如果如果用户新买了一个watch,他将会进行匹配行为,将watchiphone匹配。


He will launch the Apple Watch app. Work his way through the pairing, setting these devices up.

//如果他匹配成功了,并且在watch上登录这个应用


And now, when your app launches, you will get a delegate callback. The session Watch state did change.

//此时,如果你iOS端应用打开,你将会收到一个delegate回调,session的状态发生改变了。表示watchiPhone匹配上了的属性paired返回yes


When you check the value of the paired property, you will see it will return True, because the devices are now paired.

//所以当你再检查iPhonewatch的匹配属性时,他将会返回true,代表两个设备限制是匹配状态


So this is a trigger for you to go ahead and check this next property, which is, is your Watch app installed? If it is not installed, then there's no one to talk to, your work is done. But -- and by default, the Watch app will be default -- but the user might choose to uninstall it for some reason. In this case, the user will go ahead and reinstall it. He will go back into the Apple Watch app and he will flip that switch, and now if your Apple is running, you will again get the delegate callback and you can check this properties value, and you would see that Watch App Installed is now True. Now you do have someone to communicate with. This should be a trigger for you to start communicating with your Watch app. It will need content that only you can provide for it. Whenever the Watch App Installed switches to True, there's this other property that's going to be available, Watch Directory URL. You will find that this, whenever Watch App Installed is True, Watch Directory URL will have a non-nil value. It will be a path to a directory that we create in your container. Let's discuss this a little bit more in depth. So the directory and its contents, its lifetime is tied to the Watch App Installed property. This means whenever Watch App Installed switches from True to False, this directory and all of its contents goes away.

//第二个要检查的属性是watch上的应用有没有安装,如果没有安装,那么不需要做什么了。如果watch上的应用安装了,那么watch上的这些属性就可以使用了:watch Directory url.如果watch app安装状态从true转成false,那么这个属性就消失不能使用了


Whenever it switches back to True, the directory will be present, but this time it will be empty. We recommend you only use it for data relevant to the specific instance of your Watch app. What do I mean by instance? Well, things like last queued item marker would be a good thing to store there. If the user uninstalls and reinstalls your app, that Watch app is starting with a clean container.

//当再次重新安装watch app的时候,这个directory将会再次出现,但是是空的。


Therefore, this directory will start clean, and you will need to sync up where your app is communicating. Other things you can put in is something like preferences.


When the user is running the iOS app for the first time, you might like him to set up what he would like his Watch app experience to be.


Maybe he doesn't want to show the full content but the top ten news items for a particular topic like international news or sports.

//directory可以用来存储偏好


This would be a good place to store them. Also if you are taking your full-sized assets and generating Watch-specific assets, you are compressing images, audio, video, this would be a good place to store those while they are cued for transfer, using the WatchConnectivity APIs that we will discuss later. So that's the Watch directory. We suggest you store content in there, because then we will clean it up, if the Watch goes away, if he unpairs his watch, we will automatically clean up this content, so you don't have to micromanage all of this.

//放在这里的东西不用清理,当在iPhone上设置不显示watch上该应用时,这个路劲里面的内容就会被清除


The final property that's part of the session state is Complication Enabled. Currently, the user does not have the complication enabled, but he will go in and edit his Watch face and he will enable it and you will get the same delicate callback, session or stated change.

//最后一个属性就是complicationEnabled,是否能自定义表盘上的小部件。当状态改变时,也会返回代理。


And when you check this property, it will now be True. Now you have set up your WatchConnectivity session. You have figured out what the state of the world is, what your relationship between your iOS app and your Watch app is. The next thing you will want to do is start communicating information over to the Watch or from the Watch to the iOS app. And to do that, I will hand over to Alex, who will talk about the communication APIs. ALEXANDER LEDWITH: Thank you.

//以上就是安装session的全部过程,下面开始介绍如果在ioswatchOS上交换数据


Okay. So like Chris said, you set up your session. You have checked that devices are paired, your Apple Watch app is installed.


Now let's start talking about how you can communicate between these two devices. We have a couple of different categories for communication.

//有好几个不同的类别可以进行ioswatchOS的沟通


First category is background transfers. Background transfers are meant for content that is not needed immediately on the receiving side.

//第一种类型是:后台传输。适用于接收方不是当前立马需要的数据


Because the content is not needed immediately, this means the system can do more intelligent things when transferring that content.


In addition to background transfers, we are also going to talk about interactive messaging. Interactive messaging is meant for communicating between two apps with live communication. So both apps are up and running. They are sending messages back and forth, request response, that kind of thing. Some examples of when you might want to use interactive messaging.

//第二种类型是:及时互动。适用于两个app都在前台运行的时候,需要发送信息以及做出相应。


Say you have a game where the user is using both apps at the same time. Or you are on your Apple Watch, and you need to trigger something to happen on the iOS side. Like you want to trigger the iOS device to start tracking the user's location.

//比如我们我们同时在两个设备中玩游戏,需要及时沟通。或者需要在watch上显示iphone上应用的最新情况,这也需要及时沟通。


So let's dig into this first one, background transfers. The first thing to talk about for background transfers is the type of content your apps have and how the user is going to interact with these two devices. So let's take that news app example again, this news app has some content. It's fetching some more content from the server, and it determines some of this content could be useful for your Watch. Now, the user isn't using the Watch at this point in time. So the content isn't needed immediately on the Watch side.

//现在开始详细介绍后台交互.以新闻app举例,这个ios app从服务器上获取一些对watch有用的内容,但是现在用户不在使用watch,那么这些内容不需要立即发送到watch端。


Rather, the iOS app, the news app, wants to just pick some of that content and queue it up with the system, and then allow the system to pick the right conditions to transfer that content across. The system will look at things like power, performance, when the user is actually using the receiving side, in this case the Apple Watch. When conditions are right, that content will transfer across, and it will wait on the receiving side, in this case the Apple Watch, until the user launches the receiving app. When the receiving app is launched, then that content will be delivered and the app can update its state. So this is what background transfers provide.

//然后,ios app想要挑选出一些有用的内容存放在iPhone系统中,然后允许系统在合适的情况下将内容发送给watch。这些合适的情况是指:当用户在使用接收端的时候,参考这个接收端的电量,性能。这些内容将会保存在watch上,直到用户登陆这个app的时候,watch会将这个数据传递给app.


It allows you to queue up content. The system is going to transfer the content for you. This allows the sending side, the sending side app, to exit.


The system will handle the rest. It allows the system to pick the opportune time to transfer that content, and it allows the system to store the information on the receiving side and wait for the receiving app to launch. For a lot of the content your apps have, we definitely recommend that you use background transfers.

//大多数的情况下,我们建议使用后台传输


The reason is most of that content will not be needed immediately on the receiving side. Rather, it will be needed when the receiving app actually launches. So let's get into some nuts and bolts. We have three different types of background transfers.

//有三种后台传输的方式。第一种是使用application context


The first type is the application context. The application context represents a single set of the most interesting information your app has to offer to the other side. So, for example, let's say on the iOS side you have an app that tracks the user's location, and based on that location, the app picks a restaurant in that location and wants to recommend it to the user. In addition to sharing restaurant on the iOS side, you also want to show that restaurant in the Apple Watch app. So you could package up that suggestion into the application context, and that will get transferred across, and then the next time the user launches the app on the Apple Watch side, the content will be there, that suggestion will be there to show. Another example of when you might want to use application context, say you have a social networking app on the iOS side, it fetches a bunch of posts and determines that there's a top 10 set of really interesting posts that it wants to show on the Apple Watch side. That way the user can look at the Apple Watch and see interesting information right away.


You can also package up of those top 10 posts into an application context, which will get sent across. Now application context is the simplest way of transferring content in the background, but if you need something a little more complex, or you need to queue up more than a single set of information, we are offering two ways to do that. The first way is user info transfer. This allows you to transfer user info dictionaries, in-memory content that you want to pack up. An example of this is let's say you have a game on the Apple Watch side.

//application context比较简单,如果想要传输比较复杂的数据就使用user info transfer,或者file transfer


The user progresses through levels, and as the user progresses through levels, you want to sync back that progression to the iOS app.


The iOS app will show some nice graphs on how the user did in each level. In addition to the user info transfer, we are also offering file transfer. This is very similar. It allows you to queue up content, except in this case, the content is a file. One example that we are going to use in this presentation for file transfer is let's say you have an iOS app that allows the user to edit images and after they edit those images, the user can pick their favorites.

//第三种方法是使用file transfer


And those favorited images are the ones you want to show in Apple Watch. You can use file transfer to transfer across those favorited images. So they're available on Apple Watch so the user can show them off to their friends, that kind of thing. So let's dig into these individually. We will start with application context.

//如果你想在iPhone上编辑一些图片,然后将最好看的图片传到watch上,就使用application cotenxt


The example we will use for application context is the social networking app example. I mentioned before, this app on iOS fetches all the posts from the social networking site and then it picks the most interesting ones to send over to the Watch app.


The first thing to talk about with application context are these two properties. The first property is Application Context.

//application有两个参数。第一个参数是application context


It is the property that stores the latest content on the sending side, and then on the receiving side, there's Received Application Context, which will store the latest received content on the receiving side. So let's say this iOS app has fetched a bunch of posts, and it's packaged up the most interesting ones for the Watch. It's going to want to call Update Application Context. This method takes a dictionary, representing the latest, most interesting state you want to send across. This content, we take this content after Update Application Context is called, and we push it down into the Application Context property. And this content will sit here, and the system will determine a good time to transfer that content across, maybe when the user starts actually using their Watch. Now, in the meantime, this iOS app could fetch more content and determine that there's a newer set of interesting information that it wants to send over to the Watch.


In this case, it's going to want call Update Application Context again. And then we're going to push that content down into the Application Context property. This is going to bump out the old relevant state and put in the new relevant state because what we really care about is the most interesting, latest set of data. Now, this new content is going to sit here, again, waiting for the system to pick a good time to transfer that content across. When the system does pick a good time, that content will come across.


It will sit on the Apple Watch side. And it will wait for the user to launch the app, the Apple Watch app.


When that app is launched, we will deliver that content to your WatchKit extension, the place where all of your code is executing on the Apple Watch side.

//application context工作流程是:iOS端将需要传给watch的内容上传到context中,然后apple会在合适的时候将这些内容传递给watch.当用户打开watch上的应用的时候,watch会将这些内容传递给app.具体的流程参考下段。


So that's the flow of application context. Now, let's take a look at some code. The first thing you want to do is you want to package up your context dictionary, representing the latest state that you want to send across. And then you will call Update Application Context with that dictionary. The last thing to mention about this code example is that the call to Update Application Context is wrapped in a Do Catch block, and the call is prepended by a Try. This is new error handling in Swift. Update Application Context can return an error.


And if an error is returned, the Catch block will be invoked, and we strongly suggest that you handle your errors appropriately.

//强烈建议在更新context的时候,处理错误的产生。


So that's the sending side for application context. Now, let's take a look at the receiving side. On the receiving side, the receivers will get this delegate callback, Did Receive Application Context. It's going to pass through the dictionary that the sender packaged up. And at this point, the receiver can take that content and update its app state.


One thing to know about this delegate callback and all delegate callbacks in our API is that they're returned on a non-main serial queue.

//所有的session的代理都不是在主线程中被调用的,如果需要刷新UI,需要调用主线程去刷新UI


If you need to do something on the main queue because maybe you're updating some UI, you're going to need to dispatch over to the main queue to do that updating of your UI based on this content or something else. So that's application context. It's the most interesting relevant content that your app has for the other side. It does have overriding behavior, and this is because you should treat the latest content as the content that the receiving side cares about and anything that's not latest isn't relevant anymore. Application context takes a dictionary.

//application会让新的数据覆盖就的数据,因为我们只关心新的数据,旧的数据不需要关心了


This dictionary takes property list types. Property list types are basic object types such as numbers, strings, basic collection types, dictionaries, arrays.

//application context存储的数据类型为字典。字典的数据类型为基础的数据类型


Apple has some great documentation online if you want a refresher on property list types. So we have some specific recommended use cases for application context. Application context works really well for many Apple Watch apps because many Apple Watch apps show a subset of the information the iOS app has. So, if your app works like this, we suggest that you put that subset of the information into the application context and let it get sent across to the Apple Watch side. In addition to those apps, application context also works really well for glances.

//如果watch端只显示iOS端子集的数据,我们建议使用context来存储数据。


Glances take the single most interesting piece of data your apps have to offer. So we suggest you put that piece of data into an application context on the iOS side, so that it gets across to the Watch side. Then when the user swipes up on the clock face to show your glance, that data will be available. So moving on from application context, now we are going to talk about user info transfer.

//下面开始介绍user info类型数据交换


An example here that we are going to use is you have a game on the Apple Watch side. The user progresses through levels in this game, and as the user passes one level, you are going to sync back the progress that they made to the iOS side so that the iOS app can show some nice graphs on how the user did in that level. The first thing to talk about for user info transfer is the outstanding user info transfer queue. This holds on to all the content that's waiting to be transferred across.

//举个例子:加入我们在watch端有个游戏。当用户通过一关的时候,我们需要将这一关的成绩传输到ios端,以便显示用户在这一关中取得的好成绩。我们首先讨论user info transfer的是他的向外传输队列。这个向外传输队列存储了所有的等待被传输的内容。


The current state of the world as the user progressed through two levels. The progression is sitting in the outstanding user transfer queue. And currently the user is working on level three. Once they finish level three, you are going to want to package up that content and call Transfer User Info and pass through a dictionary that represents their progress. This will take that dictionary, and it will package it up and it will put it into the outstanding user input transfer queue. Now this content will wait here until the system determines it's a good time to transfer that content, based on power considerations or maybe when the user starts using their phone.

//游戏中用户已经闯过两关,这两关的信息都保存在user transfer queue中。用户当前正在创第三关,只要他完成了第三关,我们就会将第三关的内容放入向外传输队列中,然后等待watch系统在合适的时候将这些信息传送给iPhone.然后iPhone会在合适的时机将信息传递给iPhone上的app


The content will then transfer, and like the previous API, we are going to wait until the app on the iOS side launches. And when it does, we will deliver that content, and now the iOS app can update those graphs to show the progress the user made in their Apple Watch game. So that's the flow for user info transfer.


Let's take a look at some code. First thing you want to do is package up your user info dictionary with all the content that represents this current state that you want to send across. And then you want to call Transfer User Info with that dictionary. Transfer user info returns a user info transfer object. This object contains the dictionary that's being sent across, and it allows you to cancel this transfer if the transfer is still in the outstanding queue. In addition to this transfer object being returned, we also offer a way to get all of the outstanding user info transfers that are in the queue. This returns an array, and you can iterate over the array, look at all the contents, and potentially cancel if you need to. So that's the sending side for user info transfer.

//user info transfer只要没有进行传输的数据都可以随时取消传输。苹果提供了一些方法让我们获得向外传输队列中的内容,方便我们获取内容去取消这个内容的传输。


Let's take a look at the receiving side. On the receiving side, you will get this call, Did Receive User Info Transfer.


Like application context and all the other delegate callbacks, this is returned on a non-main serial queue. Once you get that call, you can take that content, that dictionary content, and you can update your app state. That's user info transfer. It takes user input dictionaries.

//接收方可以通过代理来接受传过来的数据


These dictionaries, like the application context dictionary, take property list types. It's good for in-memory content, like game progression.


And we give you access to the outstanding user info transfers in the queue. Next, let's talk about file transfer.

//接下来谈一谈file transfer。文件传输


An example we will use for file transfer is this image-editing app. The user can edit images on the iOS side, and then they can select their favorites, and those favorites are the ones we want to transfer across to Apple Watch.

//举个例子:图片编辑app.用户可以在iOS端编辑很多图片,然后选择出他们最喜欢的一些传递到watch


So the first thing to talk about is the outstanding file transfer queue. This is where all the file transfers will sit when they are waiting to be sent across. And then on the receiving side, the files will be put into the Documents/Inbox folder while they are waiting to be delivered to the receiving side app. The state of the world is the user has favorited two pictures, two images, that are sitting in the queue, and they are working on a third. Once they have completed that third and have selected it as a favorite, you will want to call Transfer File.

//首先要讨论的是向外文件传输队列,文件向外传输队列存放的是即将要发送的数据队列。对于接收方,文件将被传送到Documents/Inbox文件夹下。举例:这个应用已经选择了两张最喜欢的图片放在队列中,然后在等待用户选择第三个,当第三个也选择好的话,我们将会发送这些文件。


And you will pass in a file URL pointing to the file that you want to transfer, and we are offering a way to transfer additional metadata in the form of a dictionary.

//我们还可以通过传输字典来传输一些额外的数据


One example of when you might want to add some metadata is if you want to group some of these files together by putting an identifier in each metadata dictionary.

//因为我们可能想要给这个文件分组,那么久使用这个dictionary格式传输的数据来提供分组信息。


That way the receiving side can pull out that identifier, group the incoming files. So the user's favorited this image.


We called it transfer file. Now we will take that packaged-up content, and we will put it into the outstanding file transfer queue.

//再次看看文件向外传输队列


And it will wait here until the system determines a good time to transfer the content. When the system does determine a good time to transfer that content, it will move that content across and it will wait for the receiving side to launch and take care of that content. One thing to note about files, files can be a little bit larger. And the larger the file, the longer it's going to take to transfer across.

//文件传输可以传输较大的文件,相应的大文件传输的时间也会增长


Potentially you might hit power conditions, performance conditions while those are transferring. Just be aware if you have large files that are trying to transfer across, they may take longer than the transferring in some of the other APIs. Now the receiver will launch, and we will deliver these images. And now the Apple Watch app can show those images off. So that's the flow of file transfer.


Now let's take a look at the code. First thing you want to do is you want to get your URL to the file that you want to transfer.

//下面讨论下文件传输的流程。首先我们需要获得的是我们想要传输的文件的URL.


Then you want to package up your metadata and finally, you want to call Transfer File, passing through that URL and that metadata dictionary.


This returns a file transfer object, the file transfer object contains the URL, the metadata dictionary, and also gives you the ability to cancel any file transfers that are outstanding. Just like user info transfer, we offer you the ability to get the array back of all the outstanding file transfers.

//将文件放入向外传输文件队列,会返回给应用一个文件对象,这个对象包含了我们想要传输的文件的URL,额外的字典,并且我们可以通过这个文件对象取消传输这个文件。像user info transfer模式一样,我们可以获取所有向外传输文件队列中所有的对象。


You can iterate over this array, check the contents, and cancel if need be. So that's the sending side for file transfer.


Now let's take a look at the receiving side. On the receiving side, you are going to get this delegate callback, Did Receive File.

//现在开始介绍接收方。接收方通过代理Did Receive File来接受文件


There's a few things to mention about this delegate callback that are slightly different than the previous two. First, you are going to be getting this WCSession file object. This object just contains the file URL and the metadata. The second thing to talk about with this callback is that the file is now in the Documents/Inbox folder of your app's container. But to take control of this file, you need to move that file out of the Documents/Inbox folder into a more permanent location. So the main reason you need to move this file is that the Documents/Inbox folder will be cleaned up after this delegate returns. This means the file will be deleted out of there along with any additional content. So it's really important that you move this file into a more permanent location inside this delegate callback.

//这里有几点需要注意。对于接收方,我们首先需要获取session文件对象。这个对象包含了我们需要的文件的url以及dic数据。第二:接收方的文件保存在doc/inbox文件夹下,我们需要将文件从doc/Inboc文件夹转移出来,因为只要当代理返回的时候,这个路径下的文件就会被清空。所以在代理里面将doc/Inbox底下的文件取出来放在其他的路径下很重要。


One thing to keep in mind if you are dispatching to a different queue because this is returned on a non-main serial queue, you will need to move the file before you do that dispatching, if that dispatching is async. So that's file transfer.


It's very similar to user info transfer, except it allows you to transfer files or queue up files. We do offer the ability to access the outstanding files in the queue. And we provide the ability to transfer additional metadata. We suggest you keep this metadata small, and this metadata dictionary, like the other dictionaries we talked about, takes property list types.

//类似于user info传输,我们允许将文件传入到队列中。然后提供额外的传输数据用dic传输。


So those are the three background transfer modes. Use these if the receiver does not need the content immediately.

//上述就是三种后台传输application context,user info transfer,file transfer,当接收方不需要立即获取这些数据的时候就使用后台传输。


If, however, you need to send messages back and forth in a live fashion, you can use interactive messaging. And interactive messaging is meant for that live communication, both apps are up and running and they are sending messages back and forth. Like I mentioned before, some examples of when you might want to do this. Let's say you have a game where both UIs are up and you want the user to be interacting with both.

//如果需要来回的发送即时消息,我们可以使用互动信息交互方式。举个例子:有个游戏在两个设备上运行,我们需要两台设备即时沟通的时候。


Or if you are on the Apple Watch side and you need to trigger the iOS app to do something, like start tracking the user's location.

//比如我们打开watch应用,想要触发ios应用去跟踪用户的位置信息,我们就需要在两台设备上进行即时的互动。


Now, there are certain conditions that need to be met for interactive messaging to be used. So let's talk about those conditions.

//对于使用即时交互需要满足一些条件,条件如下


It all relates to this idea that we are introducing called reachability. And what reachability means is that the other app is available to receive content. It is required that the other app is available, the other app is reachable, to use interactive messaging.

//一:需要对方应用可达reachability


And the way that you check that the other side is reachable is we have this property on the default session, Reachable, that you can look at.


Now, the conditions for reachability are slightly different depending on what slide you are on, whether your code is executing in your iOS app or it's executing in the WatchKit extension. So let's look at those individually.

//判断对方设备是否可达会根据条件而略有不同,这些条件包括:在哪个设备上判断对方设备,ios app中的代码是否运行了,以及watch app的程序代码是否运行了。下面开始单独解释


We will start on the iPhone side. The first condition that needs to be met for Reachable to be True is that the devices needs to be connected.

//首先开始介绍在iPhone端,判断watch是否可达。首先需要判断的是watch是不是跟iPhone连接了


This is connected over Bluetooth or over Wi-Fi, but if the user leaves their Watch at home, takes their phone with them to work, the devices won't be connected and interactive messaging is not going to work in this case. The second condition that needs to be met for Reachable to be True on the iOS side is that the Watch app must be foreground. This means the user must be interacting with their Watch app for interactive messaging to work from the iOS side.

//iPhonewatch是通过无线网或者蓝牙连接的。如果用户把watch留在家里,带着iPhone去上班了,那么这两台设备是没有连接的并且在这种情况下不能进行即时沟通。第二:iPhone判断watch是否可达需要watch上正在使用这个app.


Once these two conditions are true, the Reachable property will be True in your iOS app. So that's the iPhone side.

//总结 iPhone上判断watch是否可达要满足两种条件:一:两台设备连接:watch上正在使用这个app.


Now let's talk about the Apple Watch side. The first condition for Reachable to be True in your WatchKit extension is that once again devices must be connected. This means that if the user goes for a run and leaves their phone at home and takes their Watch with them, Reachable will not be True. The devices will not be connected. The second condition is that the WatchKit extension needs to be foreground. We mentioned the WatchKit extension here being foreground because there are certain cases where the WatchKit extension can run in the background. They mainly relate to complications, and we will talk about this a little later in the talk.

//watch上判断iPhone是否可达。一:设备是连接状态。二:watch应用需要在前台运行。三:ios应用正在运行


For now, when the user is using your app, your WatchKit extension is going to be running and your WatchKit extension will be foreground, which means you can use interactive messaging and the Reachable property will be True. One other thing to note about this diagram.


We are not saying that the iOS app is running. The iOS app has to be running to respond to messages coming in, to send its own messages.


So how do we get into a state where the iOS app running in addition to the WatchKit extension? Well, for this direction only, sending messages from the Watch to the phone or allowing the iOS app to be launched in the background upon receiving a message. So let's take this example.

//???


You have a run tracker app and it needs to send a message over to the iPhone side to talk to CoreLocation to start tracking the user's location.

//举个例子:一个跑步跟踪app.watch端需要发送一个信息去告诉iPhone端开始使用CoreLocation去跟踪用户的位置信息。


So this app is going to package up a message that tells its iOS app to start using CoreLocation, and it's going to send that message across.


When the system receives this message, we are going to launch the iOS app in the background and deliver that message.

//iOS端接收到这个信息的时候,我们就在后台打开这个iPhone app.然后处理这条信息。


Now, both apps are running, and now they can do communication. This app in this example can start tracking the user's location.


So that's kind of flow of interactive messaging. Kind of how it relates to reachability, when you can use it.


Now let's get into the nuts and bolts of how you use it in your code. We are offering two different types of messages.

//下面开始代码看看怎么使用。传输信息有两种方式


The first type takes a dictionary and you use this call, Send Message, which takes that dictionary, plus a reply handler and an error handler. This dictionary, like the dictionaries we talked about before, takes property list types.

//第一种:使用dictionary来传输。


In addition to dictionaries, we are also introducing a way to send data. You can send data by calling Send Message Data.

//第二种:NSData


This takes that data plus that same reply handler and that same error handler. For sending data, we suggest you use this if you have custom data that you're storing your information in or if you have your own serialization format. If you are using your own serialization format, we strongly suggest you use one that's quick and compact. This way the user experience is faster because the content is transferring faster.


One thing I want to point out about these calls is replying. You probably noticed the previous two calls have reply handler.


This handler is optional. However, we do recommend in most cases you use it. The reason is that this allows the receiver to confirm the incoming message. The receiver can confirm that it received the message. The message contained the right content, and it was able to process that content. And then this way the sending side knows that it doesn't have to send anything else.


It doesn't have to send anything new because it sent the wrong stuff. The other part to talk about for the replying is what happens on the receiving side. What happens if the sender says, "I want to reply, so I'm going to supply a reply handler," versus if the sender says, "I don't want to reply, I'm not going to supply a reply handler." In these cases, we have separate delegate callbacks the receiver is going to get, depending on whether or not it should supply a reply. So let's talk about those delegate callbacks.


In the first case, the sender says, "I do need a reply, I'm giving the system a reply handler." This means that the receiving side will get this delegate callback, Did Receive Message, it has a Reply block that you can call after the receiver has received the message and processed it, and the receiver can then determine if it wants to send back some content or maybe send back an error if the message is wrong. Now, on the other hand, if the sender doesn't supply a reply handler, the receiver is going to get this delegate callback, Did Receive Message.


It doesn't have a Reply block. The receiver can process the incoming content and they are done.


The last thing to note about these two delegate callbacks is they pass a dictionary through.

//最后需要注意这两个代理的地方是:他们会返回一个dic类型的数据


This means that the sender used the send message, sending on the sending side, to send a dictionary. If instead the sender used send message data to send data, there is analogous callbacks on the receiving side that pass through data. So now that we kind of have a feel for interactive messaging, let's put it all together and code for the sending side. The first thing you want to do is you want to check reachability, make sure the other side is actually reachable. Then if Reachable is True, then you can package up your message. And once you have your message, you can call Send Message with that dictionary. We expect a reply. So we will supply the reply handler, and we want to handle our errors, so we will implement an error handler. So those are the different ways to transfer content using WatchConnectivity. So let's sum up what we've talked about for WatchConnectivity.


The first thing you want to do is you want to set up your session. To do this, you set your delegate, and you call Activate.


You want to do this early in the lifetime of the app so the app has the ability to start receiving content and the ability to start checking properties.


To check those properties, you look at the session state. And once everything is okay, once you know there's a paired Watch, once you know your Apple Watch app is installed, you can start communicating. The first type of communication is background transfers.

//总结:第一种交互类型是后台传输。第二种是及时传输


We offer three types. The first type is application context. This is for the single set of really interesting information that your app has for the other side. Or if you need to queue up content, you can use user info transfer or file transfer.


In addition to background transfers, you can use interactive messaging for live communication.


So that's WatchConnectivity. It allows device-to-device communication between your apps. And we are excited to see what you do with this API to get content back and forth and provide better user experiences. Next, we're going to talk about NSURLSession briefly.

//接下来我们将讨论NSURLSession


So what is NSURLSession? It's an existing foundation class. It allows you to make HTTP requests to your servers to fetch content. It's available in watchOS 2, and we strongly suggest you use it if your servers have content that needs to be fetched.

//NSURLSession允许watch连接网络,发送HTTP请求


And it takes advantage of the Tetherless Wi-Fi feature. The Tetherless Wi-Fi feature allows Apple Watch to connect to known Wi-Fi networks when the phone is not around.

//phone不在周围的时候,watch可以连接到wifi来工作


If the Apple Watch does connect to known Wi-Fi networks, you can use NSURLSession to go over that Wi-Fi to connect to your servers and fetch content.

//如果watch没有连上wifi我们可以使用NSURLSession来连接wifi


So what do you want to use NSURLSession? You want to use it any time your server has new content. This is very similar to how you might be doing stuff in your iOS apps. We do suggest, however, that you tailor the content that's being delivered to Apple Watch based on how Apple Watch works.

//watch上可以像iOS那样使用网络来搜索数据,更新数据


So if you have images on your server, we suggest you scale those images for the screen size of Apple Watch, or if you are a news app and you are only going to show some of article, maybe just the text, on Apple Watch, we suggest you only fetch the parts you need. So that's a very brief introduction to NSURLSession.


There's a great WWDC session on this API as well as great online resources. So we definitely suggest you check those out.


Now, the last thing we want to talk about for NSURLSession is using NSURLSession with WatchConnectivity.


So once again, we have the example of our news app. This news app has fetched a bunch of content from its server, and it knows that the Apple Watch app probably will have to fetch this same content the next time the user launches the Apple Watch app.

//以上面的新闻例子举例。iPhone从服务器上获取数据,并且我们知道watch可能也需要这些数据,所以就通过application context将这些数据传输到watch


Instead of making the Apple Watch app refetch that content, we will use application context to transfer across the content from the iOS side to the Watch side.


That content is going to come in, and it will be delivered to the Apple Watch app the next time it launches. And now the Apple Watch app has the ability to show the same content that was seen on the iOS side, and it provides a more cohesive experience. Now the next time the user launched the Apple Watch app could be a couple of hours later, which means the server has even newer content that might want to be fetched.

//watch app下次被打开的时候就会处理这些数据,然后显示出跟ios端一样的内容。但是当用户迟了几个小时之后打开watch上的app之后,服务器上产生了新的内容


So we suggest that in addition to taking in the application context that was sent over, you use an HTTP request with NSURLSession to fetch the absolute latest content from your server. But this way, while the user is waiting for that content to come down, they will see the same content they saw in the iOS side and they will have a better experience. So that's NSURLSession, NSURLSession and WatchConnectivity.

//所以我们可以使用HTTP request去服务器上请求最新的数据。但是如果用这种方法的话,最好是在屏幕上显示出之前ios上的内容,这样用户会有更好的体验。所以我们可以结合使用NSURLSessionWatchConnectivity


Now, we want to take these two APIs and we want to show you how to use them to get data to your complication. And to do so, I will bring Chris back up to the stage to talk about this. CHRIS JENSEN: Thank you, Alex.


That's some cool stuff, right? I think it's going to be great to see what you guys end up doing with the WatchConnectivity APIs and the NSURLSession APIs. Now let's discuss complications. But before we dig in too deep, let's make sure we are all on the same page. These are three Watch faces, three clock faces on the Apple Watch.

//watch上有三种watch faces,三种 clock faces。哪三种?


If you remove the timepiece, the remaining pieces are complications. They provide small snippets of information every time the user looks at their clock face. And this will allow them to get sort of the most important piece of information really quickly.

//如果你将时间部分去掉,表盘上剩下的小控件就是complications。这个小控件给用户提供了一些信息,当用户抬起手腕看表盘的时候。这也允许用户快速的获取一些信息。


So when you are implementing your complication, there's two primary tasks that you will have to solve. You will have to figure out how to update the clock face, and the second one is you need to get the content to use to update the clock face. So let's discuss how you would update the clock face briefly.

//当你实现你的表盘小控件的时候,有两点需要解决。一:需要我们自己去更新表盘上的信息。二:获取表盘上的小控件需要显示的信息。先讨论我们怎么快速的更新表盘界面的信息。


This is covered in depth at other sessions. For this example, we will use a weather app that has a moon phase complication.


The moon phase complication doesn't need any external data. It already has all the information it needs because it just needs the date and time.


So all it needs to concern itself with is how to update the clock face. To do that, it's going to use the new ClockKit API, the ClockKit framework introduced in watchOS 2. The way the flow works is we're going to launch our WatchKit extension in the background.


When this happens, you are going to want to get an instance of CLK complications server. You call Shared Instance to do that.


And you will call Extend Timeline For Complication, and you pass in the complication that you are updating. The next thing that will happen, that will trigger our process with ClockKit and they will start asking you a couple of questions. They will ask for the current timeline entry.


This is the one that's going to be shown right now. They will ask for previous timeline entries, future timeline entries, and finally, they are going to ask for a suggestion of when you think this data will be stale. This is a suggestion to the system so that we can know when you think that you need to get launched again.


So you can update your timeline further. That was a quick summary of updating the clock face. You would use the ClockKit framework to do so.


You will be able to provide content for past, present, and future. Your WatchKit extension will get launched in the background to do these updates, and you will be given a chance to specify when the content provided is going to be stale. One thing to keep in mind is that all the work that your WatchKit extension is doing on behalf of updating the complication is budgeted, so you want to try to keep this as fast and efficient as possible so that you can keep getting launched throughout the day to update your complication. As I mentioned, there's a great talk dedicated to this topic, Creating Complications with ClockKit. We want you to check that out if you haven't done so. The next you will have to deal with is how to get content to your complication. There's a very special instance, which is the initial activation. The first time the user goes into his clock face, he's going to go in and edit it and then he's going to enable your complication; in this case, the news app complication.


At this point in time, that complication very likely has very little or no data to populate its timeline.


So it has a large need for a lot of content. So what's going to happen is we are immediately going to launch your WatchKit extension in the background.


And now you have a couple of different ways of getting that content so you can initialize that timeline. You could use NSURLSession to communicate with your servers to get that content, or you could choose to use WatchConnectivity. If you are going to use WatchConnectivity in this very special circumstance, and the devices are connected, you will find that Reachable is True.


This is what Alex was referring to earlier, where this property might be True in certain special circumstances.


This is one of those. What you are going to be able to do in this case is you will be able to call Send Message, which will send a message across to the iPhone. And we will wake up the weather app in the background, and at this point, the weather app on the iOS side can use any of the WatchConnectivity APIs to communicate the information back to populate that timeline. So in summary, when you are going through the initial activation, your WatchKit extension will get launched in the background. You can use NSURLSession or, because this is a very special circumstance, you will be able to use the WatchConnectivity APIs to wake up the iOS app because Reachable is True.


We suggest you use this to populate as much of the ClockKit timeline as possible because it's starting with nothing.


The next issue is how to stay current. Your timeline is now populated, and now future updates will be happening.


How do you keep updating your complication? So there's a couple of different ways that you could use to update your complication.


You could get content pushed to your complication. This makes sense if you have an external source such as a web server that knows specific times when there is new content and it's not a regular cadence. What you are going to want to do then is have the content push from the clouds to the iPhone, and then it gets relayed over to the Apple Watch. An example of where we think this makes sense is something like a sports app, where the complication is showing game scores. Most of the time, those scores are going to be happening in a short period of time during the day, and it will be very rapid updates. So then we think it makes more sense to use the pushed approach.


The other one is what we're calling requested interval fetch. This is more for when you know there's a regular cadence where you can keep updating your complication. And then you could use something like NSURLSession to go directly to the cloud.


Something like a surfing app with a tide complications that shows what the tidal patterns will be so you know when to go out surfing.


So let's take a look at this case first. In this case, you will want to use NSURLSession and ClockKit to update the complication.


As you can see in the corner of clock face, the surfing complication is already enabled. The flow is going to go a little bit like this, where the WatchKit extension gets launched in the background. You're going to want to generate an NSURLSession request and you send that up to your servers to get content.


The server will produce a response and it will get delivered back down to the WatchKit extension. Now you want to turn around and update ClockKit.


So you will request them to extend your timeline. They will start asking you these questions, and you're going to give them the timeline updates, both past, present, and current, and finally, you are going to suggest a time for when you should be launched again. And the last thing that will happen is when you provide that time for when you next should be launched, that's a hint to the system that your work is done, and your WatchKit extension will get killed.


So now, let's pretend that some time passes, and the system has decided based upon your hint and system conditions that now is a good time to relaunch your complication. Again, you are going to get launched in the background. You are going to produce a request, using NSURLSession.


You are going to send it up to the servers. The servers are going to produce a response, and you are going to turn around and update your complication using ClockKit.


So in summary, and a couple of tips is that we suggest that you use NSURLSession background session if possible. This is because the NSURLSession request might not complete until the next time the extension runs. Using the background session enables it to deliver the content the next time you run.


The requested time that you are providing is just a suggestion to the system. It's not a guarantee.


We'll try to get you close to that time, but conditions apply and it may not always be exact. We suggest that you keep the runtime as short as possible, and you will use ClockKit to update the clock face. You want to keep runtime as short as possible and make sure that you make your next requested update time as far out as possible because these are budgeted and you don't want to run out of budget before the day is over. The other approach to getting the content, which was in our example of the sports app, was to get the content pushed. We will look at this in a couple of stages because it uses two very distinct processes. The first one is you are going to use PushKit to get the content from the cloud to the iPhone.


The second part is using WatchConnectivity to get that content from the iPhone across to your Apple Watch. So let's look at those separately.


So part number one is where you are using PushKit to get the content to your iPhone. We have updated the PushKit framework to add support for these complication pushes. The way you use it is you create an instance of PKPushRegistry. Next, you will want to set yourself as a delegate so that you are ready to receive callbacks. And finally, you will set the decide push types and pass in the new PK push type complication that that was added in iOS 9. Once this is done, you will get a delegate callback with a new Push token, which you're going to want to upload to your servers, which is going to enable your servers to send pushes to this device. Finally, when the server does send the push, you will get the Did Receive Incoming Push With Payload callback. And this when you turn around and use the WatchConnectivity APIs to send the content over to the iPhone. So for the second part, this is where you are going to use WatchConnectivity to get the content across to the Apple Watch app now that you received it in your iOS app.


The first thing you are going to want to use is the transfer user info API that Alex discussed earlier. This will allow you to queue up timeline entries for both the past and the future that your iOS -- sorry, your Watch complication might need. Once you have queued up all the timeline entries, the last thing you want to do before you are done with your work is called a special API. It's also part of WatchConnectivity.


It's called transfer current complication user info. This is a special version of the transfer user info, and at any point in time, there can only be one current complication user info. If you call this twice, only the most recent call is the one that is tagged as the current complication user info.


When you call this, this is a hint to the system that the work is done, and on the receiving side all of these callbacks will produce this delegate callback, Did Receive User Info. So let's look at what this all would look like from a full flow.


All right? So the user has launched a sports app for the very first time.


Your app early in its life cycle will want to set up the PK push registry and set the desired types. This will register this push -- this device with the Apple push servers. So that will get pushed up to the Apple servers. It will turn around and produce a Push token, and you will get that delegate callback in your iOS app. You will want to take that token and upload it to your servers, enabling your servers to send pushes to this device in the future. At that point, the initial setup of the PushKit is done and your app can go away.


Let's say the game starts, and the server decided it needs to update the complication. It will send a push down to your device.


That will get received on the device, and we will wake up the sports app in the background and deliver the push. That was that other delegate callback.


At this point, you are going to want to look at the data in the push payload and figure out what needs to get sent across using WatchConnectivity.


You will call Transfer User Info to queue up the timeline entries, both past and future, and that will go into the outstanding user info transfers queue. And then you call the special transfer current complication user info with the one that's most important, and that's the one that should be shown on the Watch face right now. That will also go into the outstanding user info transfers queue, but it will skip to the front because it's the most important one. And because this is considered urgent, we will try to get that across to the Apple Watch right away, and wake up the WatchKit extension in the background and deliver that current complication user info.


Given conditions, some of other content might also transfer at this point in time and you will get those other timeline entries, but at least the most important one made it across.


Finally, you want to use ClockKit to update your complication. So there we go.


You have updated your complication using PushKit. We have added the new PK push type complication to enable you to very quickly update your complication using information that's on your servers. There's a couple of restrictions to be able to use these push types.


The complication must be active on the current clock face, otherwise these pushes will not be delivered, and there will be a limited number of pushes per day, so use these sparingly. Roughly one to two per hour on average, but the sports app may use them all in a short period of time.


You would use transfer user info to queue up your timeline entries. And finally, you would use transfer current complication user info to queue up the current or present timeline entry. Finally, you would use ClockKit to update the clock face.


Keep in mind that a lot of these things are budgeted. Any work you do on behalf of complication update, both on the iOS and on the WatchKit side, counts against this budget. So we recommend that any information you need to update your complication is included in that push.


The complication push type has a 4 K payload, which is larger than the standard, so that should enable you to put most of the content you needed.


If you receive one of these pushes and you turn around in your iOS app and do an NSURLSession request, you will run out of budget much faster.


So make sure you include all the content you need in the pushes. That brings us to the end of our session. Briefly going to discuss what we talked about today.


We went through the WatchConnectivity framework and APIs. We look forward to seeing what you guys can do with these APIs.


We briefly discussed NSURLSession and its use. There's other sessions that go more in depth on what and how to use NSURLSession.


And finally, we discussed how to get data to your complications, which is a more advanced topic. There's a lot of other great resources to check out.


We have some great sample code, and we have our evangelist that's ready to answer any of your questions.


As far as other related sessions, we especially suggest you check out Creating Complications with ClockKit and Networking with NSURLSession, as those are closely related to the content we discussed today. Thank you very much.


0 0