เพิ่มฟีเจอร์ขั้นสูงในแอป Android

ช่วงพักโฆษณา

Android Sender SDK ให้การสนับสนุนสำหรับช่วงพักโฆษณาและโฆษณาที่แสดงร่วมภายใน สตรีมสื่อที่กำหนด

โปรดดู ภาพรวมช่วงพักโฆษณาในเว็บรีซีฟเวอร์สำหรับข้อมูลเพิ่มเติม เกี่ยวกับวิธีการทำงานของช่วงพักโฆษณา

แม้ว่าจะสามารถระบุช่วงพักได้ทั้งกับผู้ส่งและผู้รับ แต่เราขอแนะนำให้เป็น ที่ระบุไว้ในเว็บรีซีฟเวอร์และ ตัวรับสัญญาณ Android TV เพื่อให้คงความสม่ำเสมอ พฤติกรรมบนแพลตฟอร์มต่างๆ

บน Android ให้ระบุช่วงพักโฆษณาในคำสั่งโหลดโดยใช้ AdBreakClipInfo และ AdBreakInfo:

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 ของคุณ คุณต้องเพิ่มลงในไฟล์ Manifest และตั้งค่าเป็น ใน 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) {
    }
}

เพิ่มแชแนลที่กำหนดเอง

ในการที่แอปผู้ส่งสามารถสื่อสารกับแอปตัวรับได้ แอปของคุณจะต้อง สร้างแชแนลที่กำหนดเอง ผู้ส่งสามารถใช้แชแนลที่กำหนดเองเพื่อส่งสตริง ไปยังผู้รับได้ แชแนลที่กำหนดเองแต่ละแชแนล Namespace และต้องขึ้นต้นด้วยคำนำหน้า 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 การจัดคิว

ลบล้างการเลือกรูปภาพสำหรับวิดเจ็ต UX

คอมโพเนนต์ต่างๆ ของเฟรมเวิร์ก (ได้แก่ กล่องโต้ตอบการแคสต์ หรือช่องขนาดเล็ก ตัวควบคุม และ UIMediaController หากกำหนดค่าไว้) จะแสดงอาร์ตเวิร์ก สำหรับสื่อที่กำลังแคสต์อยู่ โดยทั่วไป URL ของอาร์ตเวิร์กรูปภาพ รวมอยู่ใน MediaMetadata สำหรับสื่อ แต่แอปผู้ส่งอาจมี แหล่งที่มาสำรองของ URL

ImagePicker กำหนดวิธีการเลือกรูปภาพที่เหมาะสมจากรายการรูปภาพ ใน MediaMetadata โดยอิงตามการใช้รูปภาพ เช่น การแจ้งเตือน ภาพขนาดย่อหรือพื้นหลังแบบเต็มหน้าจอ การใช้งาน ImagePicker เริ่มต้น เลือกรูปภาพแรกเสมอ หรือแสดงผล Null หากไม่มีรูปภาพใน MediaMetadata แอปของคุณสามารถย่อย ImagePicker และลบล้าง onPickImage(MediaMetadata, ImageHints) เพื่อระบุการติดตั้งใช้งานอื่น จากนั้นเลือกคลาสย่อยนั้น พร้อมด้วย setImagePicker ของ CastMediaOptions.Builder ImageHints ให้คำแนะนำเกี่ยวกับ ImagePicker เกี่ยวกับประเภทและขนาดของรูปภาพที่จะ สำหรับแสดงใน UI

การปรับแต่งกล่องโต้ตอบการแคสต์

การจัดการวงจรเซสชัน

SessionManager เป็นศูนย์กลางในการจัดการวงจรเซสชัน ฟัง SessionManager ครั้ง สำหรับ Android MediaRouter สถานะการเลือกเส้นทางจะเปลี่ยนไปเป็นเซสชันเริ่มต้น กลับมาทำงานอีกครั้ง และสิ้นสุด เมื่อเส้นทางคือ เลือกไว้ SessionManager จะสร้าง Session และพยายามเริ่มต้นหรือดำเนินการต่อ เมื่อยกเลิกการเลือกเส้นทาง SessionManager จะสิ้นสุดเซสชันปัจจุบัน

ดังนั้นเพื่อให้ SessionManager จัดการวงจรเซสชันอย่างถูกต้อง ต้องตรวจสอบว่า

คุณอาจต้องดำเนินการเพิ่มเติม ทั้งนี้ขึ้นอยู่กับวิธีสร้างกล่องโต้ตอบการแคสต์ เสร็จ:

  • หากคุณสร้างกล่องโต้ตอบการแคสต์โดยใช้ MediaRouteChooserDialog และ MediaRouteControllerDialog กล่องโต้ตอบเหล่านี้จะอัปเดตการเลือกเส้นทางใน MediaRouter โดยอัตโนมัติ จึงไม่ต้องดำเนินการใดๆ
  • หากคุณตั้งค่าปุ่ม "แคสต์" โดยใช้ CastButtonFactory.setUpMediaRouteButton(Context, Menu, int) หรือ CastButtonFactory.setUpMediaRouteButton(Context, MediaRouteButton) กล่องโต้ตอบก็จะ สร้างโดยใช้ MediaRouteChooserDialog และ MediaRouteControllerDialog ดังนั้น คุณไม่ต้องดำเนินการใดๆ ด้วย
  • สำหรับกรณีอื่นๆ คุณจะสร้าง กล่องโต้ตอบแคสต์ที่กำหนดเอง ดังนั้นคุณต้อง ทำตามคำแนะนำข้างต้นเพื่ออัปเดตสถานะการเลือกเส้นทางใน MediaRouter

สถานะอุปกรณ์เป็นศูนย์

หากคุณสร้างกล่องโต้ตอบการแคสต์ที่กำหนดเอง MediaRouteChooserDialog ควรจัดการได้อย่างเหมาะสมในกรณีที่มีอุปกรณ์ 0 รายการ พบ กล่องโต้ตอบควรมีสัญญาณบอกสถานะให้ผู้ใช้ทราบอย่างชัดเจนเมื่อ ยังคงพยายามค้นหาอุปกรณ์ และเมื่อไม่พบ ใช้งานได้นานขึ้น

หากคุณใช้ MediaRouteChooserDialog เริ่มต้น สถานะอุปกรณ์จะเป็นศูนย์ ได้รับการจัดการแล้ว

ขั้นตอนถัดไป

ส่วนนี้ของฟีเจอร์ที่คุณสามารถเพิ่มลงในแอปผู้ส่งของ Android ตอนนี้คุณสร้างแอปผู้ส่งสำหรับแพลตฟอร์มอื่นได้แล้ว (iOS หรือเว็บ) หรือ สร้างแอป Web Receiver