一、穿山甲SDK的接入
0.进入官方下载地址,下载穿山甲AndroidSDK,下载的压缩包里包含.aar的sdk文件和工程demo。
1.将 SDK 压缩包内的 open_ad_sdk.aar 复制到 app/libs 文件夹(没有的话须手动创建), 并将以下代码添加到 app的build.gradle文件:
android {/*。。。。。。*/repositories {
flatDir {
dirs 'libs'
}
}
}depedencies {
compile(name: 'open_ad_sdk', ext: ‘aar')
}
2.在 res/xml 目录下,新建一个 xml 文件 file_paths,在该文件中添加如下代码:
3.AndroidManifest.xml文件中:
4.在AndroidManifest.xml中添加权限
5.在程序执行的第一个Activity文件中添加初始化方法:
public class OneActivity extends Activity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
/*初始化穿山甲SDK*/
TTAdConfig();
}/*初始化穿山甲SDK*/
private void TTAdConfig(){
TTAdSdk.getAdManager().requestPermissionIfNecessary(this);
TTAdConfig config=new TTAdConfig.Builder()
.appId("5066713")
.useTextureView(false)
.appName("CsjSDK")
.titleBarTheme(TTAdConstant.TITLE_BAR_THEME_DARK)
.allowShowNotify(true)
.allowShowPageWhenScreenLock(true)
.debug(true)
.directDownloadNetworkType(TTAdConstant.NETWORK_STATE_WIFI, TTAdConstant.NETWORK_STATE_3G)
.supportMultiProcess(false)
.build();
TTAdSdk.init(this,config);
}
}
6.运行程序,打开AndroidStudio的Logcat栏,SDK导入成功后如下图:
文章图片
二、开屏广告的实现
1.在实现具体的功能前,必须要先完成几个基础公共类
(1)UIUtils类,屏幕适配(官方提供的工程demo里有的)官方SDK下载地址,下载的文件里包含工程demo
public class UIUtils {public static float getScreenWidthDp(Context context){
final float scale = context.getResources().getDisplayMetrics().density;
float width = context.getResources().getDisplayMetrics().widthPixels;
return width / (scale <= 0 ? 1 : scale) + 0.5f;
}//全面屏、刘海屏适配
public staticfloat getHeight(Activity activity) {
hideBottomUIMenu(activity);
float height;
int realHeight = getRealHeight(activity);
if (UIUtils.hasNotchScreen(activity)) {
height = px2dip(activity, realHeight - getStatusBarHeight(activity));
}else {
height = px2dip(activity, realHeight);
}
return height;
}public static void hideBottomUIMenu(Activity activity) {
if (activity == null) {
return;
}
try {
//隐藏虚拟按键,并且全屏
if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
View v = activity.getWindow().getDecorView();
v.setSystemUiVisibility(View.GONE);
} else if (Build.VERSION.SDK_INT >= 19) {
//for new api versions.
View decorView = activity.getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
//| View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View.SYSTEM_UI_FLAG_IMMERSIVE;
decorView.setSystemUiVisibility(uiOptions);
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
}
} catch (Exception e) {
e.printStackTrace();
}
}//获取屏幕真实高度,不包含下方虚拟导航栏
public static int getRealHeight(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
DisplayMetrics dm = new DisplayMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
display.getRealMetrics(dm);
} else {
display.getMetrics(dm);
}
int realHeight = dm.heightPixels;
return realHeight;
}//获取状态栏高度
public static float getStatusBarHeight(Context context) {
float height = 0;
int resourceId = context.getApplicationContext().getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
height = context.getApplicationContext().getResources().getDimensionPixelSize(resourceId);
}
return height;
}public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / (scale <= 0 ? 1 : scale) + 0.5f);
}
/**
* 判断是否是刘海屏
* @return
*/
public static boolean hasNotchScreen(Activity activity){
if (getInt("ro.miui.notch",activity) == 1 || hasNotchAtHuawei(activity) || hasNotchAtOPPO(activity)
|| hasNotchAtVivo(activity) || isAndroidPHasNotch(activity)){ //TODO 各种品牌
return true;
}return false;
}/**
* Android P 刘海屏判断
* @param activity
* @return
*/
public static boolean isAndroidPHasNotch(Activity activity){
boolean ret = false;
if (Build.VERSION.SDK_INT >= 28){
try {
Class windowInsets = Class.forName("android.view.WindowInsets");
Method method = windowInsets.getMethod("getDisplayCutout");
Object displayCutout = method.invoke(windowInsets);
if (displayCutout != null) {
ret = true;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return ret;
}/**
* 小米刘海屏判断.
* @return 0 if it is not notch ;
return 1 means notch
* @throws IllegalArgumentException if the key exceeds 32 characters
*/
public static int getInt(String key, Activity activity) {
int result = 0;
if (isMiui()){
try {
ClassLoader classLoader = activity.getClassLoader();
@SuppressWarnings("rawtypes")
Class SystemProperties = classLoader.loadClass("android.os.SystemProperties");
//参数类型
@SuppressWarnings("rawtypes")
Class[] paramTypes = new Class[2];
paramTypes[0] = String.class;
paramTypes[1] = int.class;
Method getInt = SystemProperties.getMethod("getInt", paramTypes);
//参数
Object[] params = new Object[2];
params[0] = new String(key);
params[1] = new Integer(0);
result = (Integer) getInt.invoke(SystemProperties, params);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return result;
}/**
* 华为刘海屏判断
* @return
*/
public static boolean hasNotchAtHuawei(Context context) {
boolean ret = false;
try {
ClassLoader classLoader = context.getClassLoader();
Class HwNotchSizeUtil = classLoader.loadClass("com.huawei.android.util.HwNotchSizeUtil");
Method get = HwNotchSizeUtil.getMethod("hasNotchInScreen");
ret = (boolean) get.invoke(HwNotchSizeUtil);
} catch (ClassNotFoundException e) {
} catch (NoSuchMethodException e) {
} catch (Exception e) {
} finally {
return ret;
}
}public static final int VIVO_NOTCH = 0x00000020;
//是否有刘海
public static final int VIVO_FILLET = 0x00000008;
//是否有圆角/**
* VIVO刘海屏判断
* @return
*/
public static boolean hasNotchAtVivo(Context context) {
boolean ret = false;
try {
ClassLoader classLoader = context.getClassLoader();
Class FtFeature = classLoader.loadClass("android.util.FtFeature");
Method method = FtFeature.getMethod("isFeatureSupport", int.class);
ret = (boolean) method.invoke(FtFeature, VIVO_NOTCH);
} catch (ClassNotFoundException e) {
} catch (NoSuchMethodException e) {
} catch (Exception e) {
} finally {
return ret;
}
}
/**
* OPPO刘海屏判断
* @return
*/
public static boolean hasNotchAtOPPO(Context context) {
returncontext.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
}public static boolean isMiui() {
boolean sIsMiui = false;
try {
Class> clz = Class.forName("miui.os.Build");
if (clz != null) {
sIsMiui = true;
//noinspection ConstantConditions
return sIsMiui;
}
} catch (Exception e) {
// ignore
}
return sIsMiui;
}
}
【Android|Android接入穿山甲SDK并实现开屏广告】
(2)TTAdManagerHolder类:
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);
}private static void doInit(Context context) {
if (!sInit) {
TTAdSdk.init(context, buildConfig(context));
sInit = true;
}
}private static TTAdConfig buildConfig(Context context) {
return new TTAdConfig.Builder()
.appId("5000000")//你的AppID
.useTextureView(true) //使用TextureView控件播放视频,默认为SurfaceView,当有SurfaceView冲突的场景,可以使用TextureView
.appName("CsjSDK") //你的AppName
.titleBarTheme(TTAdConstant.TITLE_BAR_THEME_DARK)
.allowShowNotify(true) //是否允许sdk展示通知栏提示
.allowShowPageWhenScreenLock(true) //是否在锁屏场景支持展示广告落地页
.debug(true) //测试阶段打开,可以通过日志排查问题,上线时去除该调用
.directDownloadNetworkType(TTAdConstant.NETWORK_STATE_WIFI, TTAdConstant.NETWORK_STATE_3G) //允许直接下载的网络状态集合
.supportMultiProcess(true)//是否支持多进程
.needClearTaskReset()
//.httpStack(new MyOkStack3())//自定义网络库,demo中给出了okhttp3版本的样例,其余请自行开发或者咨询工作人员。
.build();
}
}
(3)Toast通知类
public final class TToast {
private static Toast sToast;
public static void show(Context context, String msg) {
show(context, msg, Toast.LENGTH_SHORT);
}public static void show(Context context, String msg, int duration) {
Toast toast = getToast(context);
if (toast != null) {
toast.setDuration(duration);
toast.setText(String.valueOf(msg));
toast.show();
} else {
Log.i("TToast", "toast msg: " + String.valueOf(msg));
}
}@SuppressLint("ShowToast")
private static Toast getToast(Context context) {
if (context == null) {
return sToast;
}
//if (sToast == null) {
//synchronized (TToast.class) {
//if (sToast == null) {
sToast = Toast.makeText(context.getApplicationContext(), "", Toast.LENGTH_SHORT);
//}
//}
//}
return sToast;
}public static void reset() {
sToast = null;
}
}
2.实现开屏广告
public class CsjSplashActivity extends Activity {
private static final String TAG = "SplashActivity";
private TTAdNative mTTAdNative;
private FrameLayout mSplashContainer;
//是否强制跳转到主页面
private boolean mForceGoMain;
//开屏广告加载超时时间,建议大于3000,这里为了冷启动第一次加载到广告并且展示,示例设置了3000ms
private static final int AD_TIME_OUT = 4000;
private String mCodeId = "887293945";
private boolean mIsExpress = false;
//是否请求模板广告@SuppressWarnings("RedundantCast")
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
setContentView(R.layout.a_csj_splash);
super.onCreate(savedInstanceState);
mSplashContainer = (FrameLayout) findViewById(R.id.splash_container);
//step2:创建TTAdNative对象
mTTAdNative = TTAdManagerHolder.get().createAdNative(this);
hideBottomUIMenu();
//隐藏虚拟按键,并且全屏
getExtraInfo();
loadSplashAd();
}private void getExtraInfo() {
Intent intent = getIntent();
if(intent == null) {
return;
}
String codeId = intent.getStringExtra("splash_rit");
if (!TextUtils.isEmpty(codeId)){
mCodeId = codeId;
}
mIsExpress = intent.getBooleanExtra("is_express", false);
}@Override
protected void onResume() {
//判断是否该跳转到主页面
if (mForceGoMain) {
goToMainActivity();
}
super.onResume();
}@Override
protected void onStop() {
super.onStop();
mForceGoMain = true;
}
/**
* 加载开屏广告
*/
private void loadSplashAd(){
AdSlot adSlot=null;
if (mIsExpress) {
//个性化模板广告需要传入期望广告view的宽、高,单位dp,请传入实际需要的大小,
//比如:广告下方拼接logo、适配刘海屏等,需要考虑实际广告大小
float expressViewWidth = UIUtils.getScreenWidthDp(this);
float expressViewHeight = UIUtils.getHeight(this);
adSlot = new AdSlot.Builder()
.setCodeId(mCodeId)
.setSupportDeepLink(true)
.setImageAcceptedSize(1080, 1920)
//模板广告需要设置期望个性化模板广告的大小,单位dp,代码位是否属于个性化模板广告,请在穿山甲平台查看
.setExpressViewAcceptedSize(expressViewWidth, expressViewHeight)
.build();
} else {
adSlot = new AdSlot.Builder()
.setCodeId(mCodeId)
.setSupportDeepLink(true)
.setImageAcceptedSize(1080, 1920)
.build();
}
//step4:请求广告,调用开屏广告异步请求接口,对请求回调的广告作渲染处理
mTTAdNative.loadSplashAd(adSlot, new TTAdNative.SplashAdListener() {
@Override
public void onError(int code, String message) {
Log.d(TAG, message);
showToast(message);
goToMainActivity();
}@Override
public void onTimeout() {
showToast("开屏广告加载超时");
goToMainActivity();
}@Override
public void onSplashAdLoad(com.bytedance.sdk.openadsdk.TTSplashAd ad) {
Log.d(TAG, "开屏广告请求成功");
if (ad == null) {
return;
}
//获取SplashView
View view = ad.getSplashView();
if (view != null && mSplashContainer != null && !CsjSplashActivity.this.isFinishing()) {
mSplashContainer.removeAllViews();
//把SplashView 添加到ViewGroup中,注意开屏广告view:width >=70%屏幕宽;height >=50%屏幕高
mSplashContainer.addView(view);
//设置不开启开屏广告倒计时功能以及不显示跳过按钮,如果这么设置,您需要自定义倒计时逻辑
//ad.setNotAllowSdkCountdown();
}else {
goToMainActivity();
}
//设置SplashView的交互监听器
ad.setSplashInteractionListener(new TTSplashAd.AdInteractionListener() {
@Override
public void onAdClicked(View view, int type) {
Log.d(TAG, "onAdClicked");
showToast("开屏广告点击");
}@Override
public void onAdShow(View view, int type) {
Log.d(TAG, "onAdShow");
//showToast("开屏广告展示");
}@Override
public void onAdSkip() {
Log.d(TAG, "onAdSkip");
showToast("开屏广告跳过");
goToMainActivity();
}@Override
public void onAdTimeOver() {
Log.d(TAG, "onAdTimeOver");
//showToast("开屏广告倒计时结束");
goToMainActivity();
}
});
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) {
showToast("下载中...");
hasShow = true;
}
}@Override
public void onDownloadPaused(long totalBytes, long currBytes, String fileName, String appName) {
showToast("下载暂停...");
}@Override
public void onDownloadFailed(long totalBytes, long currBytes, String fileName, String appName) {
showToast("下载失败...");
}@Override
public void onDownloadFinished(long totalBytes, String fileName, String appName) {
showToast("下载完成...");
}@Override
public void onInstalled(String fileName, String appName) {
showToast("安装完成...");
}
});
}
}
},AD_TIME_OUT);
}/**
* 跳转到主页面
*/
private void goToMainActivity(){
Intent intent=new Intent(CsjSplashActivity.this, MainActivity.class);
startActivity(intent);
//mSplashContainer.removeAllViews();
//移除所有视图
this.finish();
}private void showToast(String msg) {
ToastUtils.show(this, msg);
}/**
* 隐藏虚拟按键,并且全屏
*/
protected void hideBottomUIMenu() {
//隐藏虚拟按键,并且全屏
if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
View v = this.getWindow().getDecorView();
v.setSystemUiVisibility(View.GONE);
} else if (Build.VERSION.SDK_INT >= 19) {
//for new api versions.
View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
}
}
}
三、最后附上我的demo 下载地址 (和文中的写法稍有不同,有不明白的可以给我留言)
推荐阅读
- android|Android穿山甲SDK接入信息流广告
- 穿山甲广告接入|Android 穿山甲广告接入教程
- 学习记录|踩坑!穿山甲广告Android SDK接入
- Android|Android 接入穿山甲广告
- 微信小程序|微信小程序项目实例——图片处理小工具(自制低配版美图秀秀)
- 程序员|大牛深入讲解!Android面试中常问的MMAP到底是啥东东(再不刷题就晚了!)
- post和get区别
- Unity集成华为游戏服务SDK方式(Unity集成Android插件)
- 目标检测|YOLOv5(6.1)安卓端部署记录