GithubHelp home page GithubHelp logo

xmpp-messenger-ios's Introduction

XMPP-MESSENGER-IOS

Version License Platform

Installation

xmpp-messenger-ios is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod "xmpp-messenger-ios"

If you can't use cocoapod, you will have to download the files and add it to your Xcodeproject.

UPDATE 04/19/16

If you encounter compilation errors after the installation, you may change the following file:

  1. In XMPPFramework/Core/XMPPStream.h, change #import "CocoaAsyncSocket/GCDAsyncSocket.h" to @import CocoaAsyncSocket;

  2. In XMPPFramework/Core/XMPPLogging.h, change #import "CocoaLumberjack/DDLog.h" to @import CocoaLumberjack;

  3. In JSQMessagesViewController/JSQSystemSoundPlayer+JSQMessages.h, change to @import JSQSystemSoundPlayer;

A pull request will be made to the XMPPFramework to include thoses changes.

Disclaimer

xmpp-messenger-ios was build for Xcode 7 and Swift 2, if you haven't upgraded yet, you should.

Author

Made in Paris by ProcessOne

License

xmpp-messenger-ios is available under the MIT license. See the LICENSE file for more info.

Tutorial example: OneChat

We will build a Swift XMPP client built on XMPP Framework, using xmpp-messenger-ios and JSQMessageViewControllerSwift

Project setup

  1. Open Xcode and select create a new project, you are free to choose wich kind of template you want, for this example, we will use the single view application. Fill up the required information, select Swift language and choose the folder location.

![Xcode setup screenshot](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/Xcode setup project.png)

  1. Now quit Xcode and launch the terminal app (terminal.app) terminal screenshot

  2. Navigate to your project directory, and type pod init like so: terminal podinit

pod init will setup cocoapods for this project, so make sure that you're using the latest version.

  1. Edit the newly created Podfile by taping emacs Podfile (Feel free to use vim :)). It should look like this:

![Podfile screenshot](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/podfile scree.png)

Press ctrl+x, ctrl+s to save, then ctrl+x, ctrl+c to end editing

  1. Almost good to go, type pod install, and wait until the installation is over.

![PodInstall screenshot](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/Pod_command line.png)

From now one you will have to open your project using the xcworkspace file, and no more the xcodeproject file

  1. Open the project, add:
import xmpp_messenger_ios

to your AppDelegate.swift file. Build & run to confirm that everything went well.

if you encounter an error, try to deep clean Xcode (command+alt+shift+k)

Let's create your chat client !

At this point your project should compile without errors

We are going to create 4 classes, one to display the conversations, name it OpenChatsTableViewController.swift, one for chatting, name it ChatViewController.swift, one to display the list of contacts, name it ContactListTableViewController.swift and one to act as a settings page, name it SettingsViewController.swift.

You can remove or reuse the apple-provided ViewController.swift file

Let's start with the Storyboard

  1. Open your Main.storyboard file, and remove the current ViewController.
  2. Drop in a UITableViewController, and asign it to OpenChatsTableViewController.swift ![Class asignment](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/Class selection.png)

Now you will select this Controller as the initial view controller

initialVC screen

We will now embed an UINavigationController: within Xcode, go to editor->Embed in->Navigation controller

Embed controller

Now that we have a UINavigationBar on OpenChatsViewController, we will add two UIBarButtonItem:

  • On the left, select system item add
  • On the right, simply name it "Settings"

Once finished, it should look like this:

![finished screen](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/openchatVC .png)

  1. Drop an UIViewController, asign it to SettingsViewController.swift, then embed it inside an UINavigationController.

Return on OpenChatsTableViewController. Select the settings UIBarButtonItem with the ctrl key and drag the cursor on the SettingsViewController's UINavigationController to create a segue between the ViewControllers.

It should look like this:

![segue example](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/settings segue.png)

Now select the Segue, and in the properties, name it One.HomeToSettings

segue naming

Return on SettingsViewController, and on the UINavigationBar, add an UIBarButtonItem, and name it "Done".

Also drop two UITextField, and one UIButton.

Name the UIbutton's title "validate" and set the UITextField's placeholder to "Username" and "Password".

It should look like this:

![textfield placeholder](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/texfield username.png)

Note: you should select -secure entry- on the password's UITextField to replace every entered letter into dots

You will now split Xcode's screen to display side by side both interface and code, simply by selecting this button:

![button tosplit](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/xcode split.png)

Once done, ctrl select the textfield's and validate's button to the class to create IBOutlet's. Name them respetctivly userNameTextField, passwordTextField and validateButton.

![creating outlets](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/creating outlets.png)

For the last one, the validate button, you will have to ctrl drag again, but this time, select action instead of outlet, and name the IBAction "close".

![creating methods](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/action validate.png)

Do the same operation, but on the "Done" UIBarButtonItem, and name the method "close"

We need to do one last operation: setting the UITextField's delegates. For this, you will have to select a UITextField at the time, go to the connection tab and click-drag your cursor on the SettingsViewController.

![Setting delegates](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/settin delegate.png)

###This is all about 'connection'

  1. Open AppDelegate.swift. We will add to calls in here. One to start the services, and the other one to stop them.

In:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool

Add the following code:

OneChat.start(archiving: true, delegate: nil) { (stream, error) -> Void in
	if let _ = error {
		//handle start errors here
	} else {
		//Activate online UI
	}
}

And in:

func applicationWillTerminate(application: UIApplication)

Add:

OneChat.stop()
  1. Go back to SettingsViewController.swift, and add the following import at the top of the file:
import XMPPFramework
import xmpp_messenger_ios

We will now take care of the UITextField's delegates: we will add a method to hide the keyboard if the user if out of focus, and a method to trigger the validation if the user click on the keyboard's return key.

To hide the keyboard, Add:

let tap = UITapGestureRecognizer(target: self, action: "DismissKeyboard")

In your viewDidLoad method, then implement the DismissKeyboard method:

func DismissKeyboard() {
	if usernameTextField.isFirstResponder() {
		usernameTextField.resignFirstResponder()
	} else if passwordTextField.isFirstResponder() {
		passwordTextField.resignFirstResponder()
	}
}

And to trigger the validation, we'll use the UITextField delegates:

func textFieldShouldReturn(textField: UITextField) -> Bool {
	if passwordTextField.isFirstResponder() {
		textField.resignFirstResponder()
		validate(self)
	} else {
		textField.resignFirstResponder()
	}
	return true
}

Now we are going to set default values in the UITextfield's, and add a way to change the "validate" UIButton if the user is already connected.

Add the following in your viewWillappear:

if OneChat.sharedInstance.isConnected() {
	usernameTextField.hidden = true
	passwordTextField.hidden = true
	validateButton.setTitle("Disconnect", forState: UIControlState.Normal)
} else {
	if NSUserDefaults.standardUserDefaults().stringForKey(kXMPP.myJID) != "kXMPPmyJID" {
	usernameTextField.text = NSUserDefaults.standardUserDefaults().stringForKey(kXMPP.myJID)
	passwordTextField.text = NSUserDefaults.standardUserDefaults().stringForKey(kXMPP.myPassword)
}

Here we just change the name of the "validate" UIButton and hide the UITextField's in case the user is already connected, if not, and if the user already gave credentials, we place them in the UITextField.

Place this inside the validate() method:

if OneChat.sharedInstance.isConnected() {
	OneChat.sharedInstance.disconnect()
	usernameTextField.hidden = false
	passwordTextField.hidden = false
	validateButton.setTitle("Validate", forState: UIControlState.Normal)
} else {
	OneChat.sharedInstance.connect(username: self.usernameTextField.text!, password: 	self.passwordTextField.text!) { (stream, error) -> Void in
	if let _ = error {
		let alertController = UIAlertController(title: "Sorry", message: "An error occured: \(error)", preferredStyle: UIAlertControllerStyle.Alert)
		alertController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: { (UIAlertAction) -> Void in
				//do something
		}))
		self.presentViewController(alertController, animated: true, completion: nil)
	} else {
		self.dismissViewControllerAnimated(true, completion: nil)
	}
}

The validate method will connect the user and dismiss the settings screen if the connect() succeed, and if the user is already connected, it will disconnect him and reset the UI

  1. Return to the Storyboard, select the OpenChatsTableViewController, then select the UITableViewCell inside the UITableView and in the property tabs, fill the reuse identifier to OneCellReuse:

![reuse screen](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/cell reuse.png)

Open up the source code, OpenChatsTableViewController.swift, and add the following imports at the top of the file:

import XMPPFramework
import xmpp_messenger_ios

This Controller will be displaying all the open / stored chat conversation between two or more participants, so we need to set both datasource and delegate for the UITableView, as well as a way to know if a new conversation was added to the list.

Create a variable witch will contains the conversation:

var chatList = NSArray()

Then, implement the following datasource methods:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
	return OneChats.getChatsList().count
}

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
	return 1
}

And the most important delegate:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
	let cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("OneCellReuse", forIndexPath: indexPath)
	let user = OneChats.getChatsList().objectAtIndex(indexPath.row) as! XMPPUserCoreDataStorageObject

	cell!.textLabel!.text = user.displayName

	OneChat.sharedInstance.configurePhotoForCell(cell!, user: user)

	cell?.imageView?.layer.cornerRadius = 24
	cell?.imageView?.clipsToBounds = true

	return cell!
}

If, like me, you don't like the extra lines on the UITableView, you can add the following delegate:

override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
	return 0.01
}

override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
	return UIView()
}

Last UITableView's touch, add tableView.rowHeight = 50 at the end of your viewDidLoad.

You can now conform the class to the OneRosterDelegate:

class OpenChatsTableViewController: UITableViewController, OneRosterDelegate

An error should now pop:

xcode error

This is because we have to conform to the OneRosterProtocol. Do it by implementing the following method:

func oneRosterContentChanged(controller: NSFetchedResultsController) {
	//Will reload the tableView to reflect roster's changes
	tableView.reloadData()
}

Implementing a delegate method is great, but we need to set yourself as the delegate if we want to be notified when the roster content change. You will do this in your viewWillAppear method:

OneRoster.sharedInstance.delegate = self

Following the same logic, remove yourself as delegate in your viewWillDisapear method:

OneRoster.sharedInstance.delegate = nil

Return to the top, in your viewWillAppear, and add the connect() function, to present the SettingViewController if the user isn't logged in:

OneChat.sharedInstance.connect(username: kXMPP.myJID, password: kXMPP.myPassword) { (stream, error) -> Void in
	if let _ = error {
		self.performSegueWithIdentifier("One.HomeToSetting", sender: self)
	} else {
		//set up online UI
	}
}

Build & Run, you should be redirected to the settings page, where you can login sucessfully.

  1. Displaying a list of chat conversation is great, but creating one is even better ! Switch back to your Storyboard, and drop a UITableViewController. Asing it to ContactListTableViewController.swift. Embed a UINavigationController and name it's Storyboard ID "contactListNav":

![storyboard name](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/storyboard id.png)

Now you will create a Modal presentation segue between the + UIBarButtonItem in the OpenChatsTableViewController and the ContactListViewController.

Name this segue "chat.to.add"

![chat segue](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/segue naming.png)

Return to ContactListTableViewController and drop a UIBarButtonItem, select the system style "done" and create an action method named "close":

@IBAction func close(sender: AnyObject) {
	self.dismissViewControllerAnimated(true, completion: nil)
}

Now select the UITableViewCell and set the reuse identifier like you did for the OpenChatsTableViewController.

Let's take care of this ContactListTableViewController, at the top of the file, add:

import XMPPFramework
import xmpp_messenger_ios

Like you did for the OpenChatsTableViewController, add OneRosterDelegate to your class declaration, set up the delegate in viewWillAppear and viewWillDisapear, as well as implementing the required protocol method oneRosterContentChanged.

Let's implement the UITableViewDelegate now:

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
	let sections: NSArray? =  OneRoster.buddyList.sections

	if section < sections!.count {
		let sectionInfo: AnyObject = sections![section]

		return sectionInfo.numberOfObjects
	}

	return 0;
}

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
	return OneRoster.buddyList.sections!.count
}

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
	let sections: NSArray? = OneRoster.sharedInstance.fetchedResultsController()!.sections

	if section < sections!.count {
		let sectionInfo: AnyObject = sections![section]
		let tmpSection: Int = Int(sectionInfo.name)!

		switch (tmpSection) {
			case 0 :
				return "Available"

			case 1 :
				return "Away"

			default :
				return "Offline"

		}
	}

	return ""
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
	let cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier("OneCellReuse", forIndexPath: indexPath)
	let user = OneRoster.userFromRosterAtIndexPath(indexPath: indexPath)

	cell!.textLabel!.text = user.displayName;

	if user.unreadMessages.intValue > 0 {
		cell!.backgroundColor = .orangeColor()
	} else {
		cell!.backgroundColor = .whiteColor()
	}
	OneChat.sharedInstance.configurePhotoForCell(cell!, user: user)

	return cell!;
}

This will populate the UITableView with the content of your roster. It will display the name and picture of your contacts, ordered by status available, away, offline.

Build & Run, tap on the + button to see if everything is working properly.

  1. In this section we will add the ability to select a contact and start chatting !

Open your Storyboard and drop a UIViewController. Asign it to ChatViewController.swift.

Remove the chat.to.add segue from the + button to the ContactListTableViewController and re-create it from the ChatViewController itself. Name it "chat.to.contact". It should look like this:

![storyboard screnfromconatct](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/first segue.png)

Now you will create two more push/show segue, from OpenChatsTableViewController to ChatViewController. One from the + button, you will name it chat.to.add, and the other from the UITableViewCell of OpenChatsTableViewController to ChatViewController, name it chat.to.chat. The completed Storyboard should now look like this:

![completed storyboard](https://raw.githubusercontent.com/processone/xmpp-messenger-ios/master/Tutorial%20assets/completed storyboard.png)

You can return to ChatViewController.swift. There will be a lot going on in this ViewController so make sure you're fully loaded with cafeine !

As usual, add the following import at the top of the file:

import xmpp_messenger_ios
import JSQMessagesViewController
import XMPPFramework

There will be some interesting stuff in that class, we will need a variable to store the recipient, and a library to give us the User Interface.

Create the recipient variable:

var recipient: XMPPUserCoreDataStorageObject?

In your viewWillAppear method, we will check if a recipient has been set, in that case we will display the chat history, if not weโ€™ll present the ContactListTableViewCcontroller to allow the user to select a contact. Itโ€™ll look like this :

if let recipient = recipient {
	navigationItem.rightBarButtonItems = []
	navigationItem.title = recipient.displayName
} else {
	navigationItem.title = "New message"

	navigationItem.setRightBarButtonItem(UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "addRecipient"), animated: true)
	addRecipient()
}

Implement the addRecipient() method:

func addRecipient() {
	let navController = storyboard?.instantiateViewControllerWithIdentifier("contactListNav") as? UINavigationController

	presentViewController(navController!, animated: true, completion: nil)
}

If you Build and run at this point, you will notice that every time you tap on done, the ContactListViewController is displayed over and over, and that the cell selection does nothing โ€ฆ yet ! We will use a bool to solve the first problem, and a delegate for the second !

Add the var firstTime = true, then, in your viewWillAppear, encapsulate the addRecipient() like this :

if firstTime {
	firstTime = false
	addRecipient()
}

Now, itโ€™s time to create your delegate ! Open ContactListTableViewController, and add the following protocol behind the importโ€™s statement

protocol ContactPickerDelegate {
	func didSelectContact(recipient: XMPPUserCoreDataStorageObject)
}

It will be called whenever an user select a contact in the list. Add the following property to call on :

var delegate:ContactPickerDelegate?

And implement it in the UITableView didselectRowAtIndex method:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
	delegate?.didSelectContact(OneRoster.userFromRosterAtIndexPath(indexPath: indexPath))
	close(self)
}

Now that the protocol is setup, go back to ChatViewController.swift, and add ContactPickerDelegate to the class declaration. Implement the mandatory method didSelectContact():

func didSelectContact(recipient: XMPPUserCoreDataStorageObject) {
	self.recipient = recipient
	navigationItem.title = recipient.displayName
}

However, it will not work until you set yourself as ContactPickerDelegate. In the addRecipient(), just before presentViewController, add this line:

let contactController: ContactListTableViewController? = navController?.viewControllers[0] as? ContactListTableViewController
contactController?.delegate = self

We will now extend the contact selection, open up OpenChatsViewController and implement the segue delegates:

override func shouldPerformSegueWithIdentifier(identifier: String, sender: AnyObject?) -> Bool {
	if identifier == "chat.to.add" {
		if !OneChat.sharedInstance.isConnected() {
			let alert = UIAlertController(title: "Attention", message: "You have to be connected to start a chat", preferredStyle: UIAlertControllerStyle.Alert)
			alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))

			self.presentViewController(alert, animated: true, completion: nil)

			return false
		}
	}
	return true
}

override func prepareForSegue(segue: UIStoryboardSegue?, sender: AnyObject?) {
	if segue?.identifier == "chats.to.chat" {
		if let controller = segue?.destinationViewController as? ChatViewController {
			if let cell: UITableViewCell? = sender as? UITableViewCell {
				let user = OneChats.getChatsList().objectAtIndex(tableView.indexPathForCell(cell!)!.row) as! XMPPUserCoreDataStorageObject
				controller.recipient = user
			}
		}
	}
}

The first one will prevent contact selection if the user is offline, the second will fill the recipient corresponding at the selected cell.

BUILD & RUN, you should be able to select a contact !

  1. Now go back to ChatViewController, for the final part, the Chat !

Add JSQMessagesViewController to the class declaration, and create a variable message witch will hold the fetched message if there is some:

var messages = NSMutableArray()

Now, you will need to implement the JSQMessageViewController delegates. Thoses methods are pretty simple, they will display and create an interface for the stored messages:

override func collectionView(collectionView: JSQMessagesCollectionView!, messageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageData! {
	let message: JSQMessage = self.messages[indexPath.item] as! JSQMessage

	return message
}

override func collectionView(collectionView: JSQMessagesCollectionView!, messageBubbleImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageBubbleImageDataSource! {
	let message: JSQMessage = self.messages[indexPath.item] as! JSQMessage

	let bubbleFactory = JSQMessagesBubbleImageFactory()

	let outgoingBubbleImageData = bubbleFactory.outgoingMessagesBubbleImageWithColor(UIColor.jsq_messageBubbleLightGrayColor())
	let incomingBubbleImageData = bubbleFactory.incomingMessagesBubbleImageWithColor(UIColor.jsq_messageBubbleGreenColor())

	if message.senderId == self.senderId {
		return outgoingBubbleImageData
	}

	return incomingBubbleImageData
}

override func collectionView(collectionView: JSQMessagesCollectionView!, avatarImageDataForItemAtIndexPath indexPath: NSIndexPath!) -> JSQMessageAvatarImageDataSource! {
	let message: JSQMessage = self.messages[indexPath.item] as! JSQMessage

	if message.senderId == self.senderId {
		if let photoData = OneChat.sharedInstance.xmppvCardAvatarModule?.photoDataForJID(OneChat.sharedInstance.xmppStream?.myJID) {
			let senderAvatar = JSQMessagesAvatarImageFactory.avatarImageWithImage(UIImage(data: photoData), diameter: 30)
				return senderAvatar
			} else {
				let senderAvatar = JSQMessagesAvatarImageFactory.avatarImageWithUserInitials("SR", backgroundColor: UIColor(white: 0.85, alpha: 1.0), textColor: UIColor(white: 0.60, alpha: 1.0), font: UIFont(name: "Helvetica Neue", size: 14.0), diameter: 30)
				return senderAvatar
			}
		} else {
			if let photoData = OneChat.sharedInstance.xmppvCardAvatarModule?.photoDataForJID(recipient!.jid!) {
				let recipientAvatar = JSQMessagesAvatarImageFactory.avatarImageWithImage(UIImage(data: photoData), diameter: 30)
				return recipientAvatar
			} else {
				let recipientAvatar = JSQMessagesAvatarImageFactory.avatarImageWithUserInitials("SR", backgroundColor: UIColor(white: 0.85, alpha: 1.0), textColor: UIColor(white: 0.60, alpha: 1.0), font: UIFont(name: "Helvetica Neue", size: 14.0)!, diameter: 30)
				return recipientAvatar
			}
		}
}

override func collectionView(collectionView: JSQMessagesCollectionView!, attributedTextForCellTopLabelAtIndexPath indexPath: NSIndexPath!) -> NSAttributedString! {
	if indexPath.item % 3 == 0 {
		let message: JSQMessage = self.messages[indexPath.item] as! JSQMessage
		return JSQMessagesTimestampFormatter.sharedFormatter().attributedTimestampForDate(message.date)
	}

	return nil;
}

override func collectionView(collectionView: JSQMessagesCollectionView!, attributedTextForMessageBubbleTopLabelAtIndexPath indexPath: NSIndexPath!) -> NSAttributedString! {
	let message: JSQMessage = self.messages[indexPath.item] as! JSQMessage

	if message.senderId == self.senderId {
		return nil
	}

	if indexPath.item - 1 > 0 {
		let previousMessage: JSQMessage = self.messages[indexPath.item - 1] as! JSQMessage
		if previousMessage.senderId == message.senderId {
			return nil
		}
	}

	return nil
}

override func collectionView(collectionView: JSQMessagesCollectionView!, attributedTextForCellBottomLabelAtIndexPath indexPath: NSIndexPath!) -> NSAttributedString! {
	return nil
}

// Mark: UICollectionView DataSource

override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
	return self.messages.count
}

override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
	let cell: JSQMessagesCollectionViewCell = super.collectionView(collectionView, cellForItemAtIndexPath: indexPath) as! JSQMessagesCollectionViewCell
	let msg: JSQMessage = self.messages[indexPath.item] as! JSQMessage

	if !msg.isMediaMessage {
		if msg.senderId == self.senderId {
			cell.textView!.textColor = UIColor.blackColor()
			cell.textView!.linkTextAttributes = [NSForegroundColorAttributeName:UIColor.blackColor(), NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleSingle.rawValue]
		} else {
			cell.textView!.textColor = UIColor.whiteColor()
			cell.textView!.linkTextAttributes = [NSForegroundColorAttributeName:UIColor.whiteColor(), NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleSingle.rawValue]
		}
	}

	return cell
}

// Mark: JSQMessages collection view flow layout delegate

override func collectionView(collectionView: JSQMessagesCollectionView!, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout!, heightForCellTopLabelAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
	if indexPath.item % 3 == 0 {
		return kJSQMessagesCollectionViewCellLabelHeightDefault
	}

	return 0.0
}

override func collectionView(collectionView: JSQMessagesCollectionView!, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout!, heightForMessageBubbleTopLabelAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
	let currentMessage: JSQMessage = self.messages[indexPath.item] as! JSQMessage
		if currentMessage.senderId == self.senderId {
			return 0.0
		}

		if indexPath.item - 1 > 0 {
			let previousMessage: JSQMessage = self.messages[indexPath.item - 1] as! JSQMessage
			if previousMessage.senderId == currentMessage.senderId {
				return 0.0
			}
		}

	return kJSQMessagesCollectionViewCellLabelHeightDefault
}

override func collectionView(collectionView: JSQMessagesCollectionView!, layout collectionViewLayout: JSQMessagesCollectionViewFlowLayout!, heightForCellBottomLabelAtIndexPath indexPath: NSIndexPath!) -> CGFloat {
	return 0.0
}
  1. Now we can handle the UI, but we still need to be able to send and receive messages ! Add OneMessageDelegate to the class declaration, and implement the mandatory protocol:
func oneStream(sender: XMPPStream, didReceiveMessage message: XMPPMessage, from user: XMPPUserCoreDataStorageObject) {
	if message.isChatMessageWithBody() {
		JSQSystemSoundPlayer.jsq_playMessageReceivedSound()

		if let msg: String = message.elementForName("body")?.stringValue() {
			if let from: String = message.attributeForName("from")?.stringValue() {
				let message = JSQMessage(senderId: from, senderDisplayName: from, date: NSDate(), text: msg)
				messages.addObject(message)

				self.finishReceivingMessageAnimated(true)
			}
		}
	}
}

func oneStream(sender: XMPPStream, userIsComposing user: XMPPUserCoreDataStorageObject) {
self.showTypingIndicator = !self.showTypingIndicator
self.scrollToBottomAnimated(true)
}

The first method will be called whenever a message is received, while the second will be called when the remote user is composing a new message.

We can now receive messages ! It would be great if we could send some too no ?

  1. Add this to your viewDidLoad method :
OneMessage.sharedInstance.delegate = self

if OneChat.sharedInstance.isConnected() {
	self.senderId = OneChat.sharedInstance.xmppStream?.myJID.bare()
	self.senderDisplayName = OneChat.sharedInstance.xmppStream?.myJID.bare()
}
self.inputToolbar!.contentView!.leftBarButtonItem!.hidden = true
self.collectionView!.collectionViewLayout.springinessEnabled = true

We will now add a method in your viewWillApear to fetch stored messages, if there is some:

self.messages = OneMessage.sharedInstance.loadArchivedMessagesFrom(jid: recipient.jidStr)
self.collectionView?.reloadData()

The completed viewWillAppear function should now look like this:

override func viewWillAppear(animated: Bool) {
	if let recipient = recipient {
		navigationItem.rightBarButtonItems = []
		navigationItem.title = recipient.displayName

		self.messages = OneMessage.sharedInstance.loadArchivedMessagesFrom(jid: recipient.jidStr)
		self.collectionView?.reloadData()
	} else {
		navigationItem.title = "New message"

		navigationItem.setRightBarButtonItem(UIBarButtonItem(barButtonSystemItem: .Add, target: self, action: "addRecipient"), animated: true)

		if firstTime {
			firstTime = false
			addRecipient()
		}
	}
}

Now, edit didSelectContact, and add the following:

if !OneChats.knownUserForJid(jidStr: recipient.jidStr) {
	OneChats.addUserToChatList(jidStr: recipient.jidStr)
} else {
	messages = OneMessage.sharedInstance.loadArchivedMessagesFrom(jid: recipient.jidStr)
	finishReceivingMessageAnimated(true)
}

It will fetch the stored message of un user we just select form the roster.

The final touch, sending a message !
  1. Implement the JSQMessageViewController delegate:
override func didPressSendButton(button: UIButton!, withMessageText text: String!, senderId: String!, senderDisplayName: String!, date: NSDate!) {
	let fullMessage = JSQMessage(senderId: OneChat.sharedInstance.xmppStream?.myJID.bare(), senderDisplayName: OneChat.sharedInstance.xmppStream?.myJID.bare(), date: NSDate(), text: text)
	messages.addObject(fullMessage)

	if let recipient = recipient {
		OneMessage.sendMessage(text, to: recipient.jidStr, completionHandler: { (stream, message) -> Void in
			JSQSystemSoundPlayer.jsq_playMessageSentSound()
			self.finishSendingMessageAnimated(true)
		})
	}
}

Build & run, CONGRATULATION, you have a fully functionnal chat client !

xmpp-messenger-ios's People

Contributors

abbasmousavi avatar baoluo avatar brod-ie avatar mremond avatar orkhanalizade avatar vientooscuro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xmpp-messenger-ios's Issues

How to create send and receive media / photo

Hi, i want to ask how to send message image from photo gallery in swift?

here is the function after select photo and then sending the image

    func  imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) { 
    var image : UIImage
    image = (info[UIImagePickerControllerOriginalImage] as? UIImage)!
    var photoItem = JSQPhotoMediaItem()
    photoItem.image = image


    let fullMessage = JSQMessage(senderId: OneChat.sharedInstance.xmppStream?.myJID.bare(), senderDisplayName: OneChat.sharedInstance.xmppStream?.myJID.bare(), date: NSDate(), media: photoItem)
    messages.addObject(fullMessage)
    let mediaItem:JSQMessageMediaData = fullMessage!.media
        photoItem = mediaItem as! JSQPhotoMediaItem

    if (mediaItem.isKindOfClass(JSQPhotoMediaItem)) {

        if let recipient = recipient {

            OneMessage.sendMessage("image", to: recipient.jidStr, completionHandler: { (stream, image) -> Void in
                JSQSystemSoundPlayer.jsq_playMessageSentSound()
                self.finishSendingMessageAnimated(true)
            })
        }
    }
    self.dismissViewControllerAnimated(true, completion: nil)
}`

Pod errors

Hi I am using xcode 7.1 and getting 3 errors when I try to build the project after installing pods.

  1. Include of non-modular header inside framework module 'XMPPFramework.XMPPStream' in XMPPStream.h file
  2. Include of non-modular header inside framework module 'XMPPFramework.XMPPLogging' in XMPPLogging.h file
  3. Could not build Objective-C module 'XMPPFramework' in OneChat.swift file

How to create database using FMDB?

Hi, i want create database using FMDB, but i can't import FMDB in swift
error message : could not build objective-c module 'FMDB'
and how to update FMDB pods? this version its outdate
Thanks

Load list friend request

hi @baoluo ,
I'm trying to build xmpp client by objC connect to ejabberd but meet a issue right now.
I can send to you a buddy request via
[self.xmppRoster addUser:[XMPPJID jidWithString:_jid] withNickname:_nickName];

but i want receiver can see list of buddy requests so that he can accept/reject it.
Can u give me a help?

Unable to receive presence

I am creating a chating by xmpp protocol. I want to send the request to user so that they could begin to chat. Firstly I am adding user to roster and subscribing user by the following line of code
obj.addUser(xjid, withNickname: "new_user")

    obj.subscribePresenceToUser(xjid) //here xjid is well defined

So now i need to receive the presence and accept the presence to get the JID of the user who have sent the friend request can be achieved by [presence from] but when I print these things to verify

// NSString *presenceFromUser = [presence from] ;

// NSString *presenceType = [presence type];

// NSLog(@"Your name is %@", presenceFromUser);

// NSLog(@"Sender name is %@", presenceType);

->presenceFromUser is same by which I am login currently and presenceType is always "available".

 According to me it should be

->presenceFromUser should be "userJidWhoSentTheRequest@localhost"

->presenceType should be "Subscribe"

Hello, Problem While building this app! Need Help!

Hello,

Anyway, I am trying to build this xmpp application under Xcode 7.3.
I have this problem, I tried to google this issue and I still have not fixed this.

2016-04os x 10 11 - vmware workstation 12 player non-commercial use only

Maybe its a problem of the newer Xcode 7.3? I am using El Capitan.
Maybe it is related to Pod base project?

Just to clarify, OneChat is under Pods Project.
XMPPFramework already exists at build path, I added it manually.
Also setting "Allow Non-modular Includes in "Framework Modules" to YES under Build Setting didn't help.

Also, deep cleaning (with command+alt+shift+k) did not work!

I followed the instuctions on this github page.
https://github.com/processone/xmpp-messenger-ios

Any advice please?

Value of type 'OneChat' has no member 'xmppLastActivity'

Hi, when I run the example, I get in viewWillAppear from ChatViewController at OneLastActivity.sendLastActivityQueryToJID((recipient.jidStr), sender: OneChat.sharedInstance.xmppLastActivity) { :

Value of type 'OneChat' has no member 'xmppLastActivity'

Compile errors after Pod install

You may have compiler errors after installing the pod, first try to deep clean Xcode (command+alt+shift+k)

If the errors are "Include of non-modular header inside module XMPPFramework", you may edit those files :

In XMPPStream.h, change #import "CocoaAsyncSocket/GCDAsyncSocket.h" to @import CocoaAsyncSocket

In XMMPLogging.h, change #import "CocoaLumberjack/DDLog.h" to @import CocoaLumberjack

In JSQSystemSoundPlayer+JSQMessages.h, change to @import JSQSystemSoundPlayer;

A pull request will be made to the XMPPFramework to include thoses changes.

Xcode Crash on Break Point and Print statements not working

I have downloaded your repo. when I apply any breakpoint in Xcode then it crashes on every single breakpoint and also when I try to print any thing then it did not show any output on console. I have tried a lot of solutions on internet but nothing is helping.By the way I am using latest xcode 7.3.1

Any help would be much appreciated..thanks

error undefined _GCDAsyncSocketManuallyEvaluateTrust

Hi i tried to build your project and i got this error

Undefined symbols for architecture armv7: "_GCDAsyncSocketManuallyEvaluateTrust", referenced from: xmpp_messenger_ios.OneChat.xmppStream (xmpp_messenger_ios.OneChat)(ObjectiveC.XMPPStream?, willSecureWithSettings : ObjectiveC.NSMutableDictionary?) -> () in OneChat.o ld: symbol(s) not found for architecture armv7 clang: error: linker command failed with exit code 1 (use -v to see invocation)

I'm using Xcode 7
I have search and don't know how to reproduce it.. Do you have any solution? Thanks

Unable to get Old messages

Hi,

I have been working with this module and i found one issue

OneMessage.sharedInstance.loadArchivedMessagesFrom(jid: recipient.jidStr) works only when the app has the data, if you delete the application and install again all old messages are retrieved.

Any solutions for this ?

Trust problem?

I can't get my connection with my server done! Becouse of trust?
The objective-c code works fine with my server, so i want to try this swift messanger but it get always:
"Error Domain=kCFStreamErrorDomainSSL Code=-9825 ..."

In my objective-c code i changed this to get it running:
completionHandler(shouldTrustPeer: true) // Has to be false if SSL is rdy!
but in this project the function never triggert...

bildschirmfoto 2016-02-04 um 20 32 52

Some one know whats wrong with it, or me ;)

notice:
And if i changed this to false:
customCertEvaluation = false;
i get:
Error Domain=kCFStreamErrorDomainSSL Code=-9807

Dokumentation said:
errSSLPeerBadCert = -9825, /* misc. bad certificate /
errSSLXCertChainInvalid = -9807, /
invalid certificate chain */

ChatViewController throw error

Hello,

After following the tutorial, I reached an error in the ChatViewController viewDidLoad function after running. Not sure what is the reason. Here is the function

 override func viewDidLoad() {
        OneMessage.sharedInstance.delegate = self

        if OneChat.sharedInstance.isConnected() {
            self.senderId = OneChat.sharedInstance.xmppStream?.myJID.bare()
            self.senderDisplayName = OneChat.sharedInstance.xmppStream?.myJID.bare()
        }
        self.inputToolbar!.contentView!.leftBarButtonItem!.hidden = true
        self.collectionView!.collectionViewLayout.springinessEnabled = true
    }

and the error is fatal error: unexpectedly found nil while unwrapping an Optional value

Are there any steps that I'm missing?
Thanks!

Several issues while uploading it as a Pod.

I tried to get the framework installed via cocoapods, But now I m running into several problems eg. No such module, cannot build objective C framework as....

You can all view them on running the project I have attached herewith.
chatSwift.zip

XEP-0313 support

Is there any plan to support XEP-0313? because XEP-0136 seems to be deprecated.

Best,

Getting a lot of errors after installing via cocoapods

I'm trying to follow your guide and running into a ton of compiling errors after I add "import xmpp_messenger_ios" to my AppDelegate. I'm running latest verions of Xcode 7.3. Can you update your guide on how to avoid these problems?

Errors: Include of non-modular header inside framework module 'XMPPFramework.XMPPStream'
Could not build Objective-C module 'XMPPFramework'

Thanks!

CocoaPods

Hi there,

I am not able to run pod install without getting a lot of errors.
All I did was a git clone and cd to the Example directory.

Greetings,
Bram.

Not receiving messages until send the first message.

Hello,

I have been working with this module and i found one issue:

If I start the demo App and try to send a message for someone everything works fine. But if I close and start the app the messages sent to me will not be received until I send the first message.

Server for chat client

I had gone through the full tutorial to implement a chat client using xmpp-messenger-ios. But what about the server side? I have my own amazon instance and back-end support. So how to store the chat messages in my db?

iOS 10

I can't install on iOS 10 (swift 3.0). Will you upload a new version?

fatal error: unexpectedly found nil while unwrapping an Optional value

I am facing

fatal error: unexpectedly found nil while unwrapping an Optional value

at many lines in your library. I have latest xcode 7.3, and I also did convert to swift latest. However still I am getting.

For example

public func isConnected() -> Bool {
        return xmppStream!.isConnected() //here its crashing, 
    }

I did like this

public func isConnected() -> Bool {
        if let boolValue:Bool = xmppStream!.isConnected() {
            return boolValue
        }else {
            return false
        }
    }

Can you see what is wrong in code?

Cannot load module XMPP_Messenger_iOS as xmpp_messenger_ios

Dears

I am facing problem on build the project inder Xcode 7.2.1 and Swift 2.1 the problem is Can not load module XMPP_Messenger_iOS as xmpp_messenger_ios . but when i cleam the drived data folder and force Quit xcode then rebuild again it work as expected .

getting user nil from xmppRosterStorage

Hi
I am new to XMPP i followed all the steps told. I am able to send messages successfully but when i receive any message the app crashes with error

fatal error: unexpectedly found nil while unwrapping an Optional value

so i started using breakpoints and found that the value of user is nil in OneMessage.swift

    public func xmppStream(sender: XMPPStream, didReceiveMessage message: XMPPMessage) {
        print("sender")
        print(message.to())
        print("message")
        print(message)
        // user is nil after this line 
        let user = OneChat.sharedInstance.xmppRosterStorage.userForJID(message.from(), xmppStream: OneChat.sharedInstance.xmppStream, managedObjectContext: OneRoster.sharedInstance.managedObjectContext_roster())

        if !OneChats.knownUserForJid(jidStr: "ankit") {
            OneChats.addUserToChatList(jidStr: "ankit")
        }

        if message.isChatMessageWithBody() {
            OneMessage.sharedInstance.delegate?.oneStream(sender, didReceiveMessage: message, from: user)


        } else {
            //was composing
            if let _ = message.elementForName("composing") {
            //  OneMessage.sharedInstance.delegate?.oneStream(sender, userIsComposing: user)
            }
        }
    }

please help me

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: storage != nil'

I have need to addUser in roster and addUser function is in xmppRoster.m class so I need to create object of xmppRoster by writing xmppRoster() but whenever this method(xmppRoster()) runs its gives the error
"Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: storage != nil'"
So may I get the solution.

Running demo file shows error.

I was about to implement your framework. Before that I wanted to check the demo functionality of the framework, but on building it shows an error in ChatViewController.swift - as "use of unresolved identifier OneLastActivity"

OneLastActivity.sendLastActivityQueryToJID((recipient.jidStr), sender: OneChat.sharedInstance.xmppLastActivity) { (response, forJID, error) -> Void in
                        let lastActivityResponse = OneLastActivity.sharedInstance.getLastActivityFrom((response?.lastActivitySeconds())!)

                        self.userDetails = OneLastActivity.sharedInstance.addLastActivityLabelToNavigationBar(lastActivityResponse, displayName: recipient.displayName)
                        self.navigationController!.view.addSubview(self.userDetails!)

                        if (self.userDetails != nil) {
                                self.navigationItem.title = ""
                        }
                    }

So any idea about this?

Not able to integrate xmpp swift messenger in my iOS app

Hi

I have a create an empty xcode project in xcode7.1.1 with swift 2. I wrote pod 'xmpp-messenger-ios' in my pod file. After installing all the dependencies when I build the project it show errors as "include of non-module header inside framework module" as shown in attached screen shot. This error is not letting me proceed. please help?

screen shot 2015-12-22 at 4 06 25 pm

Compiler Error in Chat View Controller

I downloaded the master branch. Updated the pods, deep cleaned but I am getting the error as shown in the below screenshot.

I can see that in the Pod file OneLastActivity.swift, the code that has been committed last is not there in the file. The method getLastActivityFrom is not there.

Also in file OneChat.swift, the variable xmppLastActivity is not there.

Can you please check the issue. I know I can copy and paste the methods there. But the issue will be there if I update the pod again.

screen shot 2016-02-04 at 10 14 34 am
screen shot 2016-02-04 at 10 32 21 am

import Foundation
import XMPPFramework
public typealias OneMakeLastCallCompletionHandler = (response: XMPPIQ?,  forJID:XMPPJID?, error: DDXMLElement?) -> Void

    public class OneLastActivity: NSObject {

var didMakeLastCallCompletionBlock: OneMakeLastCallCompletionHandler?

// MARK: Singleton

public class var sharedInstance : OneLastActivity {
    struct OneLastActivitySingleton {
        static let instance = OneLastActivity()
    }
    return OneLastActivitySingleton.instance
}

// MARK: Public Functions

public func getStringFormattedDateFrom(second: UInt) -> NSString {
    if second > 0 {
        let time = NSNumber(unsignedLong: second)
        let interval = time.doubleValue
        let elapsedTime = NSDate(timeIntervalSince1970: interval)
        let dateFormatter = NSDateFormatter()
        dateFormatter.dateFormat = "HH:mm:ss"

        return dateFormatter.stringFromDate(elapsedTime)
    } else {
        return ""
    }
}

public func getStringFormattedElapsedTimeFrom(date: NSDate!) -> String {
    var elapsedTime = "nc"
    let startDate = NSDate()
    let components = NSCalendar.currentCalendar().components(NSCalendarUnit.Day, fromDate: date, toDate: startDate, options: NSCalendarOptions.MatchStrictly)

    if nil == date {
        return elapsedTime
    }

    if 52 < components.weekOfYear {
        elapsedTime = "more than a year"
    } else if 1 <= components.weekOfYear {
        if 1 < components.weekOfYear {
            elapsedTime = "\(components.weekOfYear) weeks"
        } else {
            elapsedTime = "\(components.weekOfYear) week"
        }
    } else if 1 <= components.day {
        if 1 < components.day {
            elapsedTime = "\(components.day) days"
        } else {
            elapsedTime = "\(components.day) day"
        }
    } else if 1 <= components.hour {
        if 1 < components.hour {
            elapsedTime = "\(components.hour) hours"
        } else {
            elapsedTime = "\(components.hour) hour"
        }
    } else if 1 <= components.minute {
        if 1 < components.minute {
            elapsedTime = "\(components.minute) minutes"
        } else {
            elapsedTime = "\(components.minute) minute"
        }
    } else if 1 <= components.second {
        if 1 < components.second {
            elapsedTime = "\(components.second) seconds"
        } else {
            elapsedTime = "\(components.second) second"
        }
    } else {
        elapsedTime = "now"
    }

    return elapsedTime
}

public class func sendLastActivityQueryToJID(userName: String, sender: XMPPLastActivity? = nil, completionHandler completion:OneMakeLastCallCompletionHandler) {
    sharedInstance.didMakeLastCallCompletionBlock = completion
    let userJID = XMPPJID.jidWithString(userName)

    sender?.sendLastActivityQueryToJID(userJID)
}
}

extension OneLastActivity: XMPPLastActivityDelegate {

public func xmppLastActivity(sender: XMPPLastActivity!, didNotReceiveResponse queryID: String!, dueToTimeout timeout: NSTimeInterval) {
    if let callback = OneLastActivity.sharedInstance.didMakeLastCallCompletionBlock {
        callback(response: nil, forJID:nil ,error: DDXMLElement(name: "TimeOut"))
    }
}

public func xmppLastActivity(sender: XMPPLastActivity!, didReceiveResponse response: XMPPIQ!) {
    if let callback = OneLastActivity.sharedInstance.didMakeLastCallCompletionBlock {
        if let resp = response {
            if resp.elementForName("error") != nil {
                if let from = resp.valueForKey("from") {
                    callback(response: resp, forJID: XMPPJID.jidWithString("\(from)"), error: resp.elementForName("error"))
                } else {
                    callback(response: resp, forJID: nil, error: resp.elementForName("error"))
                }
            } else {
                if let from = resp.attributeForName("from") {
                    callback(response: resp, forJID: XMPPJID.jidWithString("\(from)"), error: nil)
                } else {
                    callback(response: resp, forJID: nil, error: nil)
                }
            }
        }
    }
}

public func numberOfIdleTimeSecondsForXMPPLastActivity(sender: XMPPLastActivity!, queryIQ iq: XMPPIQ!, currentIdleTimeSeconds idleSeconds: UInt) -> UInt {
    return 30
}
}

Do we have any enhancements for Group chat ?

Can you brief me how we can implement group chat here ? Also do we need to change andy classes ?

Sorry to report it as issue but i didn't find any other way to raise this question

Socket closed by remote peer

Hey guys. I have been banging my head against wall with this issue for the last couple of days, so now here I am.

I am attempting to connect to my Ejabberd server (16.06) with the following c2s configuration:

`listen:

port: 5222
module: ejabberd_c2s
certfile: "/Applications/ejabberd-16.06/conf/server.pem"
#starttls: true
## To enforce TLS encryption for client connections,
## use this instead of the "starttls" option:
starttls_required: true
##
## Custom OpenSSL options
##
##protocol_options:
##  - "no_sslv3"
##   - "no_tlsv1"
max_stanza_size: 65536
shaper: c2s_shaper
access: c2s`

The server, for now, is just on my dev machine. So I am connecting to it as localhost. Now, in my AppDelegate I initialize OneChat and specify host / port / startTLSPolicy as such:

` OneChat.start(true, delegate: self) { (stream, error) in
if let _ = error {
print("Error opening one chat")
} else {
print("Successfully opened chat")
}
}

    OneChat.sharedInstance.xmppStream?.hostName = "127.0.0.1"
    OneChat.sharedInstance.xmppStream?.hostPort = 5222
    OneChat.sharedInstance.xmppStream?.startTLSPolicy = XMPPStreamStartTLSPolicy.Required`

In my ChatController I connect as such:

OneChat.sharedInstance.connect(username: String(format: "%s@%s", self.chatUsername!, ChatConversationsViewController.HOST), password: self.chatPassword!) { (stream, error) -> Void in if let _ = error { print("Failed to connect to XMPP server with \(self.chatUsername) and \(self.chatPassword)") let alertController = UIAlertController(title: "Sorry", message: "An error occured: \(error)", preferredStyle: UIAlertControllerStyle.Alert) alertController.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: { (UIAlertAction) -> Void in //do something })) self.presentViewController(alertController, animated: true, completion: nil) } else { print("Successfully Connected") } };

Firstly, my callbacks are never called for either the OneChat.start() / OneChat.sharedInstace.connect().

Secondly, the behavior I see is that when I connect my delegate's oneStreamDidConnect() gets called and then my oneStreamDidDisconnect() get's called immediately after. The error message I receive is "Socket closed by remote peer".

I put debug logging on the Ejabberd instance and I get the following:

2016-07-21 11:20:58.297 [debug] <0.613.0>@ejabberd_receiver:process_data:284 Received XML on stream = <<"<?xml version='1.0'?>">> 2016-07-21 11:20:58.298 [debug] <0.613.0>@ejabberd_receiver:process_data:284 Received XML on stream = <<60,115,116,114,101,97,109,58,115,116,114,101,97,109,32,120,109,108,110,115,61,39,106,97,98,98,101,114,58,99,108,105,101,110,116,39,32,120,109,108,110,115,58,115,116,114,101,97,109,61,39,104,116,116,112,58,47,47,101,116,104,101,114,120,46,106,97,98,98,101,114,46,111,114,103,47,115,116,114,101,97,109,115,39,32,118,101,114,115,105,111,110,61,39,49,46,48,39,32,116,111,61,39,32,226,128,158,226,136,158,14,1,39,62>> 2016-07-21 11:20:58.298 [debug] <0.614.0>@ejabberd_c2s:send_text:1852 Send XML on stream = <<"<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' id='10454082093091685755' from='localhost' version='1.0'>">> 2016-07-21 11:20:58.298 [debug] <0.614.0>@ejabberd_c2s:send_text:1852 Send XML on stream = <<"<stream:error><xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'></xml-not-well-formed></stream:error>">> 2016-07-21 11:20:58.298 [debug] <0.614.0>@ejabberd_c2s:send_text:1852 Send XML on stream = <<"</stream:stream>">>

I am sorry if this is an Ejabberd configuration error, but it's an "out of the box" configuration.

Thanks,
tc

p.s. Excuse the formatting, I am terrible with it.

Obj-C version

Do we have any version written in Obj-C?
Or do someone convert from Swift to ObjC?

Error "Incorrect argument label in call" after Pod install

Hello,

I get an error right after pod install on build. In OneChat.swift

On this line:
xmppvCardTempModule = XMPPvCardTempModule(withvCardStorage: xmppvCardStorage)
Error: Incorrect argument label in call (have 'withvCardStorage:', expected 'vCardStorage')

xmppvCardAvatarModule = XMPPvCardAvatarModule(withvCardTempModule: xmppvCardTempModule)
Error: Incorrect argument label in call (have 'withvCardTempModule:', expected 'vCardTempModule')

I've tried anything I could find on google, but I nothing helpful so far.
I am not sure if I am missing something. If there is settings related, but I did not find anything related to this particular error.

Thanks in advance!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.