Bit6 for iOS

GitHub version

Additional resources: GitHub Repo, API Reference, Code Samples

Getting Started

Prerequisites

CocoaPods Setup

Version License Platform

Bit6 is available from CocoaPods. To install it, simply add the following lines to your Podfile:

# Uncomment this line if you're using Swift
# use_frameworks!

target 'test' do
    pod 'Bit6'
end

Note Replace test with the name of the target of your Xcode project.

Manual Setup

Step 1. Download the Bit6 SDK.

Step 2. Add Bit6.framework to your project.

Step 3. Link the following frameworks and libraries: libicucore.tdb, libstdc++.tdb, GLKit and VideoToolbox.

Step 4. Set the Architectures value to be $(ARCHS_STANDARD_32_BIT) for iPhone Simulators and $(ARCHS_STANDARD) for devices.

Step 5. Set your Deployment Target to be iOS 8.0 or later.

Step 6. In your Build Settings add -ObjC to the 'Other Linker Flags'

Step 7. Disable Bitcode:

Bit6 SDK doesn't include support for Bitcode yet. You need to disable Bitcode support in your target configuration:

Disable Bitcode

Target Configurations

Localizable.strings

To make the push notifications work correctly you need to have a Localizable.string file in your project. If you don't have one in your project download this one Localizable.string, if you already have the file, copy and paste the following content in it:

// [caller name] is calling
"BX_INCOMING_CALL" = "%@ is calling...";

// [caller name]: Join a group call...
"BX_INCOMING_UNTITLED_GROUP_CALL" = "%@: Join a group call...";

// [caller name]: Join [group title] call...
"BX_INCOMING_GROUP_CALL" = "%@: Join %@ call...";

// Missed call from [caller name]
"BX_MISSED_CALL" = "Missed call from %@";

// [sender]: [message]
"BX_MESSAGE_TEXT" = "%@: %@";

// [sender]: sent a photo
"BX_MESSAGE_PHOTO" = "%@ sent a photo";

// [sender]: sent a video
"BX_MESSAGE_VIDEO" = "%@ sent a video";

// [sender]: sent an audio clip
"BX_MESSAGE_AUDIO" = "%@ sent an audio clip";

// [sender]: sent a location
"BX_MESSAGE_LOCATION" = "%@ sent a location";

// [sender]: sent a file
"BX_MESSAGE_FILE" = "%@ sent a file";

/* Decline */
"push_decline_call_action" = "Decline";

/* Answer */
"push_answer_call_action" = "Answer";

/* Reply */
"push_reply_msg_action" = "Reply";

Enable Push Notifications

In your target capabilities enable Push Notifications.

Enable Background Modes

In your target capabilities enable the following background modes:

Whitelist Bit6 for Network Requests

If you compile your app with iOS SDK 9.0, you will be affected by App Transport Security. You will need to add the following to your info.plist file to be able to work with attachments:

<key>NSAppTransportSecurity</key>
  <dict>
    <key>NSExceptionDomains</key>
    <dict>
      <key>amazonaws.com</key>
      <dict>
        <key>NSIncludesSubdomains</key>
        <true/>
        <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
        <true/>
        <key>NSTemporaryExceptionMinimumTLSVersion</key>
        <string>TLSv1.1</string>
      </dict>
    </dict>
  </dict>

Disable Bitcode

Application Delegate

Inititalize Bit6 SDK

Inititalize Bit6 SDK with your API Key:

@import Bit6;
- (BOOL)application:(UIApplication *)application
      didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        [UNUserNotificationCenter currentNotificationCenter].delegate = self;
        [Bit6 startWithApiKey:@"your_api_key"];
    }
import Bit6
func application(application: UIApplication,
  didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool
  {
        if #available(iOS 10.0, *) {
            UNUserNotificationCenter.currentNotificationCenter().delegate = self
        }
        Bit6.startWithApiKey("your_api_key")
    }

Push Notifications

NOTE. Remember to configure your development and production APNS Certificates.

Implement the following methods in your AppDelegate:

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    [application registerForRemoteNotifications];
}

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    [Bit6.pushNotification didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    [Bit6.pushNotification didFailToRegisterForRemoteNotificationsWithError:error];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    [Bit6.pushNotification didReceiveNotificationUserInfo:userInfo];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{
    [Bit6.pushNotification didReceiveNotificationUserInfo:userInfo fetchCompletionHandler:completionHandler];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
{
    [Bit6.pushNotification handleActionWithIdentifier:identifier forNotificationUserInfo:userInfo completionHandler:completionHandler];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler
{
    [Bit6.pushNotification handleActionWithIdentifier:identifier forNotificationUserInfo:userInfo withResponseInfo:responseInfo completionHandler:completionHandler];
}

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    [Bit6.pushNotification didReceiveNotificationUserInfo:notification.userInfo];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void(^)())completionHandler
{
    [Bit6.pushNotification handleActionWithIdentifier:identifier forNotificationUserInfo:notification.userInfo completionHandler:completionHandler];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(UILocalNotification *)notification withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void(^)())completionHandler
{
    [Bit6.pushNotification handleActionWithIdentifier:identifier forNotificationUserInfo:notification.userInfo withResponseInfo:responseInfo completionHandler:completionHandler];
}

#pragma mark - UNUserNotificationCenterDelegate

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler
{
    [Bit6.pushNotification userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler];
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
{
    [Bit6.pushNotification userNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler];

    NSDictionary *userInfo = notification.request.content.userInfo;

    //for incoming calls we don't show the system banner. We show a custom banner in [AppDelegate incomingCallNotification:]
    if ([Bit6PushNotificationCenter isIncomingCallNotification:userInfo]) {
        completionHandler(UNNotificationPresentationOptionNone);
    }
    else {
        Bit6Address *address = [Bit6PushNotificationCenter addressForMessageNotification:userInfo];
        //the user is not inside the conversation, we show the banner with sound
        if (![[Bit6 currentConversation].address isEqual:address]) {
            completionHandler(UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
        }
        else {
            completionHandler(UNNotificationPresentationOptionNone);
        }
    }
}
func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
    application.registerForRemoteNotifications()
}

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
    Bit6.pushNotification().didRegisterForRemoteNotificationsWithDeviceToken(deviceToken)
}

func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
    Bit6.pushNotification().didFailToRegisterForRemoteNotificationsWithError(error)
}

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject]) {
    Bit6.pushNotification().didReceiveNotificationUserInfo(userInfo)
}

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) {
    Bit6.pushNotification().didReceiveNotificationUserInfo(userInfo, fetchCompletionHandler: completionHandler)
}

func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
    Bit6.pushNotification().handleActionWithIdentifier(identifier, forNotificationUserInfo: userInfo, completionHandler: completionHandler)
}

@available(iOS 9.0, *)
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forRemoteNotification userInfo: [NSObject : AnyObject], withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
    Bit6.pushNotification().handleActionWithIdentifier(identifier, forNotificationUserInfo: userInfo, withResponseInfo: responseInfo, completionHandler: completionHandler)
}

func application(application: UIApplication, didReceiveLocalNotification notification: UILocalNotification) {
    Bit6.pushNotification().didReceiveNotificationUserInfo(notification.userInfo!)
}

func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {
    Bit6.pushNotification().handleActionWithIdentifier(identifier, forNotificationUserInfo: notification.userInfo!, completionHandler: completionHandler)
}

@available(iOS 9.0, *)
func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, withResponseInfo responseInfo: [NSObject : AnyObject], completionHandler: () -> Void) {
    Bit6.pushNotification().handleActionWithIdentifier(identifier, forNotificationUserInfo: notification.userInfo!, withResponseInfo: responseInfo, completionHandler: completionHandler)
}

// MARK: - UNUserNotificationCenterDelegate

@available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, didReceiveNotificationResponse response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) {
    Bit6.pushNotification().userNotificationCenter(center, didReceiveNotificationResponse:response, withCompletionHandler:completionHandler)
}

@available(iOS 10.0, *)
func userNotificationCenter(center: UNUserNotificationCenter, willPresentNotification notification: UNNotification, withCompletionHandler completionHandler: (UNNotificationPresentationOptions) -> Void) {

    Bit6.pushNotification().userNotificationCenter(center, willPresentNotification:notification, withCompletionHandler:completionHandler)

    let userInfo = notification.request.content.userInfo

    //for incoming calls we don't show the system banner. We show a custom banner in [AppDelegate incomingCallNotification:]
    if Bit6PushNotificationCenter.isIncomingCallNotification(userInfo) {
        completionHandler([])
    }
    else {
        let address = Bit6PushNotificationCenter.addressForMessageNotification(userInfo)

        //the user is not inside the conversation, we show the banner with sound
        if Bit6.currentConversation()?.address != address {
            completionHandler([.Sound,.Alert])
        }
        else {
            completionHandler([])
        }
    }
}

Authentication

Each user in the system has one or more identities - user id, username, email, facebook id, google account, phone number etc. Identities are required for user authentication, managing contacts, identifying user's network. An identity is represented by a URI.

Check if the user is authenticated:

BOOL authenticated = [Bit6 session].authenticated;
let authenticated = Bit6.session().authenticated

Logout:

[[Bit6 session] logoutWithCompletionHandler:^(NSDictionary *response, NSError *error) {
    if (!error) {
        //success
    }
}];
Bit6.session().logoutWithCompletionHandler({(response,error) in
    if error == nil {
        //success
    }
})

Listening to Login and Logout Notifications:

[[NSNotificationCenter defaultCenter] addObserver:self
                     selector:@selector(loginCompletedNotification:)
                                             name:Bit6LoginCompletedNotification
                                           object:nil];

[[NSNotificationCenter defaultCenter] addObserver:self
                     selector:@selector(logoutCompletedNotification:)
                                             Bit6LogoutCompletedNotification
                                           object:nil];

- (void)loginCompletedNotification:(NSNotification*)notification
{

}

- (void)logoutCompletedNotification:(NSNotification*)notification
{
    if ([notification.userInfo[Bit6ErrorKey] intValue] == NSURLErrorUserCancelledAuthentication) {
       //the session was terminated because password change or JWT expiration
    }
}
NSNotificationCenter.defaultCenter().addObserver(self,
                    selector: "loginCompletedNotification:",
                      name: Bit6LoginCompletedNotification,
                      object: nil)

NSNotificationCenter.defaultCenter().addObserver(self,
                    selector: "logoutStartedNotification:",
                      name: Bit6LogoutStartedNotification,
                      object: nil)

func loginCompletedNotification(notification:NSNotification)
{

}

func logoutStartedNotification(notification:NSNotification)
{
    if let error = notification.userInfo?[Bit6ErrorKey] as? NSNumber {
        if error.integerValue == NSURLErrorUserCancelledAuthentication {
            //the session was terminated because password change or JWT expiration
        }
    }
}

Managed

Username

An username is case-insensitive and must consist of alphanumeric characters, e.g. usr:john or usr:test123.

Create a new user account with a username identity and a password:

Bit6Address *address = [Bit6Address addressWithUsername:@"john"];

[[Bit6 session] signUpWithUserIdentity:address
                              password:@"secret"
                     completionHandler:^(NSDictionary *response, NSError *error) {
    if (!error) {
        //success
    }
}];
let address = Bit6Address(username:"john")

Bit6.session().signUpWithUserIdentity(address,
                             password:"secret") { (response,error) in
    if error == nil
        //success
    }
}

Login into an existing account using an Identity and a password:

Bit6Address *address = [Bit6Address addressWithUsername:@"john"];

[[Bit6 session] loginWithUserIdentity:address
                             password:@"secret"
                    completionHandler:^(NSDictionary *response, NSError *error) {
    if (!error) {
        //success
    }
}];
let address = Bit6Address(username:"john")

Bit6.session().loginWithUserIdentity(address,
                            password:@"secret"){ (response,error) in
    if error == nil {
        //success
    }
}

Third-Party

Bit6 integrates with various OAuth1 and OAuth2 providers for simplified user authentication. Check the sample apps for details. As an example, we will describe Facebook authentication process.

Sign in with Facebook

In this example we use Facebook Login.

[[Bit6 session] getAuthInfoCompletionHandler:^(NSDictionary *response, NSError *error) {
    if (response[@"facebook"][@"client_id"]){
        FBSDKLoginManager *login = [[FBSDKLoginManager alloc] init];
        [login logInWithReadPermissions:@[@"public_profile",@"email",@"user_friends"] fromViewController:self.view.window.rootViewController handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
            if (error || result.isCancelled) {
              //error
            }
            else {
                [Bit6.session oauthForProvider:@"facebook" params:@{@"client_id":response[@"facebook"][@"client_id"], @"access_token":[FBSDKAccessToken currentAccessToken].tokenString} completion:^(NSDictionary *response, NSError *error) {
                    if (!error) {
                        //success
                    }
                }];
            }
        }];
    }
}];
Bit6.session().getAuthInfoCompletionHandler{ (response, error) in
    if let facebook = response["facebook"] as? NSDictionary {
      let client_id = facebook["client_id"] as! NSString
    let login = FBSDKLoginManager()
        login.logInWithReadPermissions(["public_profile","email","user_friends"], fromViewController:self.view.window!.rootViewController) { (result, error) in
            if error != nil || result.isCancelled {
                //error
            }
            else {
              Bit6.session().oauthForProvider("facebook", params:["client_id":client_id, "access_token":FBSDKAccessToken.currentAccessToken().tokenString]){ (response, error) in
                    if error == nil {
                        //success
                    }
                }
            }
        }
    }
}

To get a Bit6Address object you can do the following:

Bit6Address *address = [Bit6Address addressWithFacebookId:friendId];
let address = Bit6Address(facebookId:friendId)

Delegated

You can start a session using external authentication using your own app server or a backend-as-a-service provider.

[Bit6.session authWithExternalToken:token completionHandler:^(NSDictionary *response, NSError *error) {
    if (!error) {
        //success
    }
}];
Bit6.session().authWithExternalToken(token){ (response, error) in
    if error == nil {
        //success
    }
}