How can I persist watchOS data synced from iOS? - ios

I have an iOS app, and I would like the watchOS app to have synchronized data. Currently, the data is from Firestore, since it's also synced from the web, but I'm open to re-architecting the app.
Fundamentally, what I need is the ability to synchronize user data across all three platforms: watchOS, iOS, and the web.
Currently I have the iOS sending the data to watchOS, but on the Watch if I kill the app I lose all the state until I sync again. Ideally, the state would persist until there is a chance to sync again. So, there needs to be some persistence on watchOS. It seems there's a few options:
AppStorage / UserDefaults seems like it might work, although I've had problems with it not liking arrays and not finding expected values in Info.plist
CoreData seems like the most viable option from what I've seen so far, but a lot of code to synchronize data between watchOS and iOS and especially if I'm also trying to synchronize with Firestore
JSON seems like it's technically an option but a lot of code to serialize/deserialize
Both the watchOS and the iOS apps are SwiftUI, and I'm trying to determine how to keep them on the same page. I have apps on my Watch that seem to do this ok, but I'm having trouble figuring out how to do it myself.

Related

Share AsyncStorage from iOS react native app with Apple Watch

I'm developing the main app with react native and the Apple Watch with Swift.
The main app (react native) uses AsyncStorage to store some values, that then are used as params for a fetch that shows a list.
After running the simulator, I found manifest.json inside
~/Library/Developer/CoreSimulator/Devices/D10E869B-040B-446F-9B8B-754F111442EC/data/Containers/Data/Application/AC837AFE-312B-4861-906D-EC9EEE7D029B/Document
s/RCTAsyncLocalStorage_V1
with the data inside.
I need to access those values in the Apple Watch in Xcode to do the same job as the iOS app. How do I access that data?
Since Apple Watch apps run independently from iOS app since watchOS 2, there’s really no way to directly access the data stored locally on iPhone — you’ll need to maintain some form of communication between your iOS and watchOS apps.
The framework intended for this is called WatchConnectivity. I see two more-or-less suitable solutions for your case:
Using transferFile to transfer your file from an iOS device to an Apple Watch whenever it got updated. The viability of this option highly depends on how big your file is.
Or you can just use updateApplicationContext to pass an already serialized data instead of transferring a raw JSON file — again, highly depends on your specific needs.
Unfortunately, I don’t know how WatchConnectivity is supposed to work with ReactNative. If you want a deeper introduction to this framework — I highly recommend watching this amazing video from WWDC 2015.

Did Apple change NSUserDefaults sharing from iOS app to watchOS app

I want to ask about how to use NSUserDefaults on the watchOS app.
Is its data different from the iOS app's NSUserDefaults's data?
There are a lot of stackoverflow questions about this topic and all of them have same answers. That said, for example
Watch apps that shared data with their iOS apps using a shared group
container must be redesigned to handle data differently. In watchOS 2,
each process must manage its own copy of any shared data in the local
container directory. For data that is actually shared and updated by
both apps, this requires using the Watch Connectivity framework to
move that data between them.
However, all the quoted text disappeared from the web page referred, see this accepted answer.
Instead, in current Apple Docs. There is
Additionally, iOS automatically forwards a read-only copy of your iOS
app’s preferences to Apple Watch. Your WatchKit extension can read
those preferences using an NSUserDefaults object, but it cannot make
changes directly to the defaults database.
I have 2 questions:
Which one is correct: all of StackOverflow questions' answers I mentioned above, or, the Apple Docs
Which mechanism iOS use to forward NSUserDefaults object to watchOS app? Is it reliable to be relied on for future development and how recent the data is up to date? Can this feature be deprecated in the near future?
Many thanks
To answer your first question, both answers you quoted from StackOverflow and Apple are correct. Apple forwards the iOS app's NSUserDefaults as read-only values, but the watch has it's own NSUserDefaults for its preferences. The main takeaway from the documentation is for watch apps to move away from shared container groups that use NSUserDefaults, (as this was how WatchKit apps were implemented). In watchOS, Apple has added WatchConnectivity which is the standard for sharing data between the iOS and watch apps.
To answer your second question, rely on NSUserDefaults as you would normally to store preferences related to each app separately and use WatchConnectivity for sharing data between apps.

How to access iCloud as core data for iCloud is deprecated

I am working on an app using core data as I thought I could use sync functionality provided by core data for iCloud for syncing data between iPad and iPhone, now it is deprecated.
I came across CloudKit but it is mainly to create and manage data that can be consumed by community of end users but not just one like chat apps. My app is only for single user so that user can sync their data between their apple eco system devices.
I am new to iOS development so it would be helpful to know which technology will meet my requirements.
In short, can you please suggest what should I use
If have to store data on phone for offline use
Then sync it across devices if user have say iPhone, iPad, and iWatch
P.S. Can you please suggest something that doesn't need the user to be signed into iCloud while saving the data.
The CoreData/iCloud integration is deprecated in iOS 10 / macOS Sierra, and there is no replacement (at least so far).
Way forward so far :
Use third party framework such as Ensembles : http://www.ensembles.io
Use CloudKit, which can be used for that. See this for a help : https://nickharris.wordpress.com/2016/02/09/cloudkit-core-data-nsoperations-introduction/
Note that CoreData/iCloud integration will still be working for some time in the future. Apps that are using it will not suddenly stop working.
Apple just released a new container for Core Data that can sync across devices with iCloud.
Get started here: https://developer.apple.com/documentation/coredata/mirroring_a_core_data_store_with_cloudkit/setting_up_core_data_with_cloudkit
Note, this requires iOS 13.
You should take a look at the videos from the latest WWDC.
Here is something about CloudKit Best Practices and whats new in cloud kit
CloudKit really have some nice out of the box solutions and you dont have to bother about security. Also the newest functionality enables you to use notifications for synchronising apps using the same apple id and even beyond, as the user can now opt to share certain data.
Depending how much data you are syncing, NSUbiquitousKeyValueStore.default() is also an option. But only for very less data

Persistent storage on Apple watch

I am looking for a way to store something on the Apple watch app that I can read later on enabling me to identify it uniquely.
I don't see any API at the moment that would let me do this. The closest I have got is to save an image in cache but since its just a cache, its not reliable.
My goal is to uniquely identify an Apple Watch.
Any pointers would be much appreciated.
You can save information to be accessible from both watch and iPhone in NSUserDefaults and App Groups like this:
let defaults = NSUserDefaults(suiteName: "group.com.your-bundle-id.app-group-name")
where "group.com.your-bundle-id.app-group-name" is your app group identifier.
For more details about NSUserDefaults and other ways to share data between Watch and iPhone see
Architecting Your App
for the Apple Watch
User App Groups OR NSUserDefaults to share data between your iOS apps.
Easily share small amounts of data between your iOS app and your
WatchKit extension with App Groups and NSUserDefaults. For access to
other resources, such as a Core Data store, use a shared container
between your iOS app and your WatchKit extension to simplify data
access and provide up to date information.
I think that this would be very useful, not only for identifying the watch, but also to load the UI faster (without synchronizing lots of data via Bluetooth first).
However, there seems to be no solution at the moment to do this.
It also seems to be impossible to get the hardware identifier of the watch.
Maybe this will be possible once normal third-party developers are allowed to write real watch apps (not just extensions of iPhone apps). The WWDC is in June.

Questions concerning iCloud + core data

I have an app on the app store, that uses coredata as storage. I wan't to update the app with iCloud synchronization as new feature. Following apple`s sample code, I managed to have my core data storage synchronize between devices.
However, I'm experiencing problems when either iCloud synchronization is turned off/on in the app on only one of the devices, or when the app is deleted from the device and the reinstalled. In both cases, data is not synchronized back to the device, although it is available just fine on a second device (which was not disabled/reinstalled).
I also found that all storage is effectively erased completely, when I delete the app from all devices, and then reinstall. Althrough I get a couple of merge notifications in the console (even some without errors), I can't see no data in the local storage of the device.
Browsing the mobile documents folders on my mac still reveals lots of transaction logs in the icloud storage of my app.
Even deleting the app from all devices and starting from scratch wont sort things out. I will end up in a situation where data is either only synced to one device, or not synced at all.
I wonder if there is anything I can do about this inconsistent state that is created when only one device is temporarily iCloud disabled, or the app is deleted from ONE device?
As for my code, its an 1:1 copy of the recipces example from apple.
Daniel Pasco talked about using Core Data and iCloud together at NSConference 2012. Some notes from that blog post:
launching with -com.apple.coredata.ubiquity.logLevel 3 to get a spamfest in the message log saying what Core Data and iCloud are doing.
The conclusion from this talk appears to be that using Core Data and iCloud are really not ready for each other at this stage.
He posted an updated Core Data Recipes project on Github which may or may not fix your problem.
Apple makes it seem easy, but there are a number of nuances with regard to correctly seeding iCloud with data, and what happens afterwards when iCloud support is toggled on and off on different devices.
I implemented a sample project that demonstrates a straightforward way to add iCloud support to Library-style CoreData apps. It's called iCloudStoreManager and it's available on github.
I'm still testing it before I add iCloud support to one of my own production apps. It's working, but I see unexpected errors and delays when an iPad 3 is in the mix. It works, but with long delays.
I've also tested with iPhone 4, iPhone 4S, and the original iPad, and any mix of those devices works well in my experience.

Resources