This new version comes with general improvements, comes with APIs that have been simplified to let the SDK integration be easier for third part apps.
The new version of the SDK brings a lot of new features and simplifies the integration flow by a huge margin.
UI fully re-written in compose
For more details you can view the open-sourced code of this repo
The APIs will no longer be made with Java-flavored. They will be fully developed in Kotlin and for it only.
| N.B. The SDK will continue to work with Java projects, it just will not be beautiful when used in java.
Configure the KaleyraVideo (previously BandyerSDK)
The SDK configuration has been changed and must be now implemented using the new API on the BandyerSDK singleton that follows:
v4
v3
val configuration = Configuration (
" mAppId_xxx" ,
Environment .Sandbox ,
Region .Europe , // or Region.India or Region.US
// httpStack,
// logger
)
KaleyraVideo .configure(configuration)
val configuration = BandyerSDKConfiguration .Builder (
" mAppId" ,
Environment .Sandbox ,
Region .Eu )
// .httpStack(okHttpClient)
// .logger(logger)
.build()
BandyerSDK .getInstance().configure(configuration)
v4
v3
KaleyraVideo .connect(" userA" , { expiresAt ->
Result .success(" fetchedTokenFromYourServer" ) // or Result.fail()
}) // returns a Deferred<User>
val session = Session (" userA" ,object : AccessTokenProvider {
override fun provideAccessToken (userId : String , completion : Completion <String >) {
completion.success(" fetchedTokenFromYourServer" ) // completion.fail()
}
})
BandyerSDK .getInstance().connect(session)
v4
v3
KaleyraVideo .connect(" https://" ) // returns a Deferred<User>
var callIntent = BandyerIntent .Builder ().startFromJoinCallUrl(currentActivity," https://...." ).build()
startActivity(callIntent)
v4
v3
KaleyraVideo .disconnect(clearSavedData = false )
BandyerSDK .getInstance().disconnect(clearSavedData = true ) // or BandyerSDK.getInstance().disconnect()
v4
v3
BandyerSDK .getInstance().reset()
Handle push notifications
You no longer need to give any payload to the KaleyraVideo.
You are only required to configure & connect the KaleyraVideo.
Please follow the client side requirements as specified here .
N.B. After the connect the KaleyraVideo will auto sync with the incoming calls and chat messages
v4
v3
KaleyraVideo .conference.call(listOf (" userB" )) { // vararg
callType = Call .Type .AudioOnly // Call.Type.AudioUpgradable, Call.Type.AudioVideo
// recordingType = Call.Recording.Type.Manual // Call.Recording.Type.Automatic
// maxDuration = 60L // in seconds >= 60
}: Result <Call >
var callIntent = BandyerIntent .Builder ().startWithAudioCall(activity) // startWithAudioUpgradableCall, startWithAudioVideoCall
.with (arrayListOf (" userB" ))
.build()
startActivity(callIntent)
// call.id
// call.creationDate
// call.state
// call.type
// call.participants
// call.time.maxDuration, call.time.elapsed, call.time.remaining
// call.inputs
// call.effects
// call.recording.state, call.recording.type
// call.whiteboard
// call.sharedFolder
v4
v3
KaleyraVideo .conference.joinUrl(" https://...." ) : Result <Call >
var callIntent = BandyerIntent .Builder ().startFromJoinCallUrl(currentActivity," https://...." ).build()
startActivity(callIntent)
v4
v3
// this will create the unique chat between logged user and "userB"
KaleyraVideo .conversation.chat(currentActivity, userId = " userB" ) : Result <Chat >
// this will create the unique chat between logged user, "userB" and "userC"
KaleyraVideo .conversation.chat(currentActivity, userIds = listOf (" userB" , " userC" )): Result <ChatUI >
// this will always create a new group chat between logged user, "userB" and "userC" with the
// group chat friendly name set as "soccer team!"
KaleyraVideo .conversation.chat(currentActivity, userIds = listOf (" userB" , " userC" ), friendlyName = " soccer team!" ): Result <ChatUI >
var chatIntent = BandyerIntent .Builder ().startWithChat(currentActivity).with (" userB" ).build()
startActivity(chatIntent)
SDK actions definition has been strongly simplified
v4
v3
KaleyraVideo .conference.call.onEach { ongoingCall ->
ongoingCall.buttonsProvider { defaultButtons ->
defaultButtons + CallUI .Buttons .FileShare
}
}.launchIn(MainScope ())
val callOptions: CallOptions = CallOptions ()
.withRecordingEnabled(AUTOMATIC )
.withBackCameraAsDefault()
.withProximitySensorDisabled()
.withFeedbackEnabled()
val callCapabilitySet = CustomCapabilitySet (
CustomChatConfiguration (),
CustomFileShareConfiguration (),
CustomScreenShareConfiguration (),
CustomWhiteboardConfiguration ()
)
val customCallConfiguration = CustomCallConfiguration (callCapabilitySet, callOptions)
BandyerSDK .getInstance().configure(
BandyerSDKConfiguration .Builder (" mAppId" , Environment .Sandbox , Region .Eu ).tools {
withCall {
callConfiguration = customCallConfiguration
}
}.build()
)
v4
v3
KaleyraVideo .conversation.chats.onEach { chats ->
chats.forEach {
it.buttonsProvider = { defaultButtons ->
defaultButtons + ChatUI .Button .Call (Call .Type .audioVideo())
}
}
}.launchIn(MainScope ())
val callOptions = CallOptions ()
.withRecordingEnabled(CallRecordingType .AUTOMATIC )
.withBackCameraAsDefault()
.withProximitySensorDisabled()
.withFeedbackEnabled();
val callConfiguration = CustomChatConfiguration .CustomCapabilitySet .CustomCallConfiguration (
CustomChatConfiguration .CustomCapabilitySet .CustomCallConfiguration .CustomCapabilitySet (
CustomFileShareConfiguration (),
CustomScreenShareConfiguration (),
CustomWhiteboardConfiguration ()
),
callOptions
);
val customChatConfiguration = CustomChatConfiguration (
CustomChatConfiguration .CustomCapabilitySet (
audioUpgradableCallConfiguration = callConfiguration,
audioVideoCallConfiguration = callConfiguration
)
)
BandyerSDK .getInstance().configure(
BandyerSDKConfiguration .Builder (" mAppId" , Environment .Sandbox , Region .Eu ).tools {
withChat {
chatConfiguration = customChatConfiguration
}
}.build()
)
CallObserver, CallUIObserver & CallEventBroadcastReceiver have been removed and replaced by state flow property
v4
v3
call.state.onEach { println (" callState=$it " ) }.launchIn(MainScope ())
val callObserver = object : CallObserver {
override fun onCallCreated (call : Call ) = println (" onCallCreated" )
override fun onCallStarted (call : Call ) = println (" onCallStarted" )
override fun onCallEnded (call : Call ) = println (" onCallEnded" )
override fun onCallEndedWithError (call : Call , exception : CallException ) = println (" onCallEndedWithError" )
}
BandyerSDK .getInstance().callModule?.addCallObserver(callObserver)
CallRecordingObserver has been removed and replaced by extras.recording.state flow property
v4
v3
call.recording
.flatMapLatest { it.state }
.onEach { println (" recordingState=$it " ) }
.launchIn(MainScope ())
val callRecordingObserver = object : CallRecordingObserver {
override fun onCallRecordingStateChanged (call : Call , callRecordingState : CallRecordingState ) = println (" onCallRecordingStateChanged" )
override fun onCallRecordingFailed (call : Call , reason : String ) = println (" onCallRecordingFailed" )
}
call.addCallRecordingObserver(callRecordingObserver)
ChatObserver & ChatEventBroadcastReceiver have been removed. You can now know the state of the chat by using the state flow property
v4
v3
chat.state.onEach { println (" chatState=$it " ) }.launchIn(MainScope ())
val chatObserver = object : ChatObserver {}
BandyerSDK .getInstance().chatModule?.addChatObserver(chatObserver)
v4
v3
// for the call
BandyerSDK .conference.state.onEach { println (" conferenceState=$it " ) }.launchIn(MainScope ())
// for the chat
BandyerSDK .conversation.state.onEach { println (" conversationState=$it " ) }.launchIn(MainScope ())
val moduleObserver = object : BandyerModuleObserver {
override fun onModuleReady (module : BandyerModule ) = println (" onModuleReady" )
override fun onModulePaused (module : BandyerModule ) = println (" onModulePaused" )
override fun onModuleFailed (module : BandyerModule , throwable : Throwable ) = println (" onModuleFailed" )
override fun onModuleStatusChanged (module : BandyerModule , moduleStatus : BandyerModuleStatus ) = println (" onModuleStatusChanged" )
}
BandyerSDK .getInstance().addModuleObserver(moduleObserver)
Have been removed as they are not needed.
Extras
call.withFeedback = true // or false
call.disableProximity = true // or false
BackCamera/RearCamera as Default
KaleyraVideo .conference.call.onEach {
it.inputs.useBackCamera()
}.launchIn(MainScope ())
User Identity Verification Has been removed
Please add and implement abstract class KaleyraVideoInitializer in order to handle edge cases when the connection token expires and the application has been killed from the user or from the system.
Add the following metadata to the AndroidManifest.xml inside the application tag. The metadata is needed in order to instantiate your KaleyraVideoInitializer class from within the SDK.
<!-- app manifest -->
<application >
[...]
<meta-data
android:name=" kaleyra_video_initializer"
android:value=" com.example.app.AppKaleyraVideoInitializer" /> <!-- path to your KaleyraVideInitializer implementation -->
</application >
Implement the App Initializer as follows:
package com.example.app
// KaleyraVideoInitializer implementation
class AppAppKaleyraVideoInitializer : KaleyraVideoInitializer () {
override fun onRequestKaleyraVideoConfigure () {
if (KaleyraVideo .isConfigured) return
val configuration = Configuration (
" appId" ,
Environment .Production ,
Region .Europe
)
KaleyraVideo .configure(configuration)
}
override fun onRequestKaleyraVideoConnect () {
KaleyraVideo .connect(" userId" ) { requestToken(" userId" ) }
}
}
Client UserDetailsProvider
KaleyraVideo .userDetailsProvider = { userIds: List <String > ->
Result .success(userIds.map { UserDetails (it," Alice" , Uri .EMPTY ) })
}
Server Theme customization
Since every client had to provide a Theme implementation in order to customize the client call and chat UIs, has now been integrated a new convenient and centralized way to achieve the same result.
Client Theme customization
val brandColorSeed = ColorResource (Color (0xFF2A638A ).toArgb())
val brandLogoUri = getYourBrandLogoUri()
KaleyraVideo .theme = Theme (
logo = Theme .Logo (URIResource (brandLogoUri, brandLogoUri)),
palette = Theme .Palette (seed = brandColorSeed),
typography = Theme .Typography (fontFamily = KaleyraFontFamily .default),
config = Theme .Config (style = Theme .Config .Style .System ) // or force light mode with Theme.Config.Style.Light and dark with Theme.Config.Style.Dark
)