Agentry + Apple Watch
This is a little Proof of Concept project to demonstrate how easy it is to add a WatchKit extension to an OpenUI Agentry application. It shows how events and Agentry data can be shared with the WatchKit application to be displayed in the new device. Showing that business data is not “locked” inside the Agentry application and can be shared with users in many different ways.
The full source code for the project can be found here in SAP GitHub.
This is a GIF animation of the two applications working together:
For a higher resolution video, please contact me or access it in this JAM page. Enjoy!
Steps to create the App
Development starts with Xcode 6.2 and the OpenUI framework iOS Demo project.
The project was setup to add a WatchKit App and a WatchKit Extension following the instructions provided by Apple here.
Sharing data between the iOS App and the WatchKit App is achieved by setting up “App Groups”. The instructions for doing so are described in this Apple article.
* Note: To test this, membership in an Apple Developer program is required because it will need to update the app entitlements and provisioning profiles.
Real time communication between the Watch App and the iOS App is achieved using the Darwin Notification Center and some new WatchKit APIs referenced in the documents mentioned above.
* Tip: There is an open source project available in GitHub here (MIT License) that encapsulates this paradigm rather elegantly. In this solution I manually implemented that because I wanted to see how it worked behind the scenes.
Communication from iPhone to Apple Watch
The sending happens in the MyCollectionDisplayAdapter.m file. See the updateSharedDataAndNotifyWatchKitExtension method. First, Agentry’s object data is serialized into a helper object and stored in the App Group:
NSUserDefaults *sharedData = [[NSUserDefaults alloc]
initWithSuiteName:@”group.com.syclo.agentry.SMPAgentryClientFrameworkDemo.shareddefaults”];
NSMutableArray* players = [NSMutableArray array];
for (int i = 0; i < self.model.displayedObjectCount; i++) {
// Use DataAPI to get the value of the object’s child properties
id<SMPDataAPIProtocol> agentryPalyer = [self.model displayedObjectAtIndex:i];
id<SMPDataAPIPropertyProtocol> nameProp = (id<SMPDataAPIPropertyProtocol>)[agentryPalyer descendant:0];
// …
// Create the player
Player* player = [[Player alloc] initWithName:[nameProp asString] …;
// Serialize it for saving
[players addObject:[player serialize]];
}
[sharedData setObject:players forKey:@”players”];
[sharedData synchronize];
Then the notification is fired:
CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge CFStringRef)@”playersChanged”,
NULL,
NULL,
YES /* Deliver right now! */);
The receiving happens in the InterfaceController.m file of the WatchKit extension:
– (void) watchForDataChanges {
// Listen for notifications on Darwing
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
(__bridge const void *)(self),
darwinNotificationCenterCallBack,
(__bridge CFStringRef)@”playersChanged”,
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
// Listen for our own notification to ourselves in Cocoa
[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cocoaNotificationCallBack) name:@”playersChangedCocoa” object:nil];
}
void darwinNotificationCenterCallBack() {
NSLog(@”Notification received from iPhone app!”);
// Go from Darwin to Cocoa land
[[NSNotificationCenter defaultCenter] postNotificationName:@”playersChangedCocoa” object:nil];
}
– (void) cocoaNotificationCallBack {
NSLog(@”Notification received from ourselves in Cocoa”);
[self loadTableData];
}
Note that some bridging from C to Obj-C is required to get the notification passed to the WatchKit UI code.
Also note, with this implementation, the OpenUI adapter code must be run at least once before there is any meaningful data in the Watch application to display.
Communication from Apple Watch back to iPhone
While the same method above works for two-way communication, there is another API the WatchKit API provides for communicating with the containing iPhone App.
For an example of this, check out this method in InterfaceController.m:
– (IBAction)doMenuAction {
[WKInterfaceController openParentApplication:@{@”key” : @”value”}
reply:
^(NSDictionary *replyInfo, NSError *error) {
NSLog(@”Containing app returned!”);
}];
}
And in the AppDelegate provided with the iPhone Application.
– (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply {
NSLog(@”Awoken by Apple WatchKit App!”);
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@”Alert” message:@”Alert from
Watch!” delegate:nil cancelButtonTitle:@”OK” otherButtonTitles:nil];
[alert show];
// …
}
This same Watch application could be further extended to take advantage of the Notifications and Glances paradigms provided by Apple for its new wearable device.
Enjoy and share what you find playing with Agentry!
Great post. I do love the touch of the animated GIF - very neat 🙂
Thank you Dirk! A curiosity: unlike in the phone, all animations in the Watch are done using image transitions, so they are in a way like GIFs as well 🙂