Active session controls
Cobrowse active session controls. You can fully customize the interface for a Cobrowse session, including how to end a session.
By default, the Cobrowse SDKs will show a minimal visual indicator to the end-user that a session is active. Our default UI provides an easy way for the end-user to end the session at any time.
You can fully customize the interface for a Cobrowse session, including how to end a session.
The SDK provides hooks for you to render your own interface:
CobrowseIO.showSessionControls = function() {
// your code, i.e. $('#cobrowse-control').show() or similar
}
CobrowseIO.hideSessionControls = function() {
// your code, i.e. $('#cobrowse-control').hide() or similar
}
When you override these functions, we will not show any default UI for the end-user to end their session. You can then display your own button or other UI to allow your end-user to end their session.
The SDK provides hooks via CobrowseIODelegate
for you to render your own interface:
Swift
func cobrowseShowSessionControls(_ session: CBIOSession) {
// You can render controls however you like here.
}
func cobrowseHideSessionControls(_ session: CBIOSession) {
// hide your session controls
}
Objective C
- (void)cobrowseShowSessionControls:(CBIOSession*) session {
// You can render controls however you like here.
}
- (void)cobrowseHideSessionControls:(CBIOSession*) session {
// hide your session controls
}
The SDK provides hooks via CobrowseIO.SessionControlsDelegate
for you to render your own interface:
@Override
public void showSessionControls(final Activity activity, final Session session) {
// show your own controls here
}
@Override
public void hideSessionControls(final Activity activity, final Session session) {
// hide your controls here
}
Our React Native SDK provides a component you can use to wrap your session control components. Our component will then handle showing and hiding your controls when required:
import { SessionControl } from 'cobrowse-sdk-react-native';
export default class App extends Component {
render() {
return (
<View>
<SessionControl>
<Text>This will only show when a session is active!</Text>
</SessionControl>
</View>
);
}
}
By default, the native session indicator will still be visible to the user (a red horizontal bar at the top of the application). If you wish to hide this you can set showSessionControls
to false:
CobrowseIO.showSessionControls = false;
Listen to these event emitters to override the default session indicator. These methods may be called several times as the session progresses through its lifecycle, so you may need to adjust your UI accordingly.
CobrowseIO.instance.showSessionControls.listen((session) {
// Show your session controls
});
CobrowseIO.instance.hideSessionControls.listen((session) {
// Hide your session controls
});
Xamarin.iOS / .NET iOS implementation
The SDK provides hooks via CobrowseIODelegate
for you to render your own interface:
public override void ShowSessionControls(Session session) {
// show session controls
}
public override void HideSessionControls(Session session) {
// hide session controls
}
Xamarin.Android / .NET Android implementation
You can fully customize the interface for a Cobrowse session. The SDK provides hooks via CobrowseIO.ISessionControlsDelegate
for you to render your own interface:
public void ShowSessionControls(Activity activity, Session session) {
// show session controls
}
public void HideSessionControls(Activity activity, Session session) {
// hide session controls
}
You may override the default session and active display indicator by handling CobrowseIO.Instance.SessionControlsUpdated
:
CobrowseIO.Instance.SessionControlsUpdated += OnSessionControlsUpdated;
Callback will be called when:
Session starts.
FrameInfo
will contian information about the display currently captured by the screenshare session.Active display is switched.
FrameInfo
will contain information about the display which is being switched to.Session ends.
FrameInfo
param will benull
. This means that session UI should be hidden.
Warning: Be aware that callback is called from non-UI thread.
Programmatically ending the current session
When implementing your own session controls, it's a good idea to provide the user with some UI to end the current Cobrowse session. You can call the following APIs from your UI to end the session:
if (CobrowseIO.currentSession)
await CobrowseIO.currentSession.end();
[CobrowseIO.instance.currentSession end:^(NSError * _Nullable err, CBIOSession * _Nullable session) {
// handle errors here
}];
if (CobrowseIO.instance().currentSession() != null ) {
CobrowseIO.instance().currentSession().end((err, session) -> {
// handle errors here
});
}
// Get a reference to the current session if you don't have one
const session = await CobrowseIO.currentSession();
// if there's an ongoing session, end it
if (session) await session.end()
// Get a reference to the current session if you don't have one
Session? session = await CobrowseIO.instance.currentSession();
// if there's an ongoing session, end it
if (session != null) {
await session.end()
}
CobrowseIO.Instance().CurrentSession?.End(null);
Example UIs
To illustrate how these APIs should be used we have put together some example code for customizing the active session indicators:
Here's a simple example that re-create the default UI, but with a blue button and some different text:
<script>
CobrowseIO.client().then(function() {
var button = document.createElement('div');
button.className = '__cbio_ignored';
button.textContent = 'End';
button.style.fontFamily = 'sans-serif';
button.style.padding = '10px 13px';
button.style.fontSize = '13px';
button.style.color = 'white';
button.style.boxShadow = '0px 2px 5px #33333344';
button.style.cursor = 'pointer';
button.style.borderRadius = '30px';
button.style.background = 'blue';
button.style.position = 'fixed';
button.style.zIndex = '2147483647';
button.style.bottom = '20px';
button.style.left = '50%';
button.style.transform = 'translateX(-50%)';
button.addEventListener('click', function() {
if (CobrowseIO.currentSession) CobrowseIO.currentSession.end();
});
CobrowseIO.showSessionControls = function() {
document.body.appendChild(button);
}
CobrowseIO.hideSessionControls = function() {
if (button.parentNode) button.parentNode.removeChild(button);
}
});
</script>
import CobrowseIO
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CobrowseIODelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
CobrowseIO.instance().delegate = self
// ... the rest of your app setup
return true
}
func cobrowseShowSessionControls(_ session: CBIOSession) {
// You can render controls however you like here.
// One option is to add our sample end session UI defined below.
if (indicatorInstance == nil) {
indicatorInstance = self.defaultSessionIndicator(container: UIApplication.shared.keyWindow!)
}
indicatorInstance?.isHidden = false
}
func cobrowseHideSessionControls(_ session: CBIOSession) {
indicatorInstance?.isHidden = true
}
// sample end session UIView, constructor, and tap gesture recognizer implementation
var indicatorInstance : UIView? = nil
func defaultSessionIndicator(container: UIView) -> UIView {
let indicator : UILabel = UILabel()
indicator.backgroundColor = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 0.7)
indicator.text = "End Session"
indicator.isUserInteractionEnabled = true
indicator.textAlignment = .center
indicator.font.withSize(UIFont.smallSystemFontSize)
indicator.textColor = .white
indicator.layer.cornerRadius = 10
indicator.clipsToBounds = true
indicator.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(indicator)
indicator.widthAnchor.constraint(equalToConstant: 200).isActive = true
indicator.heightAnchor.constraint(equalToConstant: 40).isActive = true
indicator.centerXAnchor.constraint(equalTo: container.centerXAnchor).isActive = true
indicator.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: -20).isActive = true
let tapRecognizer : UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(indicatorTapped(_:)))
tapRecognizer.numberOfTapsRequired = 1
indicator.addGestureRecognizer(tapRecognizer)
return indicator
}
@objc
func indicatorTapped(_ sender: UITapGestureRecognizer) {
CobrowseIO.instance().currentSession()?.end(nil)
}
}
import React from 'react';
import {StyleSheet, Text, Button} from 'react-native';
import {
Redacted,
SessionControl,
Unredacted,
useSession,
} from 'cobrowse-sdk-react-native';
import {SafeAreaView} from 'react-native';
CobrowseIO.showSessionControls = false;
function SessionIndicator() {
const session = useSession();
return (
<SessionControl>
<Unredacted style={styles.container}>
<SafeAreaView style={styles.contentWrapper}>
<Text style={styles.text}>Screen Sharing session is active</Text>
<Redacted>
<Button title="Stop" onPress={() => session?.end()} />
</Redacted>
</SafeAreaView>
</Unredacted>
</SessionControl>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'red',
width: '100%',
flexDirection: 'row',
justifyContent: 'space-between',
padding: 16,
},
contentWrapper: {
flex: 1,
alignItems: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
},
text: {fontSize: 16},
});
function App() {
return (
<>
<SessionControl/>
<Text>My App title</Text>
// the rest of your app
</>
)
}
Xamarin.iOS implementation
using Xamarin.CobrowseIO;
[Register("AppDelegate")]
public class AppDelegate : UIResponder, IUIApplicationDelegate
{
[Export("application:didFinishLaunchingWithOptions:")]
public bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
CobrowseIO.Instance.SetDelegate(new CustomCobrowseDelegate());
// ... the rest of your app setup
return true;
}
}
public class CustomCobrowseDelegate : CobrowseIODelegate
{
// Sample end session UIView, constructor, and tap gesture recognizer implementation
private UIView _indicatorInstance;
public override void ShowSessionControls(Session session)
{
// You can render controls however you like here.
// One option is to add our sample end session UI defined below.
if (_indicatorInstance == null)
{
_indicatorInstance = GetDefaultSessionIndicator(container: UIApplication.SharedApplication.KeyWindow);
}
_indicatorInstance.Hidden = false;
}
public override void HideSessionControls(Session session)
{
if (_indicatorInstance != null)
_indicatorInstance.Hidden = true;
}
private UIView GetDefaultSessionIndicator(UIView container)
{
var indicator = new UILabel();
indicator.BackgroundColor = new UIColor(red: 1.0f, green: 0.0f, blue: 0.0f, alpha: 0.7f);
indicator.Text = "End Session";
indicator.UserInteractionEnabled = true;
indicator.TextAlignment = UITextAlignment.Center;
indicator.Font.WithSize(UIFont.SmallSystemFontSize);
indicator.TextColor = UIColor.White;
indicator.Layer.CornerRadius = 10;
indicator.ClipsToBounds = true;
indicator.TranslatesAutoresizingMaskIntoConstraints = false;
container.AddSubview(indicator);
indicator.WidthAnchor.ConstraintEqualTo(200f).Active = true;
indicator.HeightAnchor.ConstraintEqualTo(40f).Active = true;
indicator.CenterXAnchor.ConstraintEqualTo(container.CenterXAnchor).Active = true;
indicator.BottomAnchor.ConstraintEqualTo(container.BottomAnchor, constant: -20f).Active = true;
var tapRecognizer = new UITapGestureRecognizer(() =>
{
CobrowseIO.Instance().CurrentSession?.End(null);
});
tapRecognizer.NumberOfTapsRequired = 1;
indicator.AddGestureRecognizer(tapRecognizer);
return indicator;
}
public override void SessionDidUpdate(Session session)
{
}
public override void SessionDidEnd(Session session)
{
}
}
Xamarin.Android implementation
You can fully customize the interface for a Cobrowse session. The SDK provides hooks via CobrowseIO.ISessionControlsDelegate
for you to render your own interface:
using Xamarin.CobrowseIO;
[Application]
public class MainApplication : Application, CobrowseIO.ISessionControlsDelegate
{
public override void OnCreate()
{
base.OnCreate();
CobrowseIO.Instance.SetDelegate(this);
// and the rest of cobrowse setup ...
}
public void ShowSessionControls(Activity activity, Session session)
{
// optionally show your own controls here
}
public void HideSessionControls(Activity activity, Session session)
{
// hide controls created by the method above here
}
//...
}
Xamarin.Forms implementation
Even though Cobrowse.io works with native views, there is nothing that would prevent you from using Xamarin.Forms.VisualElement
as a session indicator.
First, create an indicator view using Xamarin.Forms (CobrowseCustomView.xaml
):
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SampleApp.Forms.CobrowseCustomView"
HeightRequest="42"
WidthRequest="130">
<Button
BackgroundColor="Red"
TextColor="White"
Text="End Session"
CornerRadius="4"
Clicked="EndSessionButton_Clicked" />
</ContentView>
Then, in the iOS project:
using System;
using Foundation;
using UIKit;
using Xamarin.CobrowseIO;
using Xamarin.Forms.Platform.iOS;
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
CobrowseIO.Instance.SetDelegate(new CustomOverlayCobrowseDelegate());
}
}
public class CustomOverlayCobrowseDelegate : CobrowseDelegateImplementation
{
private UIView _indicatorInstance;
public override void ShowSessionControls(Session session)
{
if (_indicatorInstance == null)
{
_indicatorInstance = GetDefaultSessionIndicator(container: UIApplication.SharedApplication.KeyWindow);
}
_indicatorInstance.Hidden = false;
}
public override void HideSessionControls(Session session)
{
if (_indicatorInstance != null)
_indicatorInstance.Hidden = true;
}
private UIView GetDefaultSessionIndicator(UIView container)
{
var indicator = new CobrowseCustomView();
var renderer = Platform.CreateRenderer(indicator);
renderer.Element.Layout(new Xamarin.Forms.Rectangle(0, 0, indicator.WidthRequest, indicator.HeightRequest));
var nativeIndicator = renderer.NativeView;
nativeIndicator.TranslatesAutoresizingMaskIntoConstraints = false;
container.AddSubview(nativeIndicator);
nativeIndicator.WidthAnchor.ConstraintEqualTo((float)indicator.WidthRequest).Active = true;
nativeIndicator.HeightAnchor.ConstraintEqualTo((float)indicator.HeightRequest).Active = true;
nativeIndicator.CenterYAnchor.ConstraintEqualTo(container.CenterYAnchor).Active = true;
nativeIndicator.RightAnchor.ConstraintEqualTo(container.RightAnchor, constant: -20f).Active = true;
return nativeIndicator;
}
}
And in the Android project:
using Xamarin.CobrowseIO;
using Xamarin.Forms.Platform.Android;
[Application]
public class MainApplication : Application
{
public override void OnCreate()
{
CobrowseIO.Instance.SetDelegate(new CustomOverlayCobrowseDelegate());
}
}
public class CustomOverlayCobrowseDelegate : CobrowseDelegateImplementation, CobrowseIO.ISessionControlsDelegate
{
private View _overlayIndicator;
public void ShowSessionControls(Activity activity, Session session)
{
if (_overlayIndicator != null)
{
return;
}
if (!(activity is FormsAppCompatActivity))
{
return;
}
var indicator = new CobrowseCustomView();
var renderer = Platform.CreateRendererWithContext(indicator, activity);
renderer.Element.Layout(new Xamarin.Forms.Rectangle(0, 0, indicator.WidthRequest, indicator.HeightRequest));
var nativeIndicator = renderer.View;
var modal = new RelativeLayout(activity);
var layoutParams = new RelativeLayout.LayoutParams(
(int)TypedValue.ApplyDimension(ComplexUnitType.Dip, (float)indicator.WidthRequest, activity.Resources.DisplayMetrics),
(int)TypedValue.ApplyDimension(ComplexUnitType.Dip, (float)indicator.HeightRequest, activity.Resources.DisplayMetrics))
{
MarginEnd = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 4f, activity.Resources.DisplayMetrics)
};
layoutParams.AddRule(LayoutRules.CenterVertical);
layoutParams.AddRule(LayoutRules.AlignParentEnd);
modal.AddView(nativeIndicator, layoutParams);
var rootFrameLayout = (ViewGroup)activity.Window.PeekDecorView();
rootFrameLayout.AddView(modal, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent));
rootFrameLayout.Invalidate();
_overlayIndicator = modal;
}
public void HideSessionControls(Activity activity, Session session)
{
if (_overlayIndicator == null)
{
return;
}
if (!(activity is FormsAppCompatActivity))
{
return;
}
var rootFrameLayout = (ViewGroup)activity.Window.PeekDecorView();
rootFrameLayout.RemoveView(_overlayIndicator);
_overlayIndicator = null;
}
}
MAUI implementation
First, create an indicator view using MAUI (CobrowseCustomView.xaml
):
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="YourNamespace.CobrowseCustomView"
HeightRequest="42"
WidthRequest="130">
<Button
BackgroundColor="Red"
TextColor="White"
Text="End Session"
CornerRadius="4"
Clicked="OnEndSessionClicked" />
</ContentView>
public partial class CobrowseCustomView : ContentView
{
public CobrowseCustomView()
{
InitializeComponent();
}
private void OnEndSessionClicked(object sender, EventArgs e)
{
CobrowseIO.Instance.CurrentSession?.End(null);
}
}
Then, in the iOS-specific files:
public class CobrowseIndicatorDelegate
: Cobrowse.IO.CobrowseDelegateImplementation
{
private UIView _indicatorInstance;
public override void ShowSessionControls(Session session)
{
if (_indicatorInstance == null)
{
_indicatorInstance = GetDefaultSessionIndicator(container: UIApplication.SharedApplication.KeyWindow);
}
_indicatorInstance.Hidden = false;
}
public override void HideSessionControls(Session session)
{
if (_indicatorInstance != null)
_indicatorInstance.Hidden = true;
}
private UIView GetDefaultSessionIndicator(UIView container)
{
var indicator = new CobrowseCustomView();
var renderer = Microsoft.Maui.Controls.Compatibility.Platform.iOS.Platform.CreateRenderer(indicator);
renderer.Element.Layout(new Rect(0, 0, indicator.WidthRequest, indicator.HeightRequest));
var nativeIndicator = renderer.NativeView;
nativeIndicator.TranslatesAutoresizingMaskIntoConstraints = false;
container.AddSubview(nativeIndicator);
nativeIndicator.WidthAnchor.ConstraintEqualTo((float)indicator.WidthRequest).Active = true;
nativeIndicator.HeightAnchor.ConstraintEqualTo((float)indicator.HeightRequest).Active = true;
nativeIndicator.CenterYAnchor.ConstraintEqualTo(container.CenterYAnchor).Active = true;
nativeIndicator.RightAnchor.ConstraintEqualTo(container.RightAnchor, constant: -20f).Active = true;
return nativeIndicator;
}
}
And in the Android-specific files:
public class CobrowseIndicatorDelegate
: Cobrowse.IO.CobrowseDelegateImplementation,
Cobrowse.IO.Android.CobrowseIO.ISessionControlsDelegate
{
private global::Android.Views.View _overlayIndicator;
public void ShowSessionControls(Activity activity, Session session)
{
if (_overlayIndicator != null)
{
return;
}
if (!(activity is MauiAppCompatActivity))
{
return;
}
var indicator = new CobrowseCustomView();
var renderer = Microsoft.Maui.Controls.Compatibility.Platform.Android.Platform.CreateRendererWithContext(indicator, activity);
renderer.Element.Layout(new Rect(0, 0, indicator.WidthRequest, indicator.HeightRequest));
var nativeIndicator = renderer.View;
var modal = new RelativeLayout(activity);
var layoutParams = new RelativeLayout.LayoutParams(
(int)TypedValue.ApplyDimension(ComplexUnitType.Dip, (float)indicator.WidthRequest, activity.Resources.DisplayMetrics),
(int)TypedValue.ApplyDimension(ComplexUnitType.Dip, (float)indicator.HeightRequest, activity.Resources.DisplayMetrics))
{
MarginEnd = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 4f, activity.Resources.DisplayMetrics)
};
layoutParams.AddRule(LayoutRules.CenterVertical);
layoutParams.AddRule(LayoutRules.AlignParentEnd);
modal.AddView(nativeIndicator, layoutParams);
var rootFrameLayout = (ViewGroup)activity.Window.PeekDecorView();
rootFrameLayout.AddView(modal, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent));
rootFrameLayout.Invalidate();
_overlayIndicator = modal;
}
public void HideSessionControls(Activity activity, Session session)
{
if (_overlayIndicator == null)
{
return;
}
if (!(activity is MauiAppCompatActivity))
{
return;
}
var rootFrameLayout = (ViewGroup)activity.Window.PeekDecorView();
rootFrameLayout.RemoveView(_overlayIndicator);
_overlayIndicator = null;
}
}
Make sure the delegates you just created are passed into the Cobrowse.io SDK after the SDK is started:
public partial class App : Application
{
public App()
{
InitializeComponent();
CobrowseIO.Instance.License = "<your license key>";
CobrowseIO.Instance.Start();
#if ANDROID
Cobrowse.IO.Android.CobrowseIO.Instance.SetDelegate(new YourNamespace.Platforms.Android.CobrowseIndicatorDelegate());
#elif IOS
Cobrowse.IO.iOS.CobrowseIO.Instance.SetDelegate(new YourNamespace.Platforms.iOS.CobrowseIndicatorDelegate());
#endif
}
Last updated