2

I need to add the snapshot of a watch app to be placed in Dock as it's a new feature I can't find any resources to guide me. I have read Apple's Documentation https://developer.apple.com/library/prerelease/content/samplecode/WatchBackgroundRefresh/Introduction/Intro.html and I have implemented this code in the main InterfaceController of the Watch app based on the Apple Documentation: https://developer.apple.com/library/prerelease/content/samplecode/WatchBackgroundRefresh/Introduction/Intro.html but handleBackgroundTasks is never called. Am I doing something wrong? can I have screenshot of another InterfaceController rather than main InterfaceController to be placed in the Dock? how?

@interface ExtensionDelegate : NSObject <WKExtensionDelegate>

@property (nonatomic, weak) MainInterfaceController *interfaceController;

@implementation ExtensionDelegate

-(void)applicationDidEnterBackground {

    [self scheduleRefreshBackgroundTask];
    [self scheduleSnapshotRefreshBackgroundTask];
  }

-(void)scheduleRefreshBackgroundTask WK_AVAILABLE_WATCHOS_ONLY(3.0){

// Background Refresh

NSDictionary *backgroundRefreshUserInfo = @{@"reason": @"Bakcground Refresh"};

NSDate *backgroundRefreshDate = [NSDate dateWithTimeIntervalSinceNow:30 * 60];

[[WKExtension sharedExtension] scheduleBackgroundRefreshWithPreferredDate:backgroundRefreshDate
                                                                 userInfo:backgroundRefreshUserInfo
                                                      scheduledCompletion:^(NSError *error){

    if (error == nil) {

        DMLogVerbose(DebugLogTypeWatch, @"successfully scheduled background refresh tesk");

    } else {

        DMLogError(DebugLogTypeWatch, @"unable to schedule background refresh task, error:%@", error);

    }

}];

}

-(void)scheduleSnapshotRefreshBackgroundTask WK_AVAILABLE_WATCHOS_ONLY(3.0){

//fire in 1 hr

NSDate *inputDate = [NSDate date];

NSDate *fireDate = [inputDate initWithTimeIntervalSinceNow:1 * 60 * 60];

//optional.. any sourceCoding compliant data can be passed here

// SnapShot

NSDictionary *userInfo = @{@"reason": @"Snapshot Refresh"};

[[WKExtension sharedExtension] scheduleSnapshotRefreshWithPreferredDate:fireDate
                                                               userInfo:userInfo
                                                    scheduledCompletion:^(NSError *error){

if (error == nil) {
                                                            DMLogVerbose(DebugLogTypeWatch, @"successfully scheduled background tesk, use the crown to send the app to the background and wait for handle:backgroundTasks to fire.");
                   }
 }];

 }

-(void)handleBackgroundTasks:(NSSet<WKRefreshBackgroundTask *> *)backgroundTasks WK_AVAILABLE_WATCHOS_ONLY(3.0) {

for (WKRefreshBackgroundTask *task in backgroundTasks) {

    if ([[WKExtension sharedExtension] applicationState] == WKApplicationStateBackground) {

        // Snapshot
        if ([task isKindOfClass:[WKSnapshotRefreshBackgroundTask class]]) {

            if (self.interfaceController) {

                [self.interfaceController updateData:YES];

                [self.interfaceController initializeDefaultUI];

                [self scheduleSnapshotRefreshBackgroundTask];

            }

        }

        // Connectivity Refresh
        else if ([task isKindOfClass:[WKWatchConnectivityRefreshBackgroundTask class]]) {

            // do something

        }

        // Network (URLSession)
        else if ([task isKindOfClass:[WKURLSessionRefreshBackgroundTask class]]) {

            // Resume download

            NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:[DataManager watchDataURLSessionIdentifier]];

            NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig
                                                                  delegate:
                                     [TWNDataManager sharedDataManager].currentWatchDataDownloader
                                                             delegateQueue:nil];

            DMLogVerbose(DebugLogTypeWatch, @"Resume watch download session in background:%@", session);

        }
        // Background Refresh
        else if ([task isKindOfClass:[WKApplicationRefreshBackgroundTask class]]){

            NSDictionary *userInfo = [task userInfo];

            NSString *reason = [userInfo objectForKey:@"reason"];

            if ([reason isEqualToString:@"Bakcground Refresh"]) {

                if (self.interfaceController && !self.isBackgroundUpdating) {

                    self.isBackgroundUpdating = YES;

                    [self.interfaceController updateData:YES];

                    self.isBackgroundUpdating = NO;

                    [self scheduleRefreshBackgroundTask];

                }
            }
        }
    }

    [task setTaskCompleted];
}
}
BuLB JoBs
  • 841
  • 4
  • 20
Samira
  • 215
  • 2
  • 14
  • I have the same problem. I have tested Apple's sample code also https://developer.apple.com/library/prerelease/content/samplecode/WatchBackgroundRefresh/Introduction/Intro.html – Chiara Jul 25 '16 at 09:47
  • Helped a lot! Thanks for sharing! – Mona Jan 04 '18 at 22:11

2 Answers2

1

I have the same problem. I have tested Apple's sample code also https://developer.apple.com/library/prerelease/content/samplecode/WatchBackgroundRefresh/Introduction/Intro.html and the handle(_:) method was not called. Until I have restarted the simulators a few times, cleaned the product, did the usual stuff. Then I got it working, but only one out od 30 times testing was the method functioning properly (scheduling the snapshot request after finished downloading and then waking up the app). I have filled a bug report and I hope to see this fixed in their next beta version, since I lose a lot of time in testing that is not working as per documentation.

Chiara
  • 398
  • 5
  • 10
  • I forgot to mention, the other 29 or so times testing, the delegate method was called repeatedly. – Chiara Jul 25 '16 at 09:52
  • Yes Chiara I have the same problem handleBackgroundTasks is never called even if I reset the environment many times! I updated my question. I hope it gets fixed in the next version too. Because I need to update the complications using WKApplicationRefreshBackgroundTask and create the snapshot using WKSnapshotRefreshBackgroundTask which both require calling handleBackgroundTasks delegate's method. – Samira Jul 25 '16 at 14:58
  • I found what was the problem I was calling scheduleBackgroundRefreshWithPreferredDate which only trigger the WKApplicationRefreshBackgroundTask so I updated the code and handle method is called however sometimes it's not called due to timing issue with debugger! I still wonder is there any way to take the screenshot of another InterfaceController not the main one? – Samira Jul 25 '16 at 15:59
1

I moved the code into ExtensionDelegate now its working properly for me. I updated the code.

Samira
  • 215
  • 2
  • 14
  • Samira, is your app properly handling `WKURLSessionRefreshBackgroundTask`s? I have yet to get this working. Also, I have not been able to schedule a `WKApplicationRefreshBackgroundTask`? I (and others) have not been able to successfully recover a background URLSession task. If you have, would love to see what you're doing differently. – DeepFriedTwinkie Aug 09 '16 at 15:48
  • I have changed my implementation and I updated the code, when I debug the code every (as an example) 20 sec handle function gets called but I got an issue the UI is not updated, I'm working on it and I'll update the post if I could fix it. – Samira Aug 10 '16 at 21:22