Chat - Messaging SDK for iOS

Chat - Messaging SDK for iOS

Released 1 year ago , Last update 4 weeks ago

Fully featured customizable Objective-C framework to display and manage message based conversations - similar to Whats App or Messages. Quickly add text, picture and location based messaging functionality to your app.

Be the next WhatsApp! Quickly add messaging to your app using this fully featured SDK. This SDK provides you with a full messaging system - user interface and Firebase back end.

Android

We now have a version of this SDK for Android! Check it out here: http://www.binpress.com/app/chat-messaging-sdk-for-android/2326

Chat SDK - Core

The core version of the is ideal if you have your own messaging back end and need a user interface. Chat SDK core license provides you with the full front end ready to be connected to your message delivery system.

Features

  • Text, Picture and location messages
  • Group chat room
  • Private messages
  • Colored speech bubbles
  • Customize text color and font
  • Copy/Paste
  • Automatic highlighting of emails addresses and phone numbers
  • Profile pictures for messages
  • Flexible architecture
  • Messages saved with core data
  • Tabbed interface - profile page, contacts page, search page etc...

The SDK provides a clean simple interface that completely decouples the creation of display of messages and thread form the way they're transmitted and received over the network.

Chat SDK Screenshot 1

Thread Screen

The thread screen provides a list of conversations that the user is participating in. Single and group conversations are both supported. Each conversation has the following features:

  • The names of the members participating in the conversation
  • A photo of the recipient
  • Date of the last message received
  • The text of the last message received
  • Unread message indicatior
  • Threads are ordered by the date of the last message received

From this screen it's possible to create new threads and delete unwanted threads.

Message Screen

The message screen is the most important part of this project. It provides a speech bubble view of all the messages that have been received in the thread. It also allows new messages to be written and sent. Here are the main features:

  • Text messages
  • Location messages displayed on a map with customizable pin message and map scale
  • Picture messages selected from the album or taken using the camera
  • Speech bubbles re-size depending on the size of the text or image
  • Customizable speech bubble color (per-message basis)
  • Customizable speech bubble text color (per-message basis)
  • Speech bubble font and font-size set on a per-message basis
  • User's profile picture displayed next to the message
  • Bubbles scroll behind the keyboard and navigation bar
  • The phone vibrates when a new messages is received
  • The time the message was sent
  • Clicking on an image or location opens it full screen
  • Drag the view down to load older messages

These features provide a fully featured messaging platform which can quickly be interfaced with existing messaging infrastructure. If you're also looking for a back end system you should consider buying the Firebase license that provides an out-of-the box messaging platform.

Architecture

While designing this component I put a lot of though into the best architecture to use. I wanted to provide a flexible messaging front end while making it possible to interface with existing apps and network code. The final SDK completely decouples the networking functionality from the message presentation and creation. I also provide an example class that shows how to implement the necessary interfaces.

Other Open Source Projects

There are a number of free open source projects which support different aspects of messaging, none of which are very mature. This project combines the best parts of all of them while adding additional features and fixing showstopping bugs.

While creating this component, the code of about 15 different free open source projects were researched, and some are included in the package. The best bits of each were taken to make a simple, well designed, flexible component that just works. Even using the open source projects that are available, you're still looking at several weeks of development to create the capabilities of this component.

iOS Support

This project supports iOS 7+

Chat SDK - Firebase

Chat SDK Screenshot 2

The Firebase license provides a fully featured messaging platform out of the box. It uses Firebase which is a powerful real time back end which was designed from the ground up with messaging in mind. You can open an account for free - the free app would be perfectly sufficient for a small app. As your app grows you can upgrade your account - Firebase can easily scale to millions of monthly users.

Features

  • Real time chat
  • Login via Facebook, username/ password, twitter, anoymous
  • Google + coming soon!
  • Multiple user accounts on one device
  • Cloud message storage
  • Push notifications
  • Invite friends from Facebook
  • Powerful search API
  • Add custom meta data to users' profiles
  • Lazy loading of messages
  • Clean architecture

If you decide to buy the ChatSDK Firebase license you get the full ChatSDK front end as well as the Firebase networking code.

Login Screen

The login screen allows you to register or login to the messaging app. You can also use social logins via Facebook or Twitter.

Finding other users

If the user logged on using Facebook they can instantly see a list of their friends who are using the app.

Alternatively the SDK includes a search API. This allows you to associate key works with user accounts. As standard the user's name, phone number and email are all indexed. When a keyword matches an index in the search database, a list of users matching that keyword are presented to the user.

Customization

Version 3 of the Chat SDK adds a flexible way to associate data with a user. You can associate an unlimited number of meta data objects with any user - these objects can store data, text or images. This data is then synchronized across all devices. For example you could add "gender" meta data to all users.

It would then be possible to add this meta data to the search index. For example, I could pull up a list of all male users. Or all users that lived in London.

Conclusion

This network code represents a large amount of development time and will allow you to add instant messaging to your app in a couple of hours. The code is thoroughly tested with a clean object orientated architecture. If you find any bugs please report them on the Binpress bug tracker. I respond to issues with hours and will usually be able to provide a fixed version within 24 hours.

Extensions and customization

If you're looking to customize the Chat SDK, the Firebase networking code or you need a custom network integration you can get a quote using the "Need additional services?.. Get a Quote" button.

4.8
  • 5 4
  • 4 1
  • 3 0
  • 2 0
  • 1 0
5 Reviews Read Reviews

Pricing

$99.99

Chat SDK front end - app license

  • Perpetual license

  • 1 application

  • Can distribute binary products only

  • Commercial use

  • 1 month support

$499.99

Chat SDK front end - multi-app license

  • Perpetual license

  • 5 projects

  • Can distribute code and binary products

  • Commercial use

  • 6 months support

$799.99

ChatSDK front end + Firebase - multi-app license

  • Perpetual license

  • 5 projects

  • Can distribute code and binary products

  • Commercial use

  • 6 months support

$1,999.99

ChatSDK front end + Firebase - Developer License

  • Perpetual license

  • Unlimited projects

  • Can distribute code and binary products

  • Commercial use

  • 12 months support

Need custom services for this product? Get a quote

Documentation

Architecture

ChatSDK Front End

The front end is completely decoupled from the back end of the app. All communication passes through two interfaces:

  • BNetworkFacade: Exposes methods to alter server state (new message, delete thread etc...)
  • BNetworkActivityListener: Classes can implement this interface and register themselves to be notified when the server state changes

This process is controlled by the BNetworkManager singleton.

The easiest way to understand is to look at some examples:

Sending a message

In the SDK all entities are persisted using CoreData. Before creating a message, it's a good idea to create a new undo grouping. This means that if there's an error sending the message, the database state can be rolled back.

[[BCoreDataManager sharedManager].managedObjectContext.undoManager beginUndoGrouping];

Next the message is created:

BMessage * aMessage = [[BCoreDataManager sharedManager] createEntity:bMessageEntity];
[aMessage initialize];
aMessage.text = @"Test Message";
aMessage.type = @(bMessageTypeText);
aMessage.date = [NSDate date];
aMessage.user = [BNetworkManager sharedManager].currentUser;

aMessage.thread = _thread;

Here it would also be possible to customize the message's font, text color or bubble colour. Before sending we need to end the undo grouping:

[[BCoreDataManager sharedManager].managedObjectContext.undoManager endUndoGrouping];

Then we send the message using the network manager:

[[BNetworkManager sharedManager] sendMessage:aMessage withProgress:^(NSProgress * progress, bMessageStatus status) {

} completion:^(NSError * error) {
    if (error) {
        [[BCoreDataManager sharedManager].managedObjectContext.undoManager undo];
    }
}];

Creating a new thread or deleting a thread follows the same pattern. It’s just necessary to call a different method on the network manager.

Receiving a message

To receive a message it’s necessary for the class to implement the BNetworkActivityListener protocol. Then register itself with the network manager.

[[BNetworkManager sharedManager] addActivityListener:self];

When a message arrives the class will be notified:

-(void) messageAdded:(BMessage *)message toThread:(BThread *)thread {
    // Handle message here!
}

Custom back end

If you want to handle the network communication yourself you would need to create a class that conforms to the BNetworkAdapter protocol. This must then be registered with the network manager (in the app delegate):

[[BNetworkManager sharedManager] setNetworkAdapter:[[BFirebaseNetworkAdapter alloc] init]];

The network manager will be passes all the requests that are made to the network adapter. Then when the server state changes, it can notify the app by calling methods on it’s activityDelegate.

The SDK provides an example of a blank implementation. All the implementation does is writes new messages to the database but it should give you an idea of how to interact with the SDK front end.

ChatSDK Firebase

Now lets look at the architecture used by the Firebase implementation. Again all communication goes through the network manager.

There are two important classes in the Firebase back end:

  • BFirebaseNetworkAdapter - this class handles all communication between the Firebase server and the app.
  • BFirebaseInterface - is a helper class that simplifies communication

Firebase data structure

Firebase stores data in a JSON type format. Each object in the object tree can be accessed by its own unique URL. For example:

users: {
    1: {name: Ben}
    2: {name: John}
]

Here we have an array of users. We could access the users dictionary by appending “users” to our unique Firebase URL. If we wanted to access the name of user 1 we could use the URL:

[Firebase URL]/users/1

To have a look at the data structure of the app you can open the Forge data viewer in Firebase. You would need to have setup your Firebase account. Also, until you start using the app the Firebase will be blank so make sure to create a thread.

You’ll see that there are two main lists of data: threads and users. A thread contains a creation date, a list of messages and a list of users.

A user contains a FacebookID, name, image url as well as a list of threads it’s associated with.

This is a very flexible structure because it allows an arbitrary number of users per thread. It allows a user to leave the thread without disrupting the rest of the conversation.

Outbound traffic

When the app wants to modify the state of the server it calls BNetworkFacade methods on the network manager. These then get passes to the Firebase network adapter.

Lets look at an example of sending a message:

-(void) sendMessage: (BMessage *) message withProgress: (void(^)(NSProgress * progress,     bMessageStatus status)) progress completion: (void(^)(NSError * error)) completion {

    // Get the path to the thread's messages
    if (message.thread) {

        [BFirebaseInterface pushEntity:message completion:^(NSError * error) {
            completion(error);
        }];
    }
}

In the app, entities are abstracted using the PEntity interface. This allows the app to treat all entities the same for simple operations. When the adapter is told to send a message, it uses the Firebase interface to push the message to the server. In this case “push” checks if the message already exists, if it does it updates it, otherwise it creates a new message on the server.

If you look at the implementation of pushEntity, you’ll see that first it selects the entity from Firebase. If the entity exists, it updates it. Otherwise it creates a new entity on the server.

Inbound Traffic

Firebase is different to a standard database because it operates in realtime pushing data to the client. You don’t have to check if the data has updated or use push notifications! If you want to know when a piece of data has changed, you just need to listen to a location.

Firebase relies heavily on data paths. Data can be accessed using the data’s URL and we can listen to a URL to be notified when certain events happen. Firebase supports the following events:

  • Child Added
  • Child Removed
  • Child Changed
  • Child Moved
  • Value Changed

Keeping track of all the different data URLs can be quite tricky. Especially because URLs are composed of both dynamic and static parts. For example, the URL of a message contains two dynamic parts and two static:

[Firebase URL]/threads/[Thread ID]/messages/[Message ID]/…

The “Thread ID” and the “Message ID” are both dynamic - their value will change depending on the thread or message we’re looking at.

To help with this, every entity has a method called “getPath”. This method returns a path object which can be used to get the path to the entity as a string. Lets look at an example of listening to new messages

Firebase * threadRef = [[Firebase firebaseRef] appendPathComponent:thread.getPath.asString];

// We want to listen for new messages added so we listen to thread/messages
Firebase * messagesRef = [threadRef appendPathComponent:bMessagesPath];

// Get the last message from the thread
NSArray * messages = thread.messagesOrderedByDateDesc;

// If the message exists we only listen for newer messages
FQuery * query = messagesRef;
if (messages.count) {
    query = [messagesRef queryStartingAtPriority:@([((BMessage *)messages.firstObject).date timeIntervalSince1970])];
}

[query removeAllObservers];

[query observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot * snapshot) {
    // When a message arrives we add it to the database
    BMessage * message = [BFirebaseInterface objectForSnapshot:snapshot];

    // We should check that the user of the message exists to show their profile picture
    if (!message.user.lastUpdated || fabsf(message.user.lastUpdated.timeIntervalSinceNow) > bHours * 2) {
        // We need to retrieve the user
        [BFirebaseInterface selectEntity:message.user withCompletion:^(id<PEntity> user_) {
            [activityDelegate messageAdded:message toThread:thread];
        }];
    }
    else {
        [activityDelegate messageAdded:message toThread:thread];
    }
}];

First we get a pointer to the Firebase location. We do this by getting the path to the thread and append it to our base Firebase URL. We then append the string “messages” to the end of the URL to get the path to the thread’s messages.

Next we get the last message we received from the thread. We need to make a query so we only get updated if a more recent message is added. Firebase only stores simple data types - strings and numbers, so we need to convert the date to a time interval.

With the query setup, we first remove any previous observers. Then we add a new observer to the location. The observer works using a block. The block will be triggered if a new message is added. When this happens we’ll receive a new snapshot. A snapshot is basically a pseudo JSON data structure (made of NSArrays and NSDictionary) representing the data that was added.

To get the message from the snapshot we use the “objectForSnapshot” function. This function analyses the snapshot’s path to determine the data type, then recursively parses the data updating our CoreData store as it goes. I recommend that you take some time to study this function. Especially if you want to modify the Firebase storage behavior. The basic principle is that all paths are made up of alternating static and dynamic segments i.e.

threads/[Thread ID]…

If we get a snapshot with a path like this, we know that it’s of the type BThread and we can identify the particular thread using the Thread ID. Any other data stored at this level will belong to the particular thread i.e. “Creation date”.

If we have a path like this:

threads/[Thread ID]/messages/[Array of message IDs]

We know that we’re dealing with an array of messages associated with a particular thread. We would loop over the messages and for each message, the path would look like this:

threads/[Thread ID]/messages/[Message ID]

Now we know the thread ID and the message ID and the message data. This is all we need to update the database state.

Going back to the code example above, once we’ve added the message to the database, we want to make sure we also have the details of the message’s sender. First we check to see when the user was last updated, if it was more than 2 hours ago we re-load the user. When we’ve loaded the user’s data, we notify our Network Activity Listeners that a new message has been received.

Conclusion

This should give you an idea of the basic principles of the Firebase back end. The Firebase code is quite concise - the bulk of the network functionality is handled by two fairly short classes. However, conceptually it can take some time to fully understand the patterns used when working with Firebase as opposed to a standard relational database.

If you want to start really customizing this code, I’d recommend going through the two main classes:

  • BFirebaseNetworkAdapter
  • BFirebaseInterface

While looking at the excellent documentation provided by Firebase. I'm also always available to answer queries - I usually reply in less than an hour.

Setup / Installation

Chat SDK Front End

This project comes as a fully functional app which you can compile straight away in Xcode. If you're just buying a license to the front end, the app is setup using the BBlankNetworkAdapter. This adapter conforms to all the necessary protocols and can be used as a starting point to interface the app to your network.

Chat SDK Firebase

To get the Firebase version of the app working several steps are necessary:

1) Change Xcode bundle identifier

In Xcode click "Chat SDK" in the top left and identify the field called "Bundle Identifier". Change this field to [your url].Chat-SDK

2) Create a free Firebase account

Once you've created your new account you need to create a new Firebase. From the account screen click "Create new app". Once the app has been created click "View Firebase" this will open the dashboard. The dashboard shows you the data currently stored in the Firebase. Copy the URL of this page. It should be in the form [your-name].firebaseio.com. This is your base Firebase URL.

In the ChatSDK open BFirebaseDefines.h and copy your path in place of the bFirebasePath variable.

!! IMPORTANT !! The base URL path mush have a trailing slash like this:

#define bFirebasePath @"https://your-firebase-name.firebaseio.com/"

If you miss off the trailing slash the SDK won't be able to process the URLs properly and messages will not be updated.

3) Setup Facebook app

If you don't already have an account create one. Then click "Apps" -> "create new app". On the new app page click "Settings". Click "Add Platform" and choose iOS.

Fill in a display name and a contact email. Then add your bundle identifier. Set "Single Sign On" to yes. Then click "Save Changes".

Then click "Status & Review" and set the switch to "Yes" this will allow other people to sign on to your app.

Now the app is setup but you still need to link the Facebook account to Firebase and your app.

Go back to the Firebase dashboard and click "Simple Login". Click the Facebook tab and tick the "Enabled" box. Then copy paste your Facebook "App Id" and "App Secret" into the boxes provided.

Finally, open Xcode. Open BFirebaseDefines.h and copy your Facebook App Id to the variable bFacebookAppID.

Then open Chat SDK-Info.plist. Change the bFacebookAppID to your Facebook App Id. Then expand the "URL types" item. Drill down until you reach the "URL Schemes" array. Replace the part [your Facebook ID] with your Facebook ID. The URL scheme should look like this:

fbXXXXXX... // Where XXXXXX is your Facebook ID. 

4) Security

Finally, Firebase starts of with very lax security rules. That would mean that anyone could delete all the data in your database by writing one JavaScript query. To stop this, open the dashboard and click on the "Security" tab. Copy the following code:

{
  "rules": {
    ".read": true,
    ".write": "auth != null"
  }
}

This will mean that only authenticated users can modify your data. To read more about Firebase security look here.

**NOTE** The security rules provided above are very basic and would allow any authenticated user to have full control over your database! The reason that I've not provided more sophisticated rules is becuase I think it's important that **you** understand Firebase security. If I provide a set of rules it would be very tempting to just add them to your Firebase and forget about them. This may cause problems down the line when your chat gets hacked.

I can't guarantee that any set of rules that I would write would be completely secure. One mistake in my rules may cause your chat app to be hacked. For that reason, it's really important that **you take the time to understand Firebase security** and write your own set of secure rules.

**5) Push notifications **

Push notifications are optional so you don't have to set them up straightaway. When they're setup, the app will automatically send a push notification to the recipients of the message if they've not been online for a certain amount of time - 10 minutes by default.

To enable push notifications you need to do the following:

First you need to make a new account with Parse.com. Once you’ve registered create a new application.

Open the dashboard and select your new application. Then click “Settings” -> “Application Keys”.

Make sure that you enable "Client push enabled" in the Parse dashboard -> settings tab -> Push notifications

Then copy the Application ID and Client Key into BFirebaseDefines.h replacing bParseAppKey and bParseClientKey.

Now you need to make a push certificate with Apple. Follow the steps here:

https://www.parse.com/tutorials/ios-push-notifications

To create your push certificate and add it to your Parse account.

Make sure to change the app’s Bundle identifier to something else! When you get the app, it will be set to co.deluge.Chat-SDK. Change to:

your.domain.Something

Push notifications will not work on the simulator. To test this you’ll need to use a real device.

Make sure you create a new development provisioning profile. Usually you can develop using you phone using a default Xcode-generated development profile. This won't work with push notifications. Log in to the Apple member's center and create a new Development provisioning profile once you've created, downloaded and installed the certificate, go to Build Settings in Xcode and set Provisioning Profile to your new development profile.

Now the app should be ready to go!

If you have any problems Firebase offer good documentation and Facebook have an integration guide.

Adding a new database field

How to add a new database field:

If you want to extend the chat component to add your own data you're going to need to add new fields both to the app's CoreData storage and to Firebase.

CoreData

First we need to add the property to the CoreData schema. Open ChatSDK.xcdatamodeld in the left navigation bar and create a new version of the model.

Editor->Add Model Version

Call it DataModel v[next version number]

Click ChatSDK.xcdatamodeld again and open the right side bar. Click the icon that looks like a piece of paper at the top then change Model Version to the new model version you created.

In the left navigation bar again, expand the ChatSDK.xcdatamodeld by clicking the little arrow and select the model version. After that make the changes you need to make to the entities.

In this example, I’m going to add a last online property to the user entity.

Under the “entities” heading click the BUser entity. Under attributes click + to add a new attribute. Set the name for the variable and choose it’s type. In this case we choose Date.

Now we need to update the entities. Right click on the left in the CoreDataEntities folder and choose New File then choose Core Data then NSManagedObject subclass, select the new DataModel you created then select all the entities. Click Next and select the folder CoreDataEntities. Click Create.

This will write over the existing entities updating them with the properties you added.

CoreData will automatically update the database when you next open the app.

Next we need to update the User protocol. The user protocol encapsulates the user object. This means that if you wanted to design your own user object or use a different storage type, you could implement the protocol with your new object and it would work perfectly with the existing chat component.

Open PUser.h and add a new method to access the last updated property.

-(NSDate *) lastOnline; -(void) setLastOnline: (NSDate *) lastOnline;;

Now we can access the variable from within the chat component and we can save the variable to CoreData.

Firebase

Now we need to make sure that the variable can be saved in Firebase.

The Chat SDK comes with a framework which simplifies working with Firebase.

In order for our objects to be added to Firebase they need to be serialized. When we receive an object from Firebase it then needs to be de-serialized. The framework will handle most of the details but we still need to add the serialization and deserialization code.

Open BUser+Additions.h and find the method called “asDictionary”. We need to add this variable to the dictionary so when the user is uploaded this variable is set as well.

First we’re going to create a new key. Open BDefines.h and add a new key:

#define b_LastOnline @"last-online”

Then add the property to the user’s dictionary:

return @{b_Name: self.name,
         b_FacebookID: self.facebookID,
         b_PictureURL: self.pictureURL,
         b_PictureExists: self.pictureExists,
         b_LastOnline: @(self.lastOnline.timeIntervalSince1970)};

Now when we push a user the lastOnline value will also be pushed. We add the time interval since 1970 because Firebase can only store basic data types - not NSDates.

Now we need to make sure that when we are pushed a new user from the Firebase, that the locally stored user object is also updated.

Look at the updateFromDicationary method in BUser+Additions.m. This method updates the object when provided with a dictionary of serialized data.

NSNumber * lastOnline = snapshot.value[b_LastOnline];
if (lastOnline) {
    user.lastOnline = [NSDate  dateWithTimeIntervalSince1970:lastOnline.doubleValue];
}

Here we extract the last online time from the user and add it to the database object.

That's pretty much it. Now all we need to do is set the value and when we select or push a user object, the last online field will be updated automatically.

FAQ

In this section I'm going to put answers to frequently asked questions.

Storyboard integration

Many people think that Storyboards and XIBs can't be used together. That you either have to create the whole app in one monolithic Storyboard or you have to use hundreds of interconnected XIB files. In fact, Storyboards are just an extra tool that can be used for interface creation along side XIBs and code. In some situations it's useful to use a Storyboard and in others it's better to use an XIB.

Lets say that you want to launch the Threads view from your Storyboard using a button. First, you'd need to right click drag the button from the Storyboard into the relevant .m file to create an action. You'd end up with an action like this:

- (IBAction) openChatButtonPressed:(UIButton *)sender {

}

Now, whenever you click this button, this code will be called.

Inside this method we're going to load up the threads view controller of the group Chat SDK.

[self.navigationController pushViewController:[[BThreadsViewController alloc] initWithNibName:Nil bundle:Nil] animated:YES];

This will create a new instance of the threads view (obviously in the Firebase version, you would have had to have authenticated with Firebase before doing this). Since Storyboards use the same navigation controller as XIBs, we can just push the new view onto the stack.

To get back to our Storyboard, we would just pop the view controller:

[self.navigationController popViewControllerAnimated:YES];

This will take us back to the previous Storyboard view.

How is a user created?

To find where a user is created we need to look at the BFirebaseNetworkAdapter class. When the app first loads up it will try to authenticate the user with Facebook. Once that's successful it will call:

syncWithProgress: withCompletion:

The purpose of this method is to get the app up-to-date with the server. Lets go through the function in detail to see what's happening.

BUser * user = [[BCoreDataManager sharedManager] fetchOrCreateUserWithEntityID:Nil withFacebookID:facebookID];
user.facebookID = facebookID;

First we fetch or create a new user object with the appropriate facebook ID. If a user already exists, we'll be returned it's instance, otherwise a new user object will be added to the database.

Next we call:

[BFirebaseInterface selectEntity: user withCompletion...

In Firebase there are two ways we can access a piece of data directly, using the Firebase ID or by using the priority of the object. A priority is a user determined identifier for the data.

The selectEntity method first checks to see if an "Entity ID" exists on the entity. In this case the entity id points to the Firebase ID of the object (see user.entityID method). If the entity id doesn't exist, it will check to see if the entity has a priority. In this case, we're using the user's Facebook ID as the priority but really you could use any external ID (see user.getPriority).

Then the code calls the Firebase method:

observeSingleEventOfType:FEventTypeValue withBlock:...

This will check Firebase and return a snapshot of the data. When the snapshot arrives, it's processed using object for snapshot: (explained in more detail earlier in this documentation)

[BFirebaseInterface objectForSnapshot:snapshot];

After this, it will return the resulting BUser object to the completion block which takes us back to the sync method.

If this is the first time the user has logged on, they won't yet have a Firebase ID. In this case, user.entityID will be Nil. Since, a new user will have been generated when we called the select method, we need to delete the original "dummy" user we created and continue using the user_ variable provided by the block.

Next we retrieve the user's profile picture from Facebook. When the return block of that method is called, we add the profile picture to the user. Finally, we want to make sure that the user's details are all up-to-date on Firebase.

To do this we call:

BFirebaseInterface pushEntity: user_ completion: ...

The pushEntity method checks to see if an entity exists, if it does, it updates that entity, otherwise it creates a new entity.

Lets look at that method in more detail.

First, we call selectEntity which retrieves existing data from Firebase (as described earlier).

If the entity exists already on Firebase, it will have a Firebase ID (entity ID). In this case, we call:

ref updateChildValues: entity.asDictionary ...

Otherwise we need to create a new entity on Firebase using:

Firebase * listRef = [ref childByAutoId];

// We can set the name here!
[entity setEntityID:listRef.name];

[listRef setValue:entity.asDictionary andPriority:priority withCompletionBlock:^(NSError * error, Firebase * firebase) {
    [entity setEntityID:firebase.name];
    completion(error);
}];

First we create a new Firebase identifier - this creates space for a new item in Firebase. Then we update the entity object's ID.

It's necessary to do this here because otherwise a race condition can occur (the user object in the database doesn't have an entity ID and new data arrives from Firebase before the "withCompletionBlock" block is called. The new information looks for the user object in the local database using the entity id, because it doesn't find it, it creates a new user object).

Then we call setValue... This creates a new user object in Firebase.

Going back to the sync method. The final step is to add observers to the user object. These observers are callback methods that are called whenever a relevant piece of information about the user, their threads or messages changes on the server. Whenever a piece of data changes, the local database is updated by the method:

[BFirebaseInterface objectForSnapshot: ...];

The important thing to note about the user creation process is that a user is identified by both it's entity id (Firebase ID) and it's priority (Facebook ID). However, the priority could be any id, the user's row id on your server, the user's Twitter ID etc...

5 licenses, starting from From » $99.99 View Licenses

Get A Quote

What do you need?
  • Custom development
  • Integration
  • Customization / Reskinning
  • Consultation
When do you need it?
  • Soon
  • Next week
  • Next month
  • Anytime

Thanks for getting in touch!

Your quote details have been received and we'll get back to you soon.

or Get a quote

for customization or integration services


Or enter your name and Email
  • P Paul 1 week ago
    Hi Ben, is the UI implemented with StoryBoards or Xib files?
    • BS Ben Smiley 4 days ago
      Hi Paul, The UI is mainly implemented using XIB. The only storyboard is on the profile screen. There's a guide in the documentation that shows how XIB and storyboards can be mixed. Cheers, Ben
  • D dan License holderChatSDK front end + Firebase - app license
    1 month support
    Purchased on Dec 3, 2014
    1 week ago
    how do you import the firebase tables chatsdk.xcdatamodeld into firebase?
    • BS Ben Smiley 1 week ago
      Hi Dan, There's no need to import anything to firebase - the data is setup automatically by the client side code. Thanks, Ben
    • D dan 1 week ago
      i see. currently, when logging in the anonymous or fb login, i get, " error code: authentication_disabled ) the specifiied authentication type is not enabled for this Firebase." also i do have the trailing slash at the end of the url as specified.
    • Ben Smiley Publisher 1 week ago
      Have you enabled those login types in Firebase (Firebase dashboard -> Simple login)?. Usually when those errors come up it's because the login method isn't enabled on the Firebase side.
  • C cashmash 1 week ago
    When will you update to newest Facebook SDK? Getting this error when trying to login with Facebook: Error The operation couldn't be completed. (com.facebook.sdk error 2.) Working for one user though
    • BS Ben Smiley 1 week ago
      The first thing to try would be to replace this line: [FBSession openActiveSessionWithReadPermissions:@[@"public_profile"] with: [FBSession openActiveSessionWithReadPermissions:@[@"basic_info"] If that doesn't work let me know. Thanks, Ben
    • C cashmash 5 hours ago
      Changed it in BFireBaseNetworkAdapter.m and it is working but there are other problems now When I want to start a conversation with picking a friend it goes straight to a chat room that is public. It doesnt create the private 1on1 chat with that person i want to chat with.