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.
Related
I am trying to read the Pasteboard for 5 times in the applicatioDidEnterBackground section of the AppDelegate. To print the string I use print(UIPasteboard.general.string!) but it works only into the function and it doesn't in the other nested functions. Let me explain:
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
print(UIPasteboard.general.string!) //here it works perfectly and prints the string correctly
for _ in 0...5 {
print(UIPasteboard.general.string!) //here it returns nil
}
}
I have read other asks similar to the mine but no one of that helped me. I don't know if this is a security restriction, but if you can help me I'll appreciate 🙂
iOS 9 changed UIPasteboard to disallow background access:
iOS 9 UIPasteboard won't work in the background
Apple Developer Forums / App Frameworks / Cocoa Touch
UIPasteboard is not available in background
Presumably they made this change to prevent background apps from spying on your pasteboard contents. Sometimes people use the pasteboard to copy a password from one app to another, so blocking background pasteboard access is a security issue.
Also, some apps (like Facebook) are known to collect as much data about the user as possibly while having much looser privacy policies than Apple's. Blocking background pasteboard access is a way to reduce Facebook's ability to spy on your non-Facebook activities.
I am writing a simple app with several controllers.
After running the app using Complication interface I would like to skip main view controller and immediately pass to the second one. I know how to perform this action, but have no idea how to get the info that the app was launched using Complication. Is it possible? If so, how?
You can implement the handleUserActivity(_ userInfo: [NSObject : AnyObject]?) of the WKExensionDelegate to check if the app was launched from the complication. You would also probably want to take a look at the CLKComplicationDataSource Protocol Reference Launch Options for information on the userInfo passed to handleUserActivity
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.
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.
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.