简介

原生广告是一种需要通过定制界面将广告素材进行展示的广告。以使这类广告与应用内容融于一体。
此Codelab将引导您在应用中增加原生广告的展示。在整个过程中,将介绍添加代码的详细过程以正确展示原生广告。

你将建立什么

您将构建一个展示原生广告的应用。您的应用将:

您将会学到什么

硬件要求

软件要求

在Android Studio中打开工作项目

  1. 打开Android Studio。
  2. 创建新项目,选择"Empty Activity",命名为NativeAdExample。
  3. 点击完成按钮。

配置HUAWEI Ads SDK仓库及依赖包

在项目级build.gradle文件中配置maven仓库路径,需添加下面内容:

buildscript { repositories { google() jcenter() maven { url 'http://developer.huawei.com/repo/' } } ... } allprojects { repositories { google() jcenter() maven {url 'http://developer.huawei.com/repo/'} } }

在应用级build.gradle文件中配置依赖包,需添加下面内容

dependencies { ... implementation 'com.huawei.hms:ads-lite:13.4.28.305' ... }

点击"Sync Now"等待同步完成。

配置混淆脚本

开发者编译APK前需要配置不要混淆HUAWEI Ads SDK,避免功能异常。

  1. 打开Android工程的混淆配置文件。
  2. 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初始化。
MainActivity.java

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提供了广告视图类NativeViewNativeView用于显示原生广告中所有的素材。SDK还提供了显示不同种类素材的视图,例如MediaView用于显示多媒体素材,这类视图应该被包含在NativeView中。
现在,您需要在NativeView中为各类广告素材视图进行布局。在此Codelab中,您将使用布局XML文件方式设置原生广告视图的布局。为了节省时间,您可以使用下面创建好的XML内容。
接下来,你需要在res/layout/目录下新增native_video_template.xml文件,并在文件中添加以下列出的XML内容。
native_video_template.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>

同时需要在res/drawable/目录下新增native_flag_rounded_corners_shape.xml文件,并在文件中添加以下列出的XML内容。
native_flag_rounded_corners_shape.xml

<?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>

同时需要在res/drawable/目录下新增文件native_button_rounded_corners_shape.xml,并在文件中添加以下列出的XML内容。
native_button_rounded_corners_shape.xml

<?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>

另外,需要在res/values/strings.xml中增加下面内容。
strings.xml

<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>

定义原生广告外层容器布局

此项目中需定义原生广告外层容器布局,用于控制和重新获取原生广告,请在res/layout/activity_main.xml中添加LinearLayout部分内容,添加完成后的XML内容如下所示。
activity_main.xml

<?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>

同时需要在res/values/目录中新增dimens.xml的文件,并在文件中添加以下列出的XML内容。
dimens.xml

<resources> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> </resources>

另外,需要在res/values/strings.xml中增加下面内容。
strings.xml

<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对象中。
MainActivity.java

... 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() { // If there is a video, load a new native ad only after video playback is complete. 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()中销毁原生广告对象。
MainActivity.java

... 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) { // Call this method when an ad is successfully loaded. updateStatus(getString(R.string.status_load_ad_success), true); // Display native ad. showNativeAd(nativeAd); nativeAd.setDislikeAdListener(new DislikeAdListener() { @Override public void onAdDisliked() { // Call this method when an ad is closed. updateStatus(getString(R.string.ad_is_closed), true); } }); } }).setAdListener(new AdListener() { @Override public void onAdFailed(int errorCode) { // Call this method when an ad fails to be loaded. updateStatus(getString(R.string.status_load_ad_fail) + errorCode, true); } }); NativeAdConfiguration adConfiguration = new NativeAdConfiguration.Builder() .setChoicesPosition(NativeAdConfiguration.ChoicesPosition.BOTTOM_RIGHT) // Set custom attributes. .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) { // Destroy the original native ad. if (null != globalNativeAd) { globalNativeAd.destroy(); } globalNativeAd = nativeAd; // Obtain NativeView. NativeView nativeView = (NativeView) getLayoutInflater().inflate(layoutId, null); // Register and populate a native ad material view. initNativeAdView(globalNativeAd, nativeView); // Add NativeView to the app UI. adScrollView.removeAllViews(); adScrollView.addView(nativeView); } ... @Override protected void onDestroy() { if (null != globalNativeAd) { globalNativeAd.destroy(); } super.onDestroy(); } }

运行项目后,您将会在应用中看到原生广告。

祝贺您,您已经成功完成了Codelab并学到了:

您可以阅读下面链接,了解更多相关的信息。

本Codelab中的demo源码下载地址如下:

源码下载

已复制代码