How to send data from Iphone to Watchkit in OS2 in SWIFT - swift

I want to send a dictionary from iPhone to Watchkit in watchOS 2.
In watchOS 1 it works fine for me with appgroups but in watchOS 2 I know that we have to use WCSession but I don't know how to use it.
Please help me find the solution.

This blog post should help you out.
From that post: First, you'll create and activate a WCSession like so:
if (WCSession.isSupported()) {
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession()
}
For transferring a dictionary:
let applicationDict = // Create a dict of application data
let transfer = WCSession.defaultSession().transferUserInfo(applicationDict)
Then, on the receiving end, you'll need to implement session:didReceiveUserInfo: (Developer documentation). Note, according to Apple's "watchOS2 Transition Guide,"
To begin communication, both your Watch app and your iOS app must have an active WCSession object. Typically, each app creates, configures, and activates a session object at launch time and stores a reference to it in a central location. When you want to send data, you retrieve the session object and call its methods.

Related

NSUbiquitousKeyValueStore.didChangeExternallyNotification fires also when change is done on device itself

My app worked fine until iOS 16.0.
When I write to iCloud: NSUbiquitousKeyValueStore then the didChangeExternallyNotification notification is triggered also on the device I wrote to iCloud. So it did not change externally but internally. Therefore my app runs into a loop ;-(
Does anyone have the same issue?
I had contact with Apple and found at the you need to use 1 var:
let defaultsAppGroup = UserDefaults(suiteName:"xxx")
When using:
UserDefaults(suiteName:"xxx").set()
Multiple instances of UserDefault are made and therefore a didChangeExternallyNotification will be triggered to the other instances.

Are there still any ways to use App Groups in watch?

I want to get data from userDefaults to use in an Apple Watch app. I'm currently using WatchConnectivity. But for making session, the viewdidload should be open. Then the Phone only sends the data to the Watch when the iPhone app is loaded (viewDidLoad). To solve this, I want to use appGroupUserDefaults. But it doesn't work when I try to load the data in override func awake(withContext context: Any?) like this.
let loadedButtonList = appGroupUserDefaults.object(forKey: "Buttontitles")
if (loadedButtonList as? [String] != nil) {//do something}
It seems like loadedButtonList is nil. Can't I use appGroupUserDefaults in this watchOS version? And Does anyone know the way to share data like this without using WatchConnectivity??
You can't use App Groups to share data between phone and watch since WatchOS3.
You can use updateapplicationContext to guarantee the data will be passed to Apple Watch.

Swift UserDefault :sharing data via share group doesn't work

just started swifting recently and got an issue by using app group to share data between iOS devices.
basically I have setup the project followed the steps below:
[iPhone]
Enabled App Group for the iPhone target
initialed data below(groupID is matched what I set in the project):
sharedDefaults = NSUserDefaults.init(suiteName: groupID)
sharedDefaults?.setObject("User Default Shared String", forKey: "test")
sharedDefaults?.synchronize()
double checked the test string by loading user default locally, which is able to display in the Log.
let t_sharedDefaults = NSUserDefaults.init(suiteName: groupID);
t_sharedDefaults?.synchronize();
let str = t_sharedDefaults?.valueForKey("test") as! String;
print(str);
[watch extension]
Create a new watch extension target.
Enable App Group.
Load the User default data under awake with context via the code below:
sharedDefaults = NSUserDefaults.init(suiteName: groupID);
sharedDefaults?.synchronize();
let str = sharedDefaults?.valueForKey("test")
print(str);
I have run the iPhone target first, and then the watch app.
However, the watch app is not able to read expected data from the user default.
I have also uploaded the test project in Github, please let me know if you have any thought on this issue.
[Github]
https://github.com/mattcn/WatchOS_DataSharing
Thanks for your help in advance.
In Watch OS1 this worked, but in Watch OS2 there has been some changes. You need to use something called WatchConnectivity to send the data you want to save to the watch.
so even if you use shared user defaults or app groups the data you put inside them will be on the watch and so not accessible from the iOS app.
To send data to the watch you can use the WatchConnectivity framework.
Thanks Ashish to bring the difference between OS1 and OS2 up.
just found a good reference from:
NSUserDefaults(suiteName:) on iOS 9 and WatchOS 2 - not working?
In watchOS 2 you need to keep in mind that there is 2 different processes running:
Apple Watch Process
iPhone Process
Both of these processes have their own sandbox that's why they call it "native", so if you try to use the shared NSUserDefaults it will not work because the Apple watch app has a completely different sandbox than the host iPhone app.
If you want to save something from your phone to the NSUserDefaults on the Apple watch Target:
Use WatchConnectivity to send the data you want to save to the watch. Then when the watch receives the data you sent to it, save it to the Apple watch's default NSUserDefaults.

Problems with Watchkit Extension NSURLSession in Swift

I'm trying to call my local API to turn off my house lighting from my watch, but I'm having trouble with calling a url from within the watchkit extension.
In my ViewController (iPhone app) I've got exactly the same code (which works), but somehow it doesn't work when I call it in the InterfaceController from the Watchkit Extension.
#IBAction func confirmTapped() {
let url = NSURL(string: "http://homeserver.local/api/lights/4/0")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
print(NSString(data: data!, encoding: NSUTF8StringEncoding))
}
task!.resume()
}
I've also attached a gist: https://gist.github.com/f72125cd4678069af7af.git
Am I missing something obvious?
While Frederick's advice was solid advice for WatchKit 1, openParentApplication:reply is no longer available in WatchKit 2. With WatchKit 2, you would instead definitely open the NSURLSession in the WatchKit App Extension itself, because using a WCSession means that the URL would only be opened if and when the iPhone application itself is running, either in the foreground or if it happens to still be running in the background because the system has not closed it.
It is possible that the problems you were experiencing were because you needed to add the 'Allows Arbitrary Loads' property on the WatchKit App Extension. See discussion in this possibly related thread: NSURLSession returns data as Null on Watch OS2 using Objective-C
I don't know if it's a good thing to start a NSURLSession from within the Watch extension. If the request takes to long, it will be cancelled.
Maybe you could ping the watch via openParentApplication:reply and handle the NSURLSession on your iPhone app.

Core Data (Magical Record) + WatchKit Extension + Cocoa Touch Framework

Here's what I'm up to:
I now have
An iPhone app
A WatchKit Extension
A Cocoa Touch Framework that holds all my shared classes
What I would like to accomplish, is having a persistent storage (Core Data) that is shared between my iPhone app and WatchKit Extension.
So this is what I've done so far
Create an app group to have a shared container.
Add a Core Data Model (Model.xcdatamodeld) to my Cocoa Touch Framework.
Created one Entity in this model
Created an NSMangedObject subclass for this entity and added is to my Cocoa Touch Framework
Added a DataManager class to my Cocoa Touch Framework
Here what the initializer in my DataManager looks like
public init() {
let sharedContainerURL: NSURL? = NSFileManager.defaultManager().containerURLForSecurityApplicationGroupIdentifier("group.com.company.Project")
if let sharedContainerURL = sharedContainerURL {
let storeURL = sharedContainerURL.URLByAppendingPathComponent("Model.sqlite")
MagicalRecord.setupCoreDataStackWithAutoMigratingSqliteStoreAtURL(storeURL)
let station: Station? = Station.MR_createEntity()
}
}
The issue I'm running into
When I init my DataManager from the iPhone app's AppDelegate, no crash occures, but station will be nil.
When I replace the last line with let stations: [Station]? = Station.MR_findAll() as? [Station] the app crashes and shows the following error: A fetch request must have an entity.
I've searched all of SO and Magical Records issues on GitHub, but couldn't find anything to push me in the right direction. All help is much appreciated.
Thanks to Leo Natan's comment I now realize that I should store my core data in both my iPhone app's sandbox as well as in my WatchKit app's sandbox. And not inside a shared container, like I was trying to.
When building for Watch OS 2, I'll be able to use the WatchKit Connectivity Framework to keep both databases in sync. In the meanwhile I could use a solution like MMWormhole to achieve the same thing.
I have done my task in my live app with watch and iPhone both. i not needs 2 stores. and MMWormhole is good one to help for instant call back both the sides. also i have handled watch's event by handleWatchKitExtensionRequest.
The sync is proper and works well.
I have followed this forum. - http://www.makeandbuild.com/blog/post/watchkit-with-shared-core-data
Hope this may help you.