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

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

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

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

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

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

คอตลิน
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 ลงในไฟล์ Manifest และตั้งชื่อไฟล์ใน CastMediaOptions ด้วย ตัวอย่างนี้มีการดำเนินการที่กำหนดเองซึ่งลบล้างการสลับการเล่นสื่อระยะไกล การกดปุ่มสื่อ และการทำงานประเภทอื่นๆ

// In AndroidManifest.xml
<receiver android:name="com.example.MyMediaIntentReceiver" />
โคทลิน
// 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 ดังนี้

คอตลิน
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 ดังนี้

คอตลิน
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 เพื่อส่งข้อความสตริงไปยังผู้รับผ่านช่องทางนั้น

คอตลิน
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

คอมโพเนนต์ต่างๆ ของเฟรมเวิร์ก (ได้แก่ กล่องโต้ตอบ Cast, มินิคอนโทรลเลอร์ และ 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

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

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