เพิ่มฟีเจอร์ขั้นสูงในแอป 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 และตั้งค่าชื่อในไฟล์ 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

คอมโพเนนต์ต่างๆ ของเฟรมเวิร์ก (เช่น กล่องโต้ตอบการแคสต์ ตัวควบคุมขนาดเล็ก และ 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 ของคุณ ขณะนี้คุณสามารถสร้างแอปผู้ส่งสําหรับแพลตฟอร์มอื่น (iOS หรือเว็บ) หรือสร้างแอปตัวรับสัญญาณบนเว็บ