Introduction
Brightcove's Pulse plugin enables you to integrate Invidi's Pulse SDK with the Brightcove Native SDK for Android. Pulse is a Video Advertisement Platform. For campaigns and configuration details, see their User Guide.
Steps
Once a campaign is created in the Pulse platform, you can start using the Pulse Plugin for the Brightcove Native SDK for Android. Follow these steps to integrate the Pulse Plugin with your project:
-
In your module build.gradle file, add the Pulse plugin dependency.
dependencies { implementation 'com.brightcove.player:android-pulse-plugin:6.12.0' }
-
Download the Pulse SDK .aar file.
-
In your app/libs folder, open the build.gradle file from your module. Modify the following:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) }
-
In your MainActivity.java file, initialize the Pulse Plugin by instantiating a
PulseComponent
with the Pulse host URL created for your campaign.@Override protected void onCreate(Bundle savedInstanceState) { // ... // Creating pulse component PulseComponent pulseComponent = new PulseComponent( "your pulse host url", brightcoveVideoView.getEventEmitter(), brightcoveVideoView); // ... }
-
Set the
PulseComponent
Listener.pulseComponent.setListener(new PulseComponent.Listener() { @NonNull @Override public PulseSession onCreatePulseSession( @NonNull String hostUrl, @NonNull Video video, @NonNull ContentMetadata contentMetadata, @NonNull RequestSettings requestSettings) { // See step 3a return Pulse.createSession(contentMetadata, requestSettings); } @Override public void onOpenClickthrough(@NonNull PulseVideoAd pulseVideoAd) { } });
-
Implement the
onCreatePulseSession
method, which creates aPulseSession
and returns it to thePulseComponent
. There are three parameters:- The pulse host
- The content metadata settings
- The request settings
@NonNull @Override public PulseSession onCreatePulseSession( @NonNull String hostUrl, @NonNull Video video, @NonNull ContentMetadata contentMetadata, @NonNull RequestSettings requestSettings) { // Set the pulse Host: Pulse.setPulseHost(pulseHostUrl, null, null); // Content metadata settings contentMetadata.setCategory("skip-always"); contentMetadata.setTags(Collections.singletonList("standard-linears")); contentMetadata.setIdentifier("demo"); // Request Settings: // Adding mid-rolls List<Float> midrollCuePoints = new ArrayList<>(); midrollCuePoints.add(60f); requestSettings.setLinearPlaybackPositions(midrollCuePoints); // Create and return the PulseSession return Pulse.createSession(contentMetadata, requestSettings); }
-
Implement the
onOpenClickthrough
method, which is called when the learn more button from a Linear Ad is clicked. A typical action for this callback is to open the browser with the expected url.@Override public void onOpenClickthrough(@NonNull PulseVideoAd pulseVideoAd) { Intent intent = new Intent(Intent.ACTION_VIEW) .setData(Uri.parse(pulseVideoAd.getClickthroughURL().toString())); brightcoveVideoView.getContext().startActivity(intent); pulseVideoAd.adClickThroughTriggered(); }
-
Play your content
Catalog catalog = new Catalog.Builder( eventEmitter, getString(R.string.account)) .setPolicy(getString(R.string.policy)) .build(); catalog.findVideoByID(getString(R.string.videoId), new VideoListener() { // Add the video found to the queue with add(). // Start playback of the video with start(). @Override public void onVideo(Video video) { brightcoveVideoView.add(video); brightcoveVideoView.start(); } });
Pulse Pause Ads
When the Pulse campaign has "Pause Ads" configured, the Pulse plugin will show the user when the content is paused.
Error handling
All errors will be surfaced to the developer using the EventType.AD_ERROR event, as shown below:
eventEmitter.on(EventType.AD_ERROR, event -> {
Throwable error = event.getProperty(Event.ERROR, Throwable.class);
Log.e(TAG, "AD_ERROR: ", error);
});
UI Customization
Internally, the Pulse plugin inflates the PulseAdView
using the R.layout.pulse_ad_view
layout id. For a different layout, you can create a layout file with the same name and add it to the res/layout directory. This overrides the default layout.
Use the following ids to replace the defaults:
Index | View Type | View Id |
---|---|---|
A | TextView | pulse_ad_number_view |
B | TextView | pulse_ad_countdown_view |
C | TextView | pulse_ad_name_view |
D | TextView | pulse_ad_learn_more_view |
E | TextView | pulse_skip_ad_view |
Complete code sample
Here is a complete code sample for using the Pulse plugin with the Native SDK for Android.
Activity
Here is a example of the full Activity code:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
final BrightcoveVideoView videoView = findViewById(R.id.video_view);
super.onCreate(savedInstanceState);
EventEmitter eventEmitter = videoView.getEventEmitter();
// Pulse setup
PulseComponent pulseComponent = new PulseComponent(
"https://pulse-demo.videoplaza.tv",
eventEmitter,
videoView);
pulseComponent.setListener(new PulseComponent.Listener() {
@NonNull
@Override
public PulseSession onCreatePulseSession(
@NonNull String pulseHostUrl,
@NonNull Video video,
@NonNull ContentMetadata contentMetadata,
@NonNull RequestSettings requestSettings) {
Pulse.setPulseHost(pulseHostUrl, null, null);
contentMetadata.setCategory("skip-always");
contentMetadata.setTags(Collections.singletonList("standard-linears"));
contentMetadata.setIdentifier("demo");
// Adding mid-rolls
List<Float> midrollCuePoints = new ArrayList<>();
midrollCuePoints.add(60f);
requestSettings.setLinearPlaybackPositions(midrollCuePoints);
return Pulse.createSession(
contentMetadata,
requestSettings);
}
@Override
public void onOpenClickthrough(@NonNull PulseVideoAd ad) {
Intent intent = new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse(ad.getClickthroughURL().toString()));
videoView.getContext().startActivity(intent);
ad.adClickThroughTriggered();
}
});
Catalog catalog = new Catalog.Builder(eventEmitter, "YourAccountId")
.setPolicy("YourPolicyKey")
.build();
catalog.findVideoByID("YourVideoId", new VideoListener() {
// Add the video found to the queue with add().
// Start playback of the video with start().
@Override
public void onVideo(Video video) {
videoView.add(video);
videoView.start();
}
});
}
}
Layout
Here is an example of the layout code for the R.layout.pulse_ad_view
.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/view_ad_details"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/pulse_skip_button_background_selector">
<TextView
android:id="@+id/pulse_ad_name_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginTop="4dp"
android:paddingTop="4dp"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textColor="@color/white"
android:background="@color/bmc_live"
android:textStyle="bold"
tools:text="Preroll blue"/>
<TextView
android:id="@+id/pulse_ad_number_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="4dp"
android:paddingBottom="4dp"
android:layout_marginBottom="8dp"
android:layout_below="@id/pulse_ad_name_view"
android:textColor="@color/white"
android:background="@color/white_semi_trans"
tools:text="Ad (1 of 2)"/>
<TextView
android:id="@+id/pulse_ad_countdown_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="4dp"
android:paddingEnd="4dp"
android:paddingBottom="4dp"
android:layout_marginBottom="4dp"
android:layout_below="@id/pulse_ad_name_view"
android:layout_toEndOf="@+id/pulse_ad_number_view"
android:textColor="@color/green_almost_opaque"
android:text=""
tools:text="00:06"/>
<TextView
android:id="@+id/pulse_ad_learn_more_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/pulse_ad_learn_more_margin_left"
android:layout_marginTop="@dimen/pulse_ad_learn_more_margin_top"
android:layout_marginEnd="@dimen/pulse_ad_learn_more_margin_right"
android:layout_marginBottom="@dimen/pulse_ad_learn_more_margin_bottom"
android:layout_alignTop="@id/pulse_ad_name_view"
android:layout_alignBottom="@id/pulse_ad_countdown_view"
android:layout_alignParentEnd="true"
android:background="@drawable/pulse_learn_more_button_background"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:padding="@dimen/pulse_ad_learn_more_padding_default"
android:gravity="center"
android:shadowColor="@color/brightcove_semitransparent"
android:shadowDx="-1"
android:shadowDy="1"
android:shadowRadius="1.5"
android:text="@string/pulse_message_learn_more"
android:textColor="@color/pulse_button_text_color"
android:nextFocusUp="@id/pulse_skip_ad_view"
android:textSize="@dimen/pulse_message_text_size"
android:visibility="gone"
tools:visibility="visible" />
</RelativeLayout>
<TextView
android:id="@+id/pulse_skip_ad_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="164dp"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginBottom="@dimen/pulse_skip_ad_margin_bottom"
android:background="@drawable/pulse_skip_button_background_selector"
android:ellipsize="none"
android:gravity="center"
android:maxLines="2"
android:paddingStart="@dimen/pulse_skip_ad_padding_left"
android:paddingEnd="@dimen/pulse_skip_ad_padding_right"
android:paddingTop="@dimen/pulse_skip_ad_padding"
android:paddingBottom="@dimen/pulse_skip_ad_padding"
android:scrollHorizontally="false"
android:shadowColor="@color/brightcove_shadow"
android:shadowDx="-1"
android:shadowDy="1"
android:shadowRadius="1.5"
android:text="@string/pulse_message_skip_ad"
android:textColor="@color/pulse_button_text_color"
android:textSize="@dimen/pulse_message_text_size"
android:visibility="gone"
android:nextFocusUp="@id/pulse_ad_learn_more_view"
android:focusable="true"
tools:visibility="visible"/>
</RelativeLayout>