CloudKit didReceiveRemoteNotification not called on the Mac - macos

I am using the following CKNotification Info and this seems to work fine:
CKNotificationInfo *note = [[CKNotificationInfo alloc] init];
note.alertBody = #"Something Happened";
note.shouldBadge = NO;
note.shouldSendContentAvailable = NO;
When something changes on an iOS device, my Mac app receives a Push notification based on a subscription with this notification. However, didReceiveRemoteNotification is never called so I can't process the event. I need to be able to refresh and fetch new changes. How do I do that?

Calling registerForRemoteNotificationTypes: and implementing didRegisterForRemoteNotificationsWithDeviceToken:
should be enough code, and the App ID should include the Push Notifications service.
I'm using CloudKit in a cross-platform (iOS/OS X) app to synchronize favorites between devices like so:
// OS X specific code
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSApp registerForRemoteNotificationTypes:NSRemoteNotificationTypeNone];// silent push notification!
}
- (void)application:(NSApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[self.favCon handleCloudKitNotificationWithUserInfo:userInfo];
}
Note the usage of NSRemoteNotificationTypeNone which means silent push notification! This is how I set up CloudKit in the FavController class:
- (void)getOrCreateFavZoneWithCompletionHandler:(successCompletionHandler)handler {
// check if FavZone exists op
__block int createZone = 0;
CKFetchRecordZonesOperation *fetchRecZonesOp = [[CKFetchRecordZonesOperation alloc] initWithRecordZoneIDs:#[[FavController favRecordZoneID]]];
CKModifyRecordZonesOperation *saveRecZoneOp = [[CKModifyRecordZonesOperation alloc] initWithRecordZonesToSave:nil recordZoneIDsToDelete:nil];
fetchRecZonesOp.fetchRecordZonesCompletionBlock = ^(NSDictionary *recordZonesByZoneID, NSError *operationError) {
if (recordZonesByZoneID.count == 0) {// zone doesn't exist
createZone = 1;
CKRecordZone *favZone = [[CKRecordZone alloc] initWithZoneName:UTXAFavZoneName];
saveRecZoneOp.recordZonesToSave = #[favZone];
NSLog(#"Creating new Zone %#", favZone.zoneID.zoneName);
} else {
NSLog(#"Zone %# already exists.", [FavController favRecordZoneID].zoneName);
}
};
// create FavZone op
saveRecZoneOp.modifyRecordZonesCompletionBlock = ^(NSArray *savedRecordZones, NSArray *deletedRecordZoneIDs, NSError *operationError) {
[self successCompletionHandler:(savedRecordZones.count == createZone) error:operationError informDelegate:YES handler:handler];
};
[saveRecZoneOp addDependency:fetchRecZonesOp];
[[FavController favDatabase] addOperation:fetchRecZonesOp];
[[FavController favDatabase] addOperation:saveRecZoneOp];
}
- (void)subscribeToFavChanges:(successCompletionHandler)handler {
// get current subscription
[[FavController favDatabase] fetchSubscriptionWithID:UTXAFavConCKSubscriptionID completionHandler:^(CKSubscription *subscription, NSError *error) {
if (subscription) {
NSLog(#"using existing subscription: %#", subscription);
[self successCompletionHandler:YES error:nil informDelegate:NO handler:handler];
} else {
CKSubscription *sub = [[CKSubscription alloc] initWithZoneID:[FavController favRecordZoneID]
subscriptionID:UTXAFavConCKSubscriptionID
options:0];// "You must specify 0 for this parameter. Zone subscriptions currently do not support any options."
[[FavController favDatabase] saveSubscription:sub completionHandler:^(CKSubscription *subscription, NSError *error) {
NSLog(#"created new subscription: %# %#", subscription, error);
[self successCompletionHandler:(error == nil) error:error informDelegate:YES handler:handler];
}];
}
}];
}
As soon as I add or remove a record on one device, I'll get a notification on all other device, which I handle like so in the FavController class:
/// #abstract Handle push notifications sent by iCloud.
/// #discussion App delegates call this method when they receive a push notification through didReceiveRemoteNotification.
/// Currently, only airport favorites produce a PN, it is of type CKNotificationTypeRecordZone.
/// #param userInfo The userInfo dict tied to each push notification.
- (void)handleCloudKitNotificationWithUserInfo:(NSDictionary *)userInfo {
[self recursivelyCheckForPreviousCloudKitNotifications];
}
- (void)recursivelyCheckForPreviousCloudKitNotifications {
CKFetchNotificationChangesOperation *fetchOp = [[CKFetchNotificationChangesOperation alloc] initWithPreviousServerChangeToken:_defCon.notificationChangeToken];
__weak CKFetchNotificationChangesOperation *weakOp = fetchOp;
fetchOp.notificationChangedBlock = ^(CKNotification *notification) {
[self handleNotification:notification];
};
fetchOp.fetchNotificationChangesCompletionBlock = ^( CKServerChangeToken *serverChangeToken, NSError *operationError) {
NSLog(#"new notification change token: %#", serverChangeToken);
_defCon.notificationChangeToken = serverChangeToken;
if (weakOp.moreComing) {
NSLog(#"more coming!!");
[self recursivelyCheckForPreviousCloudKitNotifications];
} else {
NSLog(#"done handling notification changes.");
}
};
[[FavController favContainer] addOperation:fetchOp];
}
- (void)handleNotification:(CKNotification *)notification {// withCompletionHandler:(successCompletionHandler)handler {
if (notification.notificationType == CKNotificationTypeRecordZone) {// make sure we handle only zone changes
CKRecordZoneNotification *noti = (CKRecordZoneNotification *)notification;
if ([noti.recordZoneID.zoneName isEqualToString:[FavController favRecordZoneID].zoneName]) {
// received an update for the fav zone
[self queuedFavUpdateFromCloud];
} else {
// received an update for an unknown zone
NSLog(#"WARNING: received an update for an unknown zone: %#", noti.recordZoneID.zoneName);
}
} else {
NSLog(#"WARNING: received unknown notification: %#", notification);
}
}

Okay I've finally figured it out. If you use a CKNotificationInfo for your alerts, didReceiveRemoteNotification will NOT be called on the Mac until and unless you set CKNotificationInfo.soundName to an empty string! This looks like a bug only in OS X (10.10 & 10.11 so far) but can be worked around by this simple change.

Related

firebase_messaging : no notifications coming through

Explaining the issue :
I've now tried getting firebase_messaging to work for almost a week.
I successfully set up an legacy Xcode APNS app, which worked after generating all new certificates, etc.
But with firebase_messaging I get no notifications at all.
I even gone so far as recreating a new flutter, firebase and appstoreconnect projects/apps.
But I got no notifications at all from firebase, either implemented in native Xcode or flutter.
If I subscribe to a topic which doesn't exist yet, it's being created; Notifications on Android and Analytics and InAppMessaging on iOS and Android are working fine, so definitely something is working.
What I've tried so far :
The official example projects for firebase_messaging on native Xcode and Flutter/Dart
Recreating all licenses/projects
Sending messages by topic (which I planned to do anyway)
applying patches/fixes/tips from GitHub/stackoverflow.
Code snippets to recreate the configuration :
Steps to recreate could be just downloading the Firebase Messaging example projects or following the official docs of setting up Firebase Messaging for native Xcode or Flutter. Basic steps to recreate examples listed here :
Implemented plugins (all newest versions) :
firebase_messaging
firebase_core
firebase_analytics
Flutter/Dart (main.dart):
void firebaseCloudMessaging_Listeners() {
if (Platform.isIOS) iOS_Permission();
firebaseMessaging.getToken().then((token){
print(token);
});
firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print('on message $message');
},
onResume: (Map<String, dynamic> message) async {
print('on resume $message');
},
onLaunch: (Map<String, dynamic> message) async {
print('on launch $message');
},
);
}
void iOS_Permission() {
firebaseMessaging.requestNotificationPermissions(
IosNotificationSettings(sound: true, badge: true, alert: true)
);
firebaseMessaging.onIosSettingsRegistered
.listen((IosNotificationSettings settings)
{
print("Settings registered: $settings");
});
}
void subscribeToFB() {
firebaseMessaging.subscribeToTopic('-------------Sandbox');
print("--- SUBSCRIBED ---");
}
void unsubscribeFromFB() {
firebaseMessaging.unsubscribeFromTopic('-------------Sandbox');
print("--- UNSUBSCRIBED ---");
}
Implemented Pods (all newest versions) :
pod 'Firebase/Messaging'
pod 'Firebase/Analytics'
Native Xcode (AppDelegate.h):
#import "AppDelegate.h"
#import UserNotifications;
#interface AppDelegate () <UNUserNotificationCenterDelegate>
#end
#implementation AppDelegate
NSString *const kGCMMessageIDKey = #"gcm.message_id";
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// [START configure_firebase]
[FIRApp configure];
// [END configure_firebase]
// [START set_messaging_delegate]
[FIRMessaging messaging].delegate = self;
// [END set_messaging_delegate]
// Register for remote notifications. This shows a permission dialog on first run, to
// show the dialog at a more appropriate time move this registration accordingly.
// [START register_for_notifications]
if ([UNUserNotificationCenter class] != nil) {
// iOS 10 or later
// For iOS 10 display notification (sent via APNS)
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert |
UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter]
requestAuthorizationWithOptions:authOptions
completionHandler:^(BOOL granted, NSError * _Nullable error) {
// ...
}];
} else {
// iOS 10 notifications aren't available; fall back to iOS 8-9 notifications.
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
}
[application registerForRemoteNotifications];
// [END register_for_notifications]
return YES;
}
// [START receive_message]
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
// Print message ID.
if (userInfo[kGCMMessageIDKey]) {
NSLog(#"Message ID: %#", userInfo[kGCMMessageIDKey]);
}
// Print full message.
NSLog(#"%#", userInfo);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
// Print message ID.
if (userInfo[kGCMMessageIDKey]) {
NSLog(#"Message ID: %#", userInfo[kGCMMessageIDKey]);
}
// Print full message.
NSLog(#"%#", userInfo);
completionHandler(UIBackgroundFetchResultNewData);
}
// [END receive_message]
// [START ios_10_message_handling]
// Receive displayed notifications for iOS 10 devices.
// Handle incoming notification messages while app is in the foreground.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
NSDictionary *userInfo = notification.request.content.userInfo;
// With swizzling disabled you must let Messaging know about the message, for Analytics
// [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
// Print message ID.
if (userInfo[kGCMMessageIDKey]) {
NSLog(#"Message ID: %#", userInfo[kGCMMessageIDKey]);
}
// Print full message.
NSLog(#"%#", userInfo);
// Change this to your preferred presentation option
completionHandler(UNNotificationPresentationOptionNone);
}
// Handle notification messages after display notification is tapped by the user.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void(^)(void))completionHandler {
NSDictionary *userInfo = response.notification.request.content.userInfo;
if (userInfo[kGCMMessageIDKey]) {
NSLog(#"Message ID: %#", userInfo[kGCMMessageIDKey]);
}
// Print full message.
NSLog(#"%#", userInfo);
completionHandler();
}
// [END ios_10_message_handling]
// [START refresh_token]
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
NSLog(#"FCM registration token: %#", fcmToken);
// Notify about received token.
NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:#"token"];
[[NSNotificationCenter defaultCenter] postNotificationName:
#"FCMToken" object:nil userInfo:dataDict];
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
// [END refresh_token]
// [START ios_10_data_message]
// Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
// To enable direct data messages, you can set [Messaging messaging].shouldEstablishDirectChannel to YES.
- (void)messaging:(FIRMessaging *)messaging didReceiveMessage:(FIRMessagingRemoteMessage *)remoteMessage {
NSLog(#"Received data message: %#", remoteMessage.appData);
}
// [END ios_10_data_message]
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(#"Unable to register for remote notifications: %#", error);
}
// This function is added here only for debugging purposes, and can be removed if swizzling is enabled.
// If swizzling is disabled then this function must be implemented so that the APNs device token can be paired to
// the FCM registration token.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(#"APNs device token retrieved: %#", deviceToken);
// With swizzling disabled you must set the APNs device token here.
// [FIRMessaging messaging].APNSToken = deviceToken;
}
#end
The IDEs (Xcode/VS Code # macOS HS) do not return any errors; also no errors in debug log. The app reports to be working fine but the messages just don't come through.
Can someone please help me with this? Thanks!
The fix was to just remove the suggested .p8 Key File (from Firebase Console > Project Settings > Cloud Messaging) and instead put in the APNS Development and Release Certificates.

Parse app crashes after pressing "OK" on Push Notification Alert

I don't have any code handling or creating a new UIAlertView in my didReceiveRemoteNotification method. Simply..
PFPush.handlePush(userInfo)
if application.applicationState == UIApplicationState.Active {
print("active")
}
When I press "OK" on the alert, the app crashes with exec_bad_access and the stack is stuck on the completion(NSNotFound) line below.
if ([UIAlertController class] != nil) {
__block UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
void (^alertActionHandler)(UIAlertAction *) = [^(UIAlertAction *action){
// This block intentionally retains alertController, and releases it afterwards.
if (action.style == UIAlertActionStyleCancel) {
completion(NSNotFound);
} else {
NSUInteger index = [alertController.actions indexOfObject:action];
completion(index - 1);
}
alertController = nil;
} copy];

How to correctly set application badge value in iOS 8?

Old method
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:count];
is now gives error Attempting to badge the application icon but haven't received permission from the user to badge the application.
Then I tried to use new API (that I'm think is related to badge value)
CKModifyBadgeOperation * operation = [[CKModifyBadgeOperation alloc] initWithBadgeValue:50];
[operation setModifyBadgeCompletionBlock:^(NSError *error) {
NSLog(#"%#", error);
}];
[operation start];
But I'm receiving error <CKError 0x165048a0: "Not Authenticated" (9/1002); "This request requires an authenticated account">
How to set badge or receive some new permissions?
In addition to Daij-Djan's answer: it's possible to stack the enums so you can request them all at once. Like follows:
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
Debug output mentions I should ask for Application Badge permission
to modify the badge under ios8 you have to ask for permissions
let settings = UIUserNotificationSettings(forTypes: UIUserNotificationType.Badge, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
or in objC
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
Additional info for previous posts (in complete to registerUserNotificationSettings):
Apple makes new API for registering notifications and working with badges.
See WWDC 2014 session video , text version
and documentation.
User can change permissions for every UIUserNotificationType (UIUserNotificationTypeBadge, UIUserNotificationTypeSound, UIUserNotificationTypeAlert) in Settings.
Before changing badge you must check permissions.
Code sample from my AppDelegate:
#ifdef __IPHONE_8_0
- (BOOL)checkNotificationType:(UIUserNotificationType)type
{
UIUserNotificationSettings *currentSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];
return (currentSettings.types & type);
}
#endif
- (void)setApplicationBadgeNumber:(NSInteger)badgeNumber
{
UIApplication *application = [UIApplication sharedApplication];
#ifdef __IPHONE_8_0
// compile with Xcode 6 or higher (iOS SDK >= 8.0)
if(SYSTEM_VERSION_LESS_THAN(#"8.0"))
{
application.applicationIconBadgeNumber = badgeNumber;
}
else
{
if ([self checkNotificationType:UIUserNotificationTypeBadge])
{
NSLog(#"badge number changed to %d", badgeNumber);
application.applicationIconBadgeNumber = badgeNumber;
}
else
NSLog(#"access denied for UIUserNotificationTypeBadge");
}
#else
// compile with Xcode 5 (iOS SDK < 8.0)
application.applicationIconBadgeNumber = badgeNumber;
#endif
}
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
The CurrentUserNotificationSettings method is available in the UI application instance and will give you the most up-to-date user notification preferences.
Working with badge number:
[self setApplicationBadgeNumber:0];
instead of
application.applicationIconBadgeNumber = 0;
PS: Checking at compiling (#ifdef __IPHONE_8_0) due to the need to build in Xcode5 and Xcode6.
If you do not have this need, the code can be simplified.
I write a class to handle it when I use swift:
class ZYUtility
{
/// Set badge
class func setApplicationBadgeNumber(badge: Int) {
if ZYUtility.SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO("8.0") {
if UIApplication.sharedApplication().currentUserNotificationSettings().types & UIUserNotificationType.Badge != nil {
UIApplication.sharedApplication().applicationIconBadgeNumber = badge
} else {
println("No permission to set badge number")
}
} else {
UIApplication.sharedApplication().applicationIconBadgeNumber = badge
}
}
/// System check
class func SYSTEM_VERSION_EQUAL_TO(version: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(version,
options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedSame
}
class func SYSTEM_VERSION_GREATER_THAN(version: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(version,
options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending
}
class func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(version,
options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedAscending
}
class func SYSTEM_VERSION_LESS_THAN(version: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(version,
options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedAscending
}
class func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(version: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(version,
options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedDescending
}
}
update to 8.3, ObjC: we should add Daij-Djan script to replace NSLog(#"access denied for UIUserNotificationTypeBadge"); in Spidy & KepPM solution above. Hope this help s.o.

Is there some straightforward documentation on implementing the Game Center?

I'm trying to implement Game Center into my ios7 game (Xcode 5), but the material in the apple docs and the stuff I've seen online doesn't seem to work very well.
These are the two main methods I'm using wish produce no errors but I don't get any data either:
- (void) retrieveTopTenScores
{
GKLeaderboard *leaderboardRequest = [[GKLeaderboard alloc] init];
if (leaderboardRequest != nil)
{
leaderboardRequest.playerScope = GKLeaderboardPlayerScopeGlobal;
leaderboardRequest.timeScope = GKLeaderboardTimeScopeToday;
leaderboardRequest.identifier = kLeaderboardID;
leaderboardRequest.range = NSMakeRange(1,10);
[leaderboardRequest loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil)
{
// Handle the error.
}
if (scores != nil)
{
// Process the score information.
} else {
NSLog(#"scores retrieved successfully but no scores in the leaderboard");
}
}];
}
}
-(void)submitMyScore
{
//This is the same category id you set in your itunes connect GameCenter LeaderBoard
GKScore *myScoreValue = [[GKScore alloc] initWithLeaderboardIdentifier:kLeaderboardID];
myScoreValue.value = 5123123;
[myScoreValue reportScoreWithCompletionHandler:^(NSError *error){
if(error != nil){
NSLog(#"Score Submission Failed");
} else {
NSLog(#"Score Submitted");
}
}];
}
So I'm looking for some simple example code to do this successfully...
thanks
rich
I see nothing wrong with your code. Is the player authenticated when you run it?, what error are you getting? If you look for sample GameKit code there is some at iOS 6 Advanced Cookbook from Erica Sadun, but nothing you shouldn't be able to figure out reading the API.
the answer is this for submitting scores in iOS7 to the game centre
Game Center Helper/Manager/Control (Object).h
+ (gamecenterhelper/manager/control *)sharedInstance;
-(void)reportScore:(int64_t)score forLeaderboardID:(NSString*)identifier;
Game Center Helper/Manager/Control (Object).m
-(void)reportScore:(int64_t)score forLeaderboardID:(NSString*)identifier
{
GKScore *scoreReporter = [[GKScore alloc] initWithLeaderboardIdentifier: identifier];
scoreReporter.value = score;
scoreReporter.context = 0;
NSArray *scores = #[scoreReporter];
[GKScore reportScores:scores withCompletionHandler:^(NSError *error) {
}];
}
viewcontroller.h
#import "gamecenterhelper/manager/control"
viewcontroller.m
[[gamecenterhelper/manager/control sharedInstance] reportScore:(int64_t) forLeaderboardID:(NSString*)];
//in place of int64_t place your integer you want uploaded, and instead on NNString* add your leaderboard identifier

Wrong callback in Objective-C when calling SOAP service

I have 2 SOAP services that I want to call from an IPad app.
One is used to Log the user in (SecurityASMX), the other is one that returns the current username (SecuredCalls) once logged in.
I can call the SecurityASMX no problem using the following code. The Async call callback is operation :
- (IBAction) OnButtonClick:(id) sender {
bindingSecurity = [[SecurityASMXSvc SecurityASMXSoapBinding] initWithAddress:#"http://myserver/Azur.IPADTest.Web.Services/public/Security.asmx"];
bindingSecurity.logXMLInOut = YES;
SecurityASMXSvc_Login *requestLogin = [[SecurityASMXSvc_Login alloc] init];
requestLogin.strUsername = #"test";
requestLogin.strPassword = #"testpass";
[bindingSecurity LoginAsyncUsingParameters:requestLogin delegate:self];
[requestLogin release];
self.label.text = #"Login in progress";
}
- (void) operation:(SecurityASMXSoapBindingOperation *)operation completedWithResponse:(SecurityASMXSoapBindingResponse *)response
{
[NSThread sleepForTimeInterval:2.0];
self.label.text = #"Login Done!";
}
This works fine.
However, in the same code file, I have a binding to my second web service to return the username with the following code. The async call callback is operationSecure :
- (IBAction) OnButtonSecureCallClick:(id) sender {
bindingSecuredCalls = [[SecureCallsSvc SecureCallsSoapBinding] initWithAddress:#"http://myserver/Azur.IPADTest.Web.Services/private/SecureCalls.asmx"];
bindingSecuredCalls.logXMLInOut = YES;
SecureCallsSvc_ReturnUserName *requestReturnUserName = [[SecureCallsSvc_ReturnUserName alloc] init];
[bindingSecuredCalls ReturnUserNameAsyncUsingParameters:requestReturnUserName delegate:self];
[requestReturnUserName release];
self.label.text = #"Get UserName In Progress";
}
- (void) operationSecure:(SecureCallsSoapBindingOperation *)operation completedWithResponse:(SecureCallsSoapBindingResponse *)response
{
[NSThread sleepForTimeInterval:2.0];
self.label.text = #"Get Username Done!";
}
The problem is that when the call to ReturnUserName returns, the method that gets called is the one for the login (operation) and not the one I want (operationSecure).
How can I tell my second webservice binding to call the second callback?
Thanks!
First thing would be to check if the API you're using (I assume it's a third party API) allows you to specify the callback method.
If not, you can work with the operation parameter and use isKindOfClass to see what is actually being passed.
- (void) operation:(SecurityASMXSoapBindingOperation *)operation completedWithResponse:(SecurityASMXSoapBindingResponse *)response
{
[NSThread sleepForTimeInterval:2.0];
if([operation isKindOfClass:[SecurityASMXSoapBindingOperation class]])
{
self.label.text = #"Login Done!";
}
else if([operation isKindOfClass:[SecureCallsSoapBindingOperation class]])
{
self.label.text = #"Get Username Done!";
}
}
Ideally you'd set the type of operation and response parameters to be the superclass of the respective objects returned.

Resources