本文介绍 Android 观播 SDK 进阶功能的接入方法。您可以根据实际业务需求,按需实现复杂功能。
serverType
取值不可为 SERVER_TYPE_SINGLE
。本文介绍以下功能的接入方法。
如果您需要观众先登录您的 App 再观看直播或参与评论、互动等操作,可以选择自定义登录方式,观众可以使用在您 App 中的身份信息进入直播间。
您可以按需选择观众在您 App 的登录时机。
观众先完成登录,再进入直播间。
mode
=2
时的授权 Token。示例代码如下所示。
long activityId = 1721010849258****; // 直播间的活动 ID。 String token = "ak3T%2FdaGJDL5zSFD7%2F1GPGP****wx0zaTfQ1M4Dahp8%3D"; // mode=2 时的授权 Token。 TVULiveRoom.TVURoomAuthMode roomAuthMode = TVULiveRoom.TVURoomAuthMode.CUSTOM; // 自定义模式。 boolean isPortrait = true; // 竖屏直播间。 TVULiveRoom.joinLiveRoom(context, new JoinRoomConfig(activityId,token,roomAuthMode,isPortrait));
观众先进入直播间观看直播、查看评论等,在参与评论、互动等操作时触发登录流程,将鉴权模式从公开模式切换为自定义模式。
mode
=1
时的授权 Token。mode
=2
时的授权 Token。Null
到 SDK。示例代码如下所示。
// 设置公开模式下登录自有账号系统的监听器。 CustomSettings settings = CustomSettings.Holder.mSettings; settings.setCustomLoginListener((context, activityId, callBack) -> { // 触发 onCustomLoginStart 回调后,执行 App 的自定义登录逻辑。此处以弹出自定义登录对话框为例。您可以按需跳转至指定自定义登录页面。 new AlertDialog.Builder(context) .setTitle("自定义登录") .setView(editText) .setCancelable(false) .setPositiveButton(android.R.string.yes, (dialog, which) -> { // 此处以需要观众输入 Token 为例。观众自定义登录成功,触发 onLoginFinished 回调,将自定义模式 Token 传入 SDK。在传入前,调用 URLDecoder.decode 方法对 Token 进行解码。 String token = editText.getText().toString().trim(); callBack.onLoginFinished(URLDecoder.decode(token)); }) // 观众自定义登录失败或取消自定义登录,触发 onLoginFinished 回调,传入 Null 到 SDK。 .setNegativeButton(android.R.string.no, ((dialog, which) -> callBack.onLoginFinished(null))) .setIcon(android.R.drawable.ic_dialog_alert) .show(); });
观众在点击菜单内商品卡片、浮窗商品卡片、页头广告、页中广告、浮标广告、主播账号、评论中的 URL 时,SDK 会执行后续默认的跳转行为。
说明
调用 setRedirectPageListener 方法,设置直播间内的链接点击事件监听器后,观众在点击商品卡片、页头广告等时,SDK 会触发 redirectPage 回调。您可以通过返回值,决定在执行自定义跳转逻辑时,是否拦截后续默认的跳转行为。
true
:拦截,即不执行默认的跳转行为。false
:不拦截,即执行默认的跳转行为。以下示例代码在观众点击浮标广告、菜单内商品卡片和浮窗商品卡片时仅执行自定义跳转逻辑,在观众点击页头广告、页中广告、浮标广告、主播账号、评论中的 URL 时会同时执行自定义跳转逻辑和默认的跳转行为。
// 设置直播间内的链接点击事件监听器。 CustomSettings.Holder.mSettings.setRedirectPageListener(new RedirectPageListener() { /** * * @param liveActivity 直播间所在的 Activity。 * @param redirectInfo 实现自定义跳转逻辑所需的信息。 * @return 是否拦截后续 SDK 的默认跳转行为。true:拦截,SDK 不会执行后续默认的跳转行为。false:不拦截,SDK 会执行后续默认的跳转行为。 */ @Override public boolean redirectPage(Activity liveActivity, RedirectInfo redirectInfo) { // 通过 entrance 字段查看点击事件入口。 String entrance = redirectInfo.getEntrance(); switch (redirectInfo.getContentType()) { case RedirectInfo.CONTENT_TYPE_URL: // 当内容类型为 URL 时,获取 urlRedirectInfo 字段。 UrlRedirectInfo urlRedirectInfo = redirectInfo.getUrlRedirectInfo(); // 在点击浮标广告时 if (entrance.equals(Entrance.FLOATING_ADVERTISEMENT.value)) { // 执行自定义跳转逻辑。此处以弹出 SDK 内部的 WebViewDialog 为例。您也可以使用自定义的 Dialog。 new CommonWebViewDialog(liveActivity, urlRedirectInfo.getUrl(), com.bytedance.live.sdk.R.style.TvuLiveBottomDialog).show(); // 执行自定义跳转逻辑,但不执行默认的跳转行为。 return true; } // 在点击菜单内商品卡片或浮窗商品卡片时 if (entrance.equals(Entrance.FLOATING_SHOPPING_CARD.value)) { String productUrl = urlRedirectInfo.getUrl(); ToastUtil.displayToast("click : " + productUrl); // 执行自定义跳转逻辑。此处以跳转至商品详情 Activity 为例。 startActivities(new Intent[]{new Intent(MainActivity.this, ProductActivity.class)}); // 执行自定义跳转逻辑,但不执行默认的跳转行为。 return true; } } // 执行自定义跳转逻辑和默认的跳转行为。 return false; } });
目前 SDK 支持自定义跳转逻辑的功能、entrance
字段的取值和观看页位置如下表所示。
说明
本文仅以移动端竖屏模式的观看页位置为例,如需查看 PC 端或移动端横屏模式的观看页位置,可查看对应的功能配置文档。
功能 |
| 观看页位置 |
---|---|---|
菜单内商品卡片 |
| |
浮窗商品卡片 |
| |
页头广告 |
| |
页中广告 |
| |
浮标广告 |
| |
主播账号头像或名称 |
| |
评论中的 URL |
|
默认情况下,仅主持人评论中的 URL 为可点击状态。您可以通过 setAudienceCommentLinkClickable 方法,将观众评论中的 URL 设置为可点击状态。
示例代码如下所示。
CustomSettings settings = CustomSettings.Holder.mSettings; settings.setAudienceCommentLinkClickable(true);
观众在完整直播间内点击退出按钮或物理返回键时,默认会退出完整直播间。如果正在播放直播或点播视频且观众在移动端开启了悬浮窗权限,则默认会退出完整直播间并展示悬浮窗(即画中画)。
调用 setLiveRoomActionListener 方法,设置完整直播间的退出事件监听器后,观众在点击退出按钮或物理返回键退出完整直播间时,SDK 会触发 onClickExitLiveRoom 回调。您可以通过返回值,决定在执行自定义的完整直播间退出行为时,是否拦截以上默认的点击行为。
true
:拦截,即不执行默认的点击行为。false
:不拦截,即执行默认的点击行为。说明
Android 观播 SDK 自 1.33.0 版本开始,onClickExitLiveRoom 回调支持通过返回值决定是否拦截默认的点击行为。如未集成指定的 SDK 版本,则必然拦截默认的点击行为。
以下示例代码仅会执行自定义的完整直播间退出行为,而不会执行默认的点击行为。
// 设置完整直播间的退出事件监听器。 CustomSettings settings = CustomSettings.Holder.mSettings; settings.setLiveRoomActionListener(context -> { ToastUtil.displayToast("自定义完整直播间退出行为"); TVULiveRoom.leaveLiveRoom(MainActivity.this); // 执行自定义的完整直播间退出行为。 return true; // 仅 Android 观播 SDK 1.33.0 及以上版本支持。 });
在接入独立播放器或完整播放器后,如需使用观众连麦功能,您可组件化接入连麦模块。
以下示例代码演示了如何获取连麦管理器、创建连麦相关 view,并将创建的连麦相关 view 添加到您自己的页面容器中。
private void initAudienceLinkModule() { // 设置在连麦画面 view 中显示当前连麦观众的画面。 CustomSettings.Holder.mSettings.setShowSelfVideoInRemoteView(true); // 获取连麦管理器。连麦管理器的生命周期与 TVULiveRoomServer 一致,销毁 TVULiveRoomServer 时会同步销毁连麦管理器。 IAudienceLinkManager audienceLinkManager = roomServer.getAudienceLinkManager(); // 监听连麦管理器事件。 audienceLinkManager.addListener(new AudienceLinkEventListenerAdapter() { // 首次从企业直播服务端获取到连麦布局信息时,即连麦布局已经加载完成时,会触发该回调。 @Override public void onFirstGetLayoutData() { super.onFirstGetLayoutData(); // 以下代码演示了在加入连麦时隐藏直播播放器 view。 FusionPlayerModel fusionPlayerModel = roomServer.getPlayerModel(); if (audienceLinkManager.getCurAudienceLinkState() == AudienceLinkState.LINKED) { // 此时连麦布局已经加载完成,需要隐藏直播播放器 view。 fusionPlayerModel.setHiding(true); } } // 本地连麦状态变化回调。 @Override public void onAudienceLinkStateChanged(AudienceLinkState oldState, AudienceLinkState newState) { super.onAudienceLinkStateChanged(oldState, newState); // 以下代码演示了在退出连麦时重新显示直播播放器 view。 FusionPlayerModel fusionPlayerModel = roomServer.getPlayerModel(); if (oldState == AudienceLinkState.LINKED && newState != AudienceLinkState.LINKED) { // 从已连麦变更为非连麦状态,即退出连麦时,需要显示直播播放器 view。 fusionPlayerModel.setHiding(false); } } }); // 获取连麦组件 view 的管理器。 AudienceLinkViewProvider linkViewProvider = AudienceLinkViewProvider.getInstance(); // 创建连麦画面容器 view,用于展示当前连麦观众和其他连麦参与者的画面。 AudienceLinkRemoteContainerView audienceLinkRemoteContainerView = linkViewProvider.createAudienceLinkRemoteContainerView(roomServer,this); // 设置连麦画面 view 的填充模式为 FIT_MODE。 audienceLinkRemoteContainerView.setContentMode(AudienceLinkRemoteContainerView.FIT_MODE); // 设置监听器,监听连麦画面 view 中单个连麦参与者画面的点击事件。 audienceLinkRemoteContainerView.getRemoteLinkGroupView().setUserVideoClickListener(new RemoteLinkGroupView.IUserVideoClickListener() { @Override public void onUserVideoClick(LayoutUser layoutUser, boolean isSelf) { if (isSelf) { ToastUtil.displayToast("点击了自己"); } else { ToastUtil.displayToast("点击了" + layoutUser.getUserInfo().getNickname()); } } }); // 设置连麦画面 view 中画布背景颜色。默认为黑色。 audienceLinkRemoteContainerView.getRemoteLinkGroupView().setBackgroundColor(Color.BLACK); // 将连麦画面容器 view 添加到您自己页面的 FrameLayout 中。 videoViewContainer.addView(audienceLinkRemoteContainerView); //(可选)创建连麦入口 view,并将其添加到您自己页面的 Layout 中。 AudienceLinkEntranceView audienceLinkEntranceView = linkViewProvider.createAudienceLinkEntranceView(roomServer, this); //(可选)自定义连麦入口 view 的宽高。 audienceLinkEntranceView.getLayoutParams().width = SizeUtils.dp2px(200f); audienceLinkEntranceView.getLayoutParams().height = SizeUtils.dp2px(100f); audienceLinkEntranceView.setLayoutParams(audienceLinkEntranceView.getLayoutParams()); fmCallContainer.addView(audienceLinkEntranceView); //(可选)创建连麦本地画面预览 view,并将其添加到您自己页面的 Layout中。 fmCallContainer.addView(linkViewProvider.createAudienceLinkPreviewView(roomServer,this)); // 需要断开连麦时,可以调用以下方法。 // audienceLinkManager.manualUnLink(); }
相关方法、回调等如下所示:
在接入完整直播间后,您可以自定义横屏直播间的 UI。
TvuLivePlayerLayoutBinding
实例SDK 触发 onLandLiveRoomBindingAvailable 回调后,您可以通过获取到的 ViewBinding
实例自定义横屏直播间的 UI。
示例代码如下所示。
public interface LiveRoomStatusListener { ... default void onLandLiveRoomBindingAvailable(TvuLivePlayerLayoutBinding binding, LanguageManager languageManager) { } ... }
获取到的 ViewBinding
实例 UI 结构如下所示。
rootContainer(FrameLayout) |-- contentContainer(LinearLayout) |-- headContainer(LinearLayout) |-- headTvuContainer |-- livePlayerContainer(FrameLayout) |-- livePlayerCardView(TVUAspectRatioCardView) |-- tvu_player_view(PlayerView) |-- midContainer(LinearLayout) |-- midTvuContainer |-- bottomTvuMenuContainer |-- floatingContainer(FrameLayout) |-- tvuFloatingViewsContainer
contentContainer
(内容区域)包含 head
(headContainer
)、播放器(livePlayerContainer
)、mid
(midContainer
)和 bottomMenu
(bottomTvuMenuContainer
)四个区域。floatingContainer
(悬浮区域)的层级在 contentContainer
之上。您可以通过隐藏默认组件并添加自定义 UI 组件的方式,替换横屏直播间的 UI 组件。
注意
不需要的默认 UI 组件不可移除,否则会导致空指针异常。
以下示例代码替换了横屏直播间的 head
区域并修改了播放器尺寸。
public void custom(TvuLivePlayerLayoutBinding binding) { // 隐藏横屏直播间默认的 head 组件。 binding.headTvuContainer.setVisibility(View.GONE); // 引入自定义的 head 组件。 View customHeadView = LayoutInflater.from(context).inflate(R.layout.include_custom_header, binding.headContainer, false); customHeadView.findViewById(R.id.back_btn).setOnClickListener(v -> { TVULiveRoom.manualClickLiveRoomExitBtn(context); }); customHeadView.findViewById(R.id.share_btn).setOnClickListener(v -> { ToastUtil.displayToast("点击了分享"); }); // 添加自定义的 head 组件。 binding.headContainer.addView(customHeadView); ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) binding.livePlayerContainer.getLayoutParams(); // 去掉播放器的左右外边距和上下左右内边距。 params.leftMargin = params.rightMargin = 0; binding.livePlayerContainer.setLayoutParams(params); binding.livePlayerContainer.setPadding(0, 0, 0, 0); // 将播放器尺寸设置为 16:9。 binding.livePlayerCardView.setResizeMode(TVUAspectRatioFrameLayout.RESIZE_MODE_FIXED_WIDTH); binding.livePlayerCardView.setWidthRatio(16); binding.livePlayerCardView.setHeightRatio(9); // 去掉播放器的圆角。 binding.livePlayerCardView.setRadius(0); }
floatingContainer
用于存放直播间的悬浮 View 组件,并提供 addChildViewInFrameLayout 和 addChildViewInLinearLayout 方法添加自定义悬浮 View 组件。
以下示例代码通过 setLiveRoomStatusListener 方法、onLandLiveRoomBindingAvailable 回调以及 addChildViewInLinearLayout 方法,在横屏直播间的 floatingContainer
中添加了自定义悬浮 View 组件。
// CustomSettings.Holder.mSettings.setLiveRoomStatusListener // ... @Override public void onLandLiveRoomBindingAvailable(TvuLivePlayerLayoutBinding binding, LanguageManager languageManager) { // 通过 findViewById 方法找到 floatingContainer。floatingContainer 在 Activity 中的 view id 为 R.id.tvu_floating_views_container。 FloatingContainer floatingContainer = binding.getRoot().findViewById(com.bytedance.live.sdk.R.id.tvu_floating_views_container); // 在 floatingContainer 中添加 TextView 组件。 TextView textView = new TextView(binding.getRoot().getContext()); textView.setText("Hello World"); floatingContainer.addChildViewInLinearLayout(textView, true, false, new CustomSize(20, 20)); } // ...
在 floatingContainer
中添加自定义悬浮 View 组件。该 View 组件不与 floatingContainer
中 SDK 默认的 View 组件进行位置联动,展示位置仅由 View 组件的配置决定。
说明
SDK 默认的 View 组件目前包含整组互动工具图标、浮窗商品卡片以及浮标广告。
public void addChildViewInFrameLayout(View childView, SimpleLayoutParams layoutParams)
参数
名称 | 类型 | 说明 |
---|---|---|
childView | View | 要添加的 View 组件。 |
layoutParams | 要添加的 View 组件的位置。 |
在 floatingContainer
中添加自定义悬浮 View 组件。该 View 组件与 floatingContainer
中 SDK 默认的 View 组件进行位置联动,即参与 View 组件展示顺序的重新排列。
说明
SDK 默认的 View 组件目前包含整组互动工具图标、浮窗商品卡片以及浮标广告。
public void addChildViewInLinearLayout(View childView, boolean isLeftTop, boolean isLastChild, CustomSize customSize)
参数
名称 | 类型 | 说明 |
---|---|---|
childView | View | 要添加的 View 组件。 |
isLeftTop | Boolean | 要添加的 View 组件在直播间的显示位置。
|
isLastChild | Boolean | 要添加的 View 组件与其他 View 组件的展示顺序。
|
customSize | 要添加的 View 组件的大小。 |
通过 LanguageManager.LanguageManagerListener
监听器监听到观看页语言变化后,改变自定义组件的多语言。
示例代码如下所示。
LanguageManager.LanguageManagerListener listener = new LanguageManager.LanguageManagerListener() { @Override public void onLanguageChanged(LanguageManager.LANGUAGE language, int languageIdx, Properties properties) { // 监听到观看页语言变化后,改变自定义组件的多语言。 switch (language) { case ZH_HANS: break; case EN: break; default: } } }; // 添加监听器。 LanguageManager.getInstance().addListener(listener); // 移除监听器。 LanguageManager.getInstance().removeListener(listener);
在接入完整直播间后,您可以自定义竖屏直播间的 UI。
TvuPortraitLiveRoomLayoutBinding
实例SDK 触发 onPortraitLiveRoomBindingAvailable 回调后,您可以通过获取到的 ViewBinding
实例自定义竖屏直播间的 UI。
示例代码如下所示。
public interface LiveRoomStatusListener { ...default void onPortraitLiveRoomBindingAvailable(TvuPortraitLiveRoomLayoutBinding binding, LanguageManager languageManager) { } ... }
获取到的 ViewBinding
实例 UI 结构如下所示。
rootLayout(FrameLayout) |-- portraitCommentListArea(LinearLayout) |-- portraitLiveRoomBottomBarLayout(PortraitLiveRoomBottomBarLayout) |-- floatingContainer(FloatingContainer)
floatingContainer
(悬浮区域)的层级在 portraitCommentListArea
(评论区域) 和 portraitLiveRoomBottomBarLayout
(底部图标区域)之上。
portraitLiveRoomBottomBarLayout
用于存放竖屏直播间底部的图标,并提供 setBottomOnClickListener 方法将指定图标的点击事件替换为自定义的点击事件。观众点击图标触发自定义的点击事件后,即可执行自定义的点击行为。
以下示例代码通过 setLiveRoomStatusListener 方法、onPortraitLiveRoomBindingAvailable 回调以及 setBottomOnClickListener 方法,替换了竖屏直播间底部图文介绍图标的点击事件并自定义了点击事件触发后的点击行为。
// CustomSettings.Holder.mSettings.setLiveRoomStatusListener // ... @Override public void onPortraitLiveRoomBindingAvailable(TvuPortraitLiveRoomLayoutBinding binding, LanguageManager languageManager) { // 通过 findViewById 方法找到 portraitLiveRoomBottomBarLayout。portraitLiveRoomBottomBarLayout 在 Activity 中的 view id 为 R.id.portrait_bottom_bar。 PortraitLiveRoomBottomBarLayout portraitLiveRoomBottomBarLayout = findViewById(com.bytedance.live.sdk.R.id.portrait_bottom_bar); // 将竖屏直播间底部图标的点击事件替换为您自定义的点击事件。此处以替换图文介绍图标的点击事件为例。 portraitLiveRoomBottomBarLayout.setBottomOnClickListener(PortraitLiveRoomBottomBarLayout.BottomBar.IMAGE_TEXT_ICON, new View.OnClickListener() { @Override public void onClick(View view) { // 触发图文介绍图标的点击事件后,执行自定义的点击行为。 ToastUtil.displayToast("点击了图文介绍按钮"); } }); }
将竖屏直播间底部图标的点击事件替换为您自定义的点击事件。观众点击图标触发自定义的点击事件后,即可执行自定义的点击行为。
public void setBottomOnClickListener(PortraitLiveRoomBottomBarLayout.BottomBar bottomBar, View.OnClickListener listener)
参数
名称 | 类型 | 说明 |
---|---|---|
bottomBar | 竖屏直播间底部的图标。 | |
listener | 用于自定义图标的点击行为。 |
以下示例代码通过 setLiveRoomStatusListener 方法、onPortraitLiveRoomBindingAvailable 回调以及 addChildViewInLinearLayout 方法,在竖屏直播间的 floatingContainer
中添加了自定义悬浮 View 组件。
// CustomSettings.Holder.mSettings.setLiveRoomStatusListener // ... @Override public void onPortraitLiveRoomBindingAvailable(TvuPortraitLiveRoomLayoutBinding binding, LanguageManager languageManager) { // 通过 findViewById 方法找到 floatingContainer。floatingContainer 在 Activity 中的 view id 为 R.id.tvu_floating_views_container。 FloatingContainer floatingContainer = binding.getRoot().findViewById(com.bytedance.live.sdk.R.id.tvu_floating_views_container); // 在 floatingContainer 中添加 TextView 组件。 TextView textView = new TextView(binding.getRoot().getContext()); textView.setText("Hello World"); floatingContainer.addChildViewInLinearLayout(textView, true, false, new CustomSize(20, 20)); } // ...
通过 LanguageManager.LanguageManagerListener
监听器监听到观看页语言变化后,改变自定义组件的多语言。
LanguageManager.LanguageManagerListener listener = new LanguageManager.LanguageManagerListener() { @Override public void onLanguageChanged(LanguageManager.LANGUAGE language, int languageIdx, Properties properties) { // 监听到观看页语言变化后,改变自定义组件的多语言。 switch (language) { case ZH_HANS: break; case EN: break; default: } } }; // 添加监听器。 LanguageManager.getInstance().addListener(listener); // 移除监听器。 LanguageManager.getInstance().removeListener(listener);
您可以通过观播 SDK 自定义观看页的 UI 显示。
本文以直播带货场景中高频使用的 UI 定制功能点为例。更多 UI 定制相关方法与回调,详见 mSettings 和回调。
竖屏直播间内,默认视频会保持原有宽高比例填充播放器,视频的宽高会填满播放器的宽高。如果视频宽高比与播放器宽高比不同,会有部分视频内容被裁剪掉。您可以自定义视频画面的填充模式。详见 setPortraitPlayerLayoutMode。
以下示例代码保持视频原有宽高比例填充播放器,视频的宽高会填满播放器的宽高。如果视频宽高比与播放器宽高比不同,视频会缩放显示。
CustomSettings settings = CustomSettings.Holder.mSettings; // 将视频画面的填充模式设置为 ImageAspectFit。 settings.setPortraitPlayerLayoutMode(0);
竖屏完整直播间的关闭按钮默认显示为 x。您可以自定义关闭按钮的显示样式。
以下示例代码将关闭按钮自定义为文件名为 tvu_nav_icon_back_melon
的图片。
CustomSettings settings = CustomSettings.Holder.mSettings; // 自定义按钮的图标为文件名 tvu_nav_icon_back_melon 的图片。 settings.setExitRoomIcon(ContextCompat.getDrawable(this, R.mipmap.tvu_nav_icon_back_melon));
互动工具浮窗,即包含抽奖、答题、投票、问卷和公告图标的浮窗。竖屏直播间默认展示在直播间左上方。您可以自定义互动工具浮窗的默认位置。
以下示例代码将互动工具浮窗的默认位置从左上方移动至距离底部 80 dp 的左下方。
CustomSettings settings = CustomSettings.Holder.mSettings; // 将互动工具浮窗的默认位置移动至距离底部 80 dp 的左下方。 SimpleLayoutParams simpleLayoutParams = new SimpleLayoutParams(Gravity.START | Gravity.BOTTOM, 0, 0, 0, 80); settings.setFloatInteractToolLayoutParams(simpleLayoutParams);
商品卡片菜单的默认高度为屏幕高度的 0.73 倍。您可以自定义菜单的高度。
以下示例代码将商品卡片菜单的高度设置为 700 dp。
CustomSettings settings = CustomSettings.Holder.mSettings; // 将商品卡片菜单的高度设置为 700 dp。 settings.setShoppingCardDialogHeight(700);