App is crashing, reason on crash is
'No delegate set?...how are you going to callbacks?'
Delegate for PGTransactionViewController is set. But still its not calling the delegate method.
PGTransactionViewController *txnController = [[PGTransactionViewController alloc]
initTransactionForOrder:pgOrder];
#if SERVER_PRODUCTION
txnController.serverType = eServerTypeProduction;
#else
txnController.serverType = eServerTypeStaging;
#endif
txnController.merchant = [PGMerchantConfiguration defaultConfiguration];
// Set the Delegates
txnController.delegate = self;
[self.hostViewController.navigationController pushViewController:txnController animated:YES];
The class is subclass of NSObject.
Are you using these delegate methods?
- (void)didSucceedTransaction:(PGTransactionViewController *)controller
response:(NSDictionary *)response
{
DEBUGLOG(#"ViewController::didSucceedTransactionresponse= %#", response);
}
- (void)didFailTransaction:(PGTransactionViewController *)controller error:(NSError *)error response:(NSDictionary *)response
{
DEBUGLOG(#"ViewController::didFailTransaction error = %# response= %#", error, response);
}
- (void)didCancelTransaction:(PGTransactionViewController *)controller error:(NSError*)error response:(NSDictionary *)response
{
DEBUGLOG(#"ViewController::didCancelTransaction error = %# response= %#", error, response);
}
- (void)didFinishCASTransaction:(PGTransactionViewController *)controller response:(NSDictionary *)response
{
DEBUGLOG(#"ViewController::didFinishCASTransaction:response = %#", response);
}
Related
My App was rejected by Apple because it can't connect to other device running iOS 10.1.1 on Wi-Fi connected to an IPv6 network.
When I tap on connect, the app continues to search for invitees and no further user action is produced.
I use Multi-peer Connectivity and I never tested my App being connected to an IPv6(It's my first release). But the App run very fine without having any connection or being connected to IPv4 network.
I don't know why the App is running and connecting fine using the IPv4 and doesn't connect to peer if the iPad is connected to an IPv6 network.
So my Question: Is it possible to use Multi-peer Connectivity with IPv6 so that Apple can approve the App or how should I handle this Issue ?
Here is my Code, maybe it is something wrong there.
#interface ConnectionManageriOS7 () <MCSessionDelegate, MCBrowserViewControllerDelegate>
{
UILocalNotification *_expireNotification;
UIBackgroundTaskIdentifier _taskId;
}
#property (nonatomic, strong) MCSession *session;
#property (nonatomic, strong) MCPeerID *localPeerID;
#property (nonatomic, strong) MCBrowserViewController *browserVC;
#property (nonatomic, strong) MCAdvertiserAssistant *advertiser;
#end
static ConnectionManageriOS7 *_manager = nil;
#implementation ConnectionManageriOS7
+ (ConnectionManageriOS7 *)connectManager {
#synchronized([ConnectionManageriOS7 class]){
if (_manager == nil) {
_manager = [[ConnectionManageriOS7 alloc] init];
}
return _manager;
}
return nil;
}
- (id)init {
self = [super init];
if (self) {
[self setupSessionAndAdvertiser];
}
return self;
}
- (void)setupSessionAndAdvertiser {
_localPeerID = [[MCPeerID alloc] initWithDisplayName:[UIDevice currentDevice].name];;
_session = [[MCSession alloc] initWithPeer:_localPeerID];
_session.delegate = self;
}
- (void)connectWithDelegate:(id)delegate {
_delegate = delegate;
if (_session.connectedPeers.count) {
if ([_delegate respondsToSelector:#selector(didConntectedWithManager:)]) {
[_delegate didConntectedWithManager:self];
}
} else {
if (_advertiser == nil) {
_advertiser = [[MCAdvertiserAssistant alloc] initWithServiceType:VISUS_Service
discoveryInfo:nil
session:_session];
_isConnected = NO;
[_advertiser start];
}
if (_browserVC == nil) {
_browserVC = [[MCBrowserViewController alloc] initWithServiceType:VISUS_Service session:_session];
_browserVC.delegate = self;
}
[(UIViewController *)delegate presentViewController:_browserVC
animated:YES completion:nil];
}
}
- (void)sendMessage:(NSString *)message {
NSData *textData = [message dataUsingEncoding:NSASCIIStringEncoding];
NSLog(#"Send Data: %#", message);
NSError *error = nil;
[_session sendData:textData
toPeers:_session.connectedPeers
withMode:MCSessionSendDataReliable
error:&error];
if (error) {
//
[self session:_session peer:nil didChangeState:MCSessionStateNotConnected];
NSLog(#"error %#", error.userInfo);
}
}
- (void)stopService {
NSLog(#"Stop Service");
[_advertiser stop];
_advertiser = nil;
_browserVC = nil;
}
#pragma marks -
#pragma marks MCBrowserViewControllerDelegate
- (void) dismissBrowserVC{
[_browserVC dismissViewControllerAnimated:YES completion:nil];
}
// Notifies the delegate, when the user taps the done button
- (void)browserViewControllerDidFinish:(MCBrowserViewController *)browserViewController {
if ([_delegate respondsToSelector:#selector(didConntectedWithManager:)]) {
[_delegate didConntectedWithManager:self];
}
[self dismissBrowserVC];
}
// Notifies delegate that the user taps the cancel button.
- (void)browserViewControllerWasCancelled:(MCBrowserViewController *)browserViewController{
if (_browserVC == nil) {
[browserViewController dismissViewControllerAnimated:YES completion:nil];
}else {
[self dismissBrowserVC];
}
}
#pragma marks -
#pragma marks MCBrowserViewControllerDelegate
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
if (state != MCSessionStateConnecting) {
if (state == MCSessionStateConnected) {
_isConnected = true;
if ([_delegate respondsToSelector:#selector(willConntectedWithManager:)]) {
[_delegate willConntectedWithManager:self];
}
}
else {
_isConnected = false;
[self stopService];
if ([_delegate respondsToSelector:#selector(didDisconntectedWithManager:)]) {
[_delegate didDisconntectedWithManager:self];
}
}
}
}
// Received data from remote peer
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{
// Decode data back to NSString
NSString *message = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"Receive Data: %#", message);
// append message to text box:
dispatch_async(dispatch_get_main_queue(), ^{
if ([_delegate respondsToSelector:#selector(connectionManager:receivedString:)]) {
[_delegate connectionManager:self receivedString:message];
}
});
}
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error {
_isConnected = false;
[self stopService];
NSLog(#"----- Error ----- %#", error.localizedDescription);
}
// Received a byte stream from remote peer
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID {
}
// Start receiving a resource from remote peer
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress {
}
- (void) session:(MCSession *)session didReceiveCertificate:(NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void (^)(BOOL accept))certificateHandler
{
certificateHandler(YES);
}
- (void) createExpireNotification
{
[self killExpireNotification];
if (_session.connectedPeers.count != 0) // if peers connected, setup kill switch
{
NSTimeInterval gracePeriod = 20.0f;
// create notification that will get the user back into the app when the background process time is about to expire
NSTimeInterval msgTime = UIApplication.sharedApplication.backgroundTimeRemaining - gracePeriod;
UILocalNotification* n = [[UILocalNotification alloc] init];
_expireNotification = n;
_expireNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:msgTime];
_expireNotification.alertBody = #"Bluetooth Connectivity is about to disconnect. Open the app to resume Test";
_expireNotification.soundName = UILocalNotificationDefaultSoundName;
_expireNotification.applicationIconBadgeNumber = 1;
[UIApplication.sharedApplication scheduleLocalNotification:_expireNotification];
}
}
- (void) killExpireNotification
{
if (_expireNotification != nil)
{
[UIApplication.sharedApplication cancelLocalNotification:_expireNotification];
_expireNotification = nil;
}
}
- (void)bacgroundHandling {
_taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^
{
[self stopService];
[[UIApplication sharedApplication] endBackgroundTask:_taskId];
_taskId = UIBackgroundTaskInvalid;
}];
[self createExpireNotification];
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
{
// http://down.vcnc.co.kr/WWDC_2013/Video/708.pdf -- wwdc tutorial, this part is towards the end (p119)
// self.arrayInvitationHandler = [NSArray arrayWithObject:[invitationHandler copy]];
// ask the user
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:peerID.displayName
message:#"Would like to create a session with you"
delegate:self
cancelButtonTitle:#"Decline" otherButtonTitles:#"Accept", nil];
[alertView show];
}
- (void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// retrieve the invitationHandler and check whether the user accepted or declined the invitation...
BOOL accept = (buttonIndex != alertView.cancelButtonIndex) ? YES : NO;
// respond
if(accept) {
// void (^invitationHandler)(BOOL, MCSession *) = [self.arrayInvitationHandler objectAtIndex:0];
// invitationHandler(accept, self.mySession);
}
else
{
NSLog(#"Session disallowed");
}
}
- (void)terminate {
[self killExpireNotification];
[self stopService];
}
#end
I have solved the problem. For everybody with simular problem:
It wasn't a problem with IPv6, it is a matter of how to use Multipeer connectivity. In my Case I tryied to the the IPv6 connection with a iPad and a Simulator. And I used my Macbook for creating a nat64 network. And the reason why the simulator and iPad never saw each other the fact that they where not connected to same wifi network.
Solution:
Just take for testing two iPads and use your mac as nat64 network accesspoint.
Currently i am working on XMPP protocol in ios for chatting application. i want to put alert view and authentication on Login button. if authentication will successful then user can see homescreen screen else alert view will appear please check username and password i show chat secure open source project but i can't understand.
//appdelegate.m file .//
- (BOOL)connect
{
if (![xmppStream isDisconnected]) {
return YES;
// isauthenticate=YES;
}
NSString *myJID = [[NSUserDefaults standardUserDefaults] stringForKey:kXMPPmyJID];
NSString *myPassword = [[NSUserDefaults standardUserDefaults] stringForKey:kXMPPmyPassword];
//
// If you don't want to use the Settings view to set the JID,
// uncomment the section below to hard code a JID and password.
//
// myJID = #"user#gmail.com/xmppframework";
// myPassword = #"";
if (myJID == nil || myPassword == nil) {
return NO;
}
[xmppStream setMyJID:[XMPPJID jidWithString:myJID]];
password = myPassword;
NSError *error = nil;
if (![xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&error])
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error connecting"
message:#"See console for error details."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
DDLogError(#"Error connecting: %#", error);
return NO;
}
return YES;
}
- (void)disconnect
{
[self goOffline];
[xmppStream disconnect];
}
#pragma mark UIApplicationDelegate
- (void)applicationDidEnterBackground:(UIApplication *)application
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
#if TARGET_IPHONE_SIMULATOR
DDLogError(#"The iPhone simulator does not process background network traffic. "
#"Inbound traffic is queued until the keepAliveTimeout:handler: fires.");
#endif
if ([application respondsToSelector:#selector(setKeepAliveTimeout:handler:)])
{
[application setKeepAliveTimeout:600 handler:^{
DDLogVerbose(#"KeepAliveHandler");
// Do other keep alive stuff here.
}];
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)applicationWillTerminate:(UIApplication *)application
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
[self teardownStream];
}
#pragma mark XMPPStream Delegate
- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSString *expectedCertName = [xmppStream.myJID domain];
if (expectedCertName)
{
settings[(NSString *) kCFStreamSSLPeerName] = expectedCertName;
}
if (customCertEvaluation)
{
settings[GCDAsyncSocketManuallyEvaluateTrust] = #(YES);
}
}
- (void)xmppStream:(XMPPStream *)sender didReceiveTrust:(SecTrustRef)trust
completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
// The delegate method should likely have code similar to this,
// but will presumably perform some extra security code stuff.
// For example, allowing a specific self-signed certificate that is known to the app.
dispatch_queue_t bgQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(bgQueue, ^{
SecTrustResultType result = kSecTrustResultDeny;
OSStatus status = SecTrustEvaluate(trust, &result);
if (status == noErr && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)) {
completionHandler(YES);
}
else {
completionHandler(NO);
}
});
}
- (void)xmppStreamDidSecure:(XMPPStream *)sender
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
isXmppConnected = YES;
NSError *error = nil;
if (![[self xmppStream] authenticateWithPassword:password error:&error])
{
DDLogError(#"Error authenticating: %#", error);
}
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
isauthenticate=YES;
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
[self goOnline];
}
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
i have tried with setting BOOL(isauthenticate) in xmppStreamDidAuthenticate method but not success. i can redirect to homepage but if i wrote wrong detail still it will redirect to homepage. i want to set it if username or password are wrong and did not authenticate by server.
//view controller.m file //
#import "ViewController.h"
#import "AppDelegate.h"
#interface ViewController ()<MBProgressHUDDelegate>
{
MBProgressHUD *HUD;
IBOutlet UITextField *mViewEmail;
IBOutlet UITextField *mViewPassword;
}
#end
NSString *const kXMPPmyJID = #"kXMPPmyJID";
NSString *const kXMPPmyPassword = #"kXMPPmyPassword";
#implementation ViewController
- (IBAction)checkLogin:(id)sender {
NSLog(#"Email: %# Password: %#",mViewEmail.text,mViewPassword.text);
[self setField:mViewEmail forKey:kXMPPmyJID];
[self setField:mViewPassword forKey:kXMPPmyPassword];
// if (appdelegate.connect==YES) {
if([ [self appDelegate] connect]) {
// if (appdelegate.isauthenticate==YES) {
HUD = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES] ;
HUD.delegate = self;
HUD.color = [UIColor blackColor];
HUD.labelText = #"Please Wait";
HUD.dimBackground = YES;
// HUD.detailsLabelText = #"Close chat";
[self showHome];
//}
}
//}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sorry"
message:#"Please Check Username or Password"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
- (void)showHome{
[self performSegueWithIdentifier:#"signIn" sender:self];
}
ok. so finaly my problem is solved. and i am posting my answer. first of all my mistake is i forgot to write
appdelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
appdelegate.viewController = self; // very imp when you call method in app delegate.h
in my view controller. so when i call viewcontroller's method in appdelegate it call's but do not execute due to above method is missing (Second line). and then i have call view controller's segue method in - (void)xmppStreamDidAuthenticate:(XMPPStream *)sender method. and then work perfectly. so my final solution is
//app delegate.m file//
- (BOOL)connect
{
// Setup HUD(Activity Indicator) when Connect method call //
HUD = [[MBProgressHUD alloc] initWithWindow:[UIApplication sharedApplication].keyWindow]; [self.window.rootViewController.view addSubview:HUD];
[HUD setDetailsLabelText:#"Please wait..."];
[HUD setDimBackground:YES];
[HUD setOpacity:0.5f];
[HUD show:YES];
if (![xmppStream isDisconnected]) {
return YES;
}
NSString *myJID = [[NSUserDefaults standardUserDefaults] stringForKey:kXMPPmyJID];
NSString *myPassword = [[NSUserDefaults standardUserDefaults] stringForKey:kXMPPmyPassword];
if (myJID == nil || myPassword == nil) {
return NO;
}
[xmppStream setMyJID:[XMPPJID jidWithString:myJID]];
password = myPassword;
NSError *error = nil;
if (![xmppStream connectWithTimeout:XMPPStreamTimeoutNone error:&error])
{
HUD.hidden=YES;
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error connecting"
message:#"See console for error details."
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];
DDLogError(#"Error connecting: %#", error);
return NO;
}
return YES;
}
- (void)disconnect
{
[self goOffline];
[xmppStream disconnect];
}
#pragma mark UIApplicationDelegate
- (void)applicationDidEnterBackground:(UIApplication *)application
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
#if TARGET_IPHONE_SIMULATOR
DDLogError(#"The iPhone simulator does not process background network traffic. "
#"Inbound traffic is queued until the keepAliveTimeout:handler: fires.");
#endif
if ([application respondsToSelector:#selector(setKeepAliveTimeout:handler:)])
{
[application setKeepAliveTimeout:600 handler:^{
DDLogVerbose(#"KeepAliveHandler");
// Do other keep alive stuff here.
}];
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)applicationWillTerminate:(UIApplication *)application
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
[self teardownStream];
}
#pragma mark XMPPStream Delegate
- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
NSString *expectedCertName = [xmppStream.myJID domain];
if (expectedCertName)
{
settings[(NSString *) kCFStreamSSLPeerName] = expectedCertName;
}
if (customCertEvaluation)
{
settings[GCDAsyncSocketManuallyEvaluateTrust] = #(YES);
}
}
- (void)xmppStream:(XMPPStream *)sender didReceiveTrust:(SecTrustRef)trust
completionHandler:(void (^)(BOOL shouldTrustPeer))completionHandler
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
dispatch_queue_t bgQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(bgQueue, ^{
SecTrustResultType result = kSecTrustResultDeny;
OSStatus status = SecTrustEvaluate(trust, &result);
if (status == noErr && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)) {
completionHandler(YES);
}
else {
completionHandler(NO);
}
});
}
- (void)xmppStreamDidSecure:(XMPPStream *)sender
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
}
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
isXmppConnected = YES;
NSError *error = nil;
if (![[self xmppStream] authenticateWithPassword:password error:&error])
{
DDLogError(#"Error authenticating: %#", error);
}
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
HUD.hidden=YES; //Hud Will be hide when User Authenticated
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
[self.viewController showHome]; // view controllers method to go to next view controller //
[self goOnline];
}
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
// HUD will be hidden and alertview will be shown //
HUD.hidden=YES;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sorry"
message:#"Please Check Username or Password"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
isauthenticate=NO;
DDLogVerbose(#"%#: %#", THIS_FILE, THIS_METHOD);
{
NSLog(#"error = %#", error);
}
}
and in viewcontroller.m we have show that viewcontroller is also appdelegate controller. so we have to declare it in - (void)viewDidLoad method.
// viewcontroller.m file//
- (void)viewDidLoad
{
[super viewDidLoad];
appdelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
appdelegate.viewController = self;
}
- (AppDelegate *)appDelegate
{
return (AppDelegate *)[[UIApplication sharedApplication] delegate];
}
- (IBAction)checkLogin:(id)sender {
[self dismissKeyboard];
NSLog(#"Email: %# Password: %#",mViewEmail.text,mViewPassword.text);
[self setField:mViewEmail forKey:kXMPPmyJID];
[self setField:mViewPassword forKey:kXMPPmyPassword];
[[self appDelegate ]connect];//call when loginbutton pressed
}
//call in appdelegate.h // segue(push) to next view
- (void)showHome
{
[self performSegueWithIdentifier:#"signIn" sender:self];
}
Note: I have tried to explain as much as i can.
If username and password are correct then xmppStreamDidAuthenticate method call and if one of them is incorrect then didNotAuthenticate method call.
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
}
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
NSLog(#"error = %#", error);
}
Here print error and display this error in UIALertview as you required.
Actually you are checking XMPP connection that is not means Authenticate User. if your User Name and password is correct then you received response in xmppStreamDidAuthenticate method. where you can write the code to push to HomeViewController once user is verified.
Below two methods, you can used to show alert or push to another view once user varified.
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
}
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
NSLog(#"Error");
}
this is XMPP Delegate methods
Hope this help you.
So, I have all multipeer connectivity related code in the main thread. I have a MCSession, MCNearbyServiceAdvertiser, and a MCNearbyServiceBrowser. These are all created with peerID, and I make sure only one sends an invitation.
The session becomes connected. My problems is that, two clients take around 20-30 seconds to connect. This is unacceptable. The clients are on good Wifi, and bluetooth. I want the browsing, invitation handler, and connection to take place within 1 second. Does anyone have any idea what is slowing things down?
Code is exactly as provided here and I also implemented certificateHandler(YES)
#interface SessionController () // Class extension
#property (nonatomic, strong) MCPeerID *peerID;
#property (nonatomic, strong) MCSession *session;
#property (nonatomic, strong) MCNearbyServiceAdvertiser *serviceAdvertiser;
#property (nonatomic, strong) MCNearbyServiceBrowser *serviceBrowser;
// Connected peers are stored in the MCSession
// Manually track connecting and disconnected peers
#property (nonatomic, strong) NSMutableOrderedSet *connectingPeersOrderedSet;
#property (nonatomic, strong) NSMutableOrderedSet *disconnectedPeersOrderedSet;
#end
#implementation SessionController
static NSString * const kMCSessionServiceType = #"mcsessionp2p";
#pragma mark - Initializer
- (instancetype)init
{
self = [super init];
if (self)
{
_peerID = [[MCPeerID alloc] initWithDisplayName:[[UIDevice currentDevice] name]];
_connectingPeersOrderedSet = [[NSMutableOrderedSet alloc] init];
_disconnectedPeersOrderedSet = [[NSMutableOrderedSet alloc] init];
NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
// Register for notifications
[defaultCenter addObserver:self
selector:#selector(startServices)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[defaultCenter addObserver:self
selector:#selector(stopServices)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[self startServices];
_displayName = self.session.myPeerID.displayName;
}
return self;
}
#pragma mark - Memory management
- (void)dealloc
{
// Unregister for notifications on deallocation.
[[NSNotificationCenter defaultCenter] removeObserver:self];
// Nil out delegates
_session.delegate = nil;
_serviceAdvertiser.delegate = nil;
_serviceBrowser.delegate = nil;
}
#pragma mark - Override property accessors
- (NSArray *)connectedPeers
{
return self.session.connectedPeers;
}
- (NSArray *)connectingPeers
{
return [self.connectingPeersOrderedSet array];
}
- (NSArray *)disconnectedPeers
{
return [self.disconnectedPeersOrderedSet array];
}
#pragma mark - Private methods
- (void)setupSession
{
// Create the session that peers will be invited/join into.
_session = [[MCSession alloc] initWithPeer:self.peerID];
self.session.delegate = self;
// Create the service advertiser
_serviceAdvertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.peerID
discoveryInfo:nil
serviceType:kMCSessionServiceType];
self.serviceAdvertiser.delegate = self;
// Create the service browser
_serviceBrowser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.peerID
serviceType:kMCSessionServiceType];
self.serviceBrowser.delegate = self;
}
- (void)teardownSession
{
[self.session disconnect];
[self.connectingPeersOrderedSet removeAllObjects];
[self.disconnectedPeersOrderedSet removeAllObjects];
}
- (void)startServices
{
[self setupSession];
[self.serviceAdvertiser startAdvertisingPeer];
[self.serviceBrowser startBrowsingForPeers];
}
- (void)stopServices
{
[self.serviceBrowser stopBrowsingForPeers];
[self.serviceAdvertiser stopAdvertisingPeer];
[self teardownSession];
}
- (void)updateDelegate
{
[self.delegate sessionDidChangeState];
}
- (NSString *)stringForPeerConnectionState:(MCSessionState)state
{
switch (state) {
case MCSessionStateConnected:
return #"Connected";
case MCSessionStateConnecting:
return #"Connecting";
case MCSessionStateNotConnected:
return #"Not Connected";
}
}
#pragma mark - MCSessionDelegate protocol conformance
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
{
NSLog(#"Peer [%#] changed state to %#", peerID.displayName, [self stringForPeerConnectionState:state]);
switch (state)
{
case MCSessionStateConnecting:
{
[self.connectingPeersOrderedSet addObject:peerID];
[self.disconnectedPeersOrderedSet removeObject:peerID];
break;
}
case MCSessionStateConnected:
{
[self.connectingPeersOrderedSet removeObject:peerID];
[self.disconnectedPeersOrderedSet removeObject:peerID];
break;
}
case MCSessionStateNotConnected:
{
[self.connectingPeersOrderedSet removeObject:peerID];
[self.disconnectedPeersOrderedSet addObject:peerID];
break;
}
}
[self updateDelegate];
}
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
{
// Decode the incoming data to a UTF8 encoded string
NSString *receivedMessage = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"didReceiveData %# from %#", receivedMessage, peerID.displayName);
}
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress
{
NSLog(#"didStartReceivingResourceWithName [%#] from %# with progress [%#]", resourceName, peerID.displayName, progress);
}
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error
{
NSLog(#"didFinishReceivingResourceWithName [%#] from %#", resourceName, peerID.displayName);
// If error is not nil something went wrong
if (error)
{
NSLog(#"Error [%#] receiving resource from %# ", [error localizedDescription], peerID.displayName);
}
else
{
// No error so this is a completed transfer. The resources is located in a temporary location and should be copied to a permenant location immediately.
// Write to documents directory
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *copyPath = [NSString stringWithFormat:#"%#/%#", [paths firstObject], resourceName];
if (![[NSFileManager defaultManager] copyItemAtPath:[localURL path] toPath:copyPath error:nil])
{
NSLog(#"Error copying resource to documents directory");
}
else
{
// Get a URL for the path we just copied the resource to
NSURL *url = [NSURL fileURLWithPath:copyPath];
NSLog(#"url = %#", url);
}
}
}
// Streaming API not utilized in this sample code
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID
{
NSLog(#"didReceiveStream %# from %#", streamName, peerID.displayName);
}
#pragma mark - MCNearbyServiceBrowserDelegate protocol conformance
// Found a nearby advertising peer
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info
{
NSString *remotePeerName = peerID.displayName;
NSLog(#"Browser found %#", remotePeerName);
MCPeerID *myPeerID = self.session.myPeerID;
BOOL shouldInvite = ([myPeerID.displayName compare:remotePeerName] == NSOrderedDescending);
if (shouldInvite)
{
NSLog(#"Inviting %#", remotePeerName);
[browser invitePeer:peerID toSession:self.session withContext:nil timeout:30.0];
}
else
{
NSLog(#"Not inviting %#", remotePeerName);
}
[self updateDelegate];
}
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID
{
NSLog(#"lostPeer %#", peerID.displayName);
[self.connectingPeersOrderedSet removeObject:peerID];
[self.disconnectedPeersOrderedSet addObject:peerID];
[self updateDelegate];
}
- (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error
{
NSLog(#"didNotStartBrowsingForPeers: %#", error);
}
#pragma mark - MCNearbyServiceAdvertiserDelegate protocol conformance
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
{
NSLog(#"didReceiveInvitationFromPeer %#", peerID.displayName);
invitationHandler(YES, self.session);
[self.connectingPeersOrderedSet addObject:peerID];
[self.disconnectedPeersOrderedSet removeObject:peerID];
[self updateDelegate];
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didNotStartAdvertisingPeer:(NSError *)error
{
NSLog(#"didNotStartAdvertisingForPeers: %#", error);
}
#end
I've noticed this issue to and i can't seem to figure out whats happening here, it appears when debugging that there is a huge delay between the notification for state changing being fired, perhaps something to do with the view itself.
Update: Well i think i figured the issues out after a bit of reading, the response is pretty much instant now, in the notification in the view i have pushed the process back to the main thread like so:
-(void)peerDidChangeStateWithNotification:(NSNotification *)notification{
MCPeerID *peerID = [[notification userInfo] objectForKey:#"peerID"];
NSString *peerDisplayName = peerID.displayName;
MCSessionState state = [[[notification userInfo] objectForKey:#"state"] intValue];
if (state != MCSessionStateConnecting) {
if (state == MCSessionStateConnected) {
// add the user
[arrConnectedDevices addObject:peerDisplayName];
}
else if (state == MCSessionStateNotConnected){
// do we have connections
if ([arrConnectedDevices count] > 0) {
int indexOfPeer = [arrConnectedDevices indexOfObject:peerDisplayName];
[arrConnectedDevices removeObjectAtIndex:indexOfPeer];
}
}
}
// push to main queue for speedy response
dispatch_async(dispatch_get_main_queue(), ^(void) {
[collView reloadData];
BOOL peersExist = ([[appDelegate.mcManager.session connectedPeers] count] == 0);
NSLog(#"PEER COUNT IS %lu",(unsigned long)[[appDelegate.mcManager.session connectedPeers] count]);
[disconnectButton setEnabled:!peersExist];
if ([disconnectButton isEnabled]) {
[disconnectButton setBackgroundColor:[UIColor colorWithRed:(51/255.0) green:(202/255.0) blue:(168/255.0) alpha:1.0]];
}
else{
[disconnectButton setBackgroundColor:[UIColor colorWithRed:(107/255.0) green:(107/255.0) blue:(107/255.0) alpha:1.0]];
}
});
}
Hope this helps anyone who ran into the issues.
I'm working on integrating turn based matches in my game and a few days ago I started getting weird errors from the GameKit API saying that the local player is not authenticated, even though he is.
When I launch the app, the authenticateHandler is called, the view controller is displayed and after entering the password, the authenticaHandler is called again and the local player seems to be authenticated. isAuthenticated returns YES.
But as soon as I start using any of the GameKit APIs like loadFriendsWithCompletionHandler:, an error is returned saying that the player has not been authenticated.
This is the code for handling authentication changes.
[[GKLocalPlayer localPlayer] setAuthenticateHandler:^(UIViewController *viewController, NSError *error) {
if ([[GKLocalPlayer localPlayer] isAuthenticated]) {
// Player authenticated
} else {
// Player not authenticated
if (viewController != nil) {
// Present view controller
}
}
}];
And this is the error message I receive when calling any of the GameKit methods. Please note that -isAuthenticated still returns YES when the error is returned.
Error finding match: Error Domain=GKErrorDomain Code=6 "The requested operation could not be completed because local player has not been authenticated." UserInfo=0x14e9f950 {NSLocalizedDescription=The requested operation could not be completed because local player has not been authenticated.}
(lldb) print (BOOL) [[GKLocalPlayer localPlayer] isAuthenticated]
(BOOL) $3 = YES
I'm testing in the Game Center sandbox and it started happening a few days ago. Previously, I didn't experience the problem at all.
It only happens about one of three times when the app is started. I have tried deleting the app, restarting my devices, cleaning the build folder and everything else I could think of.
Am I missing something or has anybody else experienced similar problems?
This rich Apple documentation is a great place to look at. Here are 2 things which I would suggest -
Game Center fails to complete authentication if your device has
incorrect dates. So, go ahead and check the current date.
You might have done this. I trust you - iOS Simulator >> Reset
Content and Settings
Do you think there could be something wrong with the way you are using -[GKLocalPlayer loadFriendsWithCompletionHandler:]? Nothing wrong with your authentication function above, but I'd love to share mine if it works for you -
-(void)authenticateLocalPlayer{
// Instantiate a GKLocalPlayer object to use for authenticating a player.
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
// If it's needed display the login view controller.
[self presentViewController:viewController animated:YES completion:nil];
}
else {
if ([GKLocalPlayer localPlayer].authenticated) {
// If the player is already authenticated then indicate that the Game Center features can be used.
_gameCenterEnabled = YES;
}
else {
_gameCenterEnabled = NO;
}
}
};
}
Why are you using Game Kit Framework?
From iOS 7 you should use MultipeerConnectivity.
1) – authenticateWithCompletionHandler: Deprecated in iOS 6.0.
And if you test on iOS 7 it may be doesn't work at all.
2) Below example for create connection via MultipeerConnectivity
Client:
- (id)init {
self = [super init];
if (self) {
NSString *peerName = [NSString stringWithFormat:#"%#-%#", #"Client", [[UIDevice currentDevice] identifierForVendor].UUIDString];
self.myPeerID = [[MCPeerID alloc] initWithDisplayName:peerName];
self.servers = [NSMutableArray array];
self.session = [[MCSession alloc] initWithPeer:self.myPeerID securityIdentity:nil encryptionPreference:MCEncryptionNone];
self.session.delegate = self;
self.browser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.myPeerID serviceType:#"Connect"];
self.browser.delegate = self;
[self.browser startBrowsingForPeers];
}
return self;
}
//-----
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info {
NSLog(#"client: found a server: %#", peerID);
[self.browser invitePeer:peerID toSession:self.session withContext:nil timeout:10];
}
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID {
NSLog(#"client: lost server: %#", peerID);
}
#pragma mark - MCSessionDelegate
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
NSLog(#"client: status changed to %d for server: %#", state, peerID.displayName);
switch (state) {
case MCSessionStateNotConnected: {
}
break;
case MCSessionStateConnected: {
}
break;
default:
break;
}
}
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID {
NSLog(#"client: received data (len = %lu) from server %#",(unsigned long)[data length], peerID.displayName);
NSDictionary *receiveDictionary = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
Server:
- (id)init {
self = [super init];
if (self) {
NSString *peerName = [NSString stringWithFormat:#"%#-%#", #"Server", [[UIDevice currentDevice] identifierForVendor].UUIDString];
self.myPeerID = [[MCPeerID alloc] initWithDisplayName:peerName];
self.session = [[MCSession alloc] initWithPeer:self.myPeerID];
self.session.delegate = self;
self.advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.myPeerID
discoveryInfo:nil
serviceType:#"Connect"];
self.advertiser.delegate = self;
[self.advertiser startAdvertisingPeer];
}
return self;
}
#pragma mark - MCNearbyServiceAdvertiserDelegate
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler {
NSLog(#"server: did receive invitation from peer %#", peerID.displayName);
invitationHandler(YES, self.session);
}
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didNotStartAdvertisingPeer:(NSError *)error {
NSLog(#"server: error %#", error);
}
#pragma mark - MCSessionDelegate
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
NSLog(#"server: status changed to %ld for client: %#", state, peerID.displayName);
switch (state) {
case MCSessionStateConnected: {
NSMutableDictionary *sendDict = [NSMutableDictionary dictionary];
NSError *error = nil;
[self.session sendData:[NSKeyedArchiver archivedDataWithRootObject:sendDict]
toPeers:#[peerID]
withMode:MCSessionSendDataReliable
error:&error];
}
break;
case MCSessionStateNotConnected:
break;
default:
break;
}
NSLog(#"connectedPeers %#", self.session.connectedPeers);
}
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID {
NSLog(#"server: received data (len = %lu) from client %#", (unsigned long)[data length], peerID.displayName);
NSDictionary *dictionary = (NSDictionary*) [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID {
}
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress {
}
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error {
}
- (void)session:(MCSession*)session didReceiveCertificate:(NSArray*)certificate fromPeer:(MCPeerID*)peerID certificateHandler:(void (^)(BOOL accept))certificateHandler {
certificateHandler(YES);
}
I'm using https://github.com/robbiehanson/XMPPFramework to connect to my own ejabberd server, but it always failed after negotiation.
here is the log I got:
2014-01-17 07:14:40.780 Chat[48246:70b] error: (null)
2014-01-17 07:14:40.789 Chat[48246:70b] xmppStreamWillConnect
2014-01-17 07:14:46.076 Chat[48246:70b] socketDidConnect
2014-01-17 07:14:46.077 Chat[48246:70b] xmppStreamDidStartNegotiation
2014-01-17 07:14:51.799 Chat[48246:70b] xmppStreamDidDisconnect: Error Domain=GCDAsyncSocketErrorDomain Code=7 "Socket closed by remote peer" UserInfo=0x918d2e0 {NSLocalizedDescription=Socket closed by remote peer}
and here is the code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.stream = [[XMPPStream alloc] init];
self.stream.myJID = [XMPPJID jidWithString:#"test#gmail.com"];
self.stream.hostName = #"my host ip";
self.stream.hostPort = 5222;
[self.stream addDelegate:self delegateQueue:dispatch_get_main_queue()];
self.reconnect = [[XMPPReconnect alloc] init];
[self.reconnect activate:self.stream];
self.muc = [[XMPPMUC alloc] init];
[self.muc activate:self.stream];
NSError *error = nil;
if (![self.stream connectWithTimeout:XMPPStreamTimeoutNone error:&error]) {
NSLog(#"error: %#", error);
}
NSLog(#"error: %#", error);
}
- (void)xmppStreamWillConnect:(XMPPStream *)sender
{
NSLog(#"xmppStreamWillConnect");
}
- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket
{
NSLog(#"socketDidConnect");
}
- (void)xmppStreamDidStartNegotiation:(XMPPStream *)sender
{
NSLog(#"xmppStreamDidStartNegotiation");
}
- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary *)settings
{
NSLog(#"willSecureWithSettings: %#", settings);
}
- (void)xmppStreamDidSecure:(XMPPStream *)sender
{
NSLog(#"xmppStreamDidSecure");
}
- (void)xmppStreamDidConnect:(XMPPStream *)sender
{
NSLog(#"xmppStreamDidConnect");
NSError *error = nil;
[self.stream authenticateAnonymously:&error];
NSLog(#"authenticate: %#", error);
}
- (void)xmppStreamDidRegister:(XMPPStream *)sender
{
NSLog(#"xmppStreamDidRegister");
}
- (void)xmppStream:(XMPPStream *)sender didNotRegister:(NSXMLElement *)error
{
NSLog(#"didNotRegister: %#", error);
}
- (void)xmppStreamDidAuthenticate:(XMPPStream *)sender
{
NSLog(#"xmppStreamDidAuthenticate");
}
- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error
{
NSLog(#"didNotAuthenticate: %#", error);
}
- (void)xmppStreamWasToldToDisconnect:(XMPPStream *)sender
{
NSLog(#"xmppStreamWasToldToDisconnect");
}
- (void)xmppStreamConnectDidTimeout:(XMPPStream *)sender
{
NSLog(#"xmppStreamConnectDidTimeout");
}
- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error
{
NSLog(#"xmppStreamDidDisconnect: %#", error);
}
Check if the solution reported here https://github.com/robbiehanson/XMPPFramework/issues/131 solves your issue.
Generally when the server is closing the connection, you get this
error/ Two reasons when the server closes the connection:
You are not sending regular pings if the client idle.
You are logging in from some different client with the same credentials, and in the server settings have the setting:
Always kick - If there is a resource conflict, immediately kick the other resource. in Server>server settings>resource policy.