Transmettre des données à L'application Apple Watch
j'essaie de passer des données de mon application dans mon Apple Watch app. Fondamentalement, j'utilise la même méthode que j'ai utilisée pour créer le widget d'aujourd'hui et donc je passe des données par NSUserDefaults.
le problème est que lorsque j'exécute mon application, les données ne mettent pas à jour les étiquettes de L'application Watch comme je m'y attendais.
voilà ce que j'ai...
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)")
}
}
j'ai essayé de mettre ce code dans willActivate()
, cependant que ne semble pas faire une différence.
quelqu'un sait où je vais mal?
4 réponses
Je l'ai fait fonctionner en utilisant votre méthode. Je suppose qu'il y a quelques choses que vous pouvez vérifier:
1) synchronisez-vous les valeurs par défaut après avoir défini la valeur:
defaults?.synchronize();
NSLog("%@ ", defaults?.dictionaryRepresentation())
2) Avez-vous activé le groupe App à la fois dans votre application et dans votre extension?
3) Utilisez-vous le groupe app correctement nommé lors de la construction des NSDefaults? Par exemple, j'utilise:
NSUserDefaults(suiteName: "group.com.brindysoft.MyWatch");
une fois que tout ce qui est mis en place, je lance l'application, fixe la valeur par défaut, puis lance la cible coup d'oeil qui lit la valeur par défaut et qui semble fonctionner!
- toujours coincé? vérifiez vos groupes d'applications dans votre compte apple
la réponse acceptée s'applique à apple watch os 1. Voir Nsuerdefaults ne fonctionne pas sur Xcode beta avec montre OS2
pour OS2 - vous aurez besoin d'utiliser les cadres WatchConnectivity et mettre en œuvre le 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")
}
}
}
Exemple D'Utilisation
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)
}
}
dans mon code iphone / je peux invoquer le partage données ici
if #available(iOS 9.0, *) {
WatchData.shared.sendInbox()
} else {
// Fallback on earlier versions
}
et ailleurs j'ai un autre singleton discret pour watch data session.
@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)
})
}
}
}
voir l'exemple de regarder os2 app
https://github.com/shu223/watchOS-2-Sampler/tree/20eeebeed66764d0814603e97d3aca5933236299
comme l'a dit @johndpope, les Nuserdefaults partagées ne fonctionnent plus sur WatchOS2.
j'affiche une solution simplifiée qui n'est pas aussi complète que celle de john, mais qui fera le travail dans la plupart des cas.
dans votre application iPhone , suivez ces étapes:
choisir trouver le contrôleur de vue que vous voulez pousser des données à la montre Apple à partir et ajouter le cadre en haut.
import WatchConnectivity
maintenant, établir une session de WatchConnectivity avec la montre et envoyer quelques données.
if WCSession.isSupported() { //makes sure it's 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)
}
}
}
s'il vous plaît noter, cela ne fonctionnera pas si vous sautez la configuration du délégué, donc même si vous ne l'utilisez jamais, vous devez le définir et ajouter cette extension:
extension MyViewController: WCSessionDelegate {
}
maintenant, dans votre application de montre (ce code exact fonctionne pour les regards et d'autres types d'app kit de montre ainsi) vous ajoutez le cadre:
import WatchConnectivity
Ensuite, vous mettez en place la session de connectivité:
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
let watchSession = WCSession.defaultSession()
watchSession.delegate = self
watchSession.activateSession()
}
et vous simplement écouter et gérer les messages de l'application iOS:
extension InterfaceController: WCSessionDelegate {
func session(session: WCSession, didReceiveApplicationContext applicationContext: [String : AnyObject]) {
print("\(applicationContext)")
dispatch_async(dispatch_get_main_queue(), {
//update UI here
})
}
}
C'est tout.
les Éléments de la note:
- , Vous pouvez envoyer un nouveau applicationContext aussi souvent que vous le souhaitez et il peu importe si la montre est à proximité et connecté ou si la montre application est en cours d'exécution. Cela fournit les données en arrière-plan dans un d'une manière intelligente et que les données sont assis là à attendre quand le regarder application est lancée.
- si votre application de montre est réellement active et en cours d'exécution, il doit recevoir le message immédiatement dans la plupart des cas.
- vous pouvez inverser ce code pour que la montre envoie des messages à la l'application iPhone de la même façon.
- applicationcontexte que votre application watch reçoit quand il est vu sera seulement le dernier message que vous avez envoyé. Si vous avez envoyé 20 messages avant que l'application watch soit visualisée, elle ignorera les 19 premiers et traitera le 20ème.
- pour faire une connexion directe/dure entre les 2 applications ou pour les transferts de fichiers d'arrière-plan ou la messagerie en file d'attente, consultez le vidéo WWDC .
une autre façon de communiquer entre l'application et la montre est par vortex:
https://github.com/mutualmobile/MMWormhole
Envoyer:
[self.wormhole passMessageObject:@{@"titleString" : title}
identifier:@"messageIdentifier"];
id messageObject = [self.wormhole messageWithIdentifier:@"messageIdentifier"];
Recevoir:
[self.wormhole listenForMessageWithIdentifier:@"messageIdentifier"
listener:^(id messageObject) {
// Do Something
}];