MigrationGuide from 1.4.0 to 1.5.0 - Bandyer/Bandyer-iOS-SDK GitHub Wiki

This guide will introduce you to the changes you should perform to your code base in order to support the BandyerSDK 1.5.0 version.

## Table of contents:

iCloud Entitlement

BandyerSDK 1.5.0 version introduces in call filesharing, this feature requires access to the user's photo library and files. Since we cannot check whether the app hosting our SDK has been signed with the correct entitlements, you are required to add iCloud entitlements to avoid runtime crashes if the user access her iCloud files from the system provided file picker. Please, take a look at our permissions guide it will guide you through adding iCloud entitlements to your app.

CallWindow

CallWindow shouldPresentCallViewController(intent:completion:) method has been deprecated in favor of a new method named presentCallViewController(for:completion:). The old method had a misleading name, moreover in case of a failure it did not report any error in the completion block provided by callers. The new method has a better name instead, it reveals its designated intent and provides an error in its completion block when a failure occurs.

The following snippets of code will show you how to update your current code to use the new API (The code listing below are an excerpt taken from the BandyerSDK sample apps written in Swift).

func performCallViewControllerPresentation() {
    prepareForCallViewControllerPresentation()

    callWindow?.shouldPresentCallViewController(intent: intent, completion: { [weak self] succeeded in
        if (!succeeded) {
            let alert = UIAlertController(title: "Warning", message: "Another call ongoing.", preferredStyle: .alert)
            let defaultAction = UIAlertAction(title: "Ok", style: .default) { (_) in
                alert.dismiss(animated: true)
            }
            alert.addAction(defaultAction)
            self?.present(alert, animated: true)
        }
    })
}

Becomes

func performCallViewControllerPresentation() {
    prepareForCallViewControllerPresentation()
    
    callWindow?.presentCallViewController(for: intent) { [weak self] error in
        guard let error = error else { return }
        guard let self = self else { return }
        
        switch error {
        case let presentationError as CallPresentationError where presentationError.errorCode == CallPresentationErrorCode.anotherCallOnGoing.rawValue:
            self.presentAlert(title: "Warning", message: "Another call ongoing.")
        default:
            self.presentAlert(title: "Error", message: "Impossible to start a call now. Try again later.")
        }
    }
}

The code listing below are an excerpt taken from the BandyerSDK sample apps written in Objective-c.

- (void)performCallViewControllerPresentation
{
    [self prepareForCallViewControllerPresentation];

    [self.callWindow shouldPresentCallViewControllerWithIntent:self.intent completion:^(BOOL succeeded) {

        if (!succeeded)
        {
            UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"Another call ongoing." preferredStyle:UIAlertControllerStyleAlert];

            UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
                        [alert dismissViewControllerAnimated:YES completion:nil];
                    }];

            [alert addAction:defaultAction];
            [self presentViewController:alert animated:YES completion:nil];
        }
    }];
}

Becomes

- (void)presentCallViewControllerForIntent:(id<BDKIntent>)intent
{
    [self prepareForCallViewControllerPresentation];

    [self.callWindow presentCallViewControllerFor:intent completion:^(NSError * error) {
        if ([error.domain isEqualToString:BDKCallPresentationErrorDomain.value] && error.code == BDKCallPresentationErrorCodeAnotherCallOnGoing)
        {
            [self presentAlertControllerWithTitle:@"Warning" message:@"Another call ongoing."];
        }
        else if (error)
        {
            [self presentAlertControllerWithTitle:@"Error" message:@"Impossible to start a call now. Try again later"];
        }
    }];
}

MessageNotificationController

MessageNotificationController and all its related types are deprecated in favor of a new In-app notification sub-system introduced in the BandyerSDK 1.5.0 version. The in-app notification sub-system is responsible for presenting the user in-app notifications on a dedicated UIWindow instance. MessageNotificationController has been replaced by InAppNotificationsCoordinator protocol you can get from the BandyerSDK singleton instance. Basically the InAppNotificationsCoordinator protocol is responsible for handling the interaction and the lifecycle of in-app notifications. You start it when you want to enable in-app notifications, and you stop it when you don't want in-app notifications to be shown to your users. When an in-app notification is touched the InAppNotificationsCoordinator delivers events to its listeners (namely InAppFileShareNotificationTouchListener InAppChatNotificationTouchListener) notifying them when a "file sharing" notification or a "chat notification" have been touched by the user.

You should change your code using the MessageNotificationController, to use the InAppNotificationsCoordinator instead. Beware, unlike the controller the coordinator is instantiated only once by the BandyerSDK. There's only one global instance running at time. The deprecated MessageNotificationController instances all calls the corresponding methods on the global InAppNotificationsCoordinator instance. The steps you should make in order to replace the MessageNotificationController and all the related deprecated types and methods are the following:

Let's pretend you have instantiated a MessageNotificationController in your app main view controller like we did in our ContactsViewController from the SDK sample apps (The code snippets below are an excerpt of the SDK samples, some details have been removed to keep the code listing shorter).

import UIKit
import Bandyer

class ContactsViewController: UIViewController {

    private let messageNotificationController = MessageNotificationController()
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let addressBook = AddressBook()
        let userInfoFetcher = UserInfoFetcher(addressBook!)

        let configuration = MessageNotificationControllerConfiguration(userInfoFetcher: userInfoFetcher)
        messageNotificationController.configuration = configuration

        messageNotificationController.delegate = self
        messageNotificationController.parentViewController = self
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        messageNotificationController.show()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        messageNotificationController.hide()
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {

        messageNotificationController.viewWillTransition(to: size, withTransitionCoordinator: coordinator)
        
        super.viewWillTransition(to: size, with: coordinator)
    }

    // MARK: Message Notification Controller delegate

    func messageNotificationController(_ controller: MessageNotificationController, didTouch notification: ChatNotification) {
        presentChat(from: notification)
    }
}

Objective-c code follows:

@interface ContactsViewController ()

@property (nonatomic, strong) BCHMessageNotificationController *messageNotificationController;

@end

@implementation ContactsViewController

- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self)
    {
        [self commonInit];
    }

    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self)
    {
        [self commonInit];
    }

    return self;
}

- (void)commonInit
{
    _messageNotificationController = [BCHMessageNotificationController new];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    AddressBook *addressBook = [AddressBook new];
    UserInfoFetcher* userInfoFetcher = [[UserInfoFetcher alloc] initWithAddressBook:addressBook];
    BCHMessageNotificationControllerConfiguration* configuration = [[BCHMessageNotificationControllerConfiguration alloc] initWithUserInfoFetcher:userInfoFetcher];
    self.messageNotificationController.configuration = configuration;

    self.messageNotificationController.delegate = self;
    self.messageNotificationController.parentViewController = self;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self.messageNotificationController show];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [self.messageNotificationController hide];
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
{
    [self.messageNotificationController viewWillTransitionTo:size withTransitionCoordinator:coordinator];

    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}

#pragma mark - Message Notification Controller delegate

- (void)messageNotificationController:(BCHMessageNotificationController *)controller didTouch:(BCHChatNotification *)notification
{
    [self presentChatFrom:notification];
}

@end

After replacing all calls to deprecated methods the ContactsViewController will look like this:

import UIKit
import Bandyer

class ContactsViewController: UIViewController, InAppChatNotificationTouchListener, InAppFileShareNotificationTouchListener {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        BandyerSDK.instance().notificationsCoordinator?.chatListener = self
        BandyerSDK.instance().notificationsCoordinator?.fileShareListener = self
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        BandyerSDK.instance().notificationsCoordinator?.start()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        
        BandyerSDK.instance().notificationsCoordinator?.stop()
    }

    // MARK: In App file share notification touch listener delegate

    func onTouch(_ notification: ChatNotification) {
         if let callWindow = self.callWindow, !callWindow.isHidden {
             callWindow.isHidden = true
         }

         if presentedViewController is ChannelViewController {
             presentedViewController?.dismiss(animated: true) { [weak self] in
                 self?.presentChat(from: notification)
             }
         } else {
             presentChat(from: notification)
         }
     }

    // MARK: In App file share notification touch listener delegate

    func onTouch(_ notification: FileShareNotification) {
        callWindow?.presentCallViewController(for: OpenDownloadsIntent())
    }
}

Objective-c code follows:

@interface ContactsViewController () <BDKInAppChatNotificationTouchListener, BDKInAppFileShareNotificationTouchListener>

@end

@implementation ContactsViewController

- (instancetype)initWithNibName:(nullable NSString *)nibNameOrNil bundle:(nullable NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self)
    {
        [self commonInit];
    }

    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self)
    {
        [self commonInit];
    }

    return self;
}

- (void)commonInit
{
    //Setup does not longer contain any reference to MessageNotificationController anymore
    ...
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    BandyerSDK.instance.notificationsCoordinator.chatListener = self;
    BandyerSDK.instance.notificationsCoordinator.fileShareListener = self;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [BandyerSDK.instance.notificationsCoordinator start];
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [BandyerSDK.instance.notificationsCoordinator stop];
}

#pragma mark - In-app notifications touch listeners

- (void)didTouchFileShareNotification:(BDKFileShareNotification *)notification
{
    if (_callWindow)
    {
        [self.callWindow presentCallViewControllerFor:[BDKOpenDownloadsIntent new] completion:^(NSError *_Nullable error) {}];
    }
}

- (void)didTouchChatNotification:(BDKChatNotification * _Nonnull)notification
{
    if ([self.presentedViewController isKindOfClass:BCHChannelViewController.class])
    {
        [self.presentedViewController dismissViewControllerAnimated:YES completion:^{
            [self presentChatFrom:notification];
        }];
        return;
    }

    [self presentChatFrom:notification];
}

@end
⚠️ **GitHub.com Fallback** ⚠️