前 言
对于个人开发者来说,独立开发一款基于网络App并且上线提供用户下载使用是需要花钱购买服务器的。而且当用户的并发量比较大时开发者所花费的维护应用的费用就越高,这时,个人开发者需要在应用里嵌入广告来进行盈利才能赚回维护应用使用的成本。而在Android开发领域,有Google的子公司AdMob的广告可以在Android系统里进行投放。不过国外的广告不是很适合国内的环境,而国内的腾讯广告联盟做的比较专业一点。那么,如何在Android应用里嵌入腾讯广告联盟进行盈利实现呢?
嵌入广告前准备
- 首先访问腾讯广告联盟(http://e.qq.com/dev/index.html)官网,并注册认证成为开发者。
- 新建媒体和广告位
当通过对个人信息审核后,开发者可以进入腾讯广告联盟的后台添加广告。首先开发者需要进入管理界面,然后点击新建媒体按钮,开发者就可以根据提示填写相应的信息。
填写完相应的信息然后点击“创建”按钮提交到腾讯广告联盟后台进行审核,一般审核时间在三个工作日左右。(注意:提交要嵌入广告的应用的必须是以及在应用商店已上线的应用,否则腾讯广告联盟那边审核时不给通过的)
审核通过后,在媒体管理界面查看新建媒体的状态。首先要输入广告位的名称,然后选择广告位的类型。腾讯广告联盟支持原生广告、Banner广告、开屏广告和插屏广告这四种广告类型,具体每种广告类型的区别开发者以及查看广告联盟那边给的开发文档说明。
然后开发者进入广告位管理界面,我们这里新建开屏广告和Banner广告位。其中,开发者需要把应用ID和广告位ID记住,到时候在Android项目里会用到的。
广告位SDK嵌入
- 步骤1:添加SDK到工程中
请在工程文件根目录下创建一个名为 libs 的子目录,并将广点通 SDK 的 JAR 包拷贝到 libs 目录下。 - 步骤2: 修改AndroidManifest.xml文件
添加权限声明:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- 如果需要精确定位的话请加上此权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
接入任意广告(Banner、开屏、插屏、原生)都需要在XML中添加以下声明:
<service android:name="com.qq.e.comm.DownloadService" android:exported="false" />
<activity android:name="com.qq.e.ads.ADActivity" android:configChanges="keyboard|keyboardHidden|orientation|screenSize" />
目前支持的SDK版本,最低到API 9(即Android 2.3):
如果您打包App时的targetSdkVersion >= 23:请在先获取到SDK要求的所有权限,然后再调用SDK的广告接口。否则广点通SDK将无法工作,我们建议您在App启动时就去获取广点通SDK需要的权限,GDTUnionDemo工程中的SplashActivity也提供了基本的权限处理示例代码供开发者参考。
如果您打包App时的targetSdkVersion >= 24:除了需要处理好权限申请以外,还需要处理好文件访问的兼容性,详细说明见本文档第6章的注意事项。
在Android项目代码接入广告位的代码
- 开屏广告接入代码示例
(详细内容请参考压缩包中的代码示例)
public class SplashActivity extends Activity implements SplashADListener {
private SplashAD splashAD;
private ViewGroup container;
private TextView skipView;
private ImageView splashHolder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
container = (ViewGroup) this.findViewById(R.id.splash_container);
skipView = (TextView) findViewById(R.id.skip_view);
fetchSplashAD(this, container, skipView, Constants.APPID, Constants.SplashPosID, this, 0);
}
/**
* 拉取开屏广告,开屏广告的构造方法有3种,详细说明请参考开发者文档。
* * @param activity 展示广告的activity
* @param adContainer 展示广告的大容器
* @param skipContainer 自定义的跳过按钮:传入该view给SDK后,SDK会自动给它绑定点击跳过事件。SkipView的样式可以由开发者自由定制,其尺寸限制请参考activity_splash.xml或下面的注意事项。
* @param appId 应用ID
* @param posId 广告位ID
* @param adListener 广告状态监听器
* @param fetchDelay 拉取广告的超时时长:即开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长)取值范围[3000, 5000],设为0表示使用广点通SDK默认的超时时长。
*/
private void fetchSplashAD(Activity activity, ViewGroup adContainer, View skipContainer,
String appId, String posId, SplashADListener adListener, int fetchDelay) {
splashAD = new SplashAD(activity, adContainer, skipContainer, appId, posId, adListener, fetchDelay);
}
@Override
public void onADPresent() {
Log.i("AD_DEMO", "SplashADPresent");
splashHolder.setVisibility(View.INVISIBLE); // 广告展示后一定要把预设的开屏图片隐藏起来
}
@Override
public void onAdDismissed() {
Log.i("AD_DEMO", "SplashADDismissed");
next();
}
private void next() {
this.startActivity(new Intent(this, DemoListActivity.class));
//防止用户回退看到此页面
this.finish();
}
@Override
public void onNoAD(AdError error) {
Log.i("AD_DEMO", String.format("LoadSplashADFail, eCode=%d, errorMsg=%s", error.getErrorCode(), error.getErrorMsg()));
/** 如果加载广告失败,则直接跳转 */
this.startActivity(new Intent(this, DemoListActivity.class));
this.finish();
}
@Override
public void onADClicked() {
Log.i("AD_DEMO", "SplashADClicked");
}
/**
* 倒计时回调,返回广告还将被展示的剩余时间。
* 通过这个接口,开发者可以自行决定是否显示倒计时提示,或者还剩几秒的时候显示倒计时
* * @param millisUntilFinished 剩余毫秒数
*/
@Override
public void onADTick(long millisUntilFinished) {
Log.i("AD_DEMO", "SplashADTick " + millisUntilFinished + "ms");
skipView.setText(String.format(SKIP_TEXT, Math.round(millisUntilFinished / 1000f)));
}
//防止用户返回键退出APP
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME) {
return true;
}
return super.onKeyDown(keyCode, event);
}
}
开屏广告主要API
com.qq.e.ads.splash.SplashAD:
方法名 | 方法介绍 |
---|---|
SplashAD(Activity activity, ViewGroup adContainer, String appId, String posId,SplashADListener adListener) | 构造方法,调用后开屏广告会尝试加载广告,并将广告内容填充到adContainer参数指向的ViewGroup,该ViewGroup原有的内容会被清空。广告相关状态会通过adListener通知开发者。参数说明:activity(展示广告的activity)、adContainer(展示广告的大容器)、appId(应用ID)、posId(广告位ID)、adListener(广告状态监听器)。 |
SplashAD(Activity activity, ViewGroup adContainer, String appId, String posId,SplashADListener adListener, int fetchDelay) | 构造方法,这个方法可以通过传入fetchDelay参数,设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),取值范围为[3000, 5000]ms。如果需要使用默认值,可以调用上一个构造方法,或者给fetchDelay设为0。 |
SplashAD(Activity activity, ViewGroup adContainer, View skipContainer, String appId, String posId,SplashADListener adListener, int fetchDelay) | 构造方法,这个方法可以通过传入传入skipContainer参数,支持开发者自定义的跳过按钮。SDK要求skipContainer一定在传入后要处于VISIBLE状态,且其宽高都不得小于3x3dp。如果需要使用SDK默认的跳过按钮,可以选择上面两个构造方法。 |
com.qq.e.ads.splash.SplashADListener:
开屏广告回调接口
方法名 | 方法介绍 |
---|---|
onNoAD(AdError error) | 广告加载失败,error对象包含了错误码和错误信息 |
onADDismissed() | 广告关闭时调用,可能是用户关闭或者展示时间到。此时一般需要跳过开屏的Activity,进入应用内容页面 |
onADPresent() | 广告成功展示时调用,成功展示不等于满足计费条件(如展示时长尚未满足) |
onADClicked() | 广告被点击时调用,不代表满足计费条件(如点击时网络异常) |
onADTick(long millisUntilFinished) | 倒计时回调,返回广告还将被展示的剩余时间,单位是ms |
接入注意事项
1.开屏广告支持开发者自定义跳过View的样式,但要求开发者传入的跳过按钮参数skipContainer必须处于可见状态,且宽高都要大于等于3x3dp,注意sdk会处理skipContainer的点击事件,开发者不可以对其绑定OnClickListener。具体接入代码请参考GDTUnionDemo工程里面的SplashActivity代码及其相关xml文件。
2.开屏广告支持回调广告展示的倒计时,开发者可以根据自己的需求设计倒计时View的样式,并可以决定什么时机显示倒计时。
- Banner广告接入代码示例
(详细内容请参考压缩包中的代码示例)
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RelativeLayout l = (RelativeLayout)findViewById(R.id.adcontent);
// 创建Banner广告AdView对象
// appId : 在 http://e.qq.com/dev/ 能看到的app唯一字符串
// posId : 在 http://e.qq.com/dev/ 生成的数字串,并非 appid 或者 appkey
BannerView banner = new BannerView(this, ADSize.BANNER, Constants.APPID, Constants.BannerPosID);
//设置广告轮播时间,为0或30~120之间的数字,单位为s,0标识不自动轮播
banner.setRefresh(30);
banner.setAdListener(new AbstractBannerADListener() {
@Override
public void onNoAD(AdError error) {
Log.i("AD_DEMO", "BannerNoAD,eCode=" + error.getErrorCode());
}
@Override
public void onADReceiv() {
Log.i("AD_DEMO", "ONBannerReceive");
}
});
/* 发起广告请求,收到广告数据后会展示数据 */
adv.loadAD();
}
}
Banner广告主要API
com.qq.e.ads.banner.BannerView:
BannerView继承自Android View类,需要容器提供50dp的高度用于展示Banner广告,宽度Banner广告会自适应,但要求不少于300dp。
方法名 | 方法介绍 |
---|---|
BannerView(Activity act, ADSize adSize,String APPID,String PosID) | 构造函数 |
setRefresh(int refresh) | 设置刷新频率,为0或30~120之间的数字,单位为s,0标识不自动轮播,默认30S |
setADListener(BannerADListener adListener) | 设置状态回调函数 |
setShowClose(boolean showClose) | 设置是否展示关闭按钮,默认不展示 |
loadAD() | 加载广告 |
destroy() | 当不需要展示Banner时用于主动释放Banner广告资源,调用后实例销毁,不可以再调用 |
com.qq.e.ads.banner.BannerADListener:
Banner广告回调接口,对于大部分开发者只需要关注其中少量的方法,可以继承抽象类AbstractBannerADListener。
方法名 | 方法介绍 |
---|---|
onADReceiv() | 广告加载成功回调,表示广告相关的资源已经加载完毕,Ready To Show |
onNoAD(AdError error) | 广告加载失败,error对象包含了错误码和错误信息 |
onADExposure() | 当广告曝光时发起的回调 |
onADClicked() | 当广告点击时发起的回调,由于点击去重等原因可能和联盟平台最终的统计数据有差异 |
onADClosed() | 当广告关闭时调用,只有在使用了Banner广告自身的关闭按钮时生效 |
onADOpenOverlay() | 当广告打开浮层时调用,如打开内置浏览器、内容展示浮层,一般发生在点击之后 |
onADCloseOverlay() | 浮层关闭时调用 |
onADLeftApplication() | 由于广告点击离开APP时调用 |
com.qq.e.ads.banner.ADSize:
广告尺寸枚举,目前只有一个值Banner
com.qq.e.ads.banner.AbstractBannerADListener:
广告状态回调接口的抽象类,实现了大部分普通开发者无需关心的方法
- 注意事项
targetSDKVersion >= 24时的文件访问兼容处理 如果您打包时的targetSDKVersion >= 24,为了让SDK能够正常下载、安装App类广告,必须按照下面的三个步骤做兼容性处理。注意:如果您的targetSDKVersion < 24,不需要做这个兼容处理。
(1)在AndroidManifest.xml中的Application标签中添加provider标签,接入代码如下所示:
<application
android:allowBackup="true"
android:icon="@drawable/gdticon"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<!-- targetSDKVersion >= 24时才需要添加这个provider。provider的authorities属性的值为${applicationId}.fileprovider,请开发者根据自己的${applicationId}来设置这个值 -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/gdt_file_path" />
</provider>
<!-- 声明SDK所需要的组件 -->
<service
android:name="com.qq.e.comm.DownloadService"
android:exported="false"/>
<!-- 请开发者注意字母的大小写,ADActivity,而不是AdActivity -->
<activity
android:name="com.qq.e.ads.ADActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"/>
... ...
</application>
需要注意的是provider的authorities值为{applicationId}.fileprovider,对于每一个开发者而言,这个值都是不同的,{applicationId}在代码中和Context.getPackageName()值相等,是应用的唯一id。例如GDTUnionDemo示例工程中的applicationId为"com.qq.e.union.demo"。
(2)在项目结构下的res目录下添加一个xml文件夹,再新建一个gdt_file_path.xml的文件,文件内容如下:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 这个下载路径不可以修改,必须是GDTDOWNLOAD -->
<external-path name="gdt_sdk_download_path" path="GDTDOWNLOAD" />
</paths>
项目运行截图
开屏广告
Banner广告
———————— The end ————————
如果您觉得这篇博客写的比较好的话,赞赏一杯咖啡吧~~