Unity接入原生Android穿山甲广告
最近要接入穿山甲广告,我把穿山甲广告相关的接入流程记录一下,说说最近踩过的坑,和怎么解决的问题。穿山甲Android原生广告我接入了激励视频广告,开屏广告,Banner广告,和插屏广告,我会在下文中按照顺序一个一个的讲,文章会分2篇来讲,这一篇会讲使用Android原生接入相关流程,下一篇会讲使用unity插件的接入流程。(帖子是2019年底写的最近才发有问题可以留言或者看官方文档)
- 接入之前的准备工作
(1)、创建穿山甲平台账号账号成功之后创建自己的应用
(2)、申请代码位
这里解释一下,广告的大小是在后台设置的入banner广告和开屏广告都是可以设置大小和比例的,视频广告需要设置横屏或者竖屏。
(3)、去穿山甲官网下载穿山甲Unity插件,插件地址:
https://partner.oceanengine.com/union/media/union/download
下载完成之后是一个压缩包。打开之后包含的内容如下。
- 广告接入
(1)Unity导出Android工程具体导出如下图,这个安卓工程可以自己创建一个安卓工程或者是直接用unity导出,我自己用的是自己创建的,然后把unity的classes.jar拷贝到工程的libs里用的。后边使用的时候是通过导出一个aar放到unity中使用的。下图是unity导出安卓工程。
(2)之后用androidStudio打开工程将上图说的要用到的opne_ad_sdk.aar和在示例工程里找到的android-gif-drawable-1.2.6.aar一起导入到项目的libs文件夹下。
(3)然后找到项目中的androidManifest.xml文件,然后在文件中添加广告需要的权限。如下图
(4)如果您的应用需要适配Anroid7.0及以上,请在AndroidManifest中添加如下代码
(5)然后在找到工程的res/xml目录下,新建一个xml文件file_paths,在该文件中添加如下代码,或者直接拷贝官方提供的示例项目中的xml,如果没有xml文件夹那么需要新建文件夹。然后在创建文件。
创建好之后在文件中添加如下内容
(6)provider配置,单线程或者多线程的环境下都要配置,到此AndroidManifest中的配置就完成了
下面贴出完整的配置
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yx.yxsdk.androidsdk" >
<!--读取手机状态权限-->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--写入外部存储权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.GET_TASKS"/>
<!--最好能提供的权限-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application android:usesCleartextTraffic="true">
<uses-library android:name="org.apache.http.legacy" android:required="false" />
<!--禁止权限弹窗-->
<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />
<!-- apk安装 -->
<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/provider_paths" />
</provider>
<!-- 适配 Android7.0 及以上 -->
<provider
android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
android:authorities="${applicationId}.TTFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<!-- 单进程或多进程都必现配置 -->
<provider
android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
android:authorities="${applicationId}.TTMultiProvider"
android:exported="false" />
</application>
</manifest>
(7)找到项目中的Module中的 build.gradle 文件,添加内容如下。
我的是这样的,
请注意compileOnly fileTree和implementation fileTree的区别,这俩的的意思是将我libs下的aar和jar文件进行编译。详细介绍如下图。
(8)初始化广告脚本
在自己的导出的工程的包路径下创建初始化广告脚本TTAaManagerHolder.java。该脚本需要在onCreate()或者unity调用java脚本的初始化时调用。
然后在脚本中增加以下内容,其中TTAdConfig中的参数配置可以参考官方文档,其中有必填参数和可选参数的介绍。参考链接:
配置好初始化广告SDK的脚本之后然后在unity调用的脚本中初始化广告的init方法。或者是继承UnityPlayerActivity的MainActivity.java脚本中的onCreate()方法中调用。
完整脚本如下
package com.yx.yxsdk;
import com.bytedance.sdk.openadsdk.TTAdManager;
import android.content.Context;
import com.bytedance.sdk.openadsdk.TTAdConfig;
import com.bytedance.sdk.openadsdk.TTAdConstant;
import com.bytedance.sdk.openadsdk.TTAdSdk;
/**
* 可以用一个单例来保存 TTAdManager 实例,在需要初始化 sdk 的时候调用
*/
public class TTAdManagerHolder {
private static boolean sInit;
public static TTAdManager get() {
if (!sInit) {
throw new RuntimeException("TTAdSdk is not init, please check.");
}
return TTAdSdk.getAdManager();
}
public static void init(Context context) {
doInit(context);
}
//step1:接入网盟广告sdk的初始化操作,详情见接入文档和穿山甲平台说明
private static void doInit(Context context) {
if (!sInit) {
TTAdSdk.init(context, buildConfig(context));
sInit = true;
}
}
private static TTAdConfig buildConfig(Context context) {
//测试 5001121
return new TTAdConfig.Builder()
.appId("5001121")
.useTextureView(true) //使用TextureView控件播放视频,默认为SurfaceView,当有SurfaceView冲突的场景,可以使用TextureView
.appName("接入穿山甲广告测试")
.titleBarTheme(TTAdConstant.TITLE_BAR_THEME_DARK)
.allowShowNotify(true) //是否允许sdk展示通知栏提示
.allowShowPageWhenScreenLock(true) //是否在锁屏场景支持展示广告落地页
.debug(true) //测试阶段打开,可以通过日志排查问题,上线时去除该调用
.directDownloadNetworkType(TTAdConstant.NETWORK_STATE_WIFI, TTAdConstant.NETWORK_STATE_3G) //允许直接下载的网络状态集合
.supportMultiProcess(false)
.build();
}
}
下图是我调用SDK初始化的方法。和在c#中怎么调用的方法。
上图的UAMain脚本就是初始化广告的脚本。
(9)上边内容全部准备好之后就正式开始写广告逻辑,我会以激励视频广告,插页广告,banner广告和开屏广告的顺序来讲。先说视频广告。
1.创建视频广告
在包路径下创建RewardVideoAD脚本。如图:
下面是激励视频的完整内容
package com.yx.yxsdk.activity;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import com.yx.yxsdk.TTAdManagerHolder;
import com.yx.yxsdk.UAMain;
import com.unity3d.player.UnityPlayer;
import com.bytedance.sdk.openadsdk.AdSlot;
import com.bytedance.sdk.openadsdk.TTAdConstant;
import com.bytedance.sdk.openadsdk.TTAdManager;
import com.bytedance.sdk.openadsdk.TTAdNative;
import com.bytedance.sdk.openadsdk.TTAppDownloadListener;
import com.bytedance.sdk.openadsdk.TTRewardVideoAd;
import android.widget.Toast;
/**
* 穿山甲视频广告
*/
public class RewardVideoAD {
private Activity mActivity = null;
private Context mContext = null;
//广告接口持有者
private TTAdNative mTTAdNative;
//视频播放持有者
private com.bytedance.sdk.openadsdk.TTRewardVideoAd mttRewardVideoAd;
//是否加载完成
private boolean mHasShowDownloadActive = false;
public void init(Activity activity, Context context) {
mActivity = activity;
mContext = context;
// 要不然会显示 Android 的默认布局文件
//setContentView(R.layout.activity_main);
//初始化SDK
initAdSDK();
}
public void initAdSDK() {
//step1:初始化sdk
TTAdManager ttAdManager = TTAdManagerHolder.get();
//step2:(可选,强烈建议在合适的时机调用):申请部分权限,如read_phone_state,防止获取不了imei时候,下载类广告没有填充的问题。
TTAdManagerHolder.get().requestPermissionIfNecessary(mContext);
//step3:创建 TTAdNative 对象,用于调用广告请求接口
mTTAdNative = ttAdManager.createAdNative(mActivity.getApplicationContext());
}
// 加载(缓存)横屏广告//901121430
public void LoadHorizontalAD(String codeId) {
loadAd(codeId, TTAdConstant.HORIZONTAL);
}
// 加载(缓存)竖屏广告//901121365
public void LoadVerticalAD(String codeId) {
loadAd(codeId, TTAdConstant.VERTICAL);
}
// 加载(视频广告)完成,显示广告内容
public void ShowVedio() {
//在Android的UI线程显示
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (mttRewardVideoAd != null) {
//step6:在获取到广告后展示
TToast(mActivity, "加载成功显示");
mttRewardVideoAd.showRewardVideoAd(mActivity);
TToast(mActivity, "显示调用完成");
mttRewardVideoAd = null;
} else {
TToast(mActivity, "请先加载广告");
}
}
});
}
// TToast显示信息
public void TToast(final Context context, final String msg) {
//在Android的UI线程显示
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
});
}
// 配置广告配置,请求广告
private void loadAd(String codeId, int orientation) {
//step4:创建广告请求参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setCodeId(codeId)
.setSupportDeepLink(true)
.setImageAcceptedSize(1080, 1920)
.setRewardName("金币") //奖励的名称
.setRewardAmount(3) //奖励的数量
.setUserID("15592")//用户id,必传参数
.setMediaExtra("media_extra") //附加参数,可选
.setOrientation(orientation) //必填参数,期望视频的播放方向:TTAdConstant.HORIZONTAL 或 TTAdConstant.VERTICAL
.build();
//step5:请求广告
mTTAdNative.loadRewardVideoAd(adSlot, new TTAdNative.RewardVideoAdListener() {
@Override
public void onError(int code, String message) {
TToast(mActivity, message);
}
//视频广告加载后,视频资源缓存到本地的回调,在此回调后,播放本地视频,流畅不阻塞。
@Override
public void onRewardVideoCached() {
TToast(mActivity, "rewardVideoAd video cached");
}
//视频广告的素材加载完毕,比如视频url等,在此回调后,可以播放在线视频,网络不好可能出现加载缓冲,影响体验。
@Override
public void onRewardVideoAdLoad(com.bytedance.sdk.openadsdk.TTRewardVideoAd ad) {
TToast(mActivity, "rewardVideoAd loaded");
mttRewardVideoAd = ad;
// mttRewardVideoAd.setShowDownLoadBar(false);
mttRewardVideoAd.setRewardAdInteractionListener(new com.bytedance.sdk.openadsdk.TTRewardVideoAd.RewardAdInteractionListener() {
@Override
public void onAdShow() {
TToast(mActivity, "rewardVideoAd show");
}
@Override
public void onAdVideoBarClick() {
TToast(mActivity, "rewardVideoAd bar click");
}
@Override
public void onAdClose() {
TToast(mActivity, "rewardVideoAd close");
}
//视频播放完成回调
@Override
public void onVideoComplete() {
TToast(mActivity, "rewardVideoAd complete");
UAMain.callUnity("AndroidSDKListener","VideoComplete","");
}
@Override
public void onVideoError() {
TToast(mActivity, "rewardVideoAd error");
UAMain.callUnity("AndroidSDKListener","VideoError","");
}
//视频播放完成后,奖励验证回调,rewardVerify:是否有效,rewardAmount:奖励梳理,rewardName:奖励名称
@Override
public void onRewardVerify(boolean rewardVerify, int rewardAmount, String rewardName) {
TToast(mActivity, "verify:" + rewardVerify + " amount:" + rewardAmount +
" name:" + rewardName);
}
//跳过视频
@Override
public void onSkippedVideo() {
UAMain.callUnity("AndroidSDKListener","SkippedVideo","");
}
});
mttRewardVideoAd.setDownloadListener(new TTAppDownloadListener() {
@Override
public void onIdle() {
mHasShowDownloadActive = false;
}
@Override
public void onDownloadActive(long totalBytes, long currBytes, String fileName, String appName) {
if (!mHasShowDownloadActive) {
mHasShowDownloadActive = true;
TToast(mActivity, "下载中,点击下载区域暂停");
}
}
@Override
public void onDownloadPaused(long totalBytes, long currBytes, String fileName, String appName) {
TToast(mActivity, "下载暂停,点击下载区域继续");
}
@Override
public void onDownloadFailed(long totalBytes, long currBytes, String fileName, String appName) {
TToast(mActivity, "下载失败,点击下载区域重新下载");
}
@Override
public void onDownloadFinished(long totalBytes, String fileName, String appName) {
TToast(mActivity, "下载完成,点击下载区域重新下载");
}
@Override
public void onInstalled(String fileName, String appName) {
TToast(mActivity, "安装完成,点击下载区域打开");
}
});
}
});
}
}
2.创建插页广告
在包路径下创建InteractionExpressAD脚本。
如图:
下面是插页广告的完整内容
package com.yx.yxsdk.activity;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import com.bytedance.sdk.openadsdk.AdSlot;
import com.bytedance.sdk.openadsdk.TTAdConstant;
import com.bytedance.sdk.openadsdk.TTAdDislike;
import com.bytedance.sdk.openadsdk.TTAdNative;
import com.bytedance.sdk.openadsdk.TTAppDownloadListener;
import com.bytedance.sdk.openadsdk.TTNativeExpressAd;
import com.yx.yxsdk.TTAdManagerHolder;
import com.yx.yxsdk.UAMain;
import java.util.List;
/**
* 模板插屏广告
*/
public class InteractionExpressAD {
private TTAdNative mTTAdNative;
private TTAdDislike mTTAdDislike;
private TTNativeExpressAd mTTAd;
private Activity mActivity = null;
private Context mContext = null;
private EditText mEtWidth;
private EditText mEtHeight;
// TToast显示信息
public void TToast(final Context context, final String msg) {
//在Android的UI线程显示
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
});
}
//初始化
public void init(Activity activity, Context context) {
mActivity = activity;
mContext = context;
if(mActivity == null || context == null){
UAMain.unityLog("插屏广告初始化时mActivity或者context为空");
return;
}
InteractionExpressAD();
}
/**
* 初始模板插屏广告
*/
public void InteractionExpressAD() {
//step2:创建TTAdNative对象,createAdNative(Context context) banner广告context需要传入Activity对象
mTTAdNative = TTAdManagerHolder.get().createAdNative(mActivity);
//step3:(可选,强烈建议在合适的时机调用):申请部分权限,如read_phone_state,防止获取不了imei时候,下载类广告没有填充的问题。
TTAdManagerHolder.get().requestPermissionIfNecessary(mActivity);
}
public void loadExpressAd(String codeId) {
float expressViewWidth = 350;
float expressViewHeight = 350;
try{
expressViewWidth = Float.parseFloat(mEtWidth.getText().toString());
expressViewHeight = Float.parseFloat(mEtHeight.getText().toString());
}catch (Exception e){
expressViewHeight = 0; //高度设置为0,则高度会自适应
}
//step4:创建广告请求参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setCodeId(codeId) //广告位id
.setSupportDeepLink(true)
.setAdCount(1) //请求广告数量为1到3条
.setExpressViewAcceptedSize(expressViewWidth,expressViewHeight) //期望模板广告view的size,单位dp
.setImageAcceptedSize(640,320 )//这个参数设置即可,不影响模板广告的size
.build();
//step5:请求广告,对请求回调的广告作渲染处理
mTTAdNative.loadInteractionExpressAd(adSlot, new TTAdNative.NativeExpressAdListener() {
@Override
public void onError(int code, String message) {
TToast(mActivity, "load error : " + code + ", " + message);
}
@Override
public void onNativeExpressAdLoad(List<TTNativeExpressAd> ads) {
if (ads == null || ads.size() == 0){
return;
}
mTTAd = ads.get(0);
bindAdListener(mTTAd);
startTime = System.currentTimeMillis();
mTTAd.render();
}
});
}
private long startTime = 0;
private boolean mHasShowDownloadActive = false;
private void bindAdListener(TTNativeExpressAd ad) {
ad.setExpressInteractionListener(new TTNativeExpressAd.AdInteractionListener() {
@Override
public void onAdDismiss() {
TToast(mActivity, "广告关闭");
UAMain.callUnity("AndroidSDKListener","CloseInteractionExpressAD","True");
}
@Override
public void onAdClicked(View view, int type) {
TToast(mActivity, "广告被点击");
}
@Override
public void onAdShow(View view, int type) {
TToast(mActivity, "广告展示");
}
@Override
public void onRenderFail(View view, String msg, int code) {
Log.e("ExpressView","render fail:"+(System.currentTimeMillis() - startTime));
TToast(mActivity, msg+" code:"+code);
}
@Override
public void onRenderSuccess(View view, float width, float height) {
Log.e("ExpressView","render suc:"+(System.currentTimeMillis() - startTime));
//返回view的宽高 单位 dp
TToast(mActivity, "渲染成功");
mTTAd.showInteractionExpressAd(mActivity);
}
});
if (ad.getInteractionType() != TTAdConstant.INTERACTION_TYPE_DOWNLOAD){
return;
}
ad.setDownloadListener(new TTAppDownloadListener() {
@Override
public void onIdle() {
TToast(mActivity, "点击开始下载");
}
@Override
public void onDownloadActive(long totalBytes, long currBytes, String fileName, String appName) {
if (!mHasShowDownloadActive) {
mHasShowDownloadActive = true;
TToast(mActivity, "下载中,点击暂停 Toast.LENGTH_LONG");
}
}
@Override
public void onDownloadPaused(long totalBytes, long currBytes, String fileName, String appName) {
TToast(mActivity, "下载暂停,点击继续 Toast.LENGTH_LONG");
}
@Override
public void onDownloadFailed(long totalBytes, long currBytes, String fileName, String appName) {
TToast(mActivity, "下载失败,点击重新下载 Toast.LENGTH_LONG");
}
@Override
public void onInstalled(String fileName, String appName) {
TToast(mActivity, "安装完成,点击图片打开, Toast.LENGTH_LONG");
}
@Override
public void onDownloadFinished(long totalBytes, String fileName, String appName) {
TToast(mActivity, "点击安装, Toast.LENGTH_LON");
}
});
}
public void onDestroy() {
if (mTTAd != null) {
mTTAd.destroy();
}
}
}
3.创建Banner广告
在包路径下创建BannerExpress脚本。
如图:
Banner广告比较特殊,需要显示到界面上都需要一个显示用的载体,这就需要用到上边说到的C#传到java中的unityPlayer类了
然后在安卓工程的res目录下的layout目录中添加activity_native_express.xml
xml中内容如下
<?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/express_container"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
这一句代码的意思是将布局添加到底部的位置。
这个是一个相对布局是用来显示在unity的activity上的,如果使用官方案例中使setContentView(R.layout.activity_native_express);这方法去创建一个view那么你最后是会显示banner但是你游戏的画面就不会显示了,除了banner其他地方都是黑屏。所以我们需要创建一个相对布局将这个相对布局添加到unity的布局上来显示广告。通过下图的方法将布局添加到unity的Activity布局上。
下面是Banner广告的完整内容
package com.yx.yxsdk.activity;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.bytedance.sdk.openadsdk.AdSlot;
import com.bytedance.sdk.openadsdk.TTAdConstant;
import com.bytedance.sdk.openadsdk.TTAdDislike;
import com.bytedance.sdk.openadsdk.TTAdNative;
import com.bytedance.sdk.openadsdk.TTAppDownloadListener;
import com.bytedance.sdk.openadsdk.TTNativeExpressAd;
import com.yx.yxsdk.TTAdManagerHolder;
import com.yx.yxsdk.UAMain;
import com.yx.yxsdk.androidsdk.R;
import com.unity3d.player.UnityPlayer;
import java.util.List;
/**
* Banner广告
*/
public class BannerExpress {
private TTAdNative mTTAdNative;
private TTNativeExpressAd mTTAd;
private Activity mActivity = null;
private Context mContext = null;
private EditText mEtWidth;
private EditText mEtHeight;
// private FrameLayout mExpressContainer;
private RelativeLayout mExpressContainer;
private FrameLayout mFrameLayout;
private UnityPlayer mUnityPlayer;
// TToast显示信息
public void TToast(final Context context, final String msg) {
//在Android的UI线程显示
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
});
}
//初始化
public void init(Activity activity, Context context ,UnityPlayer unityPlayer) {
mActivity = activity;
mContext = context;
mUnityPlayer = unityPlayer;
if(mActivity == null || context == null || unityPlayer == null){
UAMain.unityLog("插屏广告初始化时mActivity或者context和unityPlayer为空");
return;
}
//原生的view直接添加到Unity的view内
//R代表你是哪个包名的R文件,然后把创建好的view嵌入在Unity view里,不要使用setContentView(R.layout.activity_native_express)
mActivity.runOnUiThread(new Runnable() {
public void run() {
View layout = LayoutInflater.from(mActivity).inflate(R.layout.activity_native_express, null);
mUnityPlayer.addView(layout);
mExpressContainer = (RelativeLayout)mActivity.findViewById(R.id.express_container);
//mFrameLayout =(FrameLayout)mFrameLayout.findViewById(UnityPlayer.generateViewId());
if(mExpressContainer==null){
UAMain.unityLog("mExpressContainer的数据为空");
}
else {
UAMain.unityLog("mExpressContainer的数据不为空");
}
//初始化Banner广告
BannerExpress();
}
});
}
/**
* Banner广告
*/
public void BannerExpress() {
UAMain.unityLog("初始化banner广告");
mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
//step2:创建TTAdNative对象,createAdNative(Context context) banner广告context需要传入Activity对象
mTTAdNative = TTAdManagerHolder.get().createAdNative(mActivity);
//step3:(可选,强烈建议在合适的时机调用):申请部分权限,如read_phone_state,防止获取不了imei时候,下载类广告没有填充的问题。
TTAdManagerHolder.get().requestPermissionIfNecessary(mActivity);
}
public void loadExpressAd(String codeId) {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
//显示
//mExpressContainer.removeAllViews();
mExpressContainer.setVisibility(View.VISIBLE);
}
});
float expressViewWidth = 350;
float expressViewHeight = 350;
try{
expressViewWidth = Float.parseFloat(mEtWidth.getText().toString());
expressViewHeight = Float.parseFloat(mEtHeight.getText().toString());
}catch (Exception e){
expressViewHeight = 0; //高度设置为0,则高度会自适应
}
//step4:创建广告请求参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setCodeId(codeId) //广告位id
.setSupportDeepLink(true)
.setAdCount(1) //请求广告数量为1到3条
.setExpressViewAcceptedSize(expressViewWidth,expressViewHeight) //期望模板广告view的size,单位dp
.setImageAcceptedSize(640,320 )//这个参数设置即可,不影响模板广告的size
.build();
//step5:请求广告,对请求回调的广告作渲染处理
mTTAdNative.loadBannerExpressAd(adSlot, new TTAdNative.NativeExpressAdListener() {
@Override
public void onError(int code, String message) {
TToast(mActivity, "load error : " + code + ", " + message);
// mExpressContainer.removeAllViews();
}
@Override
public void onNativeExpressAdLoad(List<TTNativeExpressAd> ads) {
if (ads == null || ads.size() == 0){
return;
}
mTTAd = ads.get(0);
// mTTAd.setSlideIntervalTime(30*1000);
bindAdListener(mTTAd);
startTime = System.currentTimeMillis();
mTTAd.render();
}
});
}
private long startTime = 0;
private boolean mHasShowDownloadActive = false;
private void bindAdListener(TTNativeExpressAd ad) {
ad.setExpressInteractionListener(new TTNativeExpressAd.ExpressAdInteractionListener() {
@Override
public void onAdClicked(View view, int type) {
TToast(mContext, "广告被点击");
}
@Override
public void onAdShow(View view, int type) {
TToast(mContext, "广告展示");
}
@Override
public void onRenderFail(View view, String msg, int code) {
TToast(mContext, msg+" code:"+code);
}
@Override
public void onRenderSuccess(View view, float width, float height) {
//返回view的宽高 单位 dp
TToast(mContext, "渲染成功");
//mExpressContainer.removeAllViews();
mExpressContainer.addView(view);
}
});
//dislike设置
bindDislike(ad, false);
if (ad.getInteractionType() != TTAdConstant.INTERACTION_TYPE_DOWNLOAD){
return;
}
ad.setDownloadListener(new TTAppDownloadListener() {
@Override
public void onIdle() {
TToast(mActivity, "点击开始下载 Toast.LENGTH_LONG");
}
@Override
public void onDownloadActive(long totalBytes, long currBytes, String fileName, String appName) {
if (!mHasShowDownloadActive) {
mHasShowDownloadActive = true;
TToast(mActivity, "下载中,点击暂停 Toast.LENGTH_LONG");
}
}
@Override
public void onDownloadPaused(long totalBytes, long currBytes, String fileName, String appName) {
TToast(mActivity, "下载暂停,点击继续 Toast.LENGTH_LONG");
}
@Override
public void onDownloadFailed(long totalBytes, long currBytes, String fileName, String appName) {
TToast(mActivity, "下载失败,点击重新下载 Toast.LENGTH_LONG");
}
@Override
public void onInstalled(String fileName, String appName) {
TToast(mActivity, "安装完成,点击图片打开Toast.LENGTH_LONG");
}
@Override
public void onDownloadFinished(long totalBytes, String fileName, String appName) {
TToast(mActivity, "点击安装Toast.LENGTH_LONG");
}
});
}
/**
* 设置广告的不喜欢, 注意:强烈建议设置该逻辑,如果不设置dislike处理逻辑,则模板广告中的 dislike区域不响应dislike事件。
* @param ad
* @param customStyle 是否自定义样式,true:样式自定义
*/
private void bindDislike(TTNativeExpressAd ad, boolean customStyle) {
//使用默认模板中默认dislike弹出样式
ad.setDislikeCallback(mActivity, new TTAdDislike.DislikeInteractionCallback() {
@Override
public void onSelected(int position, String value) {
TToast(mActivity, "点击 " + value);
//用户选择不喜欢原因后,移除广告展示
//mExpressContainer.removeAllViews();
closeBanner();
}
@Override
public void onCancel() {
TToast(mActivity, "点击取消 ");
}
});
}
//关闭广告销毁banner 如果你不需要广告显示,可以在想关闭的地方调用,也就是隐藏掉
public void closeBanner() {
if (mExpressContainer == null )
{
return;
}
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
mExpressContainer.setVisibility(View.GONE);
}
});
if (mTTAd != null) {
mTTAd.destroy();
}
}
}
4.创建开屏广告
在包路径下创建splashad脚本。
如图:
开屏广告和banner广告一样都需要一个布局才能显示,处理方式和上述banner一样,唯一的区别是需要全屏显示,在安卓工程的res目录下的layout目录中添加activity_splash_express.xml
xml中内容如下
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/express_splash"
android:layout_width="1080dp"
android:layout_height="1920dp"
android:layout_centerVertical = "true"/>
</RelativeLayout>
下面是开屏广告的完整内容
package com.yx.yxsdk.activity;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.bytedance.sdk.openadsdk.AdSlot;
import com.bytedance.sdk.openadsdk.TTAdConstant;
import com.bytedance.sdk.openadsdk.TTAdNative;
import com.bytedance.sdk.openadsdk.TTAppDownloadListener;
import com.bytedance.sdk.openadsdk.TTSplashAd;
import com.yx.yxsdk.TTAdManagerHolder;
import com.yx.yxsdk.UAMain;
import com.yx.yxsdk.androidsdk.R;
import com.unity3d.player.UnityPlayer;
public class SplashAD {
private Activity mActivity = null;
private Context mContext = null;
private UnityPlayer mUnityPlayer;
private TTAdNative mTTAdNative;
//private FrameLayout mSplashContainer;
private RelativeLayout mSplashContainer;
//开屏广告加载超时时间,建议大于3000,这里为了冷启动第一次加载到广告并且展示,示例设置了3000ms
private static final int AD_TIME_OUT = 3000;
private static final int MSG_GO_MAIN = 1;
//开屏广告是否已经加载
private boolean mHasLoaded;
// TToast显示信息
public void TToast(final Context context, final String msg) {
//在Android的UI线程显示
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
}
});
}
//初始化
public void init(Activity activity, Context context , UnityPlayer unityPlayer) {
mActivity = activity;
mContext = context;
mUnityPlayer = unityPlayer;
if(mActivity == null || context == null || unityPlayer == null){
UAMain.unityLog("插屏广告初始化时mActivity或者context和unityPlayer为空");
return;
}
//原生的view直接添加到Unity的view内
//R代表你是哪个包名的R文件,然后把创建好的view嵌入在Unity view里,不要使用setContentView(R.layout.activity_native_express)
mActivity.runOnUiThread(new Runnable() {
public void run() {
View layout = LayoutInflater.from(mActivity).inflate(R.layout.activity_splash_express, null);
mUnityPlayer.addView(layout);
mSplashContainer = (RelativeLayout)mActivity.findViewById(R.id.express_splash);
//mFrameLayout =(FrameLayout)mFrameLayout.findViewById(UnityPlayer.generateViewId());
if(mSplashContainer == null){
UAMain.unityLog("mExpressContainer的数据为空");
}
else {
UAMain.unityLog("mExpressContainer的数据不为空");
}
//初始化开屏广告
InitSplash();
}
});
}
public void InitSplash() {
//step2:创建TTAdNative对象
mTTAdNative = TTAdManagerHolder.get().createAdNative(mActivity);
//在合适的时机申请权限,如read_phone_state,防止获取不了imei时候,下载类广告没有填充的问题
//在开屏时候申请不太合适,因为该页面倒计时结束或者请求超时会跳转,在该页面申请权限,体验不好
// TTAdManagerHolder.getInstance(this).requestPermissionIfNecessary(this);
//定时,AD_TIME_OUT时间到时执行,如果开屏广告没有加载则跳转到主页面
}
/**
* 加载开屏广告
*/
public void loadSplashAd(String codeId) {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
//显示
//mSplashContainer.removeAllViews();
mSplashContainer.setVisibility(View.VISIBLE);
}
});
//step3:创建开屏广告请求参数AdSlot,具体参数含义参考文档
AdSlot adSlot = new AdSlot.Builder()
.setCodeId(codeId)
.setSupportDeepLink(true)
.setImageAcceptedSize(1080, 1920)
.build();
//step4:请求广告,调用开屏广告异步请求接口,对请求回调的广告作渲染处理
mTTAdNative.loadSplashAd(adSlot, new TTAdNative.SplashAdListener() {
@Override
public void onError(int code, String message) {
mHasLoaded = true;
TToast(mActivity,message);
goToGame();//出现错误切换回游戏
}
@Override
public void onTimeout() {
mHasLoaded = true;
TToast(mActivity,"开屏广告加载超时");
goToGame();//加载超时切换回游戏
}
@Override
public void onSplashAdLoad(TTSplashAd ad) {
TToast(mActivity,"开屏广告请求成功");
mHasLoaded = true;
if (ad == null) {
return;
}
//获取SplashView
View view = ad.getSplashView();
if (view != null) {
//mSplashContainer.removeAllViews();
//把SplashView 添加到Unity的View中,注意开屏广告view:width >=70%屏幕宽;height >=50%屏幕高
mSplashContainer.addView(view);
//设置不开启开屏广告倒计时功能以及不显示跳过按钮,如果这么设置,您需要自定义倒计时逻辑
//ad.setNotAllowSdkCountdown();
}else {
goToGame();
}
//设置SplashView的交互监听器
ad.setSplashInteractionListener(new TTSplashAd.AdInteractionListener() {
@Override
public void onAdClicked(View view, int type) {
TToast(mActivity,"开屏广告点击");
}
@Override
public void onAdShow(View view, int type) {
TToast(mActivity,"开屏广告展示");
}
@Override
public void onAdSkip() {
TToast(mActivity,"开屏广告跳过");
goToGame();//点击跳过广告切换回游戏
}
@Override
public void onAdTimeOver() {
TToast(mActivity,"开屏广告倒计时结束");
goToGame();//倒计时结束切换回游戏
}
});
if(ad.getInteractionType() == TTAdConstant.INTERACTION_TYPE_DOWNLOAD) {
ad.setDownloadListener(new TTAppDownloadListener() {
boolean hasShow = false;
@Override
public void onIdle() {
}
@Override
public void onDownloadActive(long totalBytes, long currBytes, String fileName, String appName) {
if (!hasShow) {
TToast(mActivity,"下载中...");
hasShow = true;
}
}
@Override
public void onDownloadPaused(long totalBytes, long currBytes, String fileName, String appName) {
TToast(mActivity,"下载暂停...");
}
@Override
public void onDownloadFailed(long totalBytes, long currBytes, String fileName, String appName) {
TToast(mActivity,"下载失败...");
}
@Override
public void onDownloadFinished(long totalBytes, String fileName, String appName) {
}
@Override
public void onInstalled(String fileName, String appName) {
}
});
}
}
}, AD_TIME_OUT);
}
/**
* 通知走游戏流程
*/
private void goToGame() {
UAMain.callUnity("AndroidSDKListener","SplashGoToGame","True");
closeSplash();//隐藏开屏广告
}
//关闭广告销毁开屏 如果你不需要广告显示,可以在想关闭的地方调用,也就是隐藏掉
protected void closeSplash() {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
mSplashContainer.setVisibility(View.GONE);
//mSplashContainer.removeAllViews();
}
});
}
}
5.在UAMain中初始化广告脚本和添加调用广告的接口完整代码如下
import com.yx.yxsdk.activity.BannerExpress;
import com.yx.yxsdk.activity.InteractionExpressAD;
import com.yx.yxsdk.activity.RewardVideoAD;
import com.yx.yxsdk.activity.SplashAD;
import com.unity3d.player.UnityPlayer;
import com.unity3d.player.UnityPlayerActivity;
public class UAMain {
private static Context unityContext;
private static UnityPlayerActivity unityActivity;
public static UnityPlayer unityPlayer;
//激励视频广告
private static RewardVideoAD rewardVideoAD;
//插屏广告
private static InsertAd insertAd;
private static InteractionExpressAD interactionExpressAD;
//Banner广告
private static BannerExpress bannerExpress;
//开屏广告
private static SplashAD splashAD;
//init方法,用来传入上下文
public static void init(Context paramContext, String channelName, UnityPlayer player) {
unityContext = paramContext.getApplicationContext();
unityActivity = (UnityPlayerActivity) paramContext;
unityPlayer = player;
if (unityPlayer != null) {
unityLog("init unity player!!");
}
//初始化广告配置参数
TTAdManagerHolder.init(unityContext);
TTAdManagerHolder.get().requestPermissionIfNecessary(unityContext);
//初始化视频广告
rewardVideoAD = new RewardVideoAD();
rewardVideoAD.init(unityActivity, unityContext);
//初始化插屏自渲染广告
insertAd = new InsertAd();
insertAd.init(unityActivity, unityContext);
//初始化插屏模板广告
interactionExpressAD = new InteractionExpressAD();
interactionExpressAD.init(unityActivity, unityContext);
//初始化banner广告
bannerExpress = new BannerExpress();
bannerExpress.init(unityActivity, unityContext, unityPlayer);
//初始化开屏广告
splashAD = new SplashAD();
splashAD.init(unityActivity, unityContext, unityPlayer);
}
/**
* 调用Unity的方法
*/
public static void callUnity(String className, String methodName, String params) {
UnityPlayer.UnitySendMessage(className, methodName, params);
}
/**
* 加载横屏广告
*/
public static void loadHorizontalAD(String codeID) {
rewardVideoAD.LoadHorizontalAD(codeID);
unityLog("加载横屏广告" + codeID);
}
/**
* 加载竖屏广告
*/
public static void loadVerticalAD(String codeID) {
rewardVideoAD.LoadVerticalAD(codeID);
unityLog("加载竖屏广告" + codeID);
}
/**
* 显示视频广告
*/
public static void showVedioAD(String codeID) {
rewardVideoAD.ShowVedio();
unityLog("显示视频广告" + codeID);
}
/**
* 加载插屏模板广告
*/
public static void loadInteractionExpressAD(String codeID) {
interactionExpressAD.loadExpressAd(codeID);
unityLog("加载插屏模板广告" + codeID);
}
/**
* 加载Banner广告
*/
public static void loadBannerExpressAD(String codeID) {
bannerExpress.loadExpressAd(codeID);
unityLog("加载Banner广告" + codeID);
}
/**
* 关闭Banner广告
*/
public static void closeBannerAD() {
unityLog("通过UI界面按钮来关闭");
bannerExpress.closeBanner();
}
/**
* 加载开屏广告
*/
public static void loadSplasAD(String codeID) {
splashAD.loadSplashAd(codeID);
unityLog("加载开屏广告" + codeID);
}
}
到此要接的广告就全部接完了,接下来讲unity中的配置和使用。
- Unity中的使用
(1)配置unity项目将android-gif-drawable-1.2.6和open_ad_sdk和我们自己导出的sdk的aar导入到unity的plugins/Android/libs文件夹下,没有这些目录的话创建目录。
(2)然后打开buildSettings窗口设置gradle模式点击playerSettings按钮设置,gradle模式必须设置,不然会打不出安卓包。
勾选build下的这俩选项
会生成mainTemplate和proguard-user这俩文件mainTemplate主要是用来添加配置的proguard-user是做混淆处理的。如果项目里有这俩文件也得勾选build下的两个选项。
(3)然后打开mainTemplate配置文件,添加安卓 build.gradle文件中添加的那些配置。
(4)打开proguard-user添加混淆,完整配置如下。
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/sumirrowu/Library/Android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-optimizationpasses 5
#混淆时不会产生形形色色的类名
-dontusemixedcaseclassnames
#指定不去忽略非公共的库类
-dontskipnonpubliclibraryclasses
#不预校验
#-dontpreverify
#不优化输入的类文件
-dontoptimize
-ignorewarnings
-verbose
#优化
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
#保护内部类
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod
-keep class com.bytedance.sdk.openadsdk.** {*;}
-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
-keep class com.ss.sys.ces.* {*;}
#以下类是原生广告的自定义java类,需要keep住,开发者自实现时,也需要keep住。
-keep class com.bytedance.android.NativeAdManager {*;}
-keep class com.bytedance.android.IntersititialView {*;}
-keep class com.bytedance.android.BannerView {*;}
(5)我这的androidManifest.xml是包含在aar中的,如果你的unity工程中有自己的androidManifest的话需要把上边安卓中配置的广告需要的权限添加到你的androidManifest中。
(6)将安卓工程中添加的file_paths.xml添加到unity中的Android/res/xml下,没目录的话创建目录,该文件主要是适配Anroid7.0及以上的广告点击之后的应用下载。
(7)接下来在C#代码中添加调用java中广告接口的逻辑如下,调用AndroidSDKHelper进行初始化,然后创建按钮调用下边接口填写后台配置的广告code。注意 UAMain.callUnity("AndroidSDKListener","SplashGoToGame","True");这个方法就是Java中调用C#脚本的接口第一个参数是脚本的名字,第二个参数是脚本中的方法名字,第三个是参数。具体UAMain.callUnity方法参考上边的UAMain.java脚本中的逻辑。
static class AndroidSDKListener
{
private readonly static AndroidJavaClass unityPlayer;
private readonly static AndroidJavaObject currentActivity;
private readonly static AndroidJavaClass sdkCallHandler;
static AndroidSDKHelper()
{
#if UNITY_ANDROID
unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
currentActivity = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");
sdkCallHandler = new AndroidJavaClass("com.yx.yxsdk.UAMain");
try
{
sdkCallHandler.CallStatic("init", currentActivity, "yx", currentActivity.Get<AndroidJavaObject>("mUnityPlayer"));
}
catch (Exception ex)
{
Logger.LogError("call sdk get exception methodName:init" + " message: " + ex.Message);
}
Logger.Log("C# AndroidSDKHelper init");
#endif
}
public static void FuncCall(string methodName, params object[] param)
{
#if UNITY_ANDROID
try
{
sdkCallHandler.CallStatic(methodName, param);
}
catch (Exception ex)
{
Logger.LogError("call sdk get exception methodName:" + methodName + " message: " + ex.Message);
}
#endif
}
//设置视频广告是不是竖屏广告
public void loadVerticalAD (string id){
FuncCall("loadVerticalAD",id);
Logger.Log("设置视频广告是不是竖屏广告");
}
// 设置视频广告是不是横屏广告
public void loadHorizontalAD (string id){
FuncCall("loadHorizontalAD",id);
Logger.Log("设置视频广告是不是横屏广告");
}
// 加载(缓存)视频广告
public void showVedioAD (string id)
{
FuncCall("showVedioAD","942652585");
Logger.Log("加载(缓存的)视频广告");
}
// 渲染插屏广告
public void loadInteractionAD (string id){
FuncCall("loadInteractionAD",id);
Logger.Log("渲染插页广告");
}
//模板插屏广告
public void loadInteractionExpressAD (string id){
FuncCall("loadInteractionExpressAD",id);
Logger.Log("模板插屏广告");
}
// 开屏广告
public void loadSplashAd (string id){
FuncCall("loadSplasAD",id);
Logger.Log("开屏广告");
}
// 加载Bannerad广告
public void loadBannerad (string id) {
FuncCall("loadBannerExpressAD",id);
Logger.Log("加载Bannerad广告");
}
// 关闭banner广告
public void closeBannerad () {
FuncCall("closeBannerAD");
Logger.Log("关闭Bannerad广告");
}
//下边是java回调C#中的方法如广告播放完毕要下发奖励等
//视频广告播放完成
private void VideoComplete(string msg)
{
Logger.Log("视频播放完成");
//将获取到的信息传给方法
}
//视频广告播放失败
private void VideoError(string msg)
{
Logger.Log("视频播放失败");
//将获取到的信息传给方法
}
//视频跳过
private void SkippedVideo(string msg)
{
//将获取到的信息传给方法
Logger.Log("视频跳过");
}
//开屏广告播放完成或者加载失败在或者出现错误通知进入游戏避免游戏流程卡死
private void SplashGoToGame(string msg){
Logger.Log("走游戏内流程");
}
// 关闭插屏广告时的回调
private void CloseInteractionExpressAD(string msg){
Logger.Log("关闭插屏广告时的回调");
}
}
到此就全部配置完毕,调用接口打包测试即可。下边是我调用的显示效果。
激励视频广告:
插屏广告:
banner广告:
开屏广告:
本文地址:https://blog.csdn.net/zll18201518375/article/details/103874489
上一篇: Android之Fragment嵌入到活动的两种实现方法
下一篇: Android开发常见面试
推荐阅读