J'essaie de transmettre des données de mon application dans mon Apple Watch app. Fondamentalement, j'utilise la même méthode que celle utilisée pour créer le widget d'aujourd'hui et je transmets donc des données via 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.
Voici 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()
, mais cela ne semble pas faire de différence.
Quelqu'un sait où je me trompe?
Je l'ai fait fonctionner en utilisant votre méthode. Je suppose qu'il y a deux ou trois 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 d'applications dans votre application et votre extension?
3) Utilisez-vous le groupe d'applications correctement nommé lors de la construction des NSDefaults? Par exemple, j'utilise:
NSUserDefaults(suiteName: "group.com.brindysoft.MyWatch");
Une fois tout ce qui est configuré, j'exécute l'application, définit la valeur dans les valeurs par défaut, puis exécute la cible de coup d'œil qui lit la valeur par défaut et cela semble fonctionner!
La réponse acceptée s'applique à Apple watch os 1. Voir NSUserDefaults ne fonctionne pas sur Xcode beta avec Watch OS2
Pour OS2 - vous devrez utiliser les frameworks WatchConnectivity et implémenter 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 de 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 la session de données de surveillance.
@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)
})
}
}
}
Reportez-vous à l'exemple d'application montre os2
https://github.com/shu223/watchOS-2-Sampler/tree/20eeebeed66764d0814603e97d3aca5933236299
Comme l'a dit @johndpope, les NSUserDefaults partagés ne fonctionnent plus sur WatchOS2.
Je publie une solution simplifiée qui n'est pas aussi complète que John's mais qui fera le travail dans la plupart des cas.
Dans votre application iPhone , procédez comme suit:
Choisissez trouver le contrôleur de vue que vous souhaitez pousser les données vers le Apple Watch from et ajoutez le cadre en haut.
import WatchConnectivity
Maintenant, établissez une session WatchConnectivity avec la montre et envoyez des 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)
}
}
}
Veuillez noter que cela ne fonctionnera PAS si vous ignorez la définition 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 également pour Glances et d'autres types d'applications de kit de montre), vous ajoutez le cadre:
import WatchConnectivity
Ensuite, vous configurez la session de connectivité:
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
let watchSession = WCSession.defaultSession()
watchSession.delegate = self
watchSession.activateSession()
}
et vous écoutez et gérez simplement 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 ce qu'on peut en dire.
Éléments à noter:
Une autre façon de communiquer entre l'application et la montre est via le trou de ver:
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
}];
Utilisez simplement la connectivité de veille pour communiquer entre ces deux plates-formes, vous pouvez en savoir plus à ce sujet dans le document Apple document