Передача данных в приложение Apple Watch
Я пытаюсь передать данные из своего приложения в приложение Apple Watch. В основном, я использую тот же метод, что и для создания виджета Today, поэтому я передаю данные через NSUserDefaults.
Проблема заключается в том, что при запуске моего приложения данные не обновляют ярлыки в приложении Watch, как я ожидал бы.
Вот что я имею...
override init(context: AnyObject?) {
// Initialize variables here.
super.init(context: context)
// Configure interface objects here.
NSLog("%@ init", self)
var defaults = NSUserDefaults(suiteName: "group.AffordIt")
var totalBudgetCalculation = ""
if (defaults!.stringForKey("totalBudgetWidget") != nil) {
println("Worked")
totalBudgetCalculation = defaults!.stringForKey("totalBudgetWidget")!
initialBudgetLabel.setText("Initial: \(totalBudgetCalculation)")
}
var currentBudgetCalculation = ""
if (defaults!.stringForKey("currentBudgetWidget") != nil) {
currentBudgetCalculation = defaults!.stringForKey("currentBudgetWidget")!
currentBudgetLabel.setText("Current: \(currentBudgetCalculation)")
}
}
Я попытался поместить этот код в willActivate()
, однако это, похоже, не имеет значения.
Кто-нибудь знает, где я ошибаюсь?
Ответы
Ответ 1
Это относится только к ОС 1. Ниже приведены лучшие ответы.
Я получил это с помощью вашего метода. Я думаю, есть несколько вещей, которые вы можете проверить:
1) Синхронизируете ли вы значения по умолчанию после установки значения:
defaults?.synchronize();
NSLog("%@ ", defaults?.dictionaryRepresentation())
2) Включили ли вы группу приложений как в приложении, так и в добавочном номере?
![App Group capability for Watch Extension Target]()
3) Используете ли вы правильно названную группу приложений при создании NSDefaults? Например, я использую:
NSUserDefaults(suiteName: "group.com.brindysoft.MyWatch");
После того, как все, что я настроил, я запустил приложение, установите значение по умолчанию, затем запустите цель glance, которая считывает значение из значения по умолчанию, и это, похоже, работает!
![enter image description here]()
- Все еще застряли? проверьте группы приложений в вашей учетной записи Apple
Ответ 2
Принятый ответ относится к Apple Watch OS 1. См. NSUserDefaults, не работающие в бета-версии Xcode с Watch OS2
Для OS2 - вам нужно будет использовать платформы WatchConnectivity и реализовать WCSessionDelegate.
import WatchConnectivity
import WatchKit
@available(iOS 9.0, *)
var alertDelegate:HomeIC? = nil
public class WatchData: NSObject,WCSessionDelegate {
var session = WCSession.defaultSession()
//
class var shared: WatchData {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: WatchData? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = WatchData()
}
return Static.instance!
}
public func session(session: WCSession, didReceiveFile file: WCSessionFile){
print(__FUNCTION__)
print(session)
}
public func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
print(__FUNCTION__)
print(session)
alertDelegate?.showMessage("didReceiveApplicationContext")
}
public func sessionReachabilityDidChange(session: WCSession){
print(__FUNCTION__)
print(session)
print("reachability changed:\(session.reachable)")
let text = session.reachable ? "reachable" : "unreachable"
alertDelegate?.showMessage(text)
}
public func sessionWatchStateDidChange(session: WCSession) {
print(__FUNCTION__)
print(session)
print("reachable:\(session.reachable)")
// alertDelegate?.showMessage("sessionWatchStateDidChange")
if !session.receivedApplicationContext.keys.isEmpty {
alertDelegate?.showMessage(session.receivedApplicationContext.description)
}
}
public func session(session: WCSession, didReceiveMessageData messageData: NSData){
if !session.receivedApplicationContext.keys.isEmpty {
alertDelegate?.showMessage(session.receivedApplicationContext.description)
}
}
public func session(session: WCSession, didReceiveMessage message: [String : AnyObject]){
print(__FUNCTION__)
if let data = message["data"] {
alertDelegate?.showMessage(data as! String)
return
}
}
public func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
print(__FUNCTION__)
if let data = message["data"] {
alertDelegate?.showMessage(data as! String)
return
}
guard message["request"] as? String == "showAlert" else {return}
}
public func activate(){
if WCSession.isSupported() { // it is supported
session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
print("watch activating WCSession")
} else {
print("watch does not support WCSession")
}
if(!session.reachable){
print("not reachable")
return
}else{
print("watch is reachable")
}
}
}
Пример использования
class HomeIC: WKInterfaceController {
// MARK: Properties
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Initialize the 'WCSession'.
WatchData.shared.activate()
alertDelegate = self
}
internal func showMessage(msg:String){
let defaultAction = WKAlertAction(title: msg, style: WKAlertActionStyle.Default) { () -> Void in }
let actions = [defaultAction]
self.presentAlertControllerWithTitle( "Info", message: "", preferredStyle: WKAlertControllerStyle.Alert, actions: actions)
}
}
![enter image description here]()
в моем коде iphone/я могу вызвать обмен данными здесь
if #available(iOS 9.0, *) {
WatchData.shared.sendInbox()
} else {
// Fallback on earlier versions
}
А где-то еще у меня есть еще один отдельный синглтон для сеанса просмотра данных.
@available(iOS 9.0, *)
public class WatchData: NSObject,WCSessionDelegate {
var session = WCSession.defaultSession()
var payload:String = ""
class var shared: WatchData {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: WatchData? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = WatchData()
}
return Static.instance!
}
public func sessionReachabilityDidChange(session: WCSession){
print(__FUNCTION__)
print(session)
print("reachability changed:\(session.reachable)")
if (session.reachable){
}
}
public func sessionWatchStateDidChange(session: WCSession) {
print(__FUNCTION__)
print(session)
print("reachable:\(session.reachable)")
}
public func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) {
print(__FUNCTION__)
guard message["request"] as? String == "showAlert" else {return}
guard let m = message["m"] as? String else { return }
print("msg:",m)
}
public func sendInbox(){
if (!session.reachable){
if WCSession.isSupported() { // it is supported
session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
print("iphone activating WCSession")
} else {
print("iphone does not support WCSession")
}
session.activateSession()
}
if(session.paired){
if(session.watchAppInstalled){
print("paired | watchAppInstalled")
}
}else{
print("not paired | or no watchAppInstalled")
}
if(!session.reachable){
print("not reachable")
return
}else{
/*let transfer:WCSessionUserInfoTransfer = (session.transferUserInfo(["data" : "Test2"]) as WCSessionUserInfoTransfer?)!
if(transfer.transferring){
print("-> iphone")
}else{
print("!-> iphone")
}*/
session.sendMessage(["data" :"test"],
replyHandler: { reply in
},
errorHandler: { error in
print(error)
})
}
}
}
См. пример приложения watch os2
https://github.com/shu223/watchOS-2-Sampler/tree/20eeebeed66764d0814603e97d3aca5933236299
Ответ 3
Как сказал @johndpope, общие NSUserDefaults больше не работают на WatchOS2.
Я публикую упрощенное решение, которое не так полно, как Джон, но в большинстве случаев выполнит свою работу.
В приложении для iPhone выполните следующие действия:
Выберите контроллер представления, с которого вы хотите передать данные в Apple Watch, и добавьте фреймворк вверху.
import WatchConnectivity
Теперь установите сеанс WatchConnectivity с часами и отправьте некоторые данные.
if WCSession.isSupported() { //makes sure it not an iPad or iPod
let watchSession = WCSession.defaultSession()
watchSession.delegate = self
watchSession.activateSession()
if watchSession.paired && watchSession.watchAppInstalled {
do {
try watchSession.updateApplicationContext(["foo": "bar"])
} catch let error as NSError {
print(error.description)
}
}
}
Обратите внимание, это НЕ будет работать, если вы пропустите настройку делегата, поэтому даже если вы никогда не используете его, вы должны установить его и добавить это расширение:
extension MyViewController: WCSessionDelegate {
}
Теперь в приложении для часов (этот точный код работает и для Glances, и для других типов приложений для часов) вы добавляете фреймворк:
import WatchConnectivity
Затем вы настраиваете сеанс связи:
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
let watchSession = WCSession.defaultSession()
watchSession.delegate = self
watchSession.activateSession()
}
и вы просто слушаете и обрабатываете сообщения из приложения iOS:
extension InterfaceController: WCSessionDelegate {
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
print("\(applicationContext)")
dispatch_async(dispatch_get_main_queue(), {
//update UI here
})
}
}
Это все, что нужно сделать.
Примечания:
- Вы можете отправить новое приложение контекста так часто, как вам нравится, и это
не имеет значения, находятся ли часы рядом и подключены ли часы
приложение работает. Это доставляет данные в фоновом режиме в
интеллектуальный способ, и эти данные сидят там, ожидая, когда
приложение Watch запущено.
- Если ваше приложение для часов действительно активно и работает, оно должно получить
сообщение сразу в большинстве случаев.
- Вы можете отменить этот код, чтобы часы отправляли сообщения
Приложение для iPhone таким же образом.
- applicationContext, который ваше приложение для часов получает при просмотре, будет ТОЛЬКО последним отправленным вами сообщением. Если вы отправили 20 сообщений до того, как приложение просмотра будет просмотрено, оно проигнорирует первые 19 и обработает 20-е.
- Чтобы установить прямое/жесткое соединение между двумя приложениями, фоновую передачу файлов или обмен сообщениями в очереди, посмотрите WWDC-видео.
Ответ 4
Другим способом общения между приложением и часами является червоточина:
https://github.com/mutualmobile/MMWormhole
Send:
[self.wormhole passMessageObject:@{@"titleString" : title}
identifier:@"messageIdentifier"];
id messageObject = [self.wormhole messageWithIdentifier:@"messageIdentifier"];
Recieve:
[self.wormhole listenForMessageWithIdentifier:@"messageIdentifier"
listener:^(id messageObject) {
// Do Something
}];