Android|Android接入穿山甲SDK并实现开屏广告

一、穿山甲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导入成功后如下图:
Android|Android接入穿山甲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 下载地址 (和文中的写法稍有不同,有不明白的可以给我留言)

    推荐阅读