293 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
		
		
			
		
	
	
			293 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
|  | package com.novelbook.android.AD.qq; | |||
|  | 
 | |||
|  | 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.provider.Settings; | |||
|  | import android.text.TextUtils; | |||
|  | import android.util.Log; | |||
|  | import android.view.KeyEvent; | |||
|  | import android.view.View; | |||
|  | import android.view.ViewGroup; | |||
|  | import android.widget.ImageView; | |||
|  | import android.widget.TextView; | |||
|  | import android.widget.Toast; | |||
|  | 
 | |||
|  | 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 java.util.ArrayList; | |||
|  | import java.util.HashMap; | |||
|  | import java.util.List; | |||
|  | import java.util.Map; | |||
|  | 
 | |||
|  | import static com.novelbook.android.bean.AdSetting.getAppID; | |||
|  | 
 | |||
|  | /** | |||
|  |  * 这是demo工程的入口Activity,在这里会首次调用广点通的SDK。 | |||
|  |  * | |||
|  |  * 在调用SDK之前,如果您的App的targetSDKVersion >= 23,那么一定要把"READ_PHONE_STATE"、"WRITE_EXTERNAL_STORAGE"、"ACCESS_FINE_LOCATION"这几个权限申请到,否则SDK将不会工作。 | |||
|  |  */ | |||
|  | public class SplashActivity extends Activity implements SplashADListener { | |||
|  | 
 | |||
|  |   private SplashAD splashAD; | |||
|  |   private ViewGroup container; | |||
|  |   private TextView skipView; | |||
|  |   //private ImageView splashHolder; | |||
|  |   private TextView splashHolder; | |||
|  |   private TextView tvTitle; | |||
|  |   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()); | |||
|  | 
 | |||
|  |   @Override | |||
|  |   protected void onCreate(Bundle savedInstanceState) { | |||
|  |     super.onCreate(savedInstanceState); | |||
|  |     setContentView(R.layout.ad_qq_activity_splash ); | |||
|  |     container = (ViewGroup) this.findViewById(R.id.splash_container); | |||
|  |     skipView = (TextView) findViewById(R.id.skip_view); | |||
|  |     tvTitle = (TextView) findViewById(R.id.textTile); | |||
|  |     splashHolder = (TextView) findViewById(R.id.splash_holder); | |||
|  | 
 | |||
|  |     tvTitle.setText(R.string.app_name); | |||
|  |     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 | |||
|  |     ); | |||
|  | 
 | |||
|  |    /* boolean needLogo = getIntent().getBooleanExtra("need_logo", true); | |||
|  |     needStartDemoList = getIntent().getBooleanExtra("need_start_demo_list", true); | |||
|  |     if (!needLogo) { | |||
|  |       findViewById(R.id.app_logo).setVisibility(View.GONE); | |||
|  |     }*/ | |||
|  |     // 如果targetSDKVersion >= 23,就要申请好权限。如果您的App没有适配到Android6.0(即targetSDKVersion < 23),那么只需要在这里直接调用fetchSplashAD接口。 | |||
|  |     if (Build.VERSION.SDK_INT >= 23) { | |||
|  |       checkAndRequestPermission(); | |||
|  |     } else { | |||
|  |       // 如果是Android6.0以下的机器,默认在安装时获得了所有权限,可以直接调用SDK | |||
|  |       fetchSplashAD(this, container, skipView, getAppID(Constants.AD_TENCENT_QQ),  getPosId(), this, 0); | |||
|  |     } | |||
|  |   } | |||
|  | 
 | |||
|  |   private String getPosId() { | |||
|  |     return    Constants.AD_SETTING.getSplash().getSlotId(Constants.AD_TENCENT_QQ); | |||
|  |   } | |||
|  | 
 | |||
|  |   /** | |||
|  |    * | |||
|  |    * ----------非常重要---------- | |||
|  |    * | |||
|  |    * 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, container, 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, container, 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(); | |||
|  |     } | |||
|  |   } | |||
|  | 
 | |||
|  |   /** | |||
|  |    * 拉取开屏广告,开屏广告的构造方法有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"); | |||
|  |     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(); | |||
|  |       } | |||
|  |     }, shouldDelayMills); | |||
|  |   } | |||
|  | 
 | |||
|  |   /** | |||
|  |    * 设置一个变量来控制当前开屏页面是否可以跳转,当开屏广告为普链类广告时,点击会打开一个广告落地页,此时开发者还不能打开自己的App主页。当从广告落地页返回以后, | |||
|  |    * 才可以跳转到开发者自己的App主页;当开屏广告是App类广告时只会下载App。 | |||
|  |    */ | |||
|  |   private void next() { | |||
|  |     if (canJump) { | |||
|  | 
 | |||
|  |       this.finish(); | |||
|  |     } else { | |||
|  |       canJump = true; | |||
|  |     } | |||
|  |   } | |||
|  | 
 | |||
|  |   @Override | |||
|  |   protected void onPause() { | |||
|  |     super.onPause(); | |||
|  |     canJump = false; | |||
|  |   } | |||
|  | 
 | |||
|  |   @Override | |||
|  |   protected void onResume() { | |||
|  |     super.onResume(); | |||
|  |     if (canJump) { | |||
|  |       next(); | |||
|  |     } | |||
|  |     canJump = true; | |||
|  |   } | |||
|  | 
 | |||
|  |   @Override | |||
|  |   protected void onDestroy() { | |||
|  |     super.onDestroy(); | |||
|  |     handler.removeCallbacksAndMessages(null); | |||
|  |   } | |||
|  | 
 | |||
|  |   /** 开屏页一定要禁止用户对返回按钮的控制,否则将可能导致用户手动退出了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); | |||
|  |   } | |||
|  | 
 | |||
|  | } |