WatchKit开发的博客

同步新浪微博:@WatchKit开发

【译】构建AppleWatch应用(iOS App与WatchKit Extension的数据通信)

NSUserDefaults

NSUserDefaults是快速共享信息的途径。它适合存储各种快速访问和计算的小型数据,比如用户名与档案信息。如果希望使用UserDefaults,请用于静态数据这样用户不必考虑数值的变化。

你需要设定App Group来让设备通过共享容器来实现数据共享,确保手表扩展和ios target都已如此设置。基本上就是针对两个设备创建一个统一的App Group标识符。如果需要删除它,可以以类似的方法进行。

你可以通过之前创建的App Group名来使用defaults,基本上就是为特定的key键值设置对象。在iPhone上,用户输入了文本,保存,文本就存到了应用共享的UserDefaults里。在Watch上,你可以从AppGroup得到defaults然后进行手表显示内容的更新。

// on the iPhone app
letdefaults=NSUserDefaults(suiteName:"group.com.natashatherobot.userdefaults")
    letkey="userInput"
    
    overridefuncviewDidLoad(){
        super.viewDidLoad()

        textLabel.text=defaults?.stringForKey(key)??"Type Something..."
    }


    @IBActionfunconSaveTap(sender:AnyObject){
        
        letsharedText=textField.text
        
        textLabel.text=sharedText
        
        defaults?.setObject(sharedText,forKey:key)
        defaults?.synchronize()
    }

// WatchKit
classInterfaceController:WKInterfaceController{

    @IBOutletweakvartextLabel:WKInterfaceLabel!
    
    letdefaults=NSUserDefaults(suiteName:
        "group.com.natashatherobot.userdefaults")
    
    varuserInput:String?{
        defaults?.synchronize()
        returndefaults?.stringForKey("userInput")
    }

 

NSFileCoordinator

对更大型的数据来说,NSFileCoordinator是管理应用和watch扩展的共享空间里文件的方式之一。对于有限列表的内容它很合适,同时也适用于图像文件。

下面的例子是个简单的代办事项列表app,在手机上增加任务然后暑假传输到WatchKit扩展并在手表上显示。你的视图控制器需要遵循NSFilePresenter协议,除了实现两个必需方法,其它不是很关键。FilePresenter协议有一个item URL,就是填你的AppGroup标识符的地方。通过URL,你在对应目录建立一个文件。有必要的话你也可以通过操作队列来控制多线程访问。

另外,presentedItemDidChange这个代理方法,在FilePresenter里通知你是否一个对象发生了改变,来让你更新app数据而无需用户手动刷新。

然而这里还是有个关于NSFileCoordinator与NSFilePresenter 的bug而不方便在扩展里使用。具体可参见Natasha的网站。

在代办事项数组里利用FileCoordinator写入一个文件,可以通过读写文件以实现打包和解包事项的数据到事项数组,接下来可以依据文件里的事项数据计算生成表格。需要注意的是如果你设计了删除功能,而watch扩展和iPhone应用都能修改文件,会遇到线程同步的麻烦。

// iPhone app
    privatefuncsaveTodoItem(todoItem:String){
            
            // write item into the todo items array
            ifletpresentedItemURL=presentedItemURL{
                
                fileCoordinator.coordinateWritingItemAtURL(presentedItemURL,options:nil,error:nil)
                    {[unownedself](newURL)->Voidin
                        
                        self.todoItems.insert(todoItem,atIndex:0)
                        
                        letdataToSave=NSKeyedArchiver.archivedDataWithRootObject(self.todoItems)
                        letsuccess=dataToSave.writeToURL(newURL,atomically:true)
                }
            }
        }

// in the Watch
// MARK: Populate Table From File Coordinator
    
    privatefuncfetchTodoItems(){
        
        letfileCoordinator=NSFileCoordinator()
        
        ifletpresentedItemURL=presentedItemURL{
            
            fileCoordinator.coordinateReadingItemAtURL(presentedItemURL,options:nil,error:nil)
                {[unownedself](newURL)->Voidin
                    
                    ifletsavedData=NSData(contentsOfURL:newURL){
                        self.todoItems=NSKeyedUnarchiver.unarchiveObjectWithData(savedData)as[String]
                        self.populateTableWithTodoItems(self.todoItems)
                    }
            }
        }
    }

Frameworks

“If the code appears more than once, it probably belongs in a framework.(如果代码出现超过一次,应该考虑能否放到框架里)”
-WWDC 2014, Building Modern Frameworks

框架对于业务逻辑、CoreData、可重用UI组件来说很棒。就像WWDC里说的那样,你可以将重复代码放到框架里。在FileCoordinator的例子里,我们获取和读写文件的代码出现了两次,可以把它们提取到一个framework框架里。建立框架很简单:建立新target,选择Cocoa Touch framework,然后命名。它会在你的iOS应用里自动链接,因此也不要忘了在WatchKit扩展里进行链接。

关键的一点,特别是对于Swift语言来说,应该把框架认作一个API。它需要声明为公共的(public),因为这是iOS应用和watchkit扩展共用的接口。因此如果你在建立对象类,确保public关键字也加上了。这样在手机和手表应用里你导入了框架就可以访问任何公共内容。

importWatchKit
importMySharedDataLayer

classInterfaceController:WKInterfaceController{

    @IBOutletweakvarfavoriteThingsLabel:WKInterfaceLabel!
    
    overridefuncawakeWithContext(context:AnyObject?){
        super.awakeWithContext(context)
        
        letmyFavoriteThings=MySharedData().myFavoriteThings
        
        letfavoriteThingsString=", ".join(myFavoriteThings)
        favoriteThingsLabel.setText("My favorite things are \(favoriteThingsString)")
    }

}

Keychain Sharing

钥匙链共享是针对更高安全性要求的数据的。UserDefaults提供的安全性不满足时,你可以用钥匙链共享来保障信息安全及跨扩展的共享能力。

WatchKit目前的一个大问题是没有认证机制。苹果提供了KeychainIteamWrapper的示例,但API太老不支持ARC。我推荐使用这个版本https://gist.github.com/dhoerl/1170641,它基于ARC并有清晰的接口。

根据问题是如何通过access group初始化KeychainItemWrapper。与AppGroup的概念类似,设备之间有共享空间。你在iOS和WatchKit扩展中都需要钥匙链来访问用户数据。通过键值存储体系,你设定用户名和密码并用同一个标识符建立同一类型的keychain项。这个例子里仅展示了当用户填好用户名密码时WatchKit扩展展示数据的这一工作过程。

// iPhone app
@IBActionfunconSaveTap(sender:AnyObject){
        
        letusername=usernameTextField.text
        letpassword=passwordTextField.text
        
        letkeychainItem=KeychainItemWrapper(identifier:"SharingViaKeychain",accessGroup:"W6GNU64U6Q.com.natashatherobot.SharingViaKeychain")
        
// WatchKit extension
letkeychainItem=KeychainItemWrapper(identifier:"SharingViaKeychain",accessGroup:"W6GNU64U6Q.com.natashatherobot.SharingViaKeychain")
        
        
        letpasswordData=keychainItem.objectForKey(kSecValueData)asNSData
        letpassword=NSString(data:passwordData,encoding:NSUTF8StringEncoding)
        
        letusername=keychainItem.objectForKey(kSecAttrAccount)as?String

Q&A (暂不翻译)

 

评论

热度(3)