原生广告是与应用内容融于一体的广告,通过"和谐"的内容呈现广告信息,在不破坏用户体验的前提下,为用户提供有价值的信息,展示形式包含图片、文字和视频,支持您自由定制界面。
此codelab将引导您在应用中增加原生广告的展示。在整个过程中,将介绍添加代码的详细过程以正确展示原生广告。
您将在您的应用中通过HUAWEI Ads SDK定制原生广告样式、获取原生广告和展示原生广告。
支持EMUI 3.0及以上的华为手机、华为平板。
Android基础开发能力。
Android Studio的代码库配置在Gradle 插件7.0以下版本、7.0版本和7.1及以上版本有所不同。请根据您当前的Gradle 插件版本,选择对应的配置过程。
7.0以下版本 | 7.0版本 | 7.1及以上版本 |
7.0以下版本
i. 打开Android Studio项目级"build.gradle"文件。
ii. 添加Maven代码库。
buildscript {
repositories {
google()
jcenter()
// 配置HUAWEI Ads SDK的Maven仓地址
maven {url 'https://developer.huawei.com/repo/'}
}
}
allprojects {
repositories {
google()
jcenter()
// 配置HUAWEI Ads SDK的Maven仓地址
maven {url 'https://developer.huawei.com/repo/'}
}
}
7.0版本
i. 打开Android Studio项目级"build.gradle"文件。
ii. 添加Maven代码库。
在"buildscript > repositories"中配置Maven仓地址。
buildscript {
repositories {
google()
jcenter()
// 配置HUAWEI Ads SDK的Maven仓地址
maven {url 'https://developer.huawei.com/repo/'}
}
}
iii. 打开项目级"settings.gradle"文件,配置Maven仓地址。
dependencyResolutionManagement {
...
repositories {
google()
jcenter()
// 配置HUAWEI Ads SDK的Maven仓地址
maven {url 'https://developer.huawei.com/repo/'}
}
}
7.1及以上版本
打开项目级"settings.gradle"文件,配置Maven仓地址。
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
// 配置HUAWEI Ads SDK的Maven仓地址
maven { url 'https://developer.huawei.com/repo/' }
}
}
dependencyResolutionManagement {
...
repositories {
google()
mavenCentral()
// 配置HUAWEI Ads SDK的Maven仓地址
maven { url 'https://developer.huawei.com/repo/' }
}
}
dependencies {
...
implementation 'com.huawei.hms:ads-lite:{version}'
...
}
您编译APK前需要配置不要混淆HUAWEI Ads SDK,避免功能异常。
打开Android工程应用级根目录下的"app/proguard-rules.pro"混淆配置文件,添加如下两行代码,加入排除HUAWEI Ads SDK的混淆配置。
-keep class com.huawei.openalliance.ad.** { *; }
-keep class com.huawei.hms.ads.** { *; }
要借助于HUAWEI Ads SDK获取广告,必须先在您的应用中调用HwAds.init()方法初始化SDK ,此过程需要在应用程序启动时完成,在应用后续运行过程中无需重复执行此过程。
在MainActivity类的onCreate()方法中调用HwAds.init()以执行HUAWEI Ads SDK初始化。
import com.huawei.hms.ads.HwAds;
...
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化HUAWEI Ads SDK
HwAds.init(this);
...
}
...
}
对于原生广告,HUAWEI Ads SDK提供了广告视图类NativeView,NativeView用于显示原生广告中所有的素材。SDK还提供了显示不同种类素材的视图,例如MediaView用于显示多媒体素材,这类视图应该被包含在NativeView中。
现在,您需要在NativeView中为各类广告素材视图进行布局。在本章节中,您将使用布局XML文件方式设置原生广告视图的布局。为了节省时间,您可以使用下面创建好的XML内容。
<com.huawei.hms.ads.nativead.NativeView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/native_video_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#FFFFFF"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/background"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.huawei.hms.ads.nativead.MediaView
android:id="@+id/ad_media"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RelativeLayout
android:id="@+id/left_bottom_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/ad_media">
<TextView
android:id="@+id/ad_title"
android:layout_width="180dp"
android:layout_height="19dp"
android:layout_marginStart="24dp"
android:layout_marginTop="16dp"
android:alpha="1"
android:textColor="#000000"
android:textSize="@dimen/hiad_text_13_sp" />
<TextView
android:id="@+id/ad_source"
android:layout_width="wrap_content"
android:layout_height="19dp"
android:layout_below="@id/ad_title"
android:layout_marginStart="24dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="16dp"
android:alpha="0.6"
android:maxWidth="158dp"
android:textColor="#666666"
android:textSize="@dimen/hiad_text_12_sp" />
<TextView
android:id="@+id/ad_flag"
android:layout_width="20dp"
android:layout_height="14dp"
android:layout_marginStart="8dp"
android:layout_marginTop="40dp"
android:layout_toEndOf="@+id/ad_source"
android:background="@drawable/native_flag_rounded_corners_shape"
android:gravity="center"
android:text="@string/ad_flag"
android:textColor="#FFFFFF"
android:textSize="8sp"
android:textStyle="bold" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/right_bottom_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/ad_media"
android:layout_alignParentEnd="true">
<Button
android:id="@+id/ad_call_to_action"
android:layout_width="72dp"
android:layout_height="26dp"
android:layout_alignParentEnd="true"
android:layout_marginTop="23dp"
android:layout_marginEnd="52dp"
android:layout_marginBottom="23dp"
android:background="@drawable/native_button_rounded_corners_shape"
android:textColor="#FFFFFF"
android:textSize="10sp" />
</RelativeLayout>
</RelativeLayout>
</com.huawei.hms.ads.nativead.NativeView>
<?xml version="1.0" encoding="utf-8"?>
<com.huawei.hms.ads.nativead.NativeView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/native_small_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginTop="10dp"
android:background="#FFFFFF"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/background"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:orientation="vertical">
<com.huawei.hms.ads.nativead.MediaView
android:id="@+id/ad_media"
android:layout_width="75dp"
android:layout_height="50dp"
android:layout_marginStart="24dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="#8BC34A" />
<RelativeLayout
android:id="@+id/center_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="107dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="48dp"
android:layout_marginBottom="8dp"
android:background="#FFFFFF">
<TextView
android:id="@+id/ad_title"
android:layout_width="match_parent"
android:layout_height="34dp"
android:layout_marginBottom="16dp"
android:alpha="1"
android:textColor="#000000"
android:textSize="@dimen/hiad_text_13_sp" />
<TextView
android:id="@+id/ad_source"
android:layout_width="wrap_content"
android:layout_height="14dp"
android:layout_marginTop="36dp"
android:alpha="0.6"
android:maxWidth="132dp"
android:textColor="#666666"
android:textSize="@dimen/hiad_text_9_sp" />
<TextView
android:id="@+id/ad_flag"
android:layout_width="16dp"
android:layout_height="14dp"
android:layout_marginStart="8dp"
android:layout_marginTop="36dp"
android:layout_toEndOf="@+id/ad_source"
android:background="@drawable/native_flag_rounded_corners_shape"
android:gravity="center"
android:text="@string/ad_flag"
android:textColor="#FFFFFF"
android:textSize="8sp"
android:textStyle="bold" />
<Button
android:id="@+id/ad_call_to_action"
android:layout_width="44dp"
android:layout_height="@dimen/hiad_16_dp"
android:layout_alignParentEnd="true"
android:layout_marginTop="34dp"
android:background="@drawable/native_button_rounded_corners_shape"
android:textColor="#FFFFFF"
android:textSize="6sp" />
</RelativeLayout>
</RelativeLayout>
</com.huawei.hms.ads.nativead.NativeView>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#CCCCCC" />
<padding
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp" />
<corners
android:bottomLeftRadius="2dp"
android:bottomRightRadius="2dp"
android:topLeftRadius="2dp"
android:topRightRadius="2dp" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#214EF3" />
<padding
android:bottom="1dp"
android:left="1dp"
android:right="1dp"
android:top="1dp" />
<corners
android:bottomLeftRadius="20dp"
android:bottomRightRadius="20dp"
android:topLeftRadius="20dp"
android:topRightRadius="20dp" />
</shape>
<resources>
...
<string name="app_name">NativeAdExample</string>
<string name="ad_id_native">testu7m3hc4gvm</string>
<string name="ad_id_native_small">testb65czjivt9</string>
<string name="ad_id_native_video">testy63txaom86</string>
<string name="ad_flag">Ad</string>
...
</resources>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TextView
android:id="@+id/ad_display_form"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginTop="@dimen/activity_vertical_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:text="@string/display_form"
android:textColor="#000000"
android:textSize="@dimen/hiad_text_16_sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioGroup
android:id="@+id/radio_group_display_form"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin">
<RadioButton
android:id="@+id/radio_button_large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="@string/large" />
<RadioButton
android:id="@+id/radio_button_small"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/small" />
<RadioButton
android:id="@+id/radio_button_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/video" />
</RadioGroup>
<Button
android:id="@+id/btn_load"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/activity_horizontal_margin"
android:layout_marginRight="@dimen/activity_horizontal_margin"
android:text="@string/load_button_text" />
</LinearLayout>
<ScrollView
android:id="@+id/scroll_view_ad"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
<resources>
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>
<resources>
...
<string name="display_form">Display form:</string>
<string name="large">Large image with text.</string>
<string name="small">Small image with text.</string>
<string name="video">Video with text.</string>
<string name="load_button_text">LOAD AD</string>
<string name="status_ad_loading">Ad loading state: being loaded.</string>
<string name="status_load_ad_success">Ad loading state: loaded successfully.</string>
<string name="status_load_ad_fail">Ad loading state: failed to be loaded. Error code: </string>
<string name="status_play_start">Video playback state: starting to be played.</string>
<string name="status_playing">Video playback state: being played.</string>
<string name="status_play_end">Video playback state: playback completed.</string>
<string name="ad_is_closed">Ad is closed.</string>
...
</resources>
现在,您需要注册原生广告素材视图,并将原生广告中的素材填充到原生广告素材视图中。下面代码片段中的initNativeAdView()方法展示了这一过程。在完成广告视图填充后,您还需要通过setNativeAd()方法将NativeAd对象注册到原生广告视图NativeView对象中。
...
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.huawei.hms.ads.VideoOperator;
import com.huawei.hms.ads.nativead.MediaView;
import com.huawei.hms.ads.nativead.NativeAd;
import com.huawei.hms.ads.nativead.NativeView;
...
private VideoOperator.VideoLifecycleListener videoLifecycleListener = new VideoOperator.VideoLifecycleListener() {
@Override
public void onVideoStart() {
updateStatus(getString(R.string.status_play_start), false);
}
@Override
public void onVideoPlay() {
updateStatus(getString(R.string.status_playing), false);
}
@Override
public void onVideoEnd() {
// 如果有视频,需要等待视频播放完成后再加载新的原生广告
updateStatus(getString(R.string.status_play_end), true);
}
};
...
/**
* 注册并填充原生广告素材视图
*
* @param nativeAd 包含广告素材的原生广告对象
* @param nativeView 待填充的原生广告视图
*/
private void initNativeAdView(NativeAd nativeAd, NativeView nativeView) {
// 注册原生广告素材视图
nativeView.setTitleView(nativeView.findViewById(R.id.ad_title));
nativeView.setMediaView((MediaView) nativeView.findViewById(R.id.ad_media));
nativeView.setAdSourceView(nativeView.findViewById(R.id.ad_source));
nativeView.setCallToActionView(nativeView.findViewById(R.id.ad_call_to_action));
// 填充原生广告素材视图,原生广告中必有标题和媒体素材
((TextView) nativeView.getTitleView()).setText(nativeAd.getTitle());
nativeView.getMediaView().setMediaContent(nativeAd.getMediaContent());
if (null != nativeAd.getAdSource()) {
((TextView) nativeView.getAdSourceView()).setText(nativeAd.getAdSource());
}
nativeView.getAdSourceView().setVisibility(null != nativeAd.getAdSource() ? View.VISIBLE : View.INVISIBLE);
if (null != nativeAd.getCallToAction()) {
((Button) nativeView.getCallToActionView()).setText(nativeAd.getCallToAction());
}
nativeView.getCallToActionView().setVisibility(null != nativeAd.getCallToAction() ? View.VISIBLE : View.INVISIBLE);
// 获取视频控制器
VideoOperator videoOperator = nativeAd.getVideoOperator();
// 判断原生广告中是否包含视频素材
if (videoOperator.hasVideo()) {
// 添加视频生命周期事件监听器
videoOperator.setVideoLifecycleListener(videoLifecycleListener);
}
// 注册原生广告对象
nativeView.setNativeAd(nativeAd);
}
/**
* 更新提示信息和获取按钮的状态
*
* @param text 提示信息
* @param loadBtnEnabled 获取按钮的状态
*/
private void updateStatus(String text, boolean loadBtnEnabled) {
if (null != text) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
loadBtn.setEnabled(loadBtnEnabled);
}
...
您将使用NativeAdLoader类获取原生广告,该类还提供了NativeAdLoader.Builder类,可用于设置广告位ID、设置自定义选项和构建NativeAdLoader对象。
新增获取原生广告的loadAd()方法,将其作为刷新按钮的响应函数,并将其添加到MainActivity类的onCreate()方法中。一旦获取完成,则可调用initNativeAdView()将获取到的广告添加到对应的广告视图中。最后您需在onDestroy()中销毁原生广告对象。
...
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.RadioButton;
import android.widget.TextView;
import com.huawei.hms.ads.AdListener;
import com.huawei.hms.ads.AdParam;
import com.huawei.hms.ads.HwAds;
import com.huawei.hms.ads.nativead.DislikeAdListener;
import com.huawei.hms.ads.nativead.NativeAd;
import com.huawei.hms.ads.nativead.NativeAdConfiguration;
import com.huawei.hms.ads.nativead.NativeAdLoader;
import com.huawei.hms.ads.nativead.NativeView;
...
public class MainActivity extends AppCompatActivity {
private RadioButton small;
private RadioButton video;
private Button loadBtn;
private ScrollView adScrollView;
private int layoutId;
private NativeAd globalNativeAd;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化HUAWEI Ads SDK
HwAds.init(this);
small = findViewById(R.id.radio_button_small);
video = findViewById(R.id.radio_button_video);
loadBtn = findViewById(R.id.btn_load);
adScrollView = findViewById(R.id.scroll_view_ad);
loadBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
loadAd(getAdId());
}
});
loadAd(getAdId());
}
/**
* 初始化广告位ID和布局模板
*
* @return 广告位ID
*/
private String getAdId() {
String adId;
layoutId = R.layout.native_video_template;
if (small.isChecked()) {
adId = getString(R.string.ad_id_native_small);
layoutId = R.layout.native_small_template;
} else if (video.isChecked()) {
adId = getString(R.string.ad_id_native_video);
} else {
adId = getString(R.string.ad_id_native);
}
return adId;
}
/**
* 获取原生广告
*
* @param adId 广告位ID
*/
private void loadAd(String adId) {
updateStatus(null, false);
NativeAdLoader.Builder builder = new NativeAdLoader.Builder(this, adId);
builder.setNativeAdLoadedListener(new NativeAd.NativeAdLoadedListener() {
@Override
public void onNativeAdLoaded(NativeAd nativeAd) {
// 成功加载广告时调用此方法
updateStatus(getString(R.string.status_load_ad_success), true);
// 展示原生广告
showNativeAd(nativeAd);
nativeAd.setDislikeAdListener(new DislikeAdListener() {
@Override
public void onAdDisliked() {
// 关闭广告时调用此方法
updateStatus(getString(R.string.ad_is_closed), true);
}
});
}
}).setAdListener(new AdListener() {
@Override
public void onAdFailed(int errorCode) {
// 广告加载失败时调用此方法
updateStatus(getString(R.string.status_load_ad_fail) + errorCode, true);
}
});
NativeAdConfiguration adConfiguration = new NativeAdConfiguration.Builder()
// 设置自定义属性
.setChoicesPosition(NativeAdConfiguration.ChoicesPosition.BOTTOM_RIGHT)
.build();
NativeAdLoader nativeAdLoader = builder.setNativeAdOptions(adConfiguration).build();
nativeAdLoader.loadAd(new AdParam.Builder().build());
updateStatus(getString(R.string.status_ad_loading), false);
}
/**
* 展示原生广告
*
* @param nativeAd包含广告素材的原生广告对象
*/
private void showNativeAd(NativeAd nativeAd) {
// 摧毁原始的原生广告
if (null != globalNativeAd) {
globalNativeAd.destroy();
}
globalNativeAd = nativeAd;
// 创建NativeView
NativeView nativeView = (NativeView) getLayoutInflater().inflate(layoutId, null);
// 填充NativeView
initNativeAdView(globalNativeAd, nativeView);
// 添加广告到程序界面
adScrollView.removeAllViews();
adScrollView.addView(nativeView);
}
...
@Override
protected void onDestroy() {
if (null != globalNativeAd) {
globalNativeAd.destroy();
}
super.onDestroy();
}
}
运行项目后,您将会在应用中看到原生广告。
祝贺您,您已经成功完成了codelab并学到了: