500 lines
19 KiB
Plaintext
500 lines
19 KiB
Plaintext
package com.novelbook.android.AD;
|
||
|
||
import android.Manifest;
|
||
import android.annotation.TargetApi;
|
||
import android.app.Activity;
|
||
import android.content.Intent;
|
||
import android.content.pm.PackageManager;
|
||
import android.net.Uri;
|
||
import android.os.Build;
|
||
import android.os.Bundle;
|
||
import android.os.Handler;
|
||
import android.os.Looper;
|
||
import android.os.Message;
|
||
import android.provider.Settings;
|
||
import android.support.annotation.MainThread;
|
||
import android.support.annotation.Nullable;
|
||
import android.text.TextUtils;
|
||
import android.util.Log;
|
||
import android.view.KeyEvent;
|
||
import android.view.View;
|
||
import android.view.ViewGroup;
|
||
import android.widget.FrameLayout;
|
||
import android.widget.TextView;
|
||
import android.widget.Toast;
|
||
|
||
import com.bytedance.sdk.openadsdk.AdSlot;
|
||
import com.bytedance.sdk.openadsdk.TTAdNative;
|
||
import com.bytedance.sdk.openadsdk.TTSplashAd;
|
||
import com.novelbook.android.AD.toutiao.TTAdManagerHolder;
|
||
import com.novelbook.android.AD.toutiao.WeakHandler;
|
||
import com.novelbook.android.BuildConfig;
|
||
import com.novelbook.android.Main2Activity;
|
||
import com.novelbook.android.R;
|
||
import com.novelbook.android.utils.Constants;
|
||
import com.qq.e.ads.splash.SplashAD;
|
||
import com.qq.e.ads.splash.SplashADListener;
|
||
import com.qq.e.comm.util.AdError;
|
||
|
||
import org.litepal.util.Const;
|
||
|
||
import java.util.ArrayList;
|
||
import java.util.HashMap;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
import butterknife.BindView;
|
||
import butterknife.ButterKnife;
|
||
|
||
import static com.novelbook.android.bean.AdSetting.getAppID;
|
||
|
||
|
||
/**
|
||
* 开屏广告Activity示例
|
||
*/
|
||
public class SplashActivity extends Activity implements WeakHandler.IHandler, SplashADListener {
|
||
private static final String TAG = SplashActivity.class.getSimpleName();
|
||
|
||
@BindView(R.id.splash_container)
|
||
ViewGroup mSplashContainer;
|
||
|
||
//--------tencent--->
|
||
|
||
private SplashAD splashAD;
|
||
|
||
@Nullable
|
||
@BindView(R.id.skip_view)
|
||
TextView skipView;
|
||
//private ImageView splashHolder;
|
||
@Nullable
|
||
@BindView(R.id.splash_holder)
|
||
TextView splashHolder;
|
||
private static final String SKIP_TEXT = "点击跳过 %d";
|
||
public boolean canJump = false;
|
||
/**
|
||
* 为防止无广告时造成视觉上类似于"闪退"的情况,设定无广告时页面跳转根据需要延迟一定时间,demo
|
||
* 给出的延时逻辑是从拉取广告开始算开屏最少持续多久,仅供参考,开发者可自定义延时逻辑,如果开发者采用demo
|
||
* 中给出的延时逻辑,也建议开发者考虑自定义minSplashTimeWhenNoAD的值(单位ms)
|
||
**/
|
||
private int minSplashTimeWhenNoAD = 2000;
|
||
/**
|
||
* 记录拉取广告的时间
|
||
*/
|
||
private long fetchSplashADTime = 0;
|
||
private Handler handler = new Handler(Looper.getMainLooper());
|
||
|
||
//<-----tencent-----
|
||
|
||
|
||
//------toutiao--->
|
||
private TTAdNative mTTAdNative;
|
||
|
||
//是否强制跳转到主页面
|
||
private boolean mForceGoMain;
|
||
public static final String EXTR_LUNCHER="luncher";
|
||
|
||
//开屏广告加载发生超时但是SDK没有及时回调结果的时候,做的一层保护。
|
||
private final WeakHandler mHandler = new WeakHandler(this);
|
||
//开屏广告加载超时时间,建议大于1000,这里为了冷启动第一次加载到广告并且展示,示例设置了2000ms
|
||
private static final int AD_TIME_OUT = 2000;
|
||
private static final int MSG_GO_MAIN = 1;
|
||
//开屏广告是否已经加载
|
||
private boolean mHasLoaded;
|
||
|
||
//-toutiao---<---
|
||
|
||
|
||
@BindView(R.id.textTile)
|
||
TextView tvTitle;
|
||
|
||
@SuppressWarnings("RedundantCast")
|
||
@Override
|
||
protected void onCreate(Bundle savedInstanceState) {
|
||
super.onCreate(savedInstanceState);
|
||
boolean isGoToMain= getIntent().getBooleanExtra(EXTR_LUNCHER,true);
|
||
if(!Constants.AD_SETTING.isShowAdsense() ||isGoToMain && !Constants.AD_SETTING.getSplash().isShow() ){
|
||
goToMainActivity();
|
||
return;
|
||
}
|
||
int rid =R.layout.ad_toutiao_activity_splash;
|
||
int splashSource=Constants.AD_TENCENT_QQ;
|
||
if(isGoToMain) {
|
||
if (Constants.AD_SETTING.getSplash().getSource() == Constants.AD_TENCENT_QQ) {
|
||
rid = R.layout.ad_qq_activity_splash;
|
||
} else if (Constants.AD_SETTING.getSplash().getSource() == Constants.AD_TOUTIAO) {
|
||
rid = R.layout.ad_toutiao_activity_splash;
|
||
splashSource=Constants.AD_TOUTIAO;
|
||
}
|
||
}else{
|
||
if (Constants.AD_SETTING.getSplash2().getSource() == Constants.AD_TENCENT_QQ) {
|
||
rid = R.layout.ad_qq_activity_splash;
|
||
} else if (Constants.AD_SETTING.getSplash2().getSource() == Constants.AD_TOUTIAO) {
|
||
// rid = R.layout.ad_toutiao_activity_splash;
|
||
goToMainActivity();
|
||
return;
|
||
}
|
||
}
|
||
|
||
setContentView(rid);
|
||
ButterKnife.bind(this);
|
||
|
||
//在合适的时机申请权限,如read_phone_state,防止获取不了imei时候,下载类广告没有填充的问题
|
||
//在开屏时候申请不太合适,因为该页面倒计时结束或者请求超时会跳转,在该页面申请权限,体验不好
|
||
// TTAdManagerHolder.getInstance(this).requestPermissionIfNecessary(this);
|
||
//定时,AD_TIME_OUT时间到时执行,如果开屏广告没有加载则跳转到主页面
|
||
|
||
getWindow().getDecorView().setSystemUiVisibility(
|
||
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_STICKY
|
||
// | View.SYSTEM_UI_FLAG_IMMERSIVE
|
||
);
|
||
tvTitle.setText(R.string.app_name);
|
||
//加载开屏广告
|
||
if(splashSource == Constants.AD_TOUTIAO ) {
|
||
mHandler.sendEmptyMessageDelayed(MSG_GO_MAIN, AD_TIME_OUT);
|
||
//step2:创建TTAdNative对象
|
||
try {
|
||
mTTAdNative = TTAdManagerHolder.get().createAdNative(this);
|
||
} catch (Exception e) {
|
||
goToMainActivity();
|
||
return;
|
||
}
|
||
loadSplashAd();
|
||
}else if(splashSource == Constants.AD_TENCENT_QQ ){
|
||
if (Build.VERSION.SDK_INT >= 23) {
|
||
checkAndRequestPermission();
|
||
} else {
|
||
// 如果是Android6.0以下的机器,默认在安装时获得了所有权限,可以直接调用SDK
|
||
fetchSplashAD(this, mSplashContainer, skipView, getAppID(Constants.AD_TENCENT_QQ), getPosId(), this, 0);
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* 跳转到主页面
|
||
*/
|
||
private void goToMainActivity() {
|
||
|
||
boolean isGoToMain= getIntent().getBooleanExtra(EXTR_LUNCHER,true);
|
||
if(isGoToMain) {
|
||
Intent intent = new Intent(SplashActivity.this, Main2Activity.class);
|
||
startActivity(intent);
|
||
}
|
||
if(mSplashContainer!=null) {
|
||
mSplashContainer.removeAllViews();
|
||
}
|
||
|
||
SplashAdManager.clearPages();
|
||
|
||
this.finish();
|
||
}
|
||
@Override
|
||
protected void onResume() {
|
||
//判断是否该跳转到主页面
|
||
if (mForceGoMain) {
|
||
mHandler.removeCallbacksAndMessages(null);
|
||
goToMainActivity();
|
||
}
|
||
super.onResume();
|
||
if (canJump) {
|
||
next();
|
||
}
|
||
canJump = true;
|
||
}
|
||
|
||
@Override
|
||
protected void onStop() {
|
||
super.onStop();
|
||
mForceGoMain = true;
|
||
}
|
||
@Override
|
||
protected void onPause() {
|
||
super.onPause();
|
||
canJump = false;
|
||
}
|
||
|
||
|
||
@Override
|
||
protected void onDestroy() {
|
||
super.onDestroy();
|
||
handler.removeCallbacksAndMessages(null);
|
||
}
|
||
/**
|
||
* 加载开屏广告
|
||
*/
|
||
private void loadSplashAd() {
|
||
//step3:创建开屏广告请求参数AdSlot,具体参数含义参考文档
|
||
AdSlot adSlot = new AdSlot.Builder()
|
||
.setCodeId(Constants.AD_SETTING.getSplash().getSlotId(Constants.AD_TOUTIAO) )
|
||
.setSupportDeepLink(true)
|
||
.setImageAcceptedSize(Constants.SCREEN_WIDTH_PIX, Constants.SCREEN_HEIGHT_PIX)
|
||
.build();
|
||
//step4:请求广告,调用开屏广告异步请求接口,对请求回调的广告作渲染处理
|
||
mTTAdNative.loadSplashAd(adSlot, new TTAdNative.SplashAdListener() {
|
||
@Override
|
||
@MainThread
|
||
public void onError(int code, String message) {
|
||
Log.d(TAG, message);
|
||
mHasLoaded = true;
|
||
showToast(message);
|
||
goToMainActivity();
|
||
}
|
||
|
||
@Override
|
||
@MainThread
|
||
public void onTimeout() {
|
||
mHasLoaded = true;
|
||
showToast("开屏广告加载超时");
|
||
goToMainActivity();
|
||
}
|
||
|
||
@Override
|
||
@MainThread
|
||
public void onSplashAdLoad(TTSplashAd ad) {
|
||
Log.d(TAG, "开屏广告请求成功");
|
||
SplashAdManager.setSplashTime();
|
||
mHasLoaded = true;
|
||
mHandler.removeCallbacksAndMessages(null);
|
||
if (ad == null) {
|
||
return;
|
||
}
|
||
//获取SplashView
|
||
View view = ad.getSplashView();
|
||
mSplashContainer.removeAllViews();
|
||
//把SplashView 添加到ViewGroup中,注意开屏广告view:width >=70%屏幕宽;height >=50%屏幕宽
|
||
mSplashContainer.addView(view);
|
||
//设置不开启开屏广告倒计时功能以及不显示跳过按钮,如果这么设置,您需要自定义倒计时逻辑
|
||
//ad.setNotAllowSdkCountdown();
|
||
|
||
//设置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();
|
||
}
|
||
});
|
||
}
|
||
}, AD_TIME_OUT);
|
||
}
|
||
|
||
|
||
private void showToast(String msg) {
|
||
//TToast.show(this, msg);
|
||
Log.d(TAG, "loadBannerAd: " + msg);
|
||
}
|
||
|
||
@Override
|
||
public void handleMsg(Message msg) {
|
||
if (msg.what == MSG_GO_MAIN) {
|
||
if (!mHasLoaded) {
|
||
showToast("广告已超时,跳到主页面");
|
||
goToMainActivity();
|
||
}
|
||
}
|
||
}
|
||
|
||
@Override
|
||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||
|
||
if (keyCode == KeyEvent.KEYCODE_BACK|| keyCode == KeyEvent.KEYCODE_HOME) {
|
||
|
||
return true;
|
||
|
||
}
|
||
return super.onKeyUp(keyCode,event);
|
||
}
|
||
|
||
|
||
//-----qq ad begin------>
|
||
/**
|
||
*
|
||
* ----------非常重要----------
|
||
*
|
||
* Android6.0以上的权限适配简单示例:
|
||
*
|
||
* 如果targetSDKVersion >= 23,那么必须要申请到所需要的权限,再调用广点通SDK,否则广点通SDK不会工作。
|
||
*
|
||
* Demo代码里是一个基本的权限申请示例,请开发者根据自己的场景合理地编写这部分代码来实现权限申请。
|
||
* 注意:下面的`checkSelfPermission`和`requestPermissions`方法都是在Android6.0的SDK中增加的API,如果您的App还没有适配到Android6.0以上,则不需要调用这些方法,直接调用广点通SDK即可。
|
||
*/
|
||
@TargetApi(Build.VERSION_CODES.M)
|
||
private void checkAndRequestPermission() {
|
||
List<String> lackedPermission = new ArrayList<String>();
|
||
if (!(checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)) {
|
||
lackedPermission.add(Manifest.permission.READ_PHONE_STATE);
|
||
}
|
||
|
||
if (!(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)) {
|
||
lackedPermission.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||
}
|
||
|
||
if (!(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)) {
|
||
lackedPermission.add(Manifest.permission.ACCESS_FINE_LOCATION);
|
||
}
|
||
|
||
// 权限都已经有了,那么直接调用SDK
|
||
if (lackedPermission.size() == 0) {
|
||
fetchSplashAD(this, mSplashContainer, skipView, getAppID(Constants.AD_TENCENT_QQ), getPosId(), this, 0);
|
||
} else {
|
||
// 请求所缺少的权限,在onRequestPermissionsResult中再看是否获得权限,如果获得权限就可以调用SDK,否则不要调用SDK。
|
||
String[] requestPermissions = new String[lackedPermission.size()];
|
||
lackedPermission.toArray(requestPermissions);
|
||
requestPermissions(requestPermissions, 1024);
|
||
}
|
||
}
|
||
|
||
private boolean hasAllPermissionsGranted(int[] grantResults) {
|
||
for (int grantResult : grantResults) {
|
||
if (grantResult == PackageManager.PERMISSION_DENIED) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
@Override
|
||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||
if (requestCode == 1024 && hasAllPermissionsGranted(grantResults)) {
|
||
fetchSplashAD(this, mSplashContainer, skipView, getAppID(Constants.AD_TENCENT_QQ), getPosId(), this, 0);
|
||
} else {
|
||
// 如果用户没有授权,那么应该说明意图,引导用户去设置里面授权。
|
||
Toast.makeText(this, "应用缺少必要的权限!请点击\"权限\",打开所需要的权限。", Toast.LENGTH_LONG).show();
|
||
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||
intent.setData(Uri.parse("package:" + getPackageName()));
|
||
startActivity(intent);
|
||
finish();
|
||
goToMainActivity();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 拉取开屏广告,开屏广告的构造方法有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) {
|
||
fetchSplashADTime = System.currentTimeMillis();
|
||
Map<String, String> tags = new HashMap<>();
|
||
tags.put("tag_s1", "value_s1");
|
||
tags.put("tag_s2", "value_s2");
|
||
|
||
splashAD = new SplashAD(activity, adContainer, skipContainer, appId, posId, adListener,
|
||
fetchDelay, tags);
|
||
// 如果不需要传tag,使用如下构造函数
|
||
// splashAD = new SplashAD(activity, adContainer, skipContainer, appId, posId, adListener, fetchDelay);
|
||
}
|
||
|
||
@Override
|
||
public void onADPresent() {
|
||
Log.i("AD_DEMO", "SplashADPresent");
|
||
SplashAdManager.setSplashTime();
|
||
splashHolder.setVisibility(View.INVISIBLE); // 广告展示后一定要把预设的开屏图片隐藏起来
|
||
}
|
||
|
||
@Override
|
||
public void onADClicked() {
|
||
Log.i("AD_DEMO", "SplashADClicked clickUrl: "
|
||
+ (splashAD.getExt() != null ? splashAD.getExt().get("clickUrl") : ""));
|
||
}
|
||
|
||
/**
|
||
* 倒计时回调,返回广告还将被展示的剩余时间。
|
||
* 通过这个接口,开发者可以自行决定是否显示倒计时提示,或者还剩几秒的时候显示倒计时
|
||
*
|
||
* @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)));
|
||
}
|
||
|
||
@Override
|
||
public void onADExposure() {
|
||
Log.i("AD_DEMO", "SplashADExposure");
|
||
}
|
||
|
||
@Override
|
||
public void onADDismissed() {
|
||
Log.i("AD_DEMO", "SplashADDismissed");
|
||
next();
|
||
}
|
||
|
||
@Override
|
||
public void onNoAD(AdError error) {
|
||
Log.i(
|
||
"AD_DEMO",
|
||
String.format("LoadSplashADFail, eCode=%d, errorMsg=%s", error.getErrorCode(),
|
||
error.getErrorMsg()));
|
||
/**
|
||
* 为防止无广告时造成视觉上类似于"闪退"的情况,设定无广告时页面跳转根据需要延迟一定时间,demo
|
||
* 给出的延时逻辑是从拉取广告开始算开屏最少持续多久,仅供参考,开发者可自定义延时逻辑,如果开发者采用demo
|
||
* 中给出的延时逻辑,也建议开发者考虑自定义minSplashTimeWhenNoAD的值
|
||
**/
|
||
long alreadyDelayMills = System.currentTimeMillis() - fetchSplashADTime;//从拉广告开始到onNoAD已经消耗了多少时间
|
||
long shouldDelayMills = alreadyDelayMills > minSplashTimeWhenNoAD ? 0 : minSplashTimeWhenNoAD
|
||
- alreadyDelayMills;//为防止加载广告失败后立刻跳离开屏可能造成的视觉上类似于"闪退"的情况,根据设置的minSplashTimeWhenNoAD
|
||
// 计算出还需要延时多久
|
||
handler.postDelayed(new Runnable() {
|
||
@Override
|
||
public void run() {
|
||
|
||
SplashActivity.this.finish();
|
||
goToMainActivity();
|
||
}
|
||
}, shouldDelayMills);
|
||
}
|
||
|
||
/**
|
||
* 设置一个变量来控制当前开屏页面是否可以跳转,当开屏广告为普链类广告时,点击会打开一个广告落地页,此时开发者还不能打开自己的App主页。当从广告落地页返回以后,
|
||
* 才可以跳转到开发者自己的App主页;当开屏广告是App类广告时只会下载App。
|
||
*/
|
||
private void next() {
|
||
if (canJump) {
|
||
goToMainActivity();
|
||
this.finish();
|
||
|
||
} else {
|
||
canJump = true;
|
||
}
|
||
}
|
||
private String getPosId() {
|
||
return Constants.AD_SETTING.getSplash().getSlotId(Constants.AD_TENCENT_QQ);
|
||
}
|
||
|
||
//----qq ad end <---
|
||
}
|