Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I want to ask a question about watch connectivity.
1) Is it possible to read data from iPhone when the iWatch app opened. I not want to wait to open iPhone app for transfering data to iWatch.
2) Is it possible to create login screen(to get user input from text fields) on iWatch
3) iWatch has device token and vendor id? How to get these infos from iWatch?
4) Is it possible to read iPhone app's database(like sql lite db on iPhone app) from iWatch application
5) How to transfer dictionary from iPhone app to iWatch app. Share any example plz.
1) Is it possible to read data from iPhone when the iWatch app opened. I not want to wait to open iPhone app for transferring data to iWatch.
YES, Using any of background methods (transferUserInfo:, transferCurrentComplicationUserInfo:, transferFile:,updateApplicationContext:infoToSend ) you can awake iPhone app and get things done. vice versa is not possible Watch app has to be Opened.
2) Is it possible to create login screen(to get user input from text fields) on iWatch
NO, Text fields are not available in WatchOS2.
3) iWatch has device token and vendor id? How to get these info from iWatch?
With watchOS 1, the vendor ID and the advertising ID were actually on the iPhone as the WatchKit extension itself ran on the iPhone.
With watchOS 2, you will need to sync the vendor ID and advertising ID from the iPhone to the Watch and use it there.
And you will need to maintain the vendor ID and advertising ID up-to-date.
4) Is it possible to read iPhone app's database(like sql lite db on iPhone app) from iWatch application
It was possible in WatchKit but with the introduction of WatchConnectivity Framework App group based common container has been restricted.I am sure for UserDefualts but not have yet tested for Files.
5) How to transfer dictionary from iPhone app to iWatch app. Share any example plz.
There are Two ways to perform these things:
Using TransferUserInfo
With this method, Watch will receive dictionary everytime, that means if Watch is inactive and iphone sends 3 Dictionary during that time period, Whenever watch will activate, it will receive all the 3 dictionary by multiple calls of delegate methods - - (void)session:(WCSession *)session didReceiveUserInfo:(NSDictionary<NSString *, id> *)userInfo on watch side.
-(void)sendDictionaryToWatch:(NSDictionary*)infoToSend{
if([WCSession isSupported]){
WCSession *aDefaultSession = [WCSession defaultSession];
aDefaultSession.delegate = self;
if([aDefaultSession isPaired] && [aDefaultSession isWatchAppInstalled]){
[aDefaultSession activateSession];
[aDefaultSession transferUserInfo:infoToSend];
}
}
}
Using updateApplicationContext:error:
In this case, Device will send the latest Context to Watch on activation. That means let say If you have sent three Info back to back then When Watch is Activated it will receive only latest one, not previous ones in delegate method - -(void)session:(WCSession *)session didReceiveApplicationContext:(nonnull NSDictionary<NSString *,id> *)applicationContext.
-(void)sendDictionaryToWatch:(NSDictionary*)infoToSend{
if([WCSession isSupported]){
WCSession *aDefaultSession = [WCSession defaultSession];
aDefaultSession.delegate = self;
if([aDefaultSession isPaired] && [aDefaultSession isWatchAppInstalled]){
[aDefaultSession activateSession];
[aDefaultSession updateApplicationContext:infoToSend error:nil];
}
}
}
Related
I started messing around with the Watch OS framework today and wanted to throw together a quick app, but have come to a couple questions.
I made an iOS app that just shows the current battery % as well as the state of the battery. I then wanted to show that over on the watch.
The only time the watch app will update is when I totally close the iOS app, then open it, while the watch app is active. How do I allow my watch app to be updated if I open it after the iOS app has been opened?
This kind of goes with number 2. But how do I allow the watch app to fetch info from the iOS app, after it has been in the background? As an example, lets say the iOS app has been in the background and I wanted to fetch the battery % without opening the iOS app to the foreground.
Some side notes on how I set this up -
Within the iOS app, in the viewDidLoad method, I start my session.
if ([WCSession isSupported]) {
wcSession = [WCSession defaultSession];
wcSession.delegate = self;
[wcSession activateSession];
}
Then call my method to update the actual battery % and state. Within that method, I have this which sends the info over to the watch:
NSDictionary *message = #{
#"message" : [NSString stringWithFormat:#"%#", [numberFormatter stringFromNumber:levelObj]],
#"message_2" : [NSString stringWithFormat:#"%ld",(long)[UIDevice currentDevice].batteryState],
};
[wcSession sendMessage:message replyHandler:nil errorHandler:^(NSError * _Nonnull error) {
NSLog(#"%#", error.localizedDescription);
}];
I also call this same method in the viewDidAppear, so I don't have to relaunch the app completely, to allow refreshing of the watch counterpart.
On the watch side I have the viewWillActivate method with the same activation as the iOS side as well as the method to handle what the watch app receives from the iOS side. But it will only update when I restart the iOS app fully.
- (void)session:(WCSession *)session didReceiveMessage:(NSDictionary<NSString *,id> *)message {
NSLog(#"Message recieved!");
[_batteryLevelLabelW setText:message[#"message"]];
}
Also in there is the code to handle the battery state message, which is a bit long.
I hope I gave a good amount of information to help.
According to documentation:
Use the sendMessage(_:replyHandler:errorHandler:) or
sendMessageData(_:replyHandler:errorHandler:) method to
transfer data to a reachable counterpart. These methods are intended
for immediate communication between your iOS app and WatchKit
extension. The isReachable property must currently be true for these
methods to succeed.
If watchapp is not foreground, message will not be delivered since isReachable is false.
Method you should use is updateApplicationContext(_:) - it will wait till watch app will be opened at foreground and only then will be delivered.
Here is a question that I know has an answer since I see apps that do this functionality. I have tried (writing directly, using background fetch) but nothing works. I found an app currently on the app store with the functionality that I am looking for. With Background Fetch set to OFF and main app NOT running in background. I go to the Widget and add an item. I open HealthKit and I see the data there as expected.
I would like to do the same for my app. I would like my today extension (widget) and/or WatchKit extension to write to the HealthKit store even when app is not running in background.
Like I said I have tested an app that does this functionality even though in Apple documentation it says this:
The HealthKit store can only be accessed by an authorized app. You
cannot access HealthKit from extensions (like the Today view) or from
a WatchKit app.
Because the HealthKit store is encrypted, your app cannot read data
from the store when the phone is locked. This means your app may not
be able to access the store when it is launched in the background.
However, apps can still write data to the store, even when the phone
is locked. The store temporarily caches the data and saves it to the
encrypted store as soon as the phone is unlocked.
Any answers or insights are appreciated. Thanks everybody.
The Health Data Store is indeed encrypted while the device is locked. Locked is defined as requiring a passcode on the device and the screen was turned off (so a passcode or touch id is required before you can get back to the main screen). While the store is encrypted it is not possible to read any data from it, no matter if the app is running in the background or not. Even setting up observer queries while the app is running will not allow it to continue to be read from. I imagine this level of protection is done simply using the Data Protection capability with the NSFileProtectionComplete option.
What HealthKit functionality have you observed in this other app? If it was displaying step and distance data, then they are likely getting this data directly from the pedometer (CMPedometer), which is not restricted when the device is locked.
Lehn0058's comment about authorization was correct. I had to request authorization explicitly from the WatchKit and Today Extension even though authorization was already given in the app. Afterwards both are able to write to the Health Store. The comment from Apple above only has to do with Reading from the Health Store and NOT writing to the Health Store. Here is some sample code for anybody else who gets in to the same problem. Thanks again.
In WatchKit InterfaceController.m
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.
[[HealthKitManager sharedManager] requestHealthKitAccess];
}
In Today Extension TodayViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[[HealthKitManager sharedManager] requestHealthKitAccess];
}
We are using Google Analytics, and want to know how many of our users are in possession of an AppleWatch. I have searched Stack for answers, and the recurring answer is to use this:
if WCSession.isSupported() { // check if the device support to handle an Apple Watch
let session = WCSession.defaultSession()
session.delegate = self
session.activateSession() // activate the session
if session.paired { // Check if the iPhone is paired with the Apple Watch
// Do stuff
}
}
The problem with this is that it prompts the user to 'accept' the app on the AppleWatch. Granted, the if-statement is true wether or not the user accepts, but I don't want the user to get their hopes up, thinking the app supports AppleWatch. I simply want to know if the user has an AppleWatch, I don't want to use it. Yet.
Is there a property on the iOS-device that can be accessed to show if the user has or ever had an AppleWatch connected, without prompting the user through the Watch?
Probably you can use (Push)Notifications, since there is no need to develop a native applewatch app to receive notifications on the watch. For example i receive "whats app messages" on my watch, but it does not have any native app on the watch either.
In your watchkit extension ExtensionDelegate.m you can handle provided answers to the push message separately. Link to Apple
This would be a(nother) approach, where you have to be creative!
Requirement :My Watch app will show latest data from our server.
I tried :
To implement this thing I used
WKInterfaceController.openParentApplication(requestDict, reply: { (returnedObject, error) -> Void in
if (returnedObject != nil) {
//loading interface data here
}
})
In my app delegate function I used
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void(^)(NSDictionary *replyInfo))reply {
// doing web service call using asynchronous nsurlconnection and replying with response dictionary
}
Problem :
Problem is that application is running fine when iPhone application is foreground but watch app not showing anything when iPhone application is running in background. I debugged it and found actually when iPhone application is running background then webservice api call(nsurlconnection) is not retuuning any data, when it's coming to foreground then it's replying data to watch app.
To solve it I used nsuserdafults to store data, but problem is that it's not always showing latest data. Let consider user opened watch app and it will go to parent application and returning old data from userdafults.
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void(^)(NSDictionary *replyInfo))reply {
if ([userInfo[#"type"] isEqualToString:#"list"]) {
[self fetchWatchData];//it will get and store data when app will be foreground
NSDictionary *replyDict = [UtiltiyManager getWatchData];//data from userdefaults
if (replyDict) {
reply(replyDict);
}else {
NSDictionary *noDataDict = #{#"data":#"nodata"};
reply(noDataDict);
}
}
}
Problem is that watch app can't get latest data from iphone while it's in background. As there are no service call api which will work in background. I checked with NSURLConnection and NSURLSessionDataTask both are foreground api call.
Any solutions or thoughts?
Update 1 :
Apple Docs Says :
Types of Tasks Within a session, the NSURLSession class supports three
types of tasks: data tasks, download tasks, and upload tasks.
Data tasks send and receive data using NSData objects. Data tasks are
intended for short, often interactive requests from your app to a
server. Data tasks can return data to your app one piece at a time
after each piece of data is received, or all at once through a
completion handler. Because data tasks do not store the data to a
file, they are not supported in background sessions. Download tasks
retrieve data in the form of a file, and support background downloads
while the app is not running. Upload tasks send data (usually in the
form of a file), and support background uploads while the app is not
running.
Apple told data tasks is not available in background.And my data is small web service data that can be fetched using data task. so my service call is not download task. So in case of watch when iPhone app is background then how app will get web service data.
Should we use download task? But I guess it's intended to download any file.
You need to create a background task in the iPhone app otherwise the OS kills your app off before it can finish downloading the data. Here's some docs to help: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
Things have substantially changed since the question and answer posted previously. openParentApplication is no longer available in WatchOS 2. On the plus side, much more can now be achieved directly on the watch to update data from the server as required. Ideally, the iPhone app would also be caching for the WatchKit App Extension with the last cached data in the meantime via one of the new communication mechanisms now available, so that the WatchKit App has something to display until the latest data is downloaded, even if the iPhone app is not currently running.
I was wondering if there is any other way besides MMWormhole to pass basic data between iPhone and Apple Watch. Do you know if any existing official Apple framework allows this?
It is possible.
Looking at: The WatchKit Doc's
There is a paragraph on sharing data between the watch app and the extension on the iPhone.
To quote the first paragraph.
Sharing Data with Your Containing iOS App
If your iOS app and WatchKit extension rely on the same data, use a shared app group to store that data. An app group is a secure container that multiple processes can access. Because your WatchKit extension and iOS app run in separate sandbox environments, they normally do not share files or communicate directly with one another. An app group lets the two processes share files or user defaults information between them.
From what I understand MMWormhole is handy for as close to realtime data changes between the 2 binaries. Whereas this method allows for accessing data used saved by the iPhone app that can be read by the Watch App and Vice Versa.
We can pass the data between iPhone & iWatch using groups.
Basically We can share data using the NSUserDefaults.
But for that you need to enable that see steps below:
1)open capabilities section in both your project target
2)open App Groups from that section
3)add container by click on + button with name group.test.demo
sample code to achieve that.
In your iphone app code
NSUserDefaults *myDefaults = [[NSUserDefaults alloc]initWithSuiteName:#"group.test.demo"];
[myDefaults setObject:#"tejas" forKey:#"name"];
now value "tejas" is set for key "name"
code to retrieve that
NSUserDefaults *myDefaults = [[NSUserDefaults alloc]initWithSuiteName:#"group.test.demo"];
[myDefaults objectForKey:#"name"];
best of luck :)
If you check the docs for WKInterfaceController, you'll find a method called openParentApplication:reply: that allows you to communicate with your host app in the background.
As stated above, I have used a shared app group and placed the core data files in that group. Using this technique, both the phone app and the watch can read and write the same data and all is good when they are run discretely. As each process is running in a separate sandbox, you run into the classic distributed database problem of potentially overwriting data from different sources.
To overcome this, you need to put data observers in place. I resorted to using the NSDistributedNotificationCenter to pass some custom messages between the app and the watch extension, but there may be a more elegant solution. Any ideas from others?
Use watch Connectivity.
// 1. In .m viewcontroller on phone & interface controller on iwatch
#import <WatchConnectivity/WatchConnectivity.h>
#interface IController()<WCSessionDelegate>
#end
if ([WCSession isSupported]) {
WCSession *session = [WCSession defaultSession];
session.delegate = self;
[session activateSession];}
// 2. Send Message - Phone or iWatch:
[[WCSession defaultSession] sendMessage:response
replyHandler:^(NSDictionary *reply) {
NSLog(#"%#",reply);
}
errorHandler:^(NSError *error) {
NSLog(#"%#",error);
}
];
// 3. Receive Message - Phone or iWatch
- (void)session:(WCSession *)session didReceiveMessage: (NSDictionary<NSString *, id> *)message
{
}