XMPPFramework - 消息未发送

Posted

技术标签:

【中文标题】XMPPFramework - 消息未发送【英文标题】:XMPPFramework - Message not sent 【发布时间】:2013-04-15 11:03:58 【问题描述】:

我是ios 的新手。我正在使用XMPPFramework 构建一个应用程序。但是最近几天我遇到了一个问题。找不到任何解决方案。问题是当我想向任何特定 id 发送消息时,消息不会被发送。发送消息的动作方法是:

- (IBAction)sendMsg:(id)sender 

    xmppStream = [[XMPPStream alloc] init];
    [xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];

    NSString *messageStr = self.msgField.text;

    if ([messageStr length] > 0) 
    

        NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
        [body setStringValue:messageStr];

        NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
        [message addAttributeWithName:@"type" stringValue:@"chat"];
        [message addAttributeWithName:@"to" stringValue:@"abc.codemen@gmail.com"];
        [message addChild:body];    
        [self.xmppStream sendElement:message];
    

这里是我的XMPPStream.m中发送NSXMLElement的sendElement方法:

- (void)sendElement:(NSXMLElement *)element

    if (element == nil)
        return;

    dispatch_block_t block = ^ @autoreleasepool 
        if (state == STATE_XMPP_CONNECTED)
            [self sendElement:element withTag:TAG_XMPP_WRITE_STREAM];
    ;

    if (dispatch_get_current_queue() == xmppQueue)
            block();
    else
            dispatch_async(xmppQueue, block);

但是我发现消息发送的方法调用没有进入if语句!

if (state == STATE_XMPP_CONNECTED)

    [self sendElement:element withTag:TAG_XMPP_WRITE_STREAM];

我认为这就是为什么我不能向任何 id 发送消息的原因。请通过建议我是错还是对来帮助我,我该如何解决这个问题?

这是我的 Appdelegate 类:

#import "iPhoneXMPPAppDelegate.h"
#import "GCDAsyncSocket.h"
#import "XMPP.h"
#import "XMPPReconnect.h"
#import "XMPPCapabilitiesCoreDataStorage.h"
#import "XMPPRosterCoreDataStorage.h"
#import "XMPPvCardAvatarModule.h"
#import "XMPPvCardCoreDataStorage.h"
#import "DDLog.h"
#import "DDTTYLogger.h"
#import <CFNetwork/CFNetwork.h>
#import "ParentLoginViewController.h"
#import "Child.h"

// Log levels: off, error, warn, info, verbose
#if DEBUG
static const int ddLogLevel = LOG_LEVEL_VERBOSE;
#else
static const int ddLogLevel = LOG_LEVEL_INFO;
#endif

@implementation iPhoneXMPPAppDelegate

//@synthesize window = _window;
@synthesize managedObjectContext = __managedObjectContext;
@synthesize managedObjectModel = __managedObjectModel;
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
@synthesize xmppStream;
@synthesize xmppReconnect;
@synthesize xmppRoster;
@synthesize xmppRosterStorage;
@synthesize xmppvCardTempModule;
@synthesize xmppvCardAvatarModule;
@synthesize xmppCapabilities;
@synthesize xmppCapabilitiesStorage;
@synthesize window;
@synthesize navigationController;

static iPhoneXMPPAppDelegate *sharedInstance = nil;

// Get the shared instance and create it if necessary.
+ (iPhoneXMPPAppDelegate *)sharedInstance 
if (sharedInstance == nil) 
    sharedInstance = [[super allocWithZone:NULL] init];


return sharedInstance;


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions


[DDLog addLogger:[DDTTYLogger sharedInstance]];

[self setupStream];

if (![self connect])

        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, 0.0 *       NSEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void)

            ParentLoginViewController *parent = [[ParentLoginViewController alloc] initWithNibName:@"ParentLoginViewController" bundle:nil];
            [navigationController presentModalViewController:parent  animated:YES];
        );
    

    return YES;


- (void)dealloc

[self teardownStream];


- (NSManagedObjectContext *)managedObjectContext_roster

    return [xmppRosterStorage mainThreadManagedObjectContext];


- (NSManagedObjectContext *)managedObjectContext_capabilities

    return [xmppCapabilitiesStorage mainThreadManagedObjectContext];


- (void)setupStream

    NSAssert(xmppStream == nil, @"Method setupStream invoked multiple times");

    xmppStream = [[XMPPStream alloc] init];

    #if !TARGET_IPHONE_SIMULATOR
    
        xmppStream.enableBackgroundingOnSocket = YES;
    
    #endif

    xmppReconnect = [[XMPPReconnect alloc] init];

    xmppRosterStorage = [[XMPPRosterCoreDataStorage alloc] init];

    xmppRoster = [[XMPPRoster alloc] initWithRosterStorage:xmppRosterStorage];

    xmppRoster.autoFetchRoster = YES;
    xmppRoster.autoAcceptKnownPresenceSubscriptionRequests = YES;

    xmppvCardStorage = [XMPPvCardCoreDataStorage sharedInstance];
    xmppvCardTempModule = [[XMPPvCardTempModule alloc]   initWithvCardStorage:xmppvCardStorage];

    xmppvCardAvatarModule = [[XMPPvCardAvatarModule alloc] initWithvCardTempModule:xmppvCardTempModule];

    xmppCapabilitiesStorage = [XMPPCapabilitiesCoreDataStorage sharedInstance];
    xmppCapabilities = [[XMPPCapabilities alloc] initWithCapabilitiesStorage:xmppCapabilitiesStorage];

    xmppCapabilities.autoFetchHashedCapabilities = YES;
    xmppCapabilities.autoFetchNonHashedCapabilities = NO;

    // Activate XMPP modules

    [xmppReconnect         activate:xmppStream];
    [xmppRoster            activate:xmppStream];
    [xmppvCardTempModule   activate:xmppStream];
    [xmppvCardAvatarModule activate:xmppStream];
    [xmppCapabilities      activate:xmppStream];

    // Add ourself as a delegate to anything we may be interested in

    [xmppStream addDelegate:self delegateQueue:dispatch_get_main_queue()];
    [xmppRoster addDelegate:self delegateQueue:dispatch_get_main_queue()];
    [xmppStream setHostName:@"talk.google.com"];
    [xmppStream setHostPort:5222];

    // You may need to alter these settings depending on the server you're connecting to
    allowSelfSignedCertificates = NO;
    allowSSLHostNameMismatch = NO;


- (void)teardownStream

    [xmppStream removeDelegate:self];
    [xmppRoster removeDelegate:self];

    [xmppReconnect         deactivate];
    [xmppRoster            deactivate];
    [xmppvCardTempModule   deactivate];
    [xmppvCardAvatarModule deactivate];
    [xmppCapabilities      deactivate];

    [xmppStream disconnect];

    xmppStream = nil;
    xmppReconnect = nil;
    xmppRoster = nil;
    xmppRosterStorage = nil;
    xmppvCardStorage = nil;
    xmppvCardTempModule = nil;
    xmppvCardAvatarModule = nil;
    xmppCapabilities = nil;
    xmppCapabilitiesStorage = nil;


- (void)goOnline

    XMPPPresence *presence = [XMPPPresence presence]; // type="available" is implicit

    [[self xmppStream] sendElement:presence];


- (void)goOffline

    XMPPPresence *presence = [XMPPPresence presenceWithType:@"unavailable"];

    [[self xmppStream] sendElement:presence];



- (BOOL)connect

    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 connect:&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];


- (void)applicationWillEnterForeground:(UIApplication *)application 

    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);



- (void)xmppStream:(XMPPStream *)sender socketDidConnect:(GCDAsyncSocket *)socket 

    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);


- (void)xmppStream:(XMPPStream *)sender willSecureWithSettings:(NSMutableDictionary  *)settings

    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);

    if (allowSelfSignedCertificates)
    
        [settings setObject:[NSNumber numberWithBool:YES] forKey:(NSString  *)kCFStreamSSLAllowsAnyRoot];
    

    if (allowSSLHostNameMismatch)
    
        [settings setObject:[NSNull null] forKey:(NSString *)kCFStreamSSLPeerName];
    

    else
    
        NSString *expectedCertName = nil;

        NSString *serverDomain = xmppStream.hostName;
        NSString *virtualDomain = [xmppStream.myJID domain];

        if ([serverDomain isEqualToString:@"talk.google.com"])
        
            if ([virtualDomain isEqualToString:@"gmail.com"])
            
                expectedCertName = virtualDomain;
            

            else
            
                expectedCertName = serverDomain;
            
        

        else if (serverDomain == nil)
        
            expectedCertName = virtualDomain;
        

        else
        
            expectedCertName = serverDomain;
        

        if (expectedCertName)
        
            [settings setObject:expectedCertName forKey:(NSString *)kCFStreamSSLPeerName];
        
    


- (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

    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);

    [self goOnline];


- (void)xmppStream:(XMPPStream *)sender didNotAuthenticate:(NSXMLElement *)error

    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);


- (BOOL)xmppStream:(XMPPStream *)sender didReceiveIQ:(XMPPIQ *)iq

    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);

    return NO;


- (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XMPPMessage *)message

    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);

    // A simple example of inbound message handling.

    if ([message isChatMessageWithBody])
    
        NSLog(@"Message is: %@",message); 

        XMPPUserCoreDataStorageObject *user = [xmppRosterStorage userForJID:[message      from]                                                                  xmppStream:xmppStream managedObjectContext:[self managedObjectContext_roster]];

        NSString *body = [[message elementForName:@"body"] stringValue];
        NSString *displayName = [user displayName];

        if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive)
        
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:displayName
                                                          message:body 
                                                         delegate:nil 
                                                cancelButtonTitle:@"Ok" 
                                                otherButtonTitles:nil];
            [alertView show];
        
        else
        
            // We are not active, so use a local notification instead
            UILocalNotification *localNotification = [[UILocalNotification alloc] init];
            localNotification.alertAction = @"Ok";
            localNotification.alertBody = [NSString stringWithFormat:@"From: %@\n\n%@",displayName,body];

            [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
        
    


- (void)xmppStream:(XMPPStream *)sender didSendMessage:(XMPPMessage *)message
  
    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);


- (void)xmppStream:(XMPPStream *)sender didReceivePresence:(XMPPPresence *)presence

    DDLogVerbose(@"%@: %@ - %@", THIS_FILE, THIS_METHOD, [presence fromStr]);


- (void)xmppStream:(XMPPStream *)sender didReceiveError:(id)error

    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);


- (void)xmppStreamDidDisconnect:(XMPPStream *)sender withError:(NSError *)error

    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);

    if (!isXmppConnected)
    
        DDLogError(@"Unable to connect to server. Check xmppStream.hostName");
    


#pragma mark XMPPRosterDelegate

- (void)xmppRoster:(XMPPRoster *)sender didReceiveBuddyRequest:(XMPPPresence *)presence

    DDLogVerbose(@"%@: %@", THIS_FILE, THIS_METHOD);

    XMPPUserCoreDataStorageObject *user = [xmppRosterStorage userForJID:[presence from]
                                                         xmppStream:xmppStream
                                               managedObjectContext:[self managedObjectContext_roster]];

    NSString *displayName = [user displayName];
    NSString *jidStrBare = [presence fromStr];
    NSString *body = nil;

    if (![displayName isEqualToString:jidStrBare])
    
        body = [NSString stringWithFormat:@"Buddy request from %@ <%@>", displayName, jidStrBare];
    
    else
    
        body = [NSString stringWithFormat:@"Buddy request from %@", displayName];
    


    if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive)
    
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:displayName
                                                        message:body 
                                                       delegate:nil 
                                              cancelButtonTitle:@"Not implemented"
                                              otherButtonTitles:nil];
        [alertView show];
     
    else 
    
        // We are not active, so use a local notification instead
        UILocalNotification *localNotification = [[UILocalNotification alloc] init];
        localNotification.alertAction = @"Not implemented";
        localNotification.alertBody = body;

        [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
    


-(void)sendingMessage
       
    NSXMLElement *body = [NSXMLElement elementWithName:@"body"];
    [body setStringValue:@"Hello brother"];

    NSXMLElement *message = [NSXMLElement elementWithName:@"message"];
    [message addAttributeWithName:@"type" stringValue:@"chat"];
    [message addAttributeWithName:@"to" stringValue:@"abc.codemen@gmail.com"];
    [message addChild:body];

    [self.xmppStream sendElement:message];

    NSLog(@"message sending! : %@",message);


@end

【问题讨论】:

【参考方案1】:

如果您是 xmpp 框架的新手,那么您应该首先为聊天客户端设置服务器(如 Ejabbered、openfire),然后您必须对其进行配置以进行聊天。您将从以下链接中找到非常好的教程,该链接分为四个部分。请一步一步看这个教程:-

http://mobile.tutsplus.com/tutorials/iphone/building-a-jabber-client-for-ios-server-setup/

【讨论】:

谢谢兄弟。实际上我想为 gtalk 实现聊天功能。我可以用 Jabber 这样做吗? @John 我没有用 gtalk 检查过,但我认为 gtalk 应该可以和 Jabber 一起使用 Sunil,如果我能知道我的代码有什么问题会更好,因为我已经从事该项目很多天了。而且由于我不确定如果我使用 jabber 是否可以使用 gmail id 和密码登录,所以我现在开始使用 Jabber 将非常耗时。如果我无法使用 gmail 凭据登录,那对我来说将更加可悲!不管怎么说,还是要谢谢你。投票给你。 @John 您目前使用的是哪台服务器? 是的 Sunil,我已经下载了 xmpp 框架,并按照我在 github 中找到的方向来实现我的项目。

以上是关于XMPPFramework - 消息未发送的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 xmppframework 在 XMPP 中检索我自己发送的最后一条消息?

如何使用 XMPPFramework iOS 发送图像(图像 url)、视频聊天 App 消息

通过 xmppframework 发送图像

XMPPFramework 整理文件传输

将传入消息附加到 ChatViewController 集合视图(XMPPFramework+JSQMessagesViewController)

XMPPFramework - 收到消息时调用两次“didReceiveMessage”