Detect user's watchOS version from iOS app - ios

I have an iOS app where I have some settings in the iOS app related to the watch. I only want to show them if the user has an Apple Watch that's compatible with my app.
In WatchConnectivity I can query WCSession's isPaired property to see if the user has a watch but I can't figure out how to determine the watchOS version (it needs to be >5.0 to use my app).
Is there a way to determine the watchOS version from the iOS app?

If the settings only apply if the user has your watch app installed, you probably just want to check that directly using WCSessions isWatchAppInstalled property.
Things get much trickier if you want to get the paired watch's OS version regardless of whether your app is installed. If the user runs the watch app, you could just grab the version on the watch side and send it over (with updateApplicationContext(_:)). Otherwise, there's no way that I know of to get the watchOS version -- and that kind of makes sense. From a platform security perspective, if the user hasn't installed your app then the details of their watch are kind of none of your business.

Here are two possible solutions. Number 1 checks for the OS which if I understand your question you already know, but then 2 checks for the OS version which is WatchOS 5.0 and later. This is what I have done so I hope it helps you.
1.
#if os(watchOS)
...your code
#endif
if #available(watchOS 5.0, *) {
...your code
}

Related

Is there a way to exclude an app that requires pedometer from the App Store?

I'm working on an app that requires step counting.
There are several devices that don't support this feature (for example in my iPad mini 2, CMPedometer.isStepCountingAvailable() returns false).
Since the app heavily relies on the pedometer, I'd like to make it unavailable to download for unsupported devices.
I would expect to find a pedometer-related entry in the documentation of UIRequiredDeviceCapabilities, but there is none.
Is this possible in any way?
No, it is not possible to make an app unavailable for download on the basis of CMPedometer.isStepCountingAvailable(). The preferred method would be to display a notice to the user once downloaded, that their device does not support the required functionality.

WatchOS app not detecting companion iOS app

I am making an independent Apple Watch app (but with a companion iPhone app which is not necessary for the watch app to function.)
The app uses WatchConnectivity to sync data between devices if iPhone companion app is installed. I am able to call session.updateApplicationContext() on the iOS app and receive session(didReceiveApplicationContext) on the Watch app. But going the other way is not possible. I always get an NSError code of 7018 which means the iOS companion app is not installed.
I have made sure both watchOS and iOS app are installed in simulator (and tested on my actual devices, iPhone 11 & Watch series 5.) But getting the same failed results from watchOS -> iOS.
I noticed there is a new WCSession instance variable available for watchOS 6.0+ isCompanionAppInstalled. When I read this variable after my WCSession is activated on my watch app, it always return false.
Is there anything else I need to look out for? I am thinking maybe there is something I did wrong in all the different info.plist. But I have checked them multiple times.
my info.plist files:
In my watch app:
WKWatchKitApp is YES
WKCompanionAppBundleIdentifier is com.abc.myapp
In my watch extension:
App can run independently of companion iPhone app is YES
NSExtension
WKAppBundleIdentifier is com.abc.myapp.watchkitapp
NSExtensionPointIdentifier is com.apple.watchkit
iOS app bundle identifier is com.abc.myapp
watchOS app is com.abc.myapp.watchkitapp
watchOS app extension is com.abc.myapp.watchkitapp.watchkitextension
Is there anything else I might be overlooking?
Thank you very much for any help/insight you can offer into this.
Ok. I found a way to get rid of the error and have the watch connectivity work from watch to iPhone.
Originally I wanted the watch app to be independent so in the watch extension target in Xcode, the check box "Supports Running Without iOS App Installation" is checked. But as soon as I uncheck this box, WCSession.isCompanionAppInstalled returns true and error goes away. Syncing from watch to iPhone starts working.
So hopefully this is not intended behavior and will soon be fixed by Apple. (I filed a bug report.) But for now, I am just going to leave the independent watchOS app unchecked because I do want WatchConnectivity in case iPhone app is installed by user.
Thank you for reading and good luck with your programming.
If you have "App is only available as a standalone watchOS app" in Info.plist, delete it even if it is false. Leave only "App can run independently of companion iPhone app". Also don't forget to set "WKCompanionAppBundleIdentifier" for Watch App (not extension). At least it works on real device for me with these parameters.
This seems to be a bug. Sometimes when I start my WatchOS app, it gets WCSession.isCompanionAppInstalled = false all the time, even though the companion app on the iPhone is running, and other apps are able to communicate with the phone.
This seems to go away when I force-restart the app on the watch (press side button, then swipe the app to the left and press the big red button, then start the app again). After the restart, everything seems to work fine.
This has happened only on Testflight builds so far. If it happens in production builds, I'm going to file a bug.
My iOS app will not launch in the Simulator if I uncheck "Supports Running Without iOS App Installation".

New feature added for newer version but not for older version

If we use an API for adding a feature, which is compatible only in iOS10 (For example Siri API), should I change my app compatibility to iOS10 or do I have a choice to inform the end user that, this feature is available only in iOS 10, but the app works normally in prior version.
thank you,
You should build against the iOS 10 SDK, set your deployment target to iOS 9, then use some Swift like this:
if #available(iOS 10, *) {
// use SFSpeechRecognizer
} else {
// show message to user
}
Clearly Apple won't be terribly happy with you in app review if it's a really critical feature that isn't available, but as long as it's not central to the app's purpose and you're clear with the user, I think the above is the best solution.
I wrote a tutorial on Swift availability checking that you might find useful.

Remove support for iPhone with new updated version of app

We released few versions of our app with universal support ( i.e. app is supported both on iPhone and iPad). Now with new version of our app (1.14) we want that this version should be available to iPad only. This means 1.14 should be available only on iPad and iPhone user may not able to install it. But when we change setting in Xcode from Universal to iPad only it gives error while uploading ipa to app store that if previous version of app supported iPhone then in updated version of app we cannot remove iPhone support. Now we are looking for solution to this problem. Please guide us what are way to over come this issue. Due to this issue we have to delay our app release so kindly give us possible suggestions as soon as possible.
There is no good way of doing what you want. Apple deliberately don't want you removing functionality for existing users.
Maybe the only way forward is to remove your current app from sale and submit a new, iPad-only version. You'll lose your reviews, sales rank, etc.

settings bundle not working on watchOS 2

This was NOT a problem on watchOS 1, but now on watchOS 2 I cannot read the values on the watch extension.
According to Apple docs, it is possible.
According to some people on this thread, it is possible.
According to an Apple employee on this thread, it is possible.
I'm setting everything up correctly as far as I can tell:
I enabled App Groups on both iOS app and watch extension with the
same identifier.
I added Settings-Watch.bundle to the iOS app
and added the ApplicationGroupContainerIdentifier with the same
identifier to the plist
When I initialize an NSUserDefaults object with the identifier as the suite name, I cannot read values on the watch extension. I can read them on the iOS app. This happens in simulator and real device.
Please DON'T post an answer about how to do this with Watch Connectivity. It is possible to do this with just Shared App Groups on watchOS 2 without Watch Connectivity, people are able to do it, and here it is straight out of the docs:
In watchOS 2, your WatchKit extension may read the values of preferences, but you cannot write new values. Preferences in watchOS 2 are forwarded from iOS to Apple Watch, but any modifications you make are not sent back to iOS.
I've edited my answer. Previously, it spoke about the inability to use App Groups to sync data in watchOS 2, but your specific question is regarding the Settings Bundle, which still syncs from iOS to Apple Watch in watchOS 2.
I am unable to get this to work in Xcode 7.1 / 7.2 in Simulator, but it does work on a real device. From the docs:
Preferences in watchOS 2 are forwarded from iOS to Apple Watch, but any modifications you make are not sent back to iOS. In watchOS 1, WatchKit extensions have direct access to the defaults database and may read and write values.
All 3 targets should have the same App Group configured (the Watch App target here seems to be the missing component in OPs question):
My settings bundle:
Some simple interface code in InterfaceController.swift:
#IBOutlet var label: WKInterfaceLabel!
#IBAction func buttonAction() {
let sharedDefaults = NSUserDefaults.init(suiteName: "group.testSettings")
let name_preference = String(sharedDefaults?.objectForKey("name_preference"))
self.label.setText(name_preference)
}
and the final outcome:
So, it does work as expected, only not in Simulator. It seems that there is some isolation occurring between the 2 devices in Simulator, and it's a little frustrating trying to put my finger on exactly what's happening there.
This is because the apps now run native on the Apple Watch, which means they are not able to get settings from the iPhone, because the settings are not stored on the same device anymore. More info here: Unable to get values from settings bundle in watchOS 2
The new process of handling using `WCSessions be see in the sample Apple app - Lister in the below mentioned file.
https://developer.apple.com/library/ios/samplecode/Lister/Listings/Objective_C_ListerKit__WatchOS__AAPLConnectivityListsController_m.html#//apple_ref/doc/uid/TP40014701-Objective_C_ListerKit__WatchOS__AAPLConnectivityListsController_m-DontLinkElementID_57
Also, the answer mentioned in https://stackoverflow.com/a/32628105/1640786 seems to make the whole process a lot more convenient.

Resources