为您的 Android 应用添加高级功能

广告插播时间点

Android Sender SDK 支持在给定的媒体流中插入广告插播时间点和随播广告。

如需详细了解广告插播时间点的工作原理,请参阅 Web 接收器广告插播时间点概览

虽然可以在发送器和接收器上指定插播时间点,但建议在 Web 接收器Android TV 接收器 上指定插播时间点,以在不同平台之间保持一致的 行为。

在 Android 上,使用 AdBreakClipInfoAdBreakInfo在加载命令中指定广告插播时间点:

Kotlin
val breakClip1: AdBreakClipInfo =
    AdBreakClipInfo.Builder("bc0")
        .setTitle("Clip title")
        .setPosterUrl("https://www.some.url")
        .setDuration(60000)
        .setWhenSkippableInMs(5000)  // Set this field so that the ad is skippable
        .build()

val breakClip2: AdBreakClipInfo = 
val breakClip3: AdBreakClipInfo = 

val break1: AdBreakClipInfo =
    AdBreakInfo.Builder(/* playbackPositionInMs= */ 10000)
        .setId("b0")
        .setBreakClipIds({"bc0","bc1","bc2"})
        
        .build()

val mediaInfo: MediaInfo = MediaInfo.Builder()
    
    .setAdBreaks({break1})
    .setAdBreakClips({breakClip1, breakClip2, breakClip3})
    .build()

val mediaLoadRequestData: MediaLoadRequestData = MediaInfo.Builder()
    
    .setMediaInfo(mediaInfo)
    .build()

remoteMediaClient.load(mediaLoadRequestData)
Java
AdBreakClipInfo breakClip1 =
    new AdBreakClipInfo.Builder("bc0")
        .setTitle("Clip title")
        .setPosterUrl("https://www.some.url")
        .setDuration(60000)
        .setWhenSkippableInMs(5000)  // Set this field so that the ad is skippable
        .build();

AdBreakClipInfo breakClip2 = 
AdBreakClipInfo breakClip3 = 

AdBreakInfo break1 =
    new AdBreakInfo.Builder(/* playbackPositionInMs= */ 10000)
        .setId("b0")
        .setBreakClipIds({"bc0","bc1","bc2"})
        
        .build();

MediaInfo mediaInfo = new MediaInfo.Builder()
    
    .setAdBreaks({break1})
    .setAdBreakClips({breakClip1, breakClip2, breakClip3})
    .build();

MediaLoadRequestData mediaLoadRequestData = new MediaInfo.Builder()
    
    .setMediaInfo(mediaInfo)
    .build();

remoteMediaClient.load(mediaLoadRequestData);

添加自定义操作

发送器应用可以扩展 MediaIntentReceiver 以处理自定义操作或替换其行为。如果您已实现自己的 MediaIntentReceiver,则需要将其添加到清单,并在 CastMediaOptions 中设置其名称。此示例提供了自定义操作,这些操作会替换切换远程媒体播放、按媒体按钮和其他类型的操作。

// In AndroidManifest.xml
<receiver android:name="com.example.MyMediaIntentReceiver" />
Kotlin
// In your OptionsProvider
var mediaOptions = CastMediaOptions.Builder()
    .setMediaIntentReceiverClassName(MyMediaIntentReceiver::class.java.name)
    .build()

// Implementation of MyMediaIntentReceiver
internal class MyMediaIntentReceiver : MediaIntentReceiver() {
    override fun onReceiveActionTogglePlayback(currentSession: Session) {
    }

    override fun onReceiveActionMediaButton(currentSession: Session, intent: Intent) {
    }

    override fun onReceiveOtherAction(context: Context?, action: String, intent: Intent) {
    }
}
Java
// In your OptionsProvider
CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
        .setMediaIntentReceiverClassName(MyMediaIntentReceiver.class.getName())
        .build();

// Implementation of MyMediaIntentReceiver
class MyMediaIntentReceiver extends MediaIntentReceiver {
    @Override
    protected void onReceiveActionTogglePlayback(Session currentSession) {
    }

    @Override
    protected void onReceiveActionMediaButton(Session currentSession, Intent intent) {
    }

    @Override
    protected void onReceiveOtherAction(Context context, String action, Intent intent) {
    }
}

添加自定义渠道

如需让发送器应用与接收器应用通信,您的应用需要创建自定义渠道。发送器可以使用自定义渠道向接收器发送字符串消息。每个自定义渠道都由唯一的 命名空间定义,并且必须以 urn:x-cast: 前缀开头,例如 urn:x-cast:com.example.custom。您可以拥有多个自定义渠道,每个渠道都有唯一的命名空间。接收器应用也可以 发送和接收消息 使用相同的命名空间。

自定义渠道通过 Cast.MessageReceivedCallback 接口实现:

Kotlin
class HelloWorldChannel : MessageReceivedCallback {
    val namespace: String
        get() = "urn:x-cast:com.example.custom"

    override fun onMessageReceived(castDevice: CastDevice, namespace: String, message: String) {
        Log.d(TAG, "onMessageReceived: $message")
    }
}
Java
class HelloWorldChannel implements Cast.MessageReceivedCallback {
    public String getNamespace() {
        return "urn:x-cast:com.example.custom";
    }
    @Override
    public void onMessageReceived(CastDevice castDevice, String namespace, String message) {
        Log.d(TAG, "onMessageReceived: " + message);
    }
}

发送器应用连接到接收器应用后,可以使用自定义渠道 创建 setMessageReceivedCallbacks 方法:

Kotlin
try {
    mCastSession.setMessageReceivedCallbacks(
        mHelloWorldChannel.namespace,
        mHelloWorldChannel)
} catch (e: IOException) {
    Log.e(TAG, "Exception while creating channel", e)
}
Java
try {
    mCastSession.setMessageReceivedCallbacks(
            mHelloWorldChannel.getNamespace(),
            mHelloWorldChannel);
} catch (IOException e) {
    Log.e(TAG, "Exception while creating channel", e);
}

创建自定义渠道后,发送器可以使用 sendMessage 方法通过该渠道向接收器发送字符串消息:

Kotlin
private fun sendMessage(message: String) {
    if (mHelloWorldChannel != null) {
        try {
            mCastSession.sendMessage(mHelloWorldChannel.namespace, message)
                .setResultCallback { status ->
                    if (!status.isSuccess) {
                        Log.e(TAG, "Sending message failed")
                    }
                }
        } catch (e: Exception) {
            Log.e(TAG, "Exception while sending message", e)
        }
    }
}
Java
private void sendMessage(String message) {
    if (mHelloWorldChannel != null) {
        try {
            mCastSession.sendMessage(mHelloWorldChannel.getNamespace(), message)
                .setResultCallback( status -> {
                    if (!status.isSuccess()) {
                        Log.e(TAG, "Sending message failed");
                    }
                });
        } catch (Exception e) {
            Log.e(TAG, "Exception while sending message", e);
        }
    }
}

支持自动播放

请参阅自动播放和排队 API部分。

替换用户体验微件的图片选择

框架的各个组件(即 Cast 对话框、迷你控制器和 UIMediaController,如果已配置)将显示当前投放媒体的封面。图片封面的网址通常包含在媒体的 MediaMetadata 中,但发送器应用可能具有网址的替代来源。

The ImagePicker 类定义了一种方法,用于根据图片的使用情况(例如通知 缩略图或全屏背景)从图片列表 中选择合适的图片。MediaMetadata默认的 ImagePicker 实现始终选择第一张图片,如果 MediaMetadata 中没有图片,则返回 null。您的应用可以对ImagePicker进行子类化,并替换 onPickImage(MediaMetadata, ImageHints) 方法以提供替代实现,然后使用 setImagePicker 方法选择该子类,该方法属于CastMediaOptions.BuilderImageHintsImagePicker 提供有关要在界面中显示的图片的类型和大小的提示。

自定义 Cast 对话框

管理会话生命周期

SessionManager 是管理会话生命周期的中心位置。SessionManager 监听 Android MediaRouter 路由选择状态更改,以启动、恢复和结束会话。选择路由后,SessionManager 将创建一个 Session 对象,并尝试启动或恢复该对象。取消选择路由后,SessionManager 将结束当前会话。

因此,为确保 SessionManager 正确管理会话生命周期,您必须确保:

根据您创建 Cast 对话框的方式,可能需要执行其他操作:

零设备状态

如果您创建自定义 Cast 对话框,则自定义 MediaRouteChooserDialog 应正确处理未找到任何设备的情况。对话框应包含指示器,以便用户清楚地了解您的应用何时仍在尝试查找设备,以及何时不再尝试查找设备。

如果您使用的是默认的 MediaRouteChooserDialog,则系统已处理零设备状态。

后续步骤

至此,您可以添加到 Android Sender 应用的功能已全部介绍完毕。 现在,您可以为其他平台 (iOSWeb)构建发送器应用,或 构建 Web 接收器应用