Customizing user information 1.x - Bandyer/Bandyer-iOS-SDK GitHub Wiki

This guide will discuss how you can customize the appeareance of the BandyerSDK Call and Chat user interface changing the user information shown to the end user while taking a call or messaging through the BandyerSDK.

Table of contents

User alias

Bandyer SDKs are designed to work with the bare minimum information about a user, this means that user contact information like first name, last name, email and so on, are not available in the SDK. We refer to a user in the Bandyer platform through hers/his "user alias", which is an alphanumeric string unique within a company (you can think of it as a slug). This approach has the advantage that we don't store any user information on our back-end, nor we send user's information over the network, but it has one drawback, whenever the end user has to be presented with contact information about another user, the only information when can show her/him is an "user alias".

custom-user-info-1

As you can see from the image above, when the call user interface is presented to the user, the BandyerSDK will show the user alias of the user by default, because it doesn't have any other information to show about the user being called. In order for the SDK to show some other user information it must be given those information and it must be told how to present them.

Fetching user information

The BandyerSDK provides a protocol named BDKUserInfoFetcher which serve the purpose of "fetching" the user information to be displayed when the call or the chat user interface is displayed to the end-user. In order for the BandyerSDK to use it, you must conform one of your class to the BDKUserInfoFetcher protocol and provide an instance of that class to the BandyerSDK before initializing it or to the call (or chat) view controller configuration object before presenting it. The following snippet of code shows how the BDKUserInfoFetcher protocol can be implemented:

#import <Bandyer/Bandyer.h>

#import "UserInfoFetcher.h"
#import "Contact.h"
#import "AddressBook.h"

@implementation UserInfoFetcher

- (instancetype)initWithAddressBook:(AddressBook *)addressBook
{
    self = [super init];

    if (self)
    {
        _addressBook = addressBook;
    }

    return self;
}

- (void)fetchUsers:(NSArray<NSString *> *)aliases completion:(void (^)(NSArray<BDKUserInfoDisplayItem *> *_Nullable items))completion
{
    NSDictionary<NSString *, Contact *> *contactsByAlias = [self.addressBook contactsByAlias];
    NSMutableArray<BDKUserInfoDisplayItem *> *items = [NSMutableArray arrayWithCapacity:aliases.count];

    for (NSString *alias in aliases)
    {
        Contact *contact = contactsByAlias[alias];
        BDKUserInfoDisplayItem *item = [[BDKUserInfoDisplayItem alloc] initWithAlias:alias];
        item.firstName = contact.firstName;
        item.lastName = contact.lastName;
        item.email = contact.email;
        item.imageURL = contact.profileImageURL;
        [items addObject:item];
    }

    completion(items);
}

- (id)copyWithZone:(nullable NSZone *)zone
{
    UserInfoFetcher *copy = (UserInfoFetcher *) [[[self class] allocWithZone:zone] init];

    if (copy != nil)
    {
        copy->_addressBook = [_addressBook copyWithZone:zone];
    }

    return copy;
}

@end
import Foundation
import Bandyer

class UserInfoFetcher: NSObject, BDKUserInfoFetcher {
    private let addressBook: AddressBook
    
    init(_ addressBook: AddressBook) {
        self.addressBook = addressBook
    }

    func fetchUsers(_ aliases: [String], completion: @escaping ([BDKUserInfoDisplayItem]?) -> Void) {
        let contactsByAlias = addressBook.contactsByAlias()
        var items:[BDKUserInfoDisplayItem] = []

        for alias in aliases {
            let contact = contactsByAlias[alias]
            let item = BDKUserInfoDisplayItem(alias: alias)
            item.firstName = contact?.firstName
            item.lastName = contact?.lastName
            item.email = contact?.email
            item.imageURL = contact?.profileImageURL

            items.append(item)
        }

        completion(items)
    }

    func copy(with zone: NSZone?) -> Any {
        return UserInfoFetcher(addressBook)
    }
}

In the above snippet of code, we are pretending there's a class in our app named "AddressBook" which contains "Contact" information for any user. The class UserInfoFetcher conforms to the SDK protocol and creates an array of BDKUserInfoDisplayItem getting the information from the "AddressBook" and then calls the completion block to signal the BandyerSDK it finished gathering the user information the SDK requested. In order for the BandyerSDK to use an instance of the "UserInfoFetcher" class we created, we must provide it to the BandyerSDK either while configuring the SDK (see BDKConfig), or when configuring the call or the chat view controllers (see BDKCallViewControllerConfiguration for the call view controller, or ChannelViewControllerConfiguration for the chat view controller). Passing an instance to the BDKConfig object, sets up the BandyerSDK to use the instance provided globally for any call or chat that will be presented. Whereas, passing an instance to the BDKCallViewControllerConfiguration object or to the ChannelViewControllerConfiguration object will affect the presented view controller only.

Below, we are going to show you how to provide the "UserInfoFetcher" instance to the call view controller, but doing it when presenting the chat view controller and the in-app message notification view is analogous.

- (void)startOutgoingCall:(NSArray<NSString *>*)callee
{
    BDKCallViewControllerConfiguration *config = [BDKCallViewControllerConfiguration new];

    NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"SIMULATOR MP4 VIDEO" ofType:@"mp4"]];
    config.fakeCapturerFileURL = url;
    
    //Here we are setting a user info fetcher instance to be used by the call view controller
    config.userInfoFetcher = [[UserInfoFetcher alloc] initWithAddressBook:self.addressBook];
    
    //Then present the call view controller
    ...
}
func startOutgoingCall(callee: [String]) {
    let config = CallViewControllerConfiguration()
    let filePath = Bundle.main.path(forResource: "SampleVideo_640x360_10mb", ofType: "mp4")
    guard let path = filePath else { fatalError("The fake file for the file capturer could not be found") }

    config.fakeCapturerFileURL = URL(fileURLWithPath:path)

    //Here we are setting a user info fetcher instance to be used by the call view controller
    config.userInfoFetcher = UserInfoFetcher(addressBook)
    
    //Then present the call view controller
    ...
}

Eventually, the final result looks like this:

custom-user-info-2

CallKit contact handles

As you might have noticed, even if the BandyerSDK call interface is updated with the user information your BDKUserInfoDisplayItem provides, the native system UI is not. To update the system native call UI with your user information you must implement another protocol named BCXHandleProvider. If you are interested in updating the system native call UI head over to our CallKit guide and look for the Contact handles section.

What's next

⚠️ **GitHub.com Fallback** ⚠️