Call Kit
  • iOS : Swift
  • Android
  • Web
  • Flutter
  • React Native
  • Overview
  • Quick start
  • Custom prebuilt UI

Custom prebuilt UI

Last updated:2023-01-12 21:13

Call Kit (ZegoUIKitPrebuiltCall) provides a set of default behaviors and styles. If those don't fully meet your design or business needs, we allow you to flexibly customize the behavior and styles through configuration, as well as add components with custom business logic.

After getting started quickly, you'll know that when you create the ZegoUIKitPrebuiltCall, in addition to the required authentication parameter, there is also a ZegoUIKitPrebuiltCallConfig, which is used for custom configuration.

In this doc, we will describe these parameters in detail to help you do further customization.

Customize prebuilt UI components

Configure layouts

Call Kit (ZegoUIKitPrebuiltCall) currently supports picture-in-picture layout and gallery layout, each layout has its own configurations. To select and configure the layout you want, use the layout parameter in the ZegoUIKitPrebuiltCallConfig:

Picture-in-picture layout

The configurations supported by the picture-in-picture layout are:

  1. isSmallViewDraggable: Whether the position of the small view in the picture-in-picture layout can be changed by dragging. It’s allowed by default.
  2. switchLargeOrSmallViewByClick: Whether to allow users to click on the small view for switching between large view and small view. It’s allowed by default.

The effect is as follows:

Display my view when my camera is off Hide my view when my camera is off Dragging Switching

Here is the reference code:

Basic call With call invitation
class ViewController: UIViewController {

    let selfUserID: String = "userID"
    let selfUserName: String = "userName"
    let yourAppID: UInt32 = YourAppID 
    let yourAppSign: String = YourAppSign
    let callID: String = "testCallID"

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @IBAction func makeNewCall(_ sender: Any) {

        // Modify your custom configurations here.
        let config: ZegoUIKitPrebuiltCallConfig = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()

        let layout: ZegoLayout = ZegoLayout()
        layout.mode = .pictureInPicture
        let pipConfig: ZegoLayoutPictureInPictureConfig = ZegoLayoutPictureInPictureConfig()
        pipConfig.isSmallViewDraggable = true;
        pipConfig.switchLargeOrSmallViewByClick = true;
        layout.config = pipConfig
        config.layout = layout

        let callVC = ZegoUIKitPrebuiltCallVC.init(yourAppID, appSign: yourAppSign, userID: selfUserID, userName: selfUserName ?? "", callID: callID, config: config)
        callVC.modalPresentationStyle = .fullScreen
        self.present(callVC, animated: true, completion: nil)
    }
}
class CallInvitationVC: UIViewController {
    let appID: UInt32 = yourAppID
    let appSign: String = "yourAppSign"
    let userID: String = "userID"
    let userName: String = "userName"
    let voiceCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.voiceCall.rawValue)
    let videoCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.videoCall.rawValue)

    override func viewDidLoad() {
        super.viewDidLoad()
        let config = ZegoUIKitPrebuiltCallInvitationConfig([ZegoUIKitSignalingPlugin()], notifyWhenAppRunningInBackgroundOrQuit: false, isSandboxEnvironment: false)
        ZegoUIKitPrebuiltCallInvitationService.shared.initWithAppID(self.appID, appSign: self.appSign, userID: self.userID, userName: self.userName, config: config)
        ZegoUIKitPrebuiltCallInvitationService.shared.delegate = self
    }
}

extension CallInvitationVC: ZegoUIKitPrebuiltCallInvitationServiceDelegate {
    //MARK: -ZegoUIKitPrebuiltCallInvitationServiceDelegate
    func requireConfig(_ data: ZegoCallInvitationData) -> ZegoUIKitPrebuiltCallConfig {
        var config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
        if data.type == .voiceCall {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVoiceCall()
            }
        } else {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVideoCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()
            }
        }
        // Modify your custom configurations here.
        let layout: ZegoLayout = ZegoLayout()
        if data.invitees?.count ?? 0 > 1 {
            layout.mode = .gallery
            let layoutConfig: ZegoLayoutGalleryConfig = ZegoLayoutGalleryConfig()
            layoutConfig.addBorderRadiusAndSpacingBetweenView = false;
            layout.config = layoutConfig
        } else {
            layout.mode = .pictureInPicture
            let pipConfig: ZegoLayoutPictureInPictureConfig = ZegoLayoutPictureInPictureConfig()
            pipConfig.isSmallViewDraggable = true;
            pipConfig.switchLargeOrSmallViewByClick = true;
            layout.config = pipConfig
        }
        config.layout = layout
        return config
    }
}

The configuration supported by the gallery layout is:

addBorderRadiusAndSpacingBetweenView: In gallery layout, this can be used to add border radius and spacing between speaker views. true: enabled (by default). false: disabled.

The effect is as follows:

Adding border radius and spacing Without border radius and spacing
Basic call Call with call invitation
class ViewController: UIViewController {

    let selfUserID: String = "userID"
    let selfUserName: String = "userName"
    let yourAppID: UInt32 = YourAppID
    let yourAppSign: String = YourAppSign
    let callID: String = "testCallID"

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @IBAction func makeNewCall(_ sender: Any) {

        // Modify your custom configurations here.
        let config: ZegoUIKitPrebuiltCallConfig = ZegoUIKitPrebuiltCallConfig.groupVideoCall()

        let layout: ZegoLayout = ZegoLayout()
        layout.mode = .gallery
        let layoutConfig: ZegoLayoutGalleryConfig = ZegoLayoutGalleryConfig()
        layoutConfig.addBorderRadiusAndSpacingBetweenView = false;
        layout.config = layoutConfig
        config.layout = layout

        let callVC = ZegoUIKitPrebuiltCallVC.init(yourAppID, appSign: yourAppSign, userID: selfUserID, userName: selfUserName ?? "", callID: callID, config: config)
        callVC.modalPresentationStyle = .fullScreen
        self.present(callVC, animated: true, completion: nil)
    }
}
class CallInvitationVC: UIViewController {
    let appID: UInt32 = yourAppID
    let appSign: String = "yourAppSign"
    let userID: String = "userID"
    let userName: String = "userName"
    let voiceCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.voiceCall.rawValue)
    let videoCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.videoCall.rawValue)

    override func viewDidLoad() {
        super.viewDidLoad()
        let config = ZegoUIKitPrebuiltCallInvitationConfig([ZegoUIKitSignalingPlugin()], notifyWhenAppRunningInBackgroundOrQuit: false, isSandboxEnvironment: false)
        ZegoUIKitPrebuiltCallInvitationService.shared.initWithAppID(self.appID, appSign: self.appSign, userID: self.userID, userName: self.userName, config: config)
        ZegoUIKitPrebuiltCallInvitationService.shared.delegate = self
    }
}

extension CallInvitationVC: ZegoUIKitPrebuiltCallInvitationServiceDelegate {
    //MARK: -ZegoUIKitPrebuiltCallInvitationServiceDelegate
    func requireConfig(_ data: ZegoCallInvitationData) -> ZegoUIKitPrebuiltCallConfig {
        var config = ZegoUIKitPrebuiltCallConfig(.groupVoiceCall)
        if data.type == .voiceCall {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVoiceCall()
            }
        } else {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVideoCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()
            }
        }
        // Modify your custom configurations here.
        let layout: ZegoLayout = ZegoLayout()
        if data.invitees?.count ?? 0 > 1 {
            layout.mode = .gallery
            let layoutConfig: ZegoLayoutGalleryConfig = ZegoLayoutGalleryConfig()
            layoutConfig.addBorderRadiusAndSpacingBetweenView = false;
            layout.config = layoutConfig
        } else {
            layout.mode = .pictureInPicture
            let pipConfig: ZegoLayoutPictureInPictureConfig = ZegoLayoutPictureInPictureConfig()
            pipConfig.isSmallViewDraggable = true;
            pipConfig.switchLargeOrSmallViewByClick = true;
            layout.config = pipConfig
        }
        config.layout = layout
        return config
    }
}

Hide the prebuilt components

By default, the Call Kit (ZegoUIKitPrebuiltCall) displays UserNameLabel, MicrophoneStateIcon, and CameraStateIcon floating above the view. If these components are not needed, you can hide them using the following three configurations in audioVideoViewConfig.

Config Effects
1. showMicrophoneStateOnView: whether to display the microphone state on the view. Displayed by default.
2. showCameraStateOnView: Whether to display the camera state on the view. Displayed by default.
3. showUserNameOnView: Indicates whether to display the username on the view. Displayed by default.
/Pics/ZegoUIKit/Flutter/_normal_switch_30_label.png

Hide sound waves

As shown in the rendering, the Call Kit (ZegoUIKitPrebuiltCall) displays the user's avatar and sound waves when the camera is turned off. If you are not satisfied with the user avatars and sound wave style, you can hide them using the showSoundWavesInAudioMode configurations in audioVideoViewConfig.

  • audioVideoViewConfig: in audio mode, whether to display the sound waves around the user avatar in audio mode. Displayed by default.

Customize the initial device state

When starting a call, the Call Kit (ZegoUIKitPrebuiltCall) turns on the camera, and microphone, and uses the speaker as the audio output device by default.

To change this default configuration, for example, turn off the camera when you start a call, or don't use the speaker (If the speaker is not used, the system's default audio output device, such as ear speaker, headset, Bluetooth, etc., will be used.), you can modify the following configurations:

  1. turnOnCameraWhenJoining: Whether to turn on the camera when the call starts. true: turn on (by default). false: turn off.
  2. turnOnMicrophoneWhenJoining: Whether to turn on the microphone when the call starts. true: turn on (by default). false: turn off.
  3. useSpeakerWhenJoining: Whether to use the speaker when the call starts. true: use the speaker (by default). false: use the system's default audio output device, such as an ear speaker, headset, Bluetooth, etc.

Here is the reference code:

Basic call With call invitation
class ViewController: UIViewController {

    let selfUserID: String = "userID"
    let selfUserName: String = "userName"
    let yourAppID: UInt32 = YourAppID 
    let yourAppSign: String = YourAppSign
    let callID: String = "testCallID"

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @IBAction func makeNewCall(_ sender: Any) {

        // Modify your custom configurations here.
        let config: ZegoUIKitPrebuiltCallConfig = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()

        config.turnOnCameraWhenJoining = false;
        config.turnOnMicrophoneWhenJoining = false;
        config.useSpeakerWhenJoining = true;

        let callVC = ZegoUIKitPrebuiltCallVC.init(yourAppID, appSign: yourAppSign, userID: selfUserID, userName: selfUserName ?? "", callID: callID, config: config)
        callVC.modalPresentationStyle = .fullScreen
        self.present(callVC, animated: true, completion: nil)
    }
}
class CallInvitationVC: UIViewController {
    let appID: UInt32 = yourAppID
    let appSign: String = "yourAppSign"
    let userID: String = "userID"
    let userName: String = "userName"
    let voiceCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.voiceCall.rawValue)
    let videoCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.videoCall.rawValue)

    override func viewDidLoad() {
        super.viewDidLoad()
        let config = ZegoUIKitPrebuiltCallInvitationConfig([ZegoUIKitSignalingPlugin()], notifyWhenAppRunningInBackgroundOrQuit: false, isSandboxEnvironment: false)
        ZegoUIKitPrebuiltCallInvitationService.shared.initWithAppID(self.appID, appSign: self.appSign, userID: self.userID, userName: self.userName, config: config)
        ZegoUIKitPrebuiltCallInvitationService.shared.delegate = self
    }
}

extension CallInvitationVC: ZegoUIKitPrebuiltCallInvitationServiceDelegate {
    //MARK: -ZegoUIKitPrebuiltCallInvitationServiceDelegate
    func requireConfig(_ data: ZegoCallInvitationData) -> ZegoUIKitPrebuiltCallConfig {
        var config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
        if data.type == .voiceCall {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVoiceCall()
            }
        } else {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVideoCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()
            }
        }
        // Modify your custom configurations here.
        config.turnOnCameraWhenJoining = false;
        config.turnOnMicrophoneWhenJoining = false;
        config.useSpeakerWhenJoining = true;
        return config
    }
}

Customize the menu bar button list

Call Kit (ZegoUIKitPrebuiltCall) allows you to configure the buttons of the menu bar. To remove the default buttons or add custom ones to the bottom menu bar, you can configure the bottomMenuBarConfig:

(Similarly, to configure top menu bar buttons or add custom buttons to the top menu bar, use the topMenuBarConfig.)

  1. buttons: Built-in buttons placed in the menu bar. By default, all buttons are displayed. If you need to hide some buttons, use this to configure them.
  2. maxCount: Maximum number of buttons that can be displayed by the menu bar. Value range [1 - 5], the default value is 5.
  3. extendButtons: Use this configuration to add your own custom buttons to menu bar.

If the total number of built-in buttons and custom buttons does not exceed 5, all buttons will be displayed. Otherwise, other buttons that cannot be displayed will be hidden in the three dots (⋮) button. Clicking this button will pop up the bottom sheet to display the remaining buttons.

The effect will be like this:

/Pics/ZegoUIKit/Flutter/menuBarLimit.gif

Customize the hidden behavior of the menu bar

The Call Kit (ZegoUIKitPrebuiltCall) supports automatic or manual hiding of the menu bar. You can control this by using the following two configurations in the ZegoBottomMenuBarConfig:

  1. hideByClick: Whether the menu bar can be hidden by clicking on the unresponsive area, enabled by default.
  2. hideAutomatically: Whether the menu bar is automatically hidden after 5 seconds of user inactivity, enabled by default.

Set a hangup confirmation dialog

Call Kit (ZegoUIKitPrebuilt) ends a call by default when the user clicks the End Call button or the Android’s Back button.

If you want to add a confirmation dialog box to double confirm whether the user wants to hang up a call, you can use the hangUpConfirmInfo config: After configuring the hangUpConfirmInfo parameter, ZegoUIKitPrebuilt will pop up a confirmation dialog box with the default style before ending the call, showing the confirmation info you set.

The effect will be like this:

/Pics/ZegoUIKit/Flutter/hangup_confirm.gif

Here is the reference code:

Basic call With call invitation
class ViewController: UIViewController {

    let selfUserID: String = "userID"
    let selfUserName: String = "userName"
    let yourAppID: UInt32 = YourAppID 
    let yourAppSign: String = YourAppSign
    let callID: String = "testCallID"

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @IBAction func makeNewCall(_ sender: Any) {

        // Modify your custom configurations here.
        let config: ZegoUIKitPrebuiltCallConfig = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()

        let hangUpConfirmDialogInfo = ZegoLeaveConfirmDialogInfo()
        hangUpConfirmDialogInfo.title = "Hangup confirm"
        hangUpConfirmDialogInfo.message = "Do you want to hangup?"
        hangUpConfirmDialogInfo.cancelButtonName = "Cancel"
        hangUpConfirmDialogInfo.confirmButtonName = "Confirm"
        config.hangUpConfirmDialogInfo = hangUpConfirmDialogInfo

        let callVC = ZegoUIKitPrebuiltCallVC.init(yourAppID, appSign: yourAppSign, userID: selfUserID, userName: selfUserName ?? "", callID: callID, config: config)
        callVC.modalPresentationStyle = .fullScreen
        self.present(callVC, animated: true, completion: nil)
    }
}
class CallInvitationVC: UIViewController {
    let appID: UInt32 = yourAppID
    let appSign: String = "yourAppSign"
    let userID: String = "userID"
    let userName: String = "userName"
    let voiceCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.voiceCall.rawValue)
    let videoCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.videoCall.rawValue)

    override func viewDidLoad() {
        super.viewDidLoad()
        let config = ZegoUIKitPrebuiltCallInvitationConfig([ZegoUIKitSignalingPlugin()], notifyWhenAppRunningInBackgroundOrQuit: false, isSandboxEnvironment: false)
        ZegoUIKitPrebuiltCallInvitationService.shared.initWithAppID(self.appID, appSign: self.appSign, userID: self.userID, userName: self.userName, config: config)
        ZegoUIKitPrebuiltCallInvitationService.shared.delegate = self
    }
}

extension CallInvitationVC: ZegoUIKitPrebuiltCallInvitationServiceDelegate {
    //MARK: -ZegoUIKitPrebuiltCallInvitationServiceDelegate
    func requireConfig(_ data: ZegoCallInvitationData) -> ZegoUIKitPrebuiltCallConfig {
        var config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
        if data.type == .voiceCall {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVoiceCall()
            }
        } else {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVideoCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()
            }
        }
        // Modify your custom configurations here.
        let hangUpConfirmDialogInfo = ZegoLeaveConfirmDialogInfo()
        hangUpConfirmDialogInfo.title = "Hangup confirm"
        hangUpConfirmDialogInfo.message = "Do you want to hangup?"
        hangUpConfirmDialogInfo.cancelButtonName = "Cancel"
        hangUpConfirmDialogInfo.confirmButtonName = "Confirm"
        config.hangUpConfirmDialogInfo = hangUpConfirmDialogInfo
        return config
    }
}

If you want to listen for hang-up events, for example, to save the call recording when ending the call, ZegoUIKitPrebuiltCall provides a setOnHangUpListener method, and the HangUpListener will be triggered when the call ends. And sure, you can also implement custom business logic in the HangUpListener.

Customize the view in audio mode

If you need to customize the user's view in audio mode, for example, setting the background image, you can use largeViewBackgroundImage, smallViewBackgroundImage, largeViewBackgroundColor, smallViewBackgroundColor in ZegoLayoutPictureInPictureConfig.

These configurations are only valid when the user turns off the camera (because the video view will be displayed automatically when the camera is on).

Here is the reference code:

Basic call With call invitation
class ViewController: UIViewController {

    let selfUserID: String = "userID"
    let selfUserName: String = "userName"
    let yourAppID: UInt32 = YourAppID 
    let yourAppSign: String = YourAppSign
    let callID: String = "testCallID"

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @IBAction func makeNewCall(_ sender: Any) {

        // Modify your custom configurations here.
        let config: ZegoUIKitPrebuiltCallConfig = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()

        let layout: ZegoLayout = ZegoLayout()
        layout.mode = .pictureInPicture
        let pipConfig: ZegoLayoutPictureInPictureConfig = ZegoLayoutPictureInPictureConfig()
        pipConfig.largeViewBackgroundColor = UIColor.darkGray
        pipConfig.smallViewBackgroundColor = UIColor.lightGray
        layout.config = pipConfig
        config.layout = layout

        let callVC = ZegoUIKitPrebuiltCallVC.init(yourAppID, appSign: yourAppSign, userID: selfUserID, userName: selfUserName ?? "", callID: callID, config: config)
        callVC.modalPresentationStyle = .fullScreen
        self.present(callVC, animated: true, completion: nil)
    }
}
class CallInvitationVC: UIViewController {
    let appID: UInt32 = yourAppID
    let appSign: String = "yourAppSign"
    let userID: String = "userID"
    let userName: String = "userName"
    let voiceCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.voiceCall.rawValue)
    let videoCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.videoCall.rawValue)

    override func viewDidLoad() {
        super.viewDidLoad()
        let config = ZegoUIKitPrebuiltCallInvitationConfig([ZegoUIKitSignalingPlugin()], notifyWhenAppRunningInBackgroundOrQuit: false, isSandboxEnvironment: false)
        ZegoUIKitPrebuiltCallInvitationService.shared.initWithAppID(self.appID, appSign: self.appSign, userID: self.userID, userName: self.userName, config: config)
        ZegoUIKitPrebuiltCallInvitationService.shared.delegate = self
    }
}

extension CallInvitationVC: ZegoUIKitPrebuiltCallInvitationServiceDelegate {
    //MARK: -ZegoUIKitPrebuiltCallInvitationServiceDelegate
    func requireConfig(_ data: ZegoCallInvitationData) -> ZegoUIKitPrebuiltCallConfig {
        var config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
        if data.type == .voiceCall {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVoiceCall()
            }
        } else {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVideoCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()
            }
        }
        // Modify your custom configurations here.
        if data.invitees?.count ?? 0 <= 1 {
            let layout: ZegoLayout = ZegoLayout()
            layout.mode = .pictureInPicture
            let pipConfig: ZegoLayoutPictureInPictureConfig = ZegoLayoutPictureInPictureConfig()
            pipConfig.largeViewBackgroundColor = UIColor.darkGray
            pipConfig.smallViewBackgroundColor = UIColor.lightGray
            layout.config = pipConfig
            config.layout = layout
        }
        return config
    }
}

Customize the foreground view

If you want to add some custom components at the top level of the view, such as you want to display the user avatars when the video view is displayed, add user-level icons, etc., then you can use ZegoUIKitPrebuiltCallVCDelegate.getForegroundView protocol. The getForegroundView requires you (the developer) to return a custom view that will be placed at the top of the view.

Here is the reference code:

Basic call With call invitation
class ViewController: UIViewController {

    let selfUserID: String = "userID"
    let selfUserName: String = "userName"
    let yourAppID: UInt32 = YourAppID 
    let yourAppSign: String = YourAppSign
    let callID: String = "testCallID"

    override func viewDidLoad() {
        super.viewDidLoad()
    }
    @IBAction func makeNewCall(_ sender: Any) {

        // Modify your custom configurations here.
        let config: ZegoUIKitPrebuiltCallConfig = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()

        config.turnOnCameraWhenjoining = false;
        config.audioVideoViewConfig.showCameraStateOnView = false;
        config.bottomMenuBarConfig.buttons = [.toggleMicrophoneButton,.hangUpButton,.swtichAudioOutputButton]

        let callVC = ZegoUIKitPrebuiltCallVC.init(yourAppID, appSign: yourAppSign, userID: selfUserID, userName: selfUserName ?? "", callID: callID, config: config)

        callVC.delegate = self

        callVC.modalPresentationStyle = .fullScreen
        self.present(callVC, animated: true, completion: nil)
    }

    func getForegroundView(_ userInfo: ZegoUIKitUser?) -> UIView? {
        return YourCustomView()
    }
// Not supported yet

Call invitation config

Customize the call ringtone

Ringtone for call invitation

If you want to set the call ringtone for receiving incoming call invitations or sending outgoing call invitations, you can use the incomingCallRingtone and outgoingCallRingtone config in the ZegoUIKitPrebuiltCallInvitationService.

Here is the reference code:

Call with call invitation
class CallInvitationVC: UIViewController {
    let appID: UInt32 = yourAppID
    let appSign: String = "yourAppSign"
    let userID: String = "userID"
    let userName: String = "userName"
    let voiceCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.voiceCall.rawValue)
    let videoCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.videoCall.rawValue)

    override func viewDidLoad() {
        super.viewDidLoad()
        let config = ZegoUIKitPrebuiltCallInvitationConfig([ZegoUIKitSignalingPlugin()], notifyWhenAppRunningInBackgroundOrQuit: false, isSandboxEnvironment: false)
        config.incomingCallRingtone = NSBundle.mainBundle().pathForResource("incomingCallRingtone", ofType: "mp3")
        config.outgoingCallRingtone = NSBundle.mainBundle().pathForResource("outgoingCallRingtone", ofType: "mp3")
        ZegoUIKitPrebuiltCallInvitationService.shared.initWithAppID(self.appID, appSign: self.appSign, userID: self.userID, userName: self.userName, config: config)
        ZegoUIKitPrebuiltCallInvitationService.shared.delegate = self
    }
}

extension CallInvitationVC: ZegoUIKitPrebuiltCallInvitationServiceDelegate {
    //MARK: -ZegoUIKitPrebuiltCallInvitationServiceDelegate
    func requireConfig(_ data: ZegoCallInvitationData) -> ZegoUIKitPrebuiltCallConfig {
        var config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
        if data.type == .voiceCall {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVoiceCall()
            }
        } else {
            if data.invitees?.count ?? 0 > 1 {
                config = ZegoUIKitPrebuiltCallConfig.groupVideoCall()
            } else {
                config = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()
            }
        }
        return config
    }
}

Ringtone for offline call invitation

To specify a ringtone for offline call invitations:

  1. Follow the steps in Quick start to enable and complete the congirations.
  2. Go to ZEGOCLOUD Admin Console to configure a Push Resource ID.
  3. Replace the resourceID parameter in the ZegoSendCallInvitationButton method with the Push Resource ID you get.

After the completion, the ringtone corresponding to the ID you set will be played when others receive offline call invitations.

Here is the reference code:

With call invitation

let callTargetUser: ZegoUIkitUser = ZegoUIkitUser.init("TargetUserID", "TargetUserName")
let sendVideoCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.videoCall.rawValue)
sendVideoCallButton.inviteeList.append(callTargetUser)
sendVideoCallButton.resourceID = "zegouikit_call" // For offline call notification

Hide the decline button

To hide the Decline button when receiving incoming call invitations, set the showDeclineButton to false.

With call invitation
class CallInvitationVC: UIViewController {
    let appID: UInt32 = yourAppID
    let appSign: String = "yourAppSign"
    let userID: String = "userID"
    let userName: String = "userName"
    let voiceCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.voiceCall.rawValue)
    let videoCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.videoCall.rawValue)

    override func viewDidLoad() {
        super.viewDidLoad()
        let config = ZegoUIKitPrebuiltCallInvitationConfig([ZegoUIKitSignalingPlugin()], notifyWhenAppRunningInBackgroundOrQuit: true, isSandboxEnvironment: false)
        config.showDeclineButton = false
        ZegoUIKitPrebuiltCallInvitationService.shared.initWithAppID(self.appID, appSign: self.appSign, userID: self.userID, userName: self.userName, config: config)
        ZegoUIKitPrebuiltCallInvitationService.shared.delegate = self
    }
}

extension CallInvitationVC: ZegoUIKitPrebuiltCallInvitationServiceDelegate {
    //MARK: -ZegoUIKitPrebuiltCallInvitationServiceDelegate
 func requireConfig(_ data: ZegoCallInvitationData) -> ZegoUIKitPrebuiltCallConfig {

    if data.type == .voiceCall {
        if data.invitees?.count ?? 0 > 1 {
            let config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
            return config
        } else {
            let config = ZegoUIKitPrebuiltCallConfig.oneOnOneVoiceCall()
            return config
        }
    } else {
        if data.invitees?.count ?? 0 > 1 {
            let config = ZegoUIKitPrebuiltCallConfig.groupVideoCall()
            return config
        } else {
            let config = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()
            return config
        }
    }
  }
}

Modify User Interface text

Call Kit (ZegoUIKitPrebuiltCallWithInvitation)'s UI text provided by the internal components is editable, to modify those, use the innerText config.

Here is the reference code:

With call invitation
class CallInvitationVC: UIViewController {
    let appID: UInt32 = yourAppID
    let appSign: String = "yourAppSign"
    let userID: String = "userID"
    let userName: String = "userName"
    let voiceCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.voiceCall.rawValue)
    let videoCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.videoCall.rawValue)

    override func viewDidLoad() {
        super.viewDidLoad()
        let config = ZegoUIKitPrebuiltCallInvitationConfig([ZegoUIKitSignalingPlugin()], notifyWhenAppRunningInBackgroundOrQuit: true, isSandboxEnvironment: false)
        config.innerText.incomingCallPageAcceptButton = "Accept"
        config.innerText.incomingCallPageDeclineButton = "Decline"
        ZegoUIKitPrebuiltCallInvitationService.shared.initWithAppID(self.appID, appSign: self.appSign, userID: self.userID, userName: self.userName, config: config)
        ZegoUIKitPrebuiltCallInvitationService.shared.delegate = self
    }
}

extension CallInvitationVC: ZegoUIKitPrebuiltCallInvitationServiceDelegate {
    //MARK: -ZegoUIKitPrebuiltCallInvitationServiceDelegate
 func requireConfig(_ data: ZegoCallInvitationData) -> ZegoUIKitPrebuiltCallConfig {

    if data.type == .voiceCall {
        if data.invitees?.count ?? 0 > 1 {
            let config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
            return config
        } else {
            let config = ZegoUIKitPrebuiltCallConfig.oneOnOneVoiceCall()
            return config
        }
    } else {
        if data.invitees?.count ?? 0 > 1 {
            let config = ZegoUIKitPrebuiltCallConfig.groupVideoCall()
            return config
        } else {
            let config = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()
            return config
        }
    }
  }
}

Listen for call invitation event callbacks

You can implement further business logic by listening for event callbacks related to the call invitation.

The following are supported event callbacks:

  • func onIncomingCallDeclineButtonPressed(): This callback will be triggered when the Decline button is pressed (the callee declines the call invitation).

  • func onIncomingCallAcceptButtonPressed(): This callback will be triggered when the Accept button is pressed (the callee accepts the call invitation).

  • func onIncomingCallReceived(_ callID: String, caller: ZegoCallUser, callType: ZegoCallType, callees: [ZegoCallUser]?): This callback will be triggered when receiving call invitations.

  • func onIncomingCallCanceled(_ callID: String, caller: ZegoCallUser): This callback will be triggered when the caller cancels the call invitation.

  • func onIncomingCallTimeout(_ callID: String, caller: ZegoCallUser): The callee will receive a notification through this callback when the callee doesn't respond to the call invitation after a timeout duration.

  • func onOutgoingCallCancelButtonPressed(): This callback will be triggered when the Cancel button is pressed (the caller cancels the call invitation).

  • func onOutgoingCallAccepted(_ callID: String, callee: ZegoCallUser): The caller will receive a notification through this callback when the callee accepts the call invitation.

  • func onOutgoingCallRejectedCauseBusy(_ callID: String, callee: ZegoCallUser): The caller will receive a notification through this callback when the callee rejects the call invitation (the callee is busy).

  • func onOutgoingCallDeclined(_ callID: String, callee: ZegoCallUser): The caller will receive a notification through this callback when the callee declines the call invitation actively.

  • func onOutgoingCallTimeout(_ callID: String, callees: [ZegoCallUser]): The caller will receive a notification through this callback when the call invitation didn't get responses after a timeout duration.

Here is the reference code:

With call invitation
class CallInvitationVC: UIViewController {
    let appID: UInt32 = yourAppID
    let appSign: String = "yourAppSign"
    let userID: String = "userID"
    let userName: String = "userName"
    let voiceCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.voiceCall.rawValue)
    let videoCallButton: ZegoSendCallInvitationButton = ZegoSendCallInvitationButton(ZegoInvitationType.videoCall.rawValue)

    override func viewDidLoad() {
        super.viewDidLoad()
        let config = ZegoUIKitPrebuiltCallInvitationConfig([ZegoUIKitSignalingPlugin()], notifyWhenAppRunningInBackgroundOrQuit: true, isSandboxEnvironment: false)
        config.innerText.incomingCallPageAcceptButton = "Accept"
        config.innerText.incomingCallPageDeclineButton = "Decline"
        ZegoUIKitPrebuiltCallInvitationService.shared.initWithAppID(self.appID, appSign: self.appSign, userID: self.userID, userName: self.userName, config: config)
        ZegoUIKitPrebuiltCallInvitationService.shared.delegate = self
    }
}

extension CallInvitationVC: ZegoUIKitPrebuiltCallInvitationServiceDelegate {
    //MARK: -ZegoUIKitPrebuiltCallInvitationServiceDelegate
 func requireConfig(_ data: ZegoCallInvitationData) -> ZegoUIKitPrebuiltCallConfig {

    if data.type == .voiceCall {
        if data.invitees?.count ?? 0 > 1 {
            let config = ZegoUIKitPrebuiltCallConfig.groupVoiceCall()
            return config
        } else {
            let config = ZegoUIKitPrebuiltCallConfig.oneOnOneVoiceCall()
            return config
        }
    } else {
        if data.invitees?.count ?? 0 > 1 {
            let config = ZegoUIKitPrebuiltCallConfig.groupVideoCall()
            return config
        } else {
            let config = ZegoUIKitPrebuiltCallConfig.oneOnOneVideoCall()
            return config
        }
    }
  }

  func onIncomingCallDeclineButtonPressed() {

  }
  func onIncomingCallAcceptButtonPressed() {

  }
  func onOutgoingCallCancelButtonPressed() {

  }

  func onIncomingCallReceived(_ callID: String, caller: ZegoCallUser, callType: ZegoCallType, callees: [ZegoCallUser]?) {

  }
  func onIncomingCallCanceled(_ callID: String, caller: ZegoCallUser) {

  }
  func onOutgoingCallAccepted(_ callID: String, callee: ZegoCallUser) {

  }
  func onOutgoingCallRejectedCauseBusy(_ callID: String, callee: ZegoCallUser) {

  }
  func onOutgoingCallDeclined(_ callID: String, callee: ZegoCallUser) {

  }
  func onIncomingCallTimeout(_ callID: String,  caller: ZegoCallUser){

  }
  func onOutgoingCallTimeout(_ callID: String, callees: [ZegoCallUser]) {

  }
}