- Home /
How to update apple watch content (from extension) with data from Unity project
So a few days down the line from first question:
Not sure if it fits here as it's mostly Xcode stuff, but still closely related to Unity to apple watch so writing here.
So progress on project is I have an Unity iOS app that has a watch kit added to it. But what is the use of adding watch to a project if you can't display anything properly?!
So for this I will share some code and write what it does and maybe someone can help me with the final step I want... Feel free to use the code, once I get this to work properly I might even make my first short tutorial about this as I spent/d long time on something that should have been fairly easy but somehow Apple managed to not do so...
The first thing I did is create a very simple script within Unity:
public class UpdateLabel : MonoBehaviour {
private int i = 0;
public Text _label = null;
void Start()
{
//Debug.Log ("UpdateLabel started");
}
// Update is called once per frame
void Update () {
i++;
_label.text = i.ToString ();
SetAppleWatchData ("i",i.ToString());
}
#if UNITY_IOS && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern void SaveStringForWatch(string KeyCode, string value);
#endif
public void SetAppleWatchData(string key, string value)
{
#if UNITY_IOS && !UNITY_EDITOR
SaveStringForWatch(key,value);
#endif
}
}
The idea is to save a key value pair within Apple's new system of groups to send the data to the Watch. For this I needed to write a small .mm file also as shown below that saves in the proper group:
extern "C" {
void SaveStringForWatch(const char* key, const char* value) {
NSString *_key = [[NSString alloc] initWithCString:key encoding:NSASCIIStringEncoding];
NSString *_value = [[NSString alloc] initWithCString:value encoding:NSASCIIStringEncoding];
::printf("still printing something\n");
NSUserDefaults *appleWatch = [[NSUserDefaults alloc] initWithSuiteName:@"group.watchtest"];
[appleWatch setObject: _value forKey:_key];
[appleWatch synchronize];
NSString* _test = [appleWatch objectForKey: _key];
//::printf(key+" " + value + "\n");
NSLog(@"%@",[appleWatch dictionaryRepresentation]);
//NSLog(@"%@",_value);
}
}
this took me some time to get to work properly, lot of logging and googling later I got this result that works great and is very simple... After this I moved to my Apple watch itself, before going all big and mighty was making something simple. I will get the information from the group and set it in a label.
class InterfaceController: WKInterfaceController {
@IBOutlet weak var label: WKInterfaceLabel!
@IBOutlet weak var _timer: WKInterfaceTimer!
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
// Configure interface objects here.
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
//while(true)
//{
ReadAppleWatchDataAndUpdateLabels()
//}
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
@IBAction func OnButtonClicked() {
ReadAppleWatchDataAndUpdateLabels()
}
func ReadAppleWatchDataAndUpdateLabels()
{
let sharedDefault = NSUserDefaults(suiteName: "group.watchtest")
if(sharedDefault?.objectForKey("i") != nil)
{
let sharedText = sharedDefault?.objectForKey("i") as String
label.setText(sharedText)
}
else
{
var _text = sharedDefault?.dictionaryRepresentation()
println(sharedDefault?.dictionaryRepresentation())
}
}
}
from the commented part you can realise what step is missing and what I'm here to ask:
How can I have my watch kit extension poll itself to update the data on the watch kit app based on new information added to the group... Also updating itself based on information inside the group (passing timer and doing something when timer runs out, or during the timer is running,...)
I want to have a watch app a bit more then just sending data from my app and statically showing it, I want the app to feel more alive by updating itself...
I'm new to swift language and a full day of googling just gave me 0 ideas, I looked up with sprite kit, but watch kit doesn't allow that for the extension, trying to call itself with a 1 sec interval but failed miserably. Used NSTimer.scheduledTimerWithTimeInterval(Double(1), target: self, selector: Selector("ReadAppleWatchDataAndUpdateLabels"), userInfo: nil, repeats: true) for that
If anyone has an idea how to get watch kit extension to update itself based on new information received from Unity or based on timer would be much appreciated...
Answer by NG_Matthieu · Apr 10, 2015 at 08:02 PM
For those interested in the solution, took me time to find it and lot of looking around but:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
//recalls itself every minute
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(60 * Double(NSEC_PER_SEC))), nil){self.UpdateAppleWatchDataLabels()}
First function needs to be global and add the 2nd code part at end of your method and change end to the correct method name and you it will recall itself every minute (works great and not resource intensive as the NSTimer) got this from stack overflow but think it's a good thing to write it here also...