Currently i am using the following watchkit delegates.. I need to check whether they are being called or not while using simulators.
-(void)session:(WCSession *)session didReceiveApplicationContext:(NSDictionary<NSString *,id> *)applicationContext
{
NSLog(#"REminders Array %#",applicationContext);
}
- (void)session:(WCSession *)session didReceiveUserInfo:(NSDictionary<NSString *,id> *)userInfo{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Received userInfo Transferr");
NSLog(#"%#", userInfo);
});
}
but they are not getting called while using simulators it is working fine in iphone applications. Any idea how to work with these??
mmm your question is not very clear, as the steps to test your capabilities? in general these delegates are launched following a submission by
- (BOOL)updateApplicationContext:(NSDictionary<NSString *,id> *)applicationContext error:(NSError * _Nullable *)error
and
- (WCSessionUserInfoTransfer *)transferCurrentComplicationUserInfo:(NSDictionary<NSString *,id> *)userInfo
Then if you're working with the simulator you have to set debugging to make sure that it can debug both applications (again if it's your case).
Related
There are multiple examples how you should set up your project to add rich notifications which use 'media attachments' technology to show images. I've read most of them but something I missed, because my project does not display any rich notifications with this payload (tested with APNS-Tool and Boodle):
{
"aps":{
"alert":{
"title": "Rich test",
"body": "Dancing Banana"
},
"mutable-content": 1
}
}
The notification is visible, but on 3D Touch, there are no additional infos displayed (like the image or the modified title). The notification extension breakpoints and NSLog messages are also not working.
Here is my demo project: https://github.com/gklka/RichTest
What I've done:
Created a new project
implemented iOS-style authorization:
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:UNAuthorizationOptionAlert completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (granted) {
NSLog(#"Granted");
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
NSLog(#"Error registering: %#", error);
}
}];
added debug to AppDelegate:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(#"Token: %#", deviceToken);
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(#"Error: %#", error);
}
Added a new target to the project: Notification Service Extension:
Added banana.gif to the project
Added code to add banana attachment into NotificationService.m
self.bestAttemptContent.title = [NSString stringWithFormat:#"%# [modified]", self.bestAttemptContent.title];
// Add image attachment
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:#"banana" withExtension:#"gif"];
NSError *error;
UNNotificationAttachment *attachment = [UNNotificationAttachment attachmentWithIdentifier:#"banana" URL:fileURL options:nil error:&error];
self.bestAttemptContent.attachments = #[attachment];
What did I miss?
Additional info: The same thing works when I use local notifications instead of remote notifications.
You're most of the way there. The way you're going to send the attachment is usually as a URL in your payload. However, if you wanted to hard-code the attachment, like your code does, I think it would work, but I think you missed one critical component. I think the service extension does not have access to the main bundle or its resources. If you added a resource to the service extension and tried to load that (using something like [NSBundle bundleForClass:[NotificationService class]]), I suspect it would work.
However, if you send the URL as part of the payload, then you're going to load the image from that URL and not the bundle anyway. In that case, I'm pretty sure you also have to use startAccessingSecurityScopedResource on NSURL (along with stopAccessingSecurityScopedResource).
Hope that helps!
I'm trying to use the CoreBluetooth module to list all the detected Bluetooth devices in a command-line OSX application.
What I have looks like this, so far:
#import CoreBluetooth;
#interface MyCentralManager : NSObject<CBCentralManagerDelegate>
- (void) centralManagerDidUpdateState: (CBCentralManager *) central;
- (void) centralManager:(CBCentralManager *) central
didDiscoverPeripheral:(CBPeripheral *) peripheral
advertisementData:(NSDictionary *) advertisementData
RSSI:(NSNumber *)RSSI;
#end
#implementation MyCentralManager
- (void) centralManagerDidUpdateState: (CBCentralManager *) central
{
NSLog(#"State changed...");
}
- (void) centralManager:(CBCentralManager *) central
didDiscoverPeripheral:(CBPeripheral *) peripheral
advertisementData:(NSDictionary *) advertisementData
RSSI:(NSNumber *)RSSI
{
NSLog(#"Discovered %#", peripheral.name);
}
#end
int main() {
MyCentralManager* myCentralManager = [[MyCentralManager alloc] init];
CBCentralManager* cbCentralManager = [[CBCentralManager alloc] initWithDelegate:myCentralManager queue:nil options:nil];
NSLog(#"Scanning devices now !");
[cbCentralManager scanForPeripheralsWithServices:nil options:nil];
sleep(5); // Wait 5 seconds before stopping the scan.
[cbCentralManager stopScan];
NSLog(#"Scanning devices ended.");
return 0;
}
Now this doesn't work at all as I never get any "State changed..." nor "Discovered ..." log output.
I never actually written any Objective C application before so I'm probably missing the obvious. If I had to guess what I'm doing wrong I would assume that:
I actually have to wait for the CentralManager to be in the appropriate state before starting the scan.
I never actually get inside the state changed delegate method so I assume that my first mistake is: instead of just sleep()'ing, I have to run an event loop of some sort so that the underlying system has a chance to notify me of the state change.
I'm basically stuck at this point: I don't have a GUI, nor do I want one but couldn't figure out a way to run an event loop (assuming that's actually what is missing). How can I do that ?
As I said, this is actually my first attempt with Objective C, so don't be afraid to state the obvious.
Simply run the thread's run loop
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5]];
More information here.
BTW: You do not have to declare the methods already declared in the protocol.
I am trying to work out how to sync a .plist file I have in the "Application Support" folder in my Sandboxed app for the Mac. I know I could use the iCloud key value store, but there is a limit of 64KB per app, which may or may not be hit depending on how many thing the user adds to the app!
I have read as much of the Apple documentation as possible, but I am still rather confused :(
Has anyone does something similar to this?
Thanks
You should create a subclass of UIDocument and use it with ubiquity directories.
There are 2 methods responsible for handling read/write. This one is called when reading:
- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)outError
And this one when writing:
- (id)contentsForType:(NSString *)typeName error:(NSError **)outError
All open/save actions are called automatically, you don't have to do anything. Howewer, there are methods that force open/save. Call this when opening:
- (void)openWithCompletionHandler:(void (^)(BOOL success))completionHandler
/* --- EXAMPLE --- */
MyDocument *doc = [[MyDocument alloc] initWithFileURL:ubiquitousFileURL];
[doc openWithCompletionHandler:^(BOOL success) {
if (success) {
// do sth
} else {
// handle error
}
}];
... and this when saving:
- (void)saveToURL:(NSURL *)url forSaveOperation:(UIDocumentSaveOperation)saveOperation completionHandler:(void (^)(BOOL success))completionHandler
/* --- EXAMPLE --- */
MyDocument *doc = [[MyDocument alloc] initWithFileURL:ubiquitousPackage];
[doc saveToURL:[doc fileURL] forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
if (success) {
// do sth
} else {
// handle error
}
}];
There are many tutorials on the web, here are some examples that I used for learning:
Beginning iCloud in iOS 5 Tutorial Part 1
Beginning iCloud in iOS 5 Tutorial Part 2
UIDocument Class Reference may also help.
I'm having trouble finding examples of the correct way to use NSError, UIAlertView, and NSErrorRecoveryAttempting together on iOS. Most of the documentation and examples I can find cover the equivalent functionality on OS X, where the relevant behaviors are integrated by Cocoa. But in iOS it seems to be necessary do do this "by hand", and I can't find good examples of how it's done.
I'd very much appreciate a few examples of best practice in using information in NSError to support recovery attempts from NSErrors reported to the user.
According to Apple's documentation:
Important: The NSError class is available on both Mac OS X and iOS. However, the error-responder and error-recovery APIs and mechanisms are available only in the Application Kit (Mac OS X).
So, I'm not sure if you can use NSErrorRecoveryAttempting even though it does appear to be defined in the documentation (it looks like this is an area of the UIKit docs that have not yet been updated after being copied from AppKit's documentation).
Here is how I handle errors in my code:
NSError *error = nil;
id result = [SomeClass doSomething:&error];
if (!result) {
NSLog(#"Do something failed: %#", error);
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"Something failed!" message:#"There was an error doing something." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease];
[alert show];
return;
}
I found a great example of this.
See the following blog post and GitHub code (including sample project) by James Beith
http://www.realmacsoftware.com/blog/cocoa-error-handling-and-recovery
https://github.com/realmacsoftware/RMErrorRecoveryAttempter
I was able to successfully use this on the iPhone simulator.
I'm trying to mirror AppKit's error handling mechanism in UIKit, mainly because I want to take advantage of the responder chain to forward errors upwards. I haven't tested this fully, but at the moment it's looking like below.
It reflects AppKit pretty closely, but the will/did hooks can be overridden to perform custom error presentation and recovery respectively. The default behaviour is to show a UIAlertView for presentation and use a psuedo-NSErrorRecoveryAttempting object for recovery.
#implementation UIResponder (ErrorHandling)
- (void)presentError:(NSError *)error
completion:(void (^)(BOOL recovered))completion
{
if (nil == (error = [self willPresentError:error])) {
return;
}
if (self.nextResponder) {
[self.nextResponder presentError:error completion:completion];
return;
}
// Code to create and show UIAlertView
// e.g. https://github.com/jayway/CWUIKit/blob/master/Classes/UIAlertView%2BCWErrorHandler.m
// The UIAlertViewDelegate calls didPresentError...
}
/*
Override to customise the error object as in AppKit.
You can also perform your own error presentation, and return nil to terminate the default handling.
Custom error presentation UI should still call didPresentError... when dismissed
*/
- (NSError *)willPresentError:(NSError *)error
{
return error;
}
/*
Override to perform custom error recovery.
*/
- (void)didPresentError:(NSError *)error optionIndex:(NSInteger)optionIndex completion:(void (^)(BOOL recovered))completion
{
id recoveryAttempter = [error recoveryAttempter];
if ([recoveryAttempter respondsToSelector:#selector(attemptRecoveryFromError:optionIndex:completion:)]) {
[recoveryAttempter attemptRecoveryFromError:error optionIndex:optionIndex completion:completion];
}
}
#end
Hey, I'm trying to trap the QTMovie progress delegate method calls, and the delegate methods don't seem to be getting called. I'm trying to trap the conversion progress event by implementing
- (BOOL)movie:(QTMovie *)movie shouldContinueOperation:(NSString *)op withPhase:(QTMovieOperationPhase)phase atPercent:(NSNumber *)percent withAttributes:(NSDictionary *)attributes
but the method is not getting called. I've looked at apples sample code here http://developer.apple.com/library/mac/#samplecode/QTKitProgressTester/Introduction/Intro.html#//apple_ref/doc/uid/DTS10003631 and can't seem to see very much difference between my code and their code. The file gets converted fine and shows up on my desktop and I can play it without issues. I just can't get the progress events. Any ideas? Here is my demo app that I'm using to test this with.
#import "testProjAppDelegate.h"
#import <QTKit/QTKit.h>
#implementation testProjAppDelegate
#synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
QTMovie* movie = [QTMovie movieWithFile:#"/Users/Morgan/Desktop/sample_iTunes.mov" error:nil];
if (movie)
{
[movie setDelegate:self];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], QTMovieExport,
[NSNumber numberWithInt:kQTFileType3GPP], QTMovieExportType, nil];
[movie writeToFile:#"/Users/Morgan/Desktop/test.mp4" withAttributes:dict error:nil];
NSLog(#"DONE");
}
}
- (BOOL)movie:(QTMovie *)movie shouldContinueOperation:(NSString *)op withPhase:(QTMovieOperationPhase)phase atPercent:(NSNumber *)percent withAttributes:(NSDictionary *)attributes
{
NSLog(#"PROGRESS");
return YES;
}
#end
It appears that this is not working because my app was compiled for 64 bit. I'm assuming this is a bug in the QTKit framework? I found a few other mentions of QTMovie delegates not working in 64 bit applications. I can compile my app for 32 bit though which isn't a problem. Still, this should work in 64 bit, shouldn't it?