diff --git a/.github/ISSUE_TEMPLATE/----.md b/.github/ISSUE_TEMPLATE/----.md
new file mode 100644
index 0000000..56b3c6a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/----.md
@@ -0,0 +1,13 @@
+---
+name: 功能建议
+about: 说出你对项目的建议
+title: ''
+labels: enhancement
+assignees: ifmvo
+
+---
+
+**你的建议基于你遇到什么问题?**
+
+
+**你希望怎样改进?**
diff --git a/.github/ISSUE_TEMPLATE/bug--.md b/.github/ISSUE_TEMPLATE/bug--.md
new file mode 100644
index 0000000..0bd02d4
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug--.md
@@ -0,0 +1,30 @@
+---
+name: Bug反馈
+about: 说出你遇到的问题
+title: '例: 开屏广告倒计时结束后发生崩溃'
+labels: bug
+assignees: ifmvo
+
+---
+
+**Bug 描述和日志**
+
+
+**Bug 复现的步骤**
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**截图**
+如果Bug展示较为明显,最好附上截图
+
+**系统版本以及设备型号**
+ - 设备型号:华为Mate40Pro]
+ - 系统版本:Android11
+ - TogetherAd版本:
+ implementation 'com.matthewchen.togetherad:csj:x.x.x-x.x.x.x'
+ implementation 'com.matthewchen.togetherad:gdt:x.x.x-x.xxx.xxxx'
+ implementation 'com.matthewchen.togetherad:baidu:x.x.x-x.xx'
+
+**附加信息**
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e80e45a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,54 @@
+# Copy from Alibaba open source
+
+# Built application files
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+# local.properties
+.classpath
+.project
+.settings/
+
+# Proguard folder generated by Eclipse
+proguard/
+
+#Log Files
+*.log
+
+# OS X
+.DS_Store
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.war
+*.ear
+*.iml
+
+# IDEA Files
+.idea/
+.svn/
+out/
+
+# MAVEN COMPILE Files
+target/
+lint.xml
+local.properties
+
+deploy.gradle
+jcenterDeploy.gradle
+jcenterInstall.gradle
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..3a8ae37
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 陈铭卓
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a8a920d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,132 @@
+# TogetherAd
+
+TogetherAd 是由 Kotlin 编写的 Android 广告聚合开源项目。
+
+能够帮助 Android 开发者``快速``、``便捷``、``灵活``的 ``接入并使用`` 国内多家主流广告 SDK。
+
+TogetherAd 也是一种将各个广告提供商``组件化处理``的解决方案。
+
+默认提供了三家广告提供商:``字节的穿山甲``、``腾讯的优量汇``、``百度的百青藤``。
+
+如果这三家满足不了你的需求,还需要其他家广告提供商,可参考[扩展文档](doc/extend.md)。
+
+TogetherAd 也提供了很多自定义功能,比如:``按权重分发广告``、``失败切换``、``超时时间``、``自定义图片加载器``、``热启动开屏广告解决方案``等...
+
+### 安装 Demo
+
+微信扫描底部二维码,回复 ``apk`` 可下载 Demo Apk 尝鲜
+
+### Gradle 添加依赖
+
+项目根目录下的 build.gradle 文件中添加 ``JitPack`` 仓库
+
+```gradle
+allprojects {
+ repositories {
+ ...
+ maven { url 'https://jitpack.io' }
+ }
+}
+```
+
+``core``是必选,其他3个根据自身需求``任选``1 ~ 3个组合搭配
+
+```gradle
+dependencies {
+
+ //核心库( 必要 )
+ implementation 'com.github.ifmvo.TogetherAd:core:5.0.3'
+
+ //优量汇( 腾讯广点通 )可选
+ implementation 'com.github.ifmvo.TogetherAd:gdt:5.0.3'
+
+ //穿山甲( 头条 )可选
+ implementation 'com.github.ifmvo.TogetherAd:csj:5.0.3'
+
+ //百青藤 ( 百度 Mob ) 可选
+ implementation 'com.github.ifmvo.TogetherAd:baidu:5.0.3'
+
+}
+```
+
+> 对应版本:穿山甲3.6.1.1;优量汇4.351.1221;百度5.91
+
+### 使用方法
+
+- [特色功能](doc/feature.md)
+
+- [准备工作及初始化](doc/prepare.md)
+
+- [开屏广告](doc/splash.md)
+
+- [Banner横幅广告](doc/banner.md)
+
+- [Interstitial插屏广告](doc/inter.md)
+
+- [原生模板](doc/express.md)
+
+- [原生自渲染](doc/native.md)
+
+- [激励广告](doc/reward.md)
+
+- [全屏视频广告](doc/full_video.md)
+
+- [混合使用](doc/hybrid.md)
+
+- [扩展](doc/extend.md)
+
+- [常见问题](doc/question.md)
+
+- [版本更新日志](doc/update_log.md)
+
+### 混淆 proguard-rules.pro
+
+资源库中已自带混淆规则,通常情况下无需手动配置。
+
+当然你也可以点击这里查看每个资源库的混淆规则: [core](core/proguard-rules.pro)、[gdt](gdt/proguard-rules.pro)、[csj](csj/proguard-rules.pro)、[baidu](baidu/proguard-rules.pro)
+
+### 相关文档收集
+
+- [优量汇接入文档](https://developers.adnet.qq.com/doc/android/access_doc)
+
+- [优量汇常见问题](https://e.qq.com/dev/help_detail.html?cid=668&pid=2208)
+
+- [优量汇SDK修订历史](https://developers.adnet.qq.com/doc/android/union/union_version)
+
+- [优量汇错误码对照](https://developers.adnet.qq.com/backend/error_code.html)
+
+- [穿山甲文档](http://partner.toutiao.com/doc?id=5dd0fe756b181e00112e3ec5)
+
+- [百青藤v5.88接入文档](https://baidu-ssp.gz.bcebos.com/mssp/sdk/BaiduMobAds_MSSP_bd_SDK_android_v5.88.pdf)
+
+### 有疑问?
+
+微信扫描下面二维码, **关注后点击联系我** 可邀请进微信交流群,更多大佬为你答疑。
+
+
+
+### License
+
+```
+MIT License
+
+Copyright (c) 2021 陈铭卓
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+```
\ No newline at end of file
diff --git a/baidu/.gitignore b/baidu/.gitignore
new file mode 100644
index 0000000..107ef7c
--- /dev/null
+++ b/baidu/.gitignore
@@ -0,0 +1,53 @@
+# Copy from Alibaba open source
+
+# Built application files
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+# local.properties
+.classpath
+.project
+.settings/
+
+# Proguard folder generated by Eclipse
+proguard/
+
+#Log Files
+*.log
+
+# OS X
+.DS_Store
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.war
+*.ear
+*.iml
+
+# IDEA Files
+.idea/
+.svn/
+out/
+
+# MAVEN COMPILE Files
+target/
+lint.xml
+
+deploy.gradle
+jcenterDeploy.gradle
+jcenterInstall.gradle
\ No newline at end of file
diff --git a/baidu/build.gradle b/baidu/build.gradle
new file mode 100644
index 0000000..a97d647
--- /dev/null
+++ b/baidu/build.gradle
@@ -0,0 +1,40 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'com.kezong.fat-aar'
+
+// JitPack Maven
+apply plugin: 'com.github.dcendents.android-maven'
+// Your Group
+group = 'com.github.ifmvo'
+
+android {
+ compileSdkVersion 28
+
+ defaultConfig {
+ minSdkVersion 16
+ targetSdkVersion 28
+ versionCode 1
+ versionName "5.0.3"
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ buildTypes {
+ release {
+ consumerProguardFiles 'proguard-rules.pro'
+ }
+ }
+
+ repositories { flatDir { dirs 'libs' } }
+}
+
+dependencies {
+ api fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+// embed(name: 'Baidu_MobAds_SDK-release', ext: 'aar')
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+
+ api project(':core')
+}
\ No newline at end of file
diff --git a/baidu/libs/Baidu_MobAds_SDK-release.aar b/baidu/libs/Baidu_MobAds_SDK-release.aar
new file mode 100644
index 0000000..1a3af7f
Binary files /dev/null and b/baidu/libs/Baidu_MobAds_SDK-release.aar differ
diff --git a/baidu/proguard-rules.pro b/baidu/proguard-rules.pro
new file mode 100644
index 0000000..abd659a
--- /dev/null
+++ b/baidu/proguard-rules.pro
@@ -0,0 +1,34 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+
+#------------------------百度的混淆---------------------------#
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+-keep class com.baidu.mobads.** { *; }
+-keep class com.baidu.mobad.** { *; }
+
+-keep class com.ifmvo.togetherad.baidu.** { *; }
\ No newline at end of file
diff --git a/baidu/src/main/AndroidManifest.xml b/baidu/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..220d2ae
--- /dev/null
+++ b/baidu/src/main/AndroidManifest.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/baidu/src/main/java/com/ifmvo/togetherad/baidu/TogetherAdBaidu.kt b/baidu/src/main/java/com/ifmvo/togetherad/baidu/TogetherAdBaidu.kt
new file mode 100644
index 0000000..f0ee7c8
--- /dev/null
+++ b/baidu/src/main/java/com/ifmvo/togetherad/baidu/TogetherAdBaidu.kt
@@ -0,0 +1,36 @@
+package com.ifmvo.togetherad.baidu
+
+import android.content.Context
+import org.jetbrains.annotations.NotNull
+import com.baidu.mobads.AdView
+import com.ifmvo.togetherad.baidu.provider.BaiduProvider
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.entity.AdProviderEntity
+
+/**
+ * 初始化百青藤
+ *
+ * Created by Matthew Chen on 2020-04-04.
+ */
+object TogetherAdBaidu {
+
+ var idMapBaidu = mutableMapOf()
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull baiduAdAppId: String) {
+ init(context, adProviderType, baiduAdAppId, null, null)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull baiduAdAppId: String, providerClassPath: String? = null) {
+ init(context, adProviderType, baiduAdAppId, null, providerClassPath)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull baiduAdAppId: String, baiduIdMap: Map? = null) {
+ init(context, adProviderType, baiduAdAppId, baiduIdMap, null)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull baiduAdAppId: String, baiduIdMap: Map? = null, providerClassPath: String? = null) {
+ TogetherAd.addProvider(AdProviderEntity(adProviderType, if (providerClassPath?.isEmpty() != false) BaiduProvider::class.java.name else providerClassPath))
+ baiduIdMap?.let { idMapBaidu.putAll(it) }
+ AdView.setAppSid(context, baiduAdAppId)
+ }
+}
\ No newline at end of file
diff --git a/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/BaseNativeViewBaidu.kt b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/BaseNativeViewBaidu.kt
new file mode 100644
index 0000000..712e4af
--- /dev/null
+++ b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/BaseNativeViewBaidu.kt
@@ -0,0 +1,93 @@
+package com.ifmvo.togetherad.baidu.native_.view
+
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.baidu.mobad.feeds.NativeResponse
+import com.ifmvo.togetherad.baidu.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeView
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+
+/**
+ *
+ * Created by Matthew Chen on 2020/9/14.
+ */
+abstract class BaseNativeViewBaidu(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeView() {
+
+ private var mOnClose = onClose
+
+ var rootView: View? = null
+
+ open fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_baidu
+ }
+
+ open fun getMainImageView(): ImageView? {
+ return rootView?.findViewById(R.id.native_main_image)
+ }
+
+ open fun getIconImageView(): ImageView? {
+ return rootView?.findViewById(R.id.native_icon_image)
+ }
+
+ open fun getBaiduLogoImageView(): ImageView? {
+ return rootView?.findViewById(R.id.native_baidulogo)
+ }
+
+ open fun getAdLogoImageView(): ImageView? {
+ return rootView?.findViewById(R.id.native_adlogo)
+ }
+
+ open fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.native_title)
+ }
+
+ open fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.native_text)
+ }
+
+ open fun getBrandNameTextView(): TextView? {
+ return rootView?.findViewById(R.id.native_brand_name)
+ }
+
+ //关闭按钮,可以重写为任意类型的View
+ open fun getCloseButton(): View? {
+ return rootView?.findViewById(R.id.btn_close)
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ if (adObject !is NativeResponse) {
+ return
+ }
+
+ //findView
+ rootView = View.inflate(container.context, getLayoutRes(), container)
+
+ //Image
+ getMainImageView()?.let { TogetherAd.mImageLoader?.loadImage(container.context, it, adObject.imageUrl) }
+ getIconImageView()?.let { TogetherAd.mImageLoader?.loadImage(container.context, it, adObject.iconUrl) }
+ getBaiduLogoImageView()?.let { TogetherAd.mImageLoader?.loadImage(container.context, it, adObject.baiduLogoUrl) }
+ getAdLogoImageView()?.let { TogetherAd.mImageLoader?.loadImage(container.context, it, adObject.adLogoUrl) }
+
+ //Text
+ getTitleTextView()?.let { it.text = adObject.title }
+ getDescTextView()?.let { it.text = adObject.desc }
+ getBrandNameTextView()?.let { it.text = adObject.brandName }
+
+ //CloseBtn
+ getCloseButton()?.visibility = if (mOnClose == null) View.GONE else View.VISIBLE
+ getCloseButton()?.setOnClickListener {
+ mOnClose?.invoke(adProviderType)
+ }
+
+ //Handle
+ adObject.recordImpression(rootView)
+ listener?.onAdExposed(adProviderType)
+ rootView?.setOnClickListener {
+ adObject.handleClick(it)
+ listener?.onAdClicked(adProviderType)
+ }
+ }
+}
\ No newline at end of file
diff --git a/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple1.kt b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple1.kt
new file mode 100644
index 0000000..3769923
--- /dev/null
+++ b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple1.kt
@@ -0,0 +1,22 @@
+package com.ifmvo.togetherad.baidu.native_.view
+
+import android.view.ViewGroup
+import com.ifmvo.togetherad.baidu.R
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewBaiduSimple1 : BaseNativeViewBaidu() {
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_baidu_simple_1
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+ //主图 16:9
+ getMainImageView()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+ }
+}
\ No newline at end of file
diff --git a/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple2.kt b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple2.kt
new file mode 100644
index 0000000..afecc7a
--- /dev/null
+++ b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple2.kt
@@ -0,0 +1,22 @@
+package com.ifmvo.togetherad.baidu.native_.view
+
+import android.view.ViewGroup
+import com.ifmvo.togetherad.baidu.R
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewBaiduSimple2 : BaseNativeViewBaidu() {
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_baidu_simple_2
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+ //主图 16:9
+ getMainImageView()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) / 3 * 9 / 16)
+ }
+}
\ No newline at end of file
diff --git a/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple3.kt b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple3.kt
new file mode 100644
index 0000000..542feaa
--- /dev/null
+++ b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple3.kt
@@ -0,0 +1,49 @@
+package com.ifmvo.togetherad.baidu.native_.view
+
+import android.os.CountDownTimer
+import android.view.ViewGroup
+import com.ifmvo.togetherad.baidu.R
+import com.ifmvo.togetherad.core.custom.splashSkip.SplashSkipViewSimple2
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import kotlin.math.roundToInt
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewBaiduSimple3(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeViewBaidu() {
+
+ private var mOnClose = onClose
+ private var mTimer: CountDownTimer? = null
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_baidu_simple_3
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+ //添加跳过按钮
+ val customSkipView = SplashSkipViewSimple2()
+ val skipView = customSkipView.onCreateSkipView(container.context)
+ skipView.run {
+ container.addView(this, customSkipView.getLayoutParams())
+ setOnClickListener {
+ mTimer?.cancel()
+ mOnClose?.invoke(adProviderType)
+ }
+ }
+
+ //开始倒计时
+ mTimer?.cancel()
+ mTimer = object : CountDownTimer(5000, 1000) {
+ override fun onFinish() {
+ mOnClose?.invoke(adProviderType)
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ val second = (millisUntilFinished / 1000f).roundToInt()
+ customSkipView.handleTime(second)
+ }
+ }
+ mTimer?.start()
+ }
+}
\ No newline at end of file
diff --git a/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple4.kt b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple4.kt
new file mode 100644
index 0000000..1f9f014
--- /dev/null
+++ b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple4.kt
@@ -0,0 +1,53 @@
+package com.ifmvo.togetherad.baidu.native_.view
+
+import android.os.CountDownTimer
+import android.view.ViewGroup
+import com.ifmvo.togetherad.baidu.R
+import com.ifmvo.togetherad.core.custom.splashSkip.SplashSkipViewSimple3
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import kotlin.math.roundToInt
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewBaiduSimple4(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeViewBaidu() {
+
+ private var mOnClose = onClose
+ private var mTimer: CountDownTimer? = null
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_baidu_simple_4
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+
+ getMainImageView()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+
+ //添加跳过按钮
+ val customSkipView = SplashSkipViewSimple3()
+ val skipView = customSkipView.onCreateSkipView(container.context)
+ skipView.run {
+ container.addView(this, customSkipView.getLayoutParams())
+ setOnClickListener {
+ mTimer?.cancel()
+ mOnClose?.invoke(adProviderType)
+ }
+ }
+
+ //开始倒计时
+ mTimer?.cancel()
+ mTimer = object : CountDownTimer(5000, 1000) {
+ override fun onFinish() {
+ mOnClose?.invoke(adProviderType)
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ val second = (millisUntilFinished / 1000f).roundToInt()
+ customSkipView.handleTime(second)
+ }
+ }
+ mTimer?.start()
+ }
+}
\ No newline at end of file
diff --git a/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple5.kt b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple5.kt
new file mode 100644
index 0000000..95e8820
--- /dev/null
+++ b/baidu/src/main/java/com/ifmvo/togetherad/baidu/native_/view/NativeViewBaiduSimple5.kt
@@ -0,0 +1,7 @@
+package com.ifmvo.togetherad.baidu.native_.view
+
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewBaiduSimple5(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeViewBaidu(onClose)
\ No newline at end of file
diff --git a/baidu/src/main/java/com/ifmvo/togetherad/baidu/provider/BaiduProvider.kt b/baidu/src/main/java/com/ifmvo/togetherad/baidu/provider/BaiduProvider.kt
new file mode 100644
index 0000000..8019ef1
--- /dev/null
+++ b/baidu/src/main/java/com/ifmvo/togetherad/baidu/provider/BaiduProvider.kt
@@ -0,0 +1,334 @@
+package com.ifmvo.togetherad.baidu.provider
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.baidu.mobad.feeds.BaiduNative
+import com.baidu.mobad.feeds.NativeErrorCode
+import com.baidu.mobad.feeds.NativeResponse
+import com.baidu.mobad.feeds.RequestParameters
+import com.baidu.mobads.*
+import com.baidu.mobads.rewardvideo.RewardVideoAd
+import com.ifmvo.togetherad.baidu.TogetherAdBaidu
+import com.ifmvo.togetherad.core.listener.*
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.logd
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import org.json.JSONObject
+
+
+/**
+ * 广告提供商:百青藤
+ *
+ * Created by Matthew Chen on 2020-04-03.
+ */
+open class BaiduProvider : BaseAdProvider() {
+
+ object Splash {
+
+ //超时时间
+ var maxFetchDelay = 4000
+
+ }
+
+ override fun loadOnlySplashAd(activity: Activity, adProviderType: String, alias: String, listener: SplashListener) {
+ callbackSplashStartRequest(adProviderType, alias, listener)
+ callbackSplashFailed(adProviderType, alias, listener, null, "百度开屏不支持加载和展示分开")
+ }
+
+ override fun showSplashAd(container: ViewGroup): Boolean {
+ return false
+ }
+
+ /**
+ * --------------------------- 开屏 ---------------------------
+ */
+ override fun loadAndShowSplashAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: SplashListener) {
+ callbackSplashStartRequest(adProviderType, alias, listener)
+
+ SplashAd(activity, container, object : SplashAdListener {
+ override fun onAdPresent() {
+ "onADLoaded".logd(tag)
+ callbackSplashLoaded(adProviderType, alias, listener)
+ }
+
+ override fun onAdDismissed() {
+ "onADLoaded".logd(tag)
+
+ callbackSplashDismiss(adProviderType, listener)
+ }
+
+ override fun onADLoaded() {
+ "onADLoaded".logd(tag)
+ }
+
+ override fun onAdFailed(errorMsg: String) {
+ "onADLoaded".logd(tag)
+ callbackSplashFailed(adProviderType, alias, listener, null, errorMsg)
+ }
+
+ override fun onAdClick() {
+ "onADLoaded".logd(tag)
+ callbackSplashClicked(adProviderType, listener)
+ }
+
+ }, TogetherAdBaidu.idMapBaidu[alias], true, Splash.maxFetchDelay)
+ }
+
+ /**
+ * --------------------------- Banner横幅 ---------------------------
+ */
+ private var adView: AdView? = null
+ override fun showBannerAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: BannerListener) {
+ callbackBannerStartRequest(adProviderType, alias, listener)
+
+ adView = AdView(activity, TogetherAdBaidu.idMapBaidu[alias])
+ adView?.setListener(object : AdViewListener {
+ override fun onAdFailed(errorMsg: String?) {
+ callbackBannerFailed(adProviderType, alias, listener, null, errorMsg)
+ }
+
+ override fun onAdShow(p0: JSONObject?) {
+ callbackBannerExpose(adProviderType, listener)
+ }
+
+ override fun onAdClick(p0: JSONObject?) {
+ callbackBannerClicked(adProviderType, listener)
+ }
+
+ override fun onAdReady(p0: AdView?) {
+ callbackBannerLoaded(adProviderType, alias, listener)
+ }
+
+ override fun onAdSwitch() {
+ "onAdSwitch".logi(tag)
+ }
+
+ override fun onAdClose(p0: JSONObject?) {
+ callbackBannerClosed(adProviderType, listener)
+ }
+ })
+ container.addView(adView)
+ }
+
+ override fun destroyBannerAd() {
+ adView?.destroy()
+ }
+
+ /**
+ * --------------------------- Inter插屏 ---------------------------
+ */
+ private var mInterAd: InterstitialAd? = null
+ override fun requestInterAd(activity: Activity, adProviderType: String, alias: String, listener: InterListener) {
+
+ callbackInterStartRequest(adProviderType, alias, listener)
+ "onStartRequest".logd(tag)
+ destroyInterAd()
+
+ mInterAd = InterstitialAd(activity, TogetherAdBaidu.idMapBaidu[alias])
+ mInterAd?.setListener(object : InterstitialAdListener {
+ override fun onAdFailed(errorMsg: String?) {
+ "onAdFailed".logd(tag)
+ callbackInterFailed(adProviderType, alias, listener, null, errorMsg)
+ }
+
+ override fun onAdDismissed() {
+ "onAdDismissed".logd(tag)
+ callbackInterClosed(adProviderType, listener)
+ }
+
+ override fun onAdPresent() {
+ "onAdPresent".logd(tag)
+ callbackInterExpose(adProviderType, listener)
+ }
+
+ override fun onAdClick(inter: InterstitialAd?) {
+ "onAdClick".logd(tag)
+ callbackInterClicked(adProviderType, listener)
+ }
+
+ override fun onAdReady() {
+ "onAdReady".logd(tag)
+ callbackInterLoaded(adProviderType, alias, listener)
+ }
+ })
+ mInterAd?.loadAd()
+ }
+
+ override fun showInterAd(activity: Activity) {
+ mInterAd?.showAd(activity)
+ }
+
+ override fun destroyInterAd() {
+ mInterAd?.destroy()
+ mInterAd = null
+ }
+
+ /**
+ * --------------------------- 原生自渲染 ---------------------------
+ */
+ override fun getNativeAdList(activity: Activity, adProviderType: String, alias: String, maxCount: Int, listener: NativeListener) {
+
+ callbackNativeStartRequest(adProviderType, alias, listener)
+
+ val baidu = BaiduNative(activity, TogetherAdBaidu.idMapBaidu[alias], object : BaiduNative.BaiduNativeNetworkListener {
+
+ override fun onNativeLoad(list: List) {
+ val subList = if (list.size > maxCount) {
+ list.subList(0, maxCount)
+ } else {
+ list
+ }
+ callbackNativeLoaded(adProviderType, alias, listener, subList)
+ }
+
+ override fun onNativeFail(nativeErrorCode: NativeErrorCode) {
+ val errorMsg = when (nativeErrorCode) {
+ NativeErrorCode.LOAD_AD_FAILED -> {
+ "请求失败"
+ }
+ NativeErrorCode.CONFIG_ERROR -> {
+ "配置错误"
+ }
+ NativeErrorCode.INTERNAL_ERROR -> {
+ "内部错误"
+ }
+ NativeErrorCode.UNKNOWN -> {
+ "未知错误"
+ }
+ }
+ callbackNativeFailed(adProviderType, alias, listener, null, errorMsg)
+ }
+ })
+ /*
+ * Step 2. 创建requestParameters对象,并将其传给baidu.makeRequest来请求广告
+ */
+ // 用户点击下载类广告时,是否弹出提示框让用户选择下载与否
+ val requestParameters = RequestParameters.Builder().build()
+
+ baidu.makeRequest(requestParameters)
+ }
+
+ override fun nativeAdIsBelongTheProvider(adObject: Any): Boolean {
+ return adObject is NativeResponse
+ }
+
+ override fun resumeNativeAd(adObject: Any) {
+ when (adObject) {
+ is NativeResponse -> {
+
+ }
+ }
+ }
+
+ override fun pauseNativeAd(adObject: Any) {
+ when (adObject) {
+ is NativeResponse -> {
+
+ }
+ }
+ }
+
+ override fun destroyNativeAd(adObject: Any) {
+ when (adObject) {
+ is NativeResponse -> {
+
+ }
+ }
+ }
+
+ override fun getNativeExpressAdList(activity: Activity, adProviderType: String, alias: String, adCount: Int, listener: NativeExpressListener) {
+ callbackNativeExpressStartRequest(adProviderType, alias, listener)
+ callbackNativeExpressFailed(adProviderType, alias, listener, null, "百度不支持原生模板类型广告")
+ }
+
+ override fun destroyNativeExpressAd(adObject: Any) {
+
+ }
+
+ override fun nativeExpressAdIsBelongTheProvider(adObject: Any): Boolean {
+ return false
+ }
+
+ override fun getNativeExpress2AdList(activity: Activity, adProviderType: String, alias: String, adCount: Int, listener: NativeExpress2Listener) {
+ callbackNativeExpressStartRequest(adProviderType, alias, listener)
+ callbackNativeExpressFailed(adProviderType, alias, listener, null, "百度不支持原生模板2类型广告")
+ }
+
+ override fun destroyNativeExpress2Ad(adObject: Any) {
+ }
+
+ override fun nativeExpress2AdIsBelongTheProvider(adObject: Any): Boolean {
+ return false
+ }
+
+ /**
+ * --------------------------- 激励 ---------------------------
+ */
+ private var mRewardVideoAd: RewardVideoAd? = null
+ override fun requestRewardAd(activity: Activity, adProviderType: String, alias: String, listener: RewardListener) {
+
+ callbackRewardStartRequest(adProviderType, alias, listener)
+
+ mRewardVideoAd = RewardVideoAd(activity, TogetherAdBaidu.idMapBaidu[alias], object : RewardVideoAd.RewardVideoAdListener {
+ override fun onAdFailed(errorMsg: String?) {
+ "onAdFailed".loge(tag)
+ callbackRewardFailed(adProviderType, alias, listener, null, errorMsg)
+ mRewardVideoAd = null
+ }
+
+ override fun playCompletion() {
+ "playCompletion".logi(tag)
+ callbackRewardVideoComplete(adProviderType, listener)
+ callbackRewardVerify(adProviderType, listener)
+ }
+
+ override fun onAdShow() {
+ "onAdShow".logi(tag)
+ callbackRewardShow(adProviderType, listener)
+ callbackRewardExpose(adProviderType, listener)
+ }
+
+ override fun onAdClick() {
+ "onAdClick".logi(tag)
+ callbackRewardClicked(adProviderType, listener)
+ }
+
+ override fun onAdClose(playScale: Float) {
+ "onAdClose".logi(tag)
+ callbackRewardClosed(adProviderType, listener)
+ mRewardVideoAd = null
+ }
+
+ override fun onVideoDownloadSuccess() {
+ "onVideoDownloadSuccess".logi(tag)
+ callbackRewardLoaded(adProviderType, alias, listener)
+ callbackRewardVideoCached(adProviderType, listener)
+ }
+
+ override fun onVideoDownloadFailed() {
+ "onVideoDownloadFailed".loge(tag)
+ callbackRewardFailed(adProviderType, alias, listener, null, "视频缓存失败")
+ }
+ }, false)
+
+ mRewardVideoAd?.load()
+ }
+
+ override fun showRewardAd(activity: Activity): Boolean {
+ if (mRewardVideoAd?.isReady == true) {
+ mRewardVideoAd?.show()
+ return true
+ }
+ return false
+ }
+
+ override fun requestFullVideoAd(activity: Activity, adProviderType: String, alias: String, listener: FullVideoListener) {
+ callbackFullVideoStartRequest(adProviderType, alias, listener)
+ callbackFullVideoFailed(adProviderType, alias, listener, null, "百度不支持全屏视频广告")
+ }
+
+ override fun showFullVideoAd(activity: Activity): Boolean {
+ return false
+ }
+}
\ No newline at end of file
diff --git a/baidu/src/main/res/layout/layout_native_view_baidu.xml b/baidu/src/main/res/layout/layout_native_view_baidu.xml
new file mode 100644
index 0000000..e17f04f
--- /dev/null
+++ b/baidu/src/main/res/layout/layout_native_view_baidu.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/baidu/src/main/res/layout/layout_native_view_baidu_simple_1.xml b/baidu/src/main/res/layout/layout_native_view_baidu_simple_1.xml
new file mode 100644
index 0000000..8bee0ad
--- /dev/null
+++ b/baidu/src/main/res/layout/layout_native_view_baidu_simple_1.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/baidu/src/main/res/layout/layout_native_view_baidu_simple_2.xml b/baidu/src/main/res/layout/layout_native_view_baidu_simple_2.xml
new file mode 100644
index 0000000..85ed4d7
--- /dev/null
+++ b/baidu/src/main/res/layout/layout_native_view_baidu_simple_2.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/baidu/src/main/res/layout/layout_native_view_baidu_simple_3.xml b/baidu/src/main/res/layout/layout_native_view_baidu_simple_3.xml
new file mode 100644
index 0000000..0d92493
--- /dev/null
+++ b/baidu/src/main/res/layout/layout_native_view_baidu_simple_3.xml
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/baidu/src/main/res/layout/layout_native_view_baidu_simple_4.xml b/baidu/src/main/res/layout/layout_native_view_baidu_simple_4.xml
new file mode 100644
index 0000000..223e234
--- /dev/null
+++ b/baidu/src/main/res/layout/layout_native_view_baidu_simple_4.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/baidu/src/main/res/values/strings.xml b/baidu/src/main/res/values/strings.xml
new file mode 100644
index 0000000..6d5a695
--- /dev/null
+++ b/baidu/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ TogetherAd
+
diff --git a/baidu/src/main/res/xml/bd_file_paths.xml b/baidu/src/main/res/xml/bd_file_paths.xml
new file mode 100644
index 0000000..482d9e7
--- /dev/null
+++ b/baidu/src/main/res/xml/bd_file_paths.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000..2692b71
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,25 @@
+buildscript {
+ ext.kotlin_version = '1.3.72'
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.3.3'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath 'com.kezong:fat-aar:1.2.12'
+ classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ maven { url 'https://jitpack.io' }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
\ No newline at end of file
diff --git a/core/.gitignore b/core/.gitignore
new file mode 100644
index 0000000..107ef7c
--- /dev/null
+++ b/core/.gitignore
@@ -0,0 +1,53 @@
+# Copy from Alibaba open source
+
+# Built application files
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+# local.properties
+.classpath
+.project
+.settings/
+
+# Proguard folder generated by Eclipse
+proguard/
+
+#Log Files
+*.log
+
+# OS X
+.DS_Store
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.war
+*.ear
+*.iml
+
+# IDEA Files
+.idea/
+.svn/
+out/
+
+# MAVEN COMPILE Files
+target/
+lint.xml
+
+deploy.gradle
+jcenterDeploy.gradle
+jcenterInstall.gradle
\ No newline at end of file
diff --git a/core/build.gradle b/core/build.gradle
new file mode 100644
index 0000000..7063fa9
--- /dev/null
+++ b/core/build.gradle
@@ -0,0 +1,33 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+// JitPack Maven
+apply plugin: 'com.github.dcendents.android-maven'
+// Your Group
+group = 'com.github.ifmvo'
+
+android {
+ compileSdkVersion 28
+
+ defaultConfig {
+ minSdkVersion 16
+ targetSdkVersion 28
+ versionCode 1
+ versionName "5.0.3"
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ buildTypes {
+ release {
+ consumerProguardFiles 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+}
\ No newline at end of file
diff --git a/core/proguard-rules.pro b/core/proguard-rules.pro
new file mode 100644
index 0000000..ee3dc0b
--- /dev/null
+++ b/core/proguard-rules.pro
@@ -0,0 +1,23 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+
+-keep class com.ifmvo.togetherad.core.** { *; }
\ No newline at end of file
diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..b04e5cf
--- /dev/null
+++ b/core/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/DispatchType.kt b/core/src/main/java/com/ifmvo/togetherad/core/DispatchType.kt
new file mode 100644
index 0000000..5987908
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/DispatchType.kt
@@ -0,0 +1,20 @@
+package com.ifmvo.togetherad.core
+
+/**
+ * 分发类型
+ *
+ * Created by Matthew Chen on 2020/12/3.
+ */
+enum class DispatchType {
+
+ /**
+ * 按照权重随机分发
+ */
+ Random,
+
+ /**
+ * 按照优先级分发广告
+ */
+ Priority
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/TogetherAd.kt b/core/src/main/java/com/ifmvo/togetherad/core/TogetherAd.kt
new file mode 100644
index 0000000..442b508
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/TogetherAd.kt
@@ -0,0 +1,132 @@
+package com.ifmvo.togetherad.core
+
+import com.ifmvo.togetherad.core.custom.native_.imageloader.AdImageLoader
+import com.ifmvo.togetherad.core.custom.native_.imageloader.DefaultImageLoader
+import com.ifmvo.togetherad.core.entity.AdProviderEntity
+import com.ifmvo.togetherad.core.listener.AllAdListener
+import com.ifmvo.togetherad.core.utils.logi
+import org.jetbrains.annotations.NotNull
+
+/**
+ * Created by Matthew Chen on 2020-04-02.
+ */
+object TogetherAd {
+
+ /**
+ * 自定义公共的的的广告提供商比例,有序
+ */
+ private val mRatioPublicMap = linkedMapOf()
+
+ /**
+ * 保存每个广告位的分发方式
+ */
+ var mDispatchTypeMap = hashMapOf()
+
+ /**
+ * 所有注册的广告提供商
+ */
+ var mProviders = mutableMapOf()
+ private set
+
+ /**
+ * 添加广告提供商
+ */
+ fun addProvider(@NotNull adProviderEntity: AdProviderEntity) {
+ mProviders[adProviderEntity.providerType] = adProviderEntity
+ "注册广告提供商:${adProviderEntity.providerType}".logi()
+ }
+
+ internal fun getProvider(providerType: String): AdProviderEntity? {
+ return mProviders[providerType]
+ }
+
+ /**
+ * 全局配置默认比例
+ *
+ * ratioMap:
+ * val map = LinkedHashLinkedHashMap()
+ * map.put(AdProviderType.GDT, 1)
+ * map.put(AdProviderType.CSJ, 1)
+ * map.put(AdProviderType.BAIDU, 2)
+ */
+ fun setPublicProviderRatio(@NotNull ratioMap: LinkedHashMap) {
+ val ratio = StringBuilder()
+ ratioMap.entries.forEach {
+ ratio.append("${it.key}:${it.value}")
+ ratio.append(",")
+ }
+ "设置默认广告提供商比例:$ratio".logi()
+
+ mRatioPublicMap.clear()
+ mRatioPublicMap.putAll(ratioMap)
+ }
+
+ /**
+ * 有自定义的就用自定义的,没有自定义就每个注册的广告商等比
+ */
+ fun getPublicProviderRatio(): LinkedHashMap {
+ return if (mRatioPublicMap.isNotEmpty()) {
+ mRatioPublicMap
+ } else {
+ val defaultMap = linkedMapOf()
+ mProviders.entries.forEach {
+ defaultMap[it.key] = 0 //所有注册的广告商权重都是 0
+ }
+ defaultMap
+ }
+ }
+
+ /**
+ * 可自定义图片加载处理
+ */
+ var mImageLoader: AdImageLoader? = DefaultImageLoader()
+ private set
+
+ /**
+ * 提供了自定义图片加载框架的接口
+ */
+ fun setCustomImageLoader(@NotNull imageLoader: AdImageLoader) {
+ mImageLoader = imageLoader
+ }
+
+ /**
+ * 是否打印 Log 日志
+ */
+ var printLogEnable: Boolean = true
+
+ /**
+ * 是否失败切换 ( 当请求广告失败时,是否允许切换到其他广告提供商再次请求 )
+ */
+ var failedSwitchEnable: Boolean = true
+
+ /**
+ * 通用最大拉取延时时间ms( 请求广告的超时时间;3000 ≤ value ≥ 10000 )
+ */
+ var maxFetchDelay: Long = 0
+ set(value) {
+ field = when {
+ value < 3000 -> {
+ 3000
+ }
+ value > 10000 -> {
+ 10000
+ }
+ else -> {
+ value
+ }
+ }
+ }
+
+ /**
+ * 所有广告商所有广告类型的广告都会回调这个监听器
+ * 主要是方便做统计:请求成功率、请求失败信息等
+ */
+ var allAdListener: AllAdListener? = null
+
+ /**
+ * 分发方式
+ * DispatchType.Random 按照权重比例随机分发
+ * DispatchType.Priority 按照优先级分发广告
+ */
+ var dispatchType: DispatchType = DispatchType.Random
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/config/AdProviderLoader.kt b/core/src/main/java/com/ifmvo/togetherad/core/config/AdProviderLoader.kt
new file mode 100644
index 0000000..b6c7f61
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/config/AdProviderLoader.kt
@@ -0,0 +1,62 @@
+package com.ifmvo.togetherad.core.config
+
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import java.lang.reflect.Constructor
+
+/*
+ * Created by Matthew Chen on 2020-04-03.
+ */
+object AdProviderLoader {
+
+ fun loadAdProvider(providerType: String): BaseAdProvider? {
+ var adProvider: BaseAdProvider? = null
+ try {
+ val providerInstance = getProviderInstance(providerType)
+ if (providerInstance is BaseAdProvider) {
+ adProvider = providerInstance
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ return adProvider
+ }
+
+ private fun getProviderInstance(providerType: String): Any? {
+ var instance: Any? = null
+ try {
+ TogetherAd.getProvider(providerType)?.classPath?.let { classPath ->
+ getSDKClass(classPath)?.let { clz ->
+ instance = getConstructor(clz)?.newInstance()
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+
+ return instance
+ }
+
+ private fun getConstructor(clz: Class<*>): Constructor<*>? {
+ var result: Constructor<*>? = null
+ try {
+ result = clz.getConstructor()
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+
+ return result
+ }
+
+ private fun getSDKClass(classPath: String): Class<*>? {
+ var result: Class<*>? = null
+ try {
+ result = Class.forName(classPath)
+ } catch (e: ClassNotFoundException) {
+ e.printStackTrace()
+ }
+
+ return result
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/express/BaseNativeExpressTemplate.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/express/BaseNativeExpressTemplate.kt
new file mode 100644
index 0000000..d718208
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/express/BaseNativeExpressTemplate.kt
@@ -0,0 +1,11 @@
+package com.ifmvo.togetherad.core.custom.express
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/27.
+ */
+abstract class BaseNativeExpressTemplate {
+
+ abstract fun getNativeExpressView(adProviderType: String): BaseNativeExpressView?
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/express/BaseNativeExpressView.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/express/BaseNativeExpressView.kt
new file mode 100644
index 0000000..8277a09
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/express/BaseNativeExpressView.kt
@@ -0,0 +1,13 @@
+package com.ifmvo.togetherad.core.custom.express
+
+import android.view.ViewGroup
+import org.jetbrains.annotations.NotNull
+
+/*
+ * Created by Matthew Chen on 2020-04-21.
+ */
+abstract class BaseNativeExpressView {
+
+ abstract fun showNativeExpress(@NotNull adProviderType: String, @NotNull adObject: Any, @NotNull container: ViewGroup)
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/express2/BaseNativeExpress2Template.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/express2/BaseNativeExpress2Template.kt
new file mode 100644
index 0000000..3e96c8c
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/express2/BaseNativeExpress2Template.kt
@@ -0,0 +1,13 @@
+package com.ifmvo.togetherad.core.custom.express2
+
+import com.ifmvo.togetherad.core.custom.express2.BaseNativeExpress2View
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/27.
+ */
+abstract class BaseNativeExpress2Template {
+
+ abstract fun getNativeExpress2View(adProviderType: String): BaseNativeExpress2View?
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/express2/BaseNativeExpress2View.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/express2/BaseNativeExpress2View.kt
new file mode 100644
index 0000000..71be56e
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/express2/BaseNativeExpress2View.kt
@@ -0,0 +1,16 @@
+package com.ifmvo.togetherad.core.custom.express2
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.listener.NativeExpress2ViewListener
+import org.jetbrains.annotations.NotNull
+import org.jetbrains.annotations.Nullable
+
+/*
+ * Created by Matthew Chen on 2020-04-21.
+ */
+abstract class BaseNativeExpress2View {
+
+ abstract fun showNativeExpress2(@NotNull activity: Activity, @NotNull adProviderType: String, @NotNull adObject: Any, @NotNull container: ViewGroup, @Nullable listener: NativeExpress2ViewListener? = null)
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/BaseNativeTemplate.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/BaseNativeTemplate.kt
new file mode 100644
index 0000000..e1f2006
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/BaseNativeTemplate.kt
@@ -0,0 +1,11 @@
+package com.ifmvo.togetherad.core.custom.native_
+
+
+/*
+ * Created by Matthew Chen on 2020-04-21.
+ */
+abstract class BaseNativeTemplate {
+
+ abstract fun getNativeView(adProviderType: String): BaseNativeView?
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/BaseNativeView.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/BaseNativeView.kt
new file mode 100644
index 0000000..ff7613b
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/BaseNativeView.kt
@@ -0,0 +1,15 @@
+package com.ifmvo.togetherad.core.custom.native_
+
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import org.jetbrains.annotations.NotNull
+import org.jetbrains.annotations.Nullable
+
+/*
+ * Created by Matthew Chen on 2020-04-21.
+ */
+abstract class BaseNativeView {
+
+ abstract fun showNative(@NotNull adProviderType: String, @NotNull adObject: Any, @NotNull container: ViewGroup, @Nullable listener: NativeViewListener? = null)
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/imageloader/AdImageLoader.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/imageloader/AdImageLoader.kt
new file mode 100644
index 0000000..24eb7f9
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/imageloader/AdImageLoader.kt
@@ -0,0 +1,16 @@
+package com.ifmvo.togetherad.core.custom.native_.imageloader
+
+import android.content.Context
+import org.jetbrains.annotations.NotNull
+import android.widget.ImageView
+
+/**
+ * 加载图片的接口
+ *
+ * Created by Matthew Chen on 2020-05-15.
+ */
+interface AdImageLoader {
+
+ fun loadImage(@NotNull context: Context, @NotNull imageView: ImageView, @NotNull imgUrl: String)
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/imageloader/DefaultImageLoader.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/imageloader/DefaultImageLoader.kt
new file mode 100644
index 0000000..eee429c
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/native_/imageloader/DefaultImageLoader.kt
@@ -0,0 +1,58 @@
+package com.ifmvo.togetherad.core.custom.native_.imageloader
+
+import android.content.Context
+import android.graphics.BitmapFactory
+import android.os.Handler
+import android.os.Looper
+import android.widget.ImageView
+import com.ifmvo.togetherad.core.utils.loge
+import java.net.HttpURLConnection
+import java.net.URL
+import java.util.concurrent.Executor
+import java.util.concurrent.Executors
+
+/*
+ * 默认的图片加载处理
+ *
+ * Created by Matthew Chen on 2020-05-15.
+ */
+class DefaultImageLoader : AdImageLoader {
+
+ object Async {
+ internal val cache: Executor = Executors.newCachedThreadPool()
+ private val HANDLER = Handler(Looper.getMainLooper())
+ internal val main: Executor = Executor { command -> HANDLER.post(command) }
+ }
+
+ override fun loadImage(context: Context, imageView: ImageView, imgUrl: String) {
+ try {
+ Async.cache.execute {
+ val url = URL(imgUrl)
+ val conn = (url.openConnection() as HttpURLConnection)
+ conn.doInput = true
+ conn.connect()
+ val inputStream = conn.inputStream
+ val bitmap = BitmapFactory.decodeStream(inputStream)
+ inputStream.close()
+ Async.main.execute {
+ imageView.setImageBitmap(bitmap)
+ }
+ }
+ } catch (e: Exception) {
+ """
+ |--------------------------------------------------------------------------------------
+ | DefaultImageLoader 默认的图片加载器出现异常,请自行设置图片加载器
+ | 设置方式,在 Application 中添加如下:
+ | TogetherAd.setCustomImageLoader(object : AdImageLoader {
+ | override fun loadImage(context: Context, imageView: ImageView, imgUrl: String) {
+ | //以 Glide 为例
+ | Glide.with(context).load(imgUrl).into(imageView)
+ | }
+ | })
+ |--------------------------------------------------------------------------------------
+
+""".loge()
+ e.printStackTrace()
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/BaseSplashSkipView.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/BaseSplashSkipView.kt
new file mode 100644
index 0000000..a7bec34
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/BaseSplashSkipView.kt
@@ -0,0 +1,31 @@
+package com.ifmvo.togetherad.core.custom.splashSkip
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+
+/*
+ * 自定义跳过按钮的基类
+ *
+ * Created by Matthew Chen on 2020-04-17.
+ */
+abstract class BaseSplashSkipView {
+
+ /**
+ * 创建跳过按钮的布局
+ */
+ abstract fun onCreateSkipView(context: Context): View
+
+ /**
+ * 处理倒计时的展示,单位:秒
+ */
+ open fun handleTime(second: Int) {
+ }
+
+ /**
+ * 获取布局参数,控制跳过按钮的位置
+ */
+ abstract fun getLayoutParams(): ViewGroup.LayoutParams
+
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/SplashSkipViewSimple1.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/SplashSkipViewSimple1.kt
new file mode 100644
index 0000000..f8bf176
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/SplashSkipViewSimple1.kt
@@ -0,0 +1,40 @@
+package com.ifmvo.togetherad.core.custom.splashSkip
+
+import android.content.Context
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import com.ifmvo.togetherad.core.R
+
+/**
+ * 简单模板1
+ * 没有显示倒计时,只有推过按钮
+ *
+ * Created by Matthew Chen on 2020-04-17.
+ */
+class SplashSkipViewSimple1 : BaseSplashSkipView() {
+
+ /**
+ * 创建跳过按钮的布局
+ */
+ override fun onCreateSkipView(context: Context): View {
+ return View.inflate(context, R.layout.layout_splash_skip_view_simple1, null)
+ }
+
+ /**
+ * 获取布局参数,控制跳过按钮的位置
+ *
+ * 注意:LayoutParams 的类型取决于 请求开屏广告时 container 参数的类型。
+ * Demo 中是使用的 FrameLayout,所以这里就是 FrameLayout.LayoutParams;
+ * LayoutParams类型必须要一致,否则会崩溃
+ */
+ override fun getLayoutParams(): ViewGroup.LayoutParams {
+ val layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT)
+ layoutParams.gravity = Gravity.END or Gravity.TOP
+ layoutParams.topMargin = 50
+ layoutParams.rightMargin = 30
+ return layoutParams
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/SplashSkipViewSimple2.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/SplashSkipViewSimple2.kt
new file mode 100644
index 0000000..a7f24a5
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/SplashSkipViewSimple2.kt
@@ -0,0 +1,52 @@
+package com.ifmvo.togetherad.core.custom.splashSkip
+
+import android.content.Context
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.widget.TextView
+import com.ifmvo.togetherad.core.R
+
+/**
+ * 简单模板2
+ * 提供了跳过按钮和倒计时展示,样式比广点通默认的样式要小一点
+ *
+ * Created by Matthew Chen on 2020-04-17.
+ */
+class SplashSkipViewSimple2 : BaseSplashSkipView() {
+
+ private lateinit var tvTime: TextView
+
+ /**
+ * 创建跳过按钮的布局
+ */
+ override fun onCreateSkipView(context: Context): View {
+ val skipView = View.inflate(context, R.layout.layout_splash_skip_view_simple2, null)
+ tvTime = skipView.findViewById(R.id.time)
+ return skipView
+ }
+
+ /**
+ * 处理倒计时的展示,单位:秒
+ */
+ override fun handleTime(second: Int) {
+ tvTime.text = second.toString()
+ }
+
+ /**
+ * 获取布局参数,控制跳过按钮的位置
+ *
+ * 注意:LayoutParams 的类型取决于 请求开屏广告时 container 参数的类型。
+ * Demo 中是使用的 FrameLayout,所以这里就是 FrameLayout.LayoutParams;
+ * LayoutParams类型必须要一致,否则会崩溃
+ */
+ override fun getLayoutParams(): ViewGroup.LayoutParams {
+ val layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT)
+ layoutParams.gravity = Gravity.END or Gravity.TOP
+ layoutParams.topMargin = 50
+ layoutParams.rightMargin = 30
+ return layoutParams
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/SplashSkipViewSimple3.kt b/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/SplashSkipViewSimple3.kt
new file mode 100644
index 0000000..4d7ee8e
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/custom/splashSkip/SplashSkipViewSimple3.kt
@@ -0,0 +1,45 @@
+package com.ifmvo.togetherad.core.custom.splashSkip
+
+import android.content.Context
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.widget.TextView
+import com.ifmvo.togetherad.core.R
+
+/**
+ * Created by Matthew Chen on 2020-04-17.
+ */
+class SplashSkipViewSimple3 : BaseSplashSkipView() {
+
+ private lateinit var tvTime: TextView
+ /**
+ * 创建跳过按钮的布局
+ */
+ override fun onCreateSkipView(context: Context): View {
+ val view = View.inflate(context, R.layout.layout_splash_skip_view_simple3, null)
+ tvTime = view.findViewById(R.id.text_count_down)
+ return tvTime
+ }
+
+ override fun handleTime(second: Int) {
+ tvTime.text = second.toString()
+ }
+
+ /**
+ * 获取布局参数,控制跳过按钮的位置
+ *
+ * 注意:LayoutParams 的类型取决于 请求开屏广告时 container 参数的类型。
+ * Demo 中是使用的 FrameLayout,所以这里就是 FrameLayout.LayoutParams;
+ * LayoutParams类型必须要一致,否则会崩溃
+ */
+ override fun getLayoutParams(): ViewGroup.LayoutParams {
+ val layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT)
+ layoutParams.gravity = Gravity.END or Gravity.TOP
+ layoutParams.topMargin = 50
+ layoutParams.rightMargin = 30
+ return layoutParams
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/entity/AdProviderEntity.kt b/core/src/main/java/com/ifmvo/togetherad/core/entity/AdProviderEntity.kt
new file mode 100644
index 0000000..33f9e57
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/entity/AdProviderEntity.kt
@@ -0,0 +1,25 @@
+package com.ifmvo.togetherad.core.entity
+
+import org.jetbrains.annotations.NotNull
+
+/*
+ * 广告提供者( 广告厂商:百度、广点通、穿山甲... )
+ *
+ * Created by Matthew Chen on 2020-04-03.
+ */
+data class AdProviderEntity(
+
+ // key 标示,唯一
+ @NotNull val providerType: String,
+
+ //Provider 类的路径
+ @NotNull val classPath: String,
+
+ //Provider 的描述
+ @NotNull val desc: String = classPath
+
+) {
+ override fun toString(): String {
+ return "AdProviderEntity(providerType=$providerType, classPath='$classPath', desc='$desc')"
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperBanner.kt b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperBanner.kt
new file mode 100644
index 0000000..0e5db9d
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperBanner.kt
@@ -0,0 +1,94 @@
+package com.ifmvo.togetherad.core.helper
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.listener.BannerListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import org.jetbrains.annotations.NotNull
+
+/**
+ * Banner 横幅广告
+ *
+ * Created by Matthew Chen on 2020/5/25.
+ */
+object AdHelperBanner : BaseHelper() {
+
+ private var adProvider: BaseAdProvider? = null
+
+ //为了照顾 Java 调用的同学
+ fun show(@NotNull activity: Activity, @NotNull alias: String, @NotNull container: ViewGroup, listener: BannerListener? = null) {
+ show(activity, alias, null, container, listener)
+ }
+
+ fun show(@NotNull activity: Activity, @NotNull alias: String, ratioMap: LinkedHashMap? = null, @NotNull container: ViewGroup, listener: BannerListener? = null) {
+ startTimer(listener)
+ realShow(activity, alias, ratioMap, container, listener)
+ }
+
+ private fun realShow(@NotNull activity: Activity, @NotNull alias: String, ratioMap: LinkedHashMap? = null, @NotNull container: ViewGroup, listener: BannerListener? = null) {
+
+ val currentRatioMap = if (ratioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else ratioMap
+
+ val adProviderType = DispatchUtil.getAdProvider(alias, currentRatioMap)
+
+ if (adProviderType?.isEmpty() != false) {
+ cancelTimer()
+ listener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${activity.getString(R.string.no_init)}".loge()
+ val newRatioMap = filterType(currentRatioMap, adProviderType)
+ realShow(activity, alias, newRatioMap, container, listener)
+ return
+ }
+
+ adProvider?.showBannerAd(activity = activity, adProviderType = adProviderType, alias = alias, container = container, listener = object : BannerListener {
+ override fun onAdStartRequest(providerType: String) {
+ listener?.onAdStartRequest(adProviderType)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ listener?.onAdLoaded(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ val newRatioMap = filterType(currentRatioMap, adProviderType)
+ realShow(activity, alias, newRatioMap, container, listener)
+
+ listener?.onAdFailed(providerType, failedMsg)
+
+ }
+
+ override fun onAdClicked(providerType: String) {
+ listener?.onAdClicked(providerType)
+ }
+
+ override fun onAdExpose(providerType: String) {
+ listener?.onAdExpose(providerType)
+ }
+
+ override fun onAdClose(providerType: String) {
+ listener?.onAdClose(providerType)
+ }
+ })
+ }
+
+ fun destroy() {
+ adProvider?.destroyBannerAd()
+ adProvider = null
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperFullVideo.kt b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperFullVideo.kt
new file mode 100644
index 0000000..d5bcf66
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperFullVideo.kt
@@ -0,0 +1,110 @@
+package com.ifmvo.togetherad.core.helper
+
+import android.app.Activity
+import com.ifmvo.togetherad.core.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.listener.FullVideoListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import org.jetbrains.annotations.NotNull
+import java.lang.ref.WeakReference
+
+/**
+ *
+ * Created by Matthew Chen on 2020/12/1.
+ */
+class AdHelperFullVideo(
+
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ ratioMap: LinkedHashMap? = null,
+ listener: FullVideoListener? = null
+
+) : BaseHelper() {
+
+ private var mActivity: WeakReference = WeakReference(activity)
+ private var mAlias: String = alias
+ private var mRatioMap: LinkedHashMap? = ratioMap
+ private var mListener: FullVideoListener? = listener
+ private var adProvider: BaseAdProvider? = null
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ listener: FullVideoListener? = null
+ ) : this(activity, alias, null, listener)
+
+ fun load() {
+ val currentRatioMap: LinkedHashMap = if (mRatioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else mRatioMap!!
+
+ startTimer(mListener)
+ reload(currentRatioMap)
+ }
+
+ private fun reload(@NotNull ratioMap: LinkedHashMap) {
+
+ val adProviderType = DispatchUtil.getAdProvider(mAlias, ratioMap)
+
+ if (adProviderType?.isEmpty() != false || mActivity.get() == null) {
+ cancelTimer()
+ mListener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${mActivity.get()?.getString(R.string.no_init)}".loge()
+ reload(filterType(ratioMap, adProviderType))
+ return
+ }
+
+ adProvider?.requestFullVideoAd(mActivity.get()!!, adProviderType, mAlias, object : FullVideoListener {
+ override fun onAdStartRequest(providerType: String) {
+ mListener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ reload(filterType(ratioMap, adProviderType))
+
+ mListener?.onAdFailed(providerType, failedMsg)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ mListener?.onAdClicked(providerType)
+ }
+
+ override fun onAdShow(providerType: String) {
+ mListener?.onAdShow(providerType)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mListener?.onAdLoaded(providerType)
+ }
+
+ override fun onAdVideoCached(providerType: String) {
+ mListener?.onAdVideoCached(providerType)
+ }
+
+ override fun onAdVideoComplete(providerType: String) {
+ mListener?.onAdVideoComplete(providerType)
+ }
+
+ override fun onAdClose(providerType: String) {
+ mListener?.onAdClose(providerType)
+ }
+ })
+ }
+
+ fun show() {
+ mActivity.get()?.let { adProvider?.showFullVideoAd(it) }
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperInter.kt b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperInter.kt
new file mode 100644
index 0000000..6e429cc
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperInter.kt
@@ -0,0 +1,108 @@
+package com.ifmvo.togetherad.core.helper
+
+import android.app.Activity
+import com.ifmvo.togetherad.core.R
+import org.jetbrains.annotations.NotNull
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.listener.InterListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import java.lang.ref.WeakReference
+
+/**
+ * 激励广告
+ *
+ * Created by Matthew Chen on 2020-04-20.
+ */
+class AdHelperInter(
+
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ ratioMap: LinkedHashMap? = null,
+ listener: InterListener? = null
+
+) : BaseHelper() {
+
+ private var mActivity: WeakReference = WeakReference(activity)
+ private var mAlias: String = alias
+ private var mRatioMap: LinkedHashMap? = ratioMap
+ private var mListener: InterListener? = listener
+ private var adProvider: BaseAdProvider? = null
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ listener: InterListener? = null
+ ) : this(activity, alias, null, listener)
+
+ fun load() {
+ val currentRatioMap: LinkedHashMap = if (mRatioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else mRatioMap!!
+
+ startTimer(mListener)
+ reload(currentRatioMap)
+ }
+
+ private fun reload(@NotNull ratioMap: LinkedHashMap) {
+
+ val adProviderType = DispatchUtil.getAdProvider(mAlias, ratioMap)
+
+ if (adProviderType?.isEmpty() != false || mActivity.get() == null) {
+ cancelTimer()
+ mListener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${mActivity.get()?.getString(R.string.no_init)}".loge()
+ reload(filterType(ratioMap, adProviderType))
+ return
+ }
+
+ adProvider?.requestInterAd(mActivity.get()!!, adProviderType, mAlias, object : InterListener {
+ override fun onAdStartRequest(providerType: String) {
+ mListener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mListener?.onAdLoaded(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ reload(filterType(ratioMap, adProviderType))
+
+ mListener?.onAdFailed(providerType, failedMsg)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ mListener?.onAdClicked(providerType)
+ }
+
+ override fun onAdExpose(providerType: String) {
+ mListener?.onAdExpose(providerType)
+ }
+
+ override fun onAdClose(providerType: String) {
+ mListener?.onAdClose(providerType)
+ }
+ })
+ }
+
+ fun show() {
+ mActivity.get()?.let { adProvider?.showInterAd(it) }
+ }
+
+ fun destroy() {
+ adProvider?.destroyInterAd()
+ adProvider = null
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperNativeExpress.kt b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperNativeExpress.kt
new file mode 100644
index 0000000..9a9a5b1
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperNativeExpress.kt
@@ -0,0 +1,170 @@
+package com.ifmvo.togetherad.core.helper
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.custom.express.BaseNativeExpressTemplate
+import com.ifmvo.togetherad.core.listener.NativeExpressListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logw
+import org.jetbrains.annotations.NotNull
+import org.jetbrains.annotations.Nullable
+import java.lang.ref.WeakReference
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/25.
+ */
+class AdHelperNativeExpress(
+
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ ratioMap: LinkedHashMap? = null,
+ adCount: Int
+
+) : BaseHelper() {
+
+ private var mActivity: WeakReference = WeakReference(activity)
+ private var mAlias: String = alias
+ private var mRatioMap: LinkedHashMap? = ratioMap
+ private var mAdCount: Int = adCount
+ private var adProvider: BaseAdProvider? = null
+
+ //所有请求到的广告容器
+ private var mAdList = mutableListOf()
+
+ companion object {
+
+ private const val defaultAdCount = 1
+
+ fun show(@Nullable adObject: Any?, @Nullable container: ViewGroup?, @NotNull nativeExpressTemplate: BaseNativeExpressTemplate) {
+ if (adObject == null) {
+ return
+ }
+ if (container == null) {
+ return
+ }
+ TogetherAd.mProviders.entries.forEach { entry ->
+ val adProvider = AdProviderLoader.loadAdProvider(entry.key)
+ if (adProvider?.nativeExpressAdIsBelongTheProvider(adObject) == true) {
+ val nativeView = nativeExpressTemplate.getNativeExpressView(entry.key)
+ nativeView?.showNativeExpress(entry.key, adObject, container)
+ return@forEach
+ }
+ }
+ }
+
+ fun destroyExpressAd(@Nullable adObject: Any?) {
+ if (adObject == null) {
+ return
+ }
+ TogetherAd.mProviders.entries.forEach { entry ->
+ val adProvider = AdProviderLoader.loadAdProvider(entry.key)
+ adProvider?.destroyNativeExpressAd(adObject)
+ }
+ }
+
+ fun destroyExpressAd(@Nullable adObjectList: List?) {
+ if (adObjectList?.isEmpty() != false) {
+ return
+ }
+ adObjectList.forEach { destroyExpressAd(it) }
+ }
+ }
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ adCount: Int
+ ) : this(activity, alias, null, adCount)
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String
+ ) : this(activity, alias, null, defaultAdCount)
+
+ fun getExpressList(listener: NativeExpressListener? = null) {
+ val currentRatioMap: LinkedHashMap = if (mRatioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else mRatioMap!!
+
+ startTimer(listener)
+ getExpressListForMap(currentRatioMap, listener)
+ }
+
+ private fun getExpressListForMap(@NotNull ratioMap: LinkedHashMap, listener: NativeExpressListener? = null) {
+
+ val currentAdCount = if (mAdCount <= 0) defaultAdCount else mAdCount
+
+ val adProviderType = DispatchUtil.getAdProvider(mAlias, ratioMap)
+
+ if (adProviderType?.isEmpty() != false || mActivity.get() == null) {
+ cancelTimer()
+ listener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${mActivity.get()?.getString(R.string.no_init)}".loge()
+ getExpressListForMap(filterType(ratioMap, adProviderType), listener)
+ return
+ }
+
+ adProvider?.getNativeExpressAdList(mActivity.get()!!, adProviderType, mAlias, currentAdCount, object : NativeExpressListener {
+ override fun onAdStartRequest(providerType: String) {
+ listener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ getExpressListForMap(filterType(ratioMap, adProviderType), listener)
+
+ listener?.onAdFailed(providerType, failedMsg)
+ }
+
+ override fun onAdLoaded(providerType: String, adList: List) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mAdList.addAll(adList)
+ listener?.onAdLoaded(providerType, adList)
+ }
+
+ override fun onAdClicked(providerType: String, adObject: Any?) {
+ listener?.onAdClicked(providerType, adObject)
+ }
+
+ override fun onAdShow(providerType: String, adObject: Any?) {
+ listener?.onAdShow(providerType, adObject)
+ }
+
+ override fun onAdRenderSuccess(providerType: String, adObject: Any?) {
+ listener?.onAdRenderSuccess(providerType, adObject)
+ }
+
+ override fun onAdRenderFail(providerType: String, adObject: Any?) {
+ listener?.onAdRenderFail(providerType, adObject)
+ }
+
+ override fun onAdClosed(providerType: String, adObject: Any?) {
+ listener?.onAdClosed(providerType, adObject)
+ }
+ })
+ }
+
+ /**
+ * 销毁所有请求到的广告
+ */
+ fun destroyAllExpressAd() {
+ destroyExpressAd(mAdList)
+ mAdList.clear()
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperNativeExpress2.kt b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperNativeExpress2.kt
new file mode 100644
index 0000000..c97199a
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperNativeExpress2.kt
@@ -0,0 +1,151 @@
+package com.ifmvo.togetherad.core.helper
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.custom.express2.BaseNativeExpress2Template
+import com.ifmvo.togetherad.core.listener.NativeExpress2Listener
+import com.ifmvo.togetherad.core.listener.NativeExpress2ViewListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logw
+import org.jetbrains.annotations.NotNull
+import org.jetbrains.annotations.Nullable
+import java.lang.ref.WeakReference
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/25.
+ */
+class AdHelperNativeExpress2(
+
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ ratioMap: LinkedHashMap? = null,
+ adCount: Int
+
+) : BaseHelper() {
+
+ private var mActivity: WeakReference = WeakReference(activity)
+ private var mAlias: String = alias
+ private var mRatioMap: LinkedHashMap? = ratioMap
+ private var mAdCount: Int = adCount
+ private var adProvider: BaseAdProvider? = null
+
+ //所有请求到的广告容器
+ private var mAdList = mutableListOf()
+
+ companion object {
+
+ private const val defaultAdCount = 1
+
+ fun show(@NotNull activity: Activity, @Nullable adObject: Any?, @Nullable container: ViewGroup?, @NotNull nativeExpress2Template: BaseNativeExpress2Template, listener: NativeExpress2ViewListener) {
+ if (adObject == null) {
+ return
+ }
+ if (container == null) {
+ return
+ }
+ TogetherAd.mProviders.entries.forEach { entry ->
+ val adProvider = AdProviderLoader.loadAdProvider(entry.key)
+ if (adProvider?.nativeExpress2AdIsBelongTheProvider(adObject) == true) {
+ val nativeView = nativeExpress2Template.getNativeExpress2View(entry.key)
+ nativeView?.showNativeExpress2(activity, entry.key, adObject, container, listener)
+ return@forEach
+ }
+ }
+ }
+
+ fun destroyExpress2Ad(@Nullable adObject: Any?) {
+ if (adObject == null) {
+ return
+ }
+ TogetherAd.mProviders.entries.forEach { entry ->
+ val adProvider = AdProviderLoader.loadAdProvider(entry.key)
+ adProvider?.destroyNativeExpress2Ad(adObject)
+ }
+ }
+
+ fun destroyExpress2Ad(@Nullable adObjectList: List?) {
+ if (adObjectList?.isEmpty() != false) {
+ return
+ }
+ adObjectList.forEach { destroyExpress2Ad(it) }
+ }
+ }
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ adCount: Int
+ ) : this(activity, alias, null, adCount)
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String
+ ) : this(activity, alias, null, defaultAdCount)
+
+ fun getExpress2List(listener: NativeExpress2Listener? = null) {
+ val currentRatioMap: LinkedHashMap = if (mRatioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else mRatioMap!!
+
+ startTimer(listener)
+ getExpress2ListForMap(currentRatioMap, listener)
+ }
+
+ private fun getExpress2ListForMap(@NotNull ratioMap: LinkedHashMap, listener: NativeExpress2Listener? = null) {
+
+ val currentAdCount = if (mAdCount <= 0) defaultAdCount else mAdCount
+
+ val adProviderType = DispatchUtil.getAdProvider(mAlias, ratioMap)
+
+ if (adProviderType?.isEmpty() != false || mActivity.get() == null) {
+ cancelTimer()
+ listener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${mActivity.get()?.getString(R.string.no_init)}".loge()
+ getExpress2ListForMap(filterType(ratioMap, adProviderType), listener)
+ return
+ }
+
+ adProvider?.getNativeExpress2AdList(mActivity.get()!!, adProviderType, mAlias, currentAdCount, object : NativeExpress2Listener {
+ override fun onAdStartRequest(providerType: String) {
+ listener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ getExpress2ListForMap(filterType(ratioMap, adProviderType), listener)
+
+ listener?.onAdFailed(providerType, failedMsg)
+ }
+
+ override fun onAdLoaded(providerType: String, adList: List) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mAdList.addAll(adList)
+ listener?.onAdLoaded(providerType, adList)
+ }
+ })
+ }
+
+ /**
+ * 销毁所有请求到的广告
+ */
+ fun destroyAllExpress2Ad() {
+ destroyExpress2Ad(mAdList)
+ mAdList.clear()
+ }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperNativePro.kt b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperNativePro.kt
new file mode 100644
index 0000000..f3ad94f
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperNativePro.kt
@@ -0,0 +1,199 @@
+package com.ifmvo.togetherad.core.helper
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeTemplate
+import com.ifmvo.togetherad.core.listener.NativeListener
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logw
+import org.jetbrains.annotations.NotNull
+import org.jetbrains.annotations.Nullable
+import java.lang.ref.WeakReference
+
+/**
+ * 原生信息流广告
+ *
+ * Created by Matthew Chen on 2020-04-20.
+ */
+class AdHelperNativePro(
+
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ ratioMap: LinkedHashMap? = null,
+ maxCount: Int
+
+) : BaseHelper() {
+
+ private var mActivity: WeakReference = WeakReference(activity)
+ private var mAlias: String = alias
+ private var mRatioMap: LinkedHashMap? = ratioMap
+ private var mMaxCount: Int = maxCount
+ private var adProvider: BaseAdProvider? = null
+
+ //所有请求到的广告容器
+ private var mAdList = mutableListOf()
+
+ companion object {
+
+ private const val defaultMaxCount = 1
+
+ fun show(@Nullable adObject: Any?, @Nullable container: ViewGroup?, @NotNull nativeTemplate: BaseNativeTemplate, @Nullable listener: NativeViewListener? = null) {
+ if (adObject == null) {
+ return
+ }
+ if (container == null) {
+ return
+ }
+ TogetherAd.mProviders.entries.forEach { entry ->
+ val adProvider = AdProviderLoader.loadAdProvider(entry.key)
+ if (adProvider?.nativeAdIsBelongTheProvider(adObject) == true) {
+ val nativeView = nativeTemplate.getNativeView(entry.key)
+ nativeView?.showNative(entry.key, adObject, container, listener)
+ return@forEach
+ }
+ }
+ }
+
+ fun pauseAd(@Nullable adObject: Any?) {
+ if (adObject == null) {
+ return
+ }
+ TogetherAd.mProviders.entries.forEach { entry ->
+ val adProvider = AdProviderLoader.loadAdProvider(entry.key)
+ adProvider?.pauseNativeAd(adObject)
+ }
+ }
+
+ fun pauseAd(@Nullable adObjectList: List?) {
+ if (adObjectList?.isEmpty() != false) {
+ return
+ }
+ adObjectList.forEach { pauseAd(it) }
+ }
+
+ fun resumeAd(@Nullable adObject: Any?) {
+ if (adObject == null) {
+ return
+ }
+ TogetherAd.mProviders.entries.forEach { entry ->
+ val adProvider = AdProviderLoader.loadAdProvider(entry.key)
+ adProvider?.resumeNativeAd(adObject)
+ }
+ }
+
+ fun resumeAd(@Nullable adObjectList: List?) {
+ if (adObjectList?.isEmpty() != false) {
+ return
+ }
+ adObjectList.forEach { resumeAd(it) }
+ }
+
+ fun destroyAd(@Nullable adObject: Any?) {
+ if (adObject == null) {
+ return
+ }
+ TogetherAd.mProviders.entries.forEach { entry ->
+ val adProvider = AdProviderLoader.loadAdProvider(entry.key)
+ adProvider?.destroyNativeAd(adObject)
+ }
+ }
+
+ fun destroyAd(@Nullable adObjectList: List?) {
+ if (adObjectList?.isEmpty() != false) {
+ return
+ }
+ adObjectList.forEach { destroyAd(it) }
+ }
+ }
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ maxCount: Int
+ ) : this(activity, alias, null, maxCount)
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String
+ ) : this(activity, alias, null, defaultMaxCount)
+
+ fun getList(listener: NativeListener? = null) {
+ val currentRatioMap: LinkedHashMap = if (mRatioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else mRatioMap!!
+
+ startTimer(listener)
+ getListForMap(currentRatioMap, listener)
+ }
+
+ private fun getListForMap(@NotNull ratioMap: LinkedHashMap, listener: NativeListener? = null) {
+
+ val currentMaxCount = if (mMaxCount <= 0) defaultMaxCount else mMaxCount
+
+ val adProviderType = DispatchUtil.getAdProvider(mAlias, ratioMap)
+
+ if (adProviderType?.isEmpty() != false || mActivity.get() == null) {
+ cancelTimer()
+ listener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${mActivity.get()?.getString(R.string.no_init)}".loge()
+ getListForMap(filterType(ratioMap, adProviderType), listener)
+ return
+ }
+
+ adProvider?.getNativeAdList(mActivity.get()!!, adProviderType, mAlias, currentMaxCount, object : NativeListener {
+ override fun onAdStartRequest(providerType: String) {
+ listener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdLoaded(providerType: String, adList: List) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mAdList.addAll(adList)
+ listener?.onAdLoaded(providerType, adList)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ getListForMap(filterType(ratioMap, adProviderType), listener)
+
+ listener?.onAdFailed(providerType, failedMsg)
+ }
+ })
+ }
+
+ /**
+ * 恢复所有可见的广告
+ */
+ fun resumeAllAd() {
+ resumeAd(mAdList)
+ }
+
+ /**
+ * 暂停所有可见的广告
+ */
+ fun pauseAllAd() {
+ pauseAd(mAdList)
+ }
+
+ /**
+ * 销毁所有请求到的广告
+ */
+ fun destroyAllAd() {
+ destroyAd(mAdList)
+ mAdList.clear()
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperReward.kt b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperReward.kt
new file mode 100644
index 0000000..4d736ec
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperReward.kt
@@ -0,0 +1,128 @@
+package com.ifmvo.togetherad.core.helper
+
+import android.app.Activity
+import com.ifmvo.togetherad.core.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.listener.RewardListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import org.jetbrains.annotations.NotNull
+import java.lang.ref.WeakReference
+
+/**
+ * 激励广告
+ *
+ * Created by Matthew Chen on 2020-04-20.
+ */
+class AdHelperReward(
+
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ ratioMap: LinkedHashMap? = null,
+ listener: RewardListener? = null
+
+) : BaseHelper() {
+
+ private var mActivity: WeakReference = WeakReference(activity)
+ private var mAlias: String = alias
+ private var mRatioMap: LinkedHashMap? = ratioMap
+ private var mListener: RewardListener? = listener
+ private var adProvider: BaseAdProvider? = null
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ listener: RewardListener? = null
+ ) : this(activity, alias, null, listener)
+
+ fun load() {
+ val currentRatioMap: LinkedHashMap = if (mRatioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else mRatioMap!!
+
+ startTimer(mListener)
+ reload(currentRatioMap)
+ }
+
+ private fun reload(@NotNull ratioMap: LinkedHashMap) {
+
+ val adProviderType = DispatchUtil.getAdProvider(mAlias, ratioMap)
+
+ if (adProviderType?.isEmpty() != false || mActivity.get() == null) {
+ cancelTimer()
+ mListener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${mActivity.get()?.getString(R.string.no_init)}".loge()
+ reload(filterType(ratioMap, adProviderType))
+ return
+ }
+
+ adProvider?.requestRewardAd(mActivity.get()!!, adProviderType, mAlias, object : RewardListener {
+ override fun onAdStartRequest(providerType: String) {
+ mListener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ reload(filterType(ratioMap, adProviderType))
+
+ mListener?.onAdFailed(providerType, failedMsg)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ mListener?.onAdClicked(providerType)
+ }
+
+ override fun onAdShow(providerType: String) {
+ mListener?.onAdShow(providerType)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mListener?.onAdLoaded(providerType)
+ }
+
+ override fun onAdExpose(providerType: String) {
+ mListener?.onAdExpose(providerType)
+ }
+
+ override fun onAdVideoComplete(providerType: String) {
+ mListener?.onAdVideoComplete(providerType)
+ }
+
+ override fun onAdVideoCached(providerType: String) {
+ mListener?.onAdVideoCached(providerType)
+ }
+
+ override fun onAdRewardVerify(providerType: String) {
+ mListener?.onAdRewardVerify(providerType)
+ }
+
+ override fun onAdClose(providerType: String) {
+ mListener?.onAdClose(providerType)
+ }
+ })
+ }
+
+ fun show(): Boolean {
+
+ if (adProvider == null) {
+ return false
+ }
+
+ mActivity.get()?.let {
+ return adProvider!!.showRewardAd(it)
+ }
+
+ return false
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperSplash.kt b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperSplash.kt
new file mode 100644
index 0000000..3a93035
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperSplash.kt
@@ -0,0 +1,84 @@
+package com.ifmvo.togetherad.core.helper
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.listener.SplashListener
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import org.jetbrains.annotations.NotNull
+
+/**
+ * 开屏广告
+ *
+ * Created by Matthew Chen on 2020-04-03.
+ */
+object AdHelperSplash : BaseHelper() {
+
+ //为了照顾 Java 调用的同学
+ fun show(@NotNull activity: Activity, @NotNull alias: String, @NotNull container: ViewGroup, listener: SplashListener? = null) {
+ show(activity, alias, null, container, listener)
+ }
+
+ fun show(@NotNull activity: Activity, @NotNull alias: String, ratioMap: LinkedHashMap? = null, @NotNull container: ViewGroup, listener: SplashListener? = null) {
+ startTimer(listener)
+ realShow(activity, alias, ratioMap, container, listener)
+ }
+
+ private fun realShow(@NotNull activity: Activity, @NotNull alias: String, ratioMap: LinkedHashMap? = null, @NotNull container: ViewGroup, listener: SplashListener? = null) {
+ val currentRatioMap = if (ratioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else ratioMap
+
+ val adProviderType = DispatchUtil.getAdProvider(alias, currentRatioMap)
+
+ if (adProviderType?.isEmpty() != false) {
+ cancelTimer()
+ listener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ val adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${activity.getString(R.string.no_init)}".loge()
+ val newRatioMap = filterType(currentRatioMap, adProviderType)
+ realShow(activity, alias, newRatioMap, container, listener)
+ return
+ }
+
+ adProvider.loadAndShowSplashAd(activity = activity, adProviderType = adProviderType, alias = alias, container = container, listener = object : SplashListener {
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ val newRatioMap = filterType(currentRatioMap, adProviderType)
+ realShow(activity, alias, newRatioMap, container, listener)
+
+ listener?.onAdFailed(providerType, failedMsg)
+ }
+
+ override fun onAdStartRequest(providerType: String) {
+ listener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ listener?.onAdLoaded(providerType)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ listener?.onAdClicked(providerType)
+ }
+
+ override fun onAdExposure(providerType: String) {
+ listener?.onAdExposure(providerType)
+ }
+
+ override fun onAdDismissed(providerType: String) {
+ listener?.onAdDismissed(providerType)
+ }
+ })
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperSplashPro.kt b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperSplashPro.kt
new file mode 100644
index 0000000..7dd33c4
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/helper/AdHelperSplashPro.kt
@@ -0,0 +1,101 @@
+package com.ifmvo.togetherad.core.helper
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.listener.SplashListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import org.jetbrains.annotations.NotNull
+import java.lang.ref.WeakReference
+
+/**
+ * 开屏广告
+ *
+ * Created by Matthew Chen on 2020-04-03.
+ */
+class AdHelperSplashPro(
+
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ ratioMap: LinkedHashMap? = null
+
+) : BaseHelper() {
+
+ private var mActivity: WeakReference = WeakReference(activity)
+ private var mAlias: String = alias
+ private var mRatioMap: LinkedHashMap? = ratioMap
+ private var adProvider: BaseAdProvider? = null
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String
+ ) : this(activity, alias, null)
+
+ //为了照顾 Java 调用的同学
+ fun loadOnly(listener: SplashListener? = null) {
+ val currentRatioMap = if (mRatioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else mRatioMap!!
+
+ startTimer(listener)
+ realLoadOnly(currentRatioMap, listener)
+ }
+
+ private fun realLoadOnly(@NotNull ratioMap: LinkedHashMap, listener: SplashListener? = null) {
+
+ val adProviderType = DispatchUtil.getAdProvider(mAlias, ratioMap)
+
+ if (adProviderType?.isEmpty() != false || mActivity.get() == null) {
+ cancelTimer()
+ listener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${mActivity.get()?.getString(R.string.no_init)}".loge()
+ realLoadOnly(filterType(ratioMap, adProviderType))
+ return
+ }
+
+ adProvider?.loadOnlySplashAd(activity = mActivity.get()!!, adProviderType = adProviderType, alias = mAlias, listener = object : SplashListener {
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ realLoadOnly(filterType(ratioMap, adProviderType), listener)
+ listener?.onAdFailed(providerType, failedMsg)
+ }
+
+ override fun onAdStartRequest(providerType: String) {
+ listener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ listener?.onAdLoaded(providerType)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ listener?.onAdClicked(providerType)
+ }
+
+ override fun onAdExposure(providerType: String) {
+ listener?.onAdExposure(providerType)
+ }
+
+ override fun onAdDismissed(providerType: String) {
+ listener?.onAdDismissed(providerType)
+ }
+ })
+ }
+
+ fun showAd(@NotNull container: ViewGroup): Boolean {
+ return adProvider?.showSplashAd(container) ?: false
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/helper/BaseHelper.kt b/core/src/main/java/com/ifmvo/togetherad/core/helper/BaseHelper.kt
new file mode 100644
index 0000000..4f37870
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/helper/BaseHelper.kt
@@ -0,0 +1,75 @@
+package com.ifmvo.togetherad.core.helper
+
+import android.os.CountDownTimer
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.listener.BaseListener
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.core.utils.logv
+import org.jetbrains.annotations.NotNull
+
+
+/*
+ * Created by Matthew Chen on 2020-04-03.
+ */
+abstract class BaseHelper {
+
+ object FailedAllMsg {
+ const val failedAll_noDispatch = "全部请求失败或没有分配任何广告"
+ const val timeOut = "请求超时"
+ }
+
+ /**
+ * 将传进来的 adProviderType 权重设置为 0,其他不变
+ * 如果是不允许失败切换的时候,将所有广告提供商的权重都清空
+ */
+ fun filterType(@NotNull ratioMap: LinkedHashMap, adProviderType: String): LinkedHashMap {
+ val newRatioMap = linkedMapOf()
+ newRatioMap.putAll(ratioMap)
+ newRatioMap[adProviderType] = 0
+
+ //不允许失败切换的时候,将所有广告提供商的权重都清空
+ if (!TogetherAd.failedSwitchEnable) {
+ newRatioMap.keys.forEach { newRatioMap[it] = 0 }
+ }
+
+ return newRatioMap
+ }
+
+ private var mTimer: CountDownTimer? = null
+ var isFetchOverTime = false
+
+ /**
+ * 启动超时计时
+ */
+ fun startTimer(listener: BaseListener?) {
+ //0 就不开启倒计时
+ if (TogetherAd.maxFetchDelay <= 0L) {
+ return
+ }
+
+ cancelTimer()
+ "开始倒计时:${TogetherAd.maxFetchDelay}".logv()
+ mTimer = object : CountDownTimer(TogetherAd.maxFetchDelay, 1000) {
+ override fun onFinish() {
+ "倒计时结束".logv()
+ "请求超时".logi()
+ isFetchOverTime = true
+ listener?.onAdFailedAll(FailedAllMsg.timeOut)
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ "倒计时:$millisUntilFinished".logv()
+ }
+ }
+ isFetchOverTime = false
+ mTimer?.start()
+ }
+
+ /**
+ * 取消超时计时
+ */
+ fun cancelTimer() {
+ mTimer?.cancel()
+ mTimer = null
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/AllAdListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/AllAdListener.kt
new file mode 100644
index 0000000..f4781fc
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/AllAdListener.kt
@@ -0,0 +1,26 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+/**
+ *
+ * Created by Matthew Chen on 2020/12/2.
+ */
+interface AllAdListener {
+
+ /**
+ * 开始请求前回调
+ */
+ fun onAdStartRequest(@NotNull providerType: String, @NotNull alias: String) {}
+
+ /**
+ * 单个提供商请求失败
+ */
+ fun onAdFailed(@NotNull providerType: String, @NotNull alias: String, failedMsg: String?) {}
+
+ /**
+ * 请求到了广告
+ */
+ fun onAdLoaded(@NotNull providerType: String, @NotNull alias: String) {}
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/BannerListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/BannerListener.kt
new file mode 100644
index 0000000..0fa25ae
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/BannerListener.kt
@@ -0,0 +1,31 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+
+/**
+ * Created by Matthew Chen on 2020/5/25.
+ */
+interface BannerListener : BaseListener {
+
+ /**
+ * 请求到了广告
+ */
+ fun onAdLoaded(@NotNull providerType: String) {}
+
+ /**
+ * 广告被点击了
+ */
+ fun onAdClicked(@NotNull providerType: String) {}
+
+ /**
+ * 广告曝光了
+ */
+ fun onAdExpose(@NotNull providerType: String) {}
+
+ /**
+ * 广告被关闭了
+ */
+ fun onAdClose(@NotNull providerType: String) {}
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/BaseListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/BaseListener.kt
new file mode 100644
index 0000000..94c3062
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/BaseListener.kt
@@ -0,0 +1,26 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+
+/**
+ * Created by Matthew Chen on 2020-04-20.
+ */
+interface BaseListener {
+
+ /**
+ * 开始请求前回调
+ */
+ fun onAdStartRequest(@NotNull providerType: String) {}
+
+ /**
+ * 所有的提供商都请求失败,或请求超时,或没有分配任何广告商比例
+ */
+ fun onAdFailedAll(failedMsg: String?) {}
+
+ /**
+ * 单个提供商请求失败
+ */
+ fun onAdFailed(@NotNull providerType: String, failedMsg: String?) {}
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/FullVideoListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/FullVideoListener.kt
new file mode 100644
index 0000000..1c22c19
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/FullVideoListener.kt
@@ -0,0 +1,41 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+/**
+ *
+ * Created by Matthew Chen on 2020/12/2.
+ */
+interface FullVideoListener : BaseListener {
+
+ /**
+ * 请求到了广告
+ */
+ fun onAdLoaded(@NotNull providerType: String) {}
+
+ /**
+ * 广告被点击了
+ */
+ fun onAdClicked(@NotNull providerType: String) {}
+
+ /**
+ * 广告展示了
+ */
+ fun onAdShow(@NotNull providerType: String) {}
+
+ /**
+ * 视频缓存完成
+ */
+ fun onAdVideoCached(@NotNull providerType: String) {}
+
+ /**
+ * 视频播放完成
+ */
+ fun onAdVideoComplete(@NotNull providerType: String) {}
+
+ /**
+ * 广告被关闭了
+ */
+ fun onAdClose(@NotNull providerType: String) {}
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/InterListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/InterListener.kt
new file mode 100644
index 0000000..4d161f4
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/InterListener.kt
@@ -0,0 +1,32 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+/**
+ * 插屏的回调
+ *
+ * Created by Matthew Chen on 2020/7/3.
+ */
+interface InterListener : BaseListener {
+
+ /**
+ * 请求到了广告
+ */
+ fun onAdLoaded(@NotNull providerType: String) {}
+
+ /**
+ * 广告被点击了
+ */
+ fun onAdClicked(@NotNull providerType: String) {}
+
+ /**
+ * 广告曝光了
+ */
+ fun onAdExpose(@NotNull providerType: String) {}
+
+ /**
+ * 广告被关闭了
+ */
+ fun onAdClose(@NotNull providerType: String) {}
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeExpress2Listener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeExpress2Listener.kt
new file mode 100644
index 0000000..25ee6cf
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeExpress2Listener.kt
@@ -0,0 +1,16 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+
+/**
+ * Created by Matthew Chen on 2020-04-20.
+ */
+interface NativeExpress2Listener : BaseListener {
+
+ /**
+ * 请求到了广告
+ */
+ fun onAdLoaded(@NotNull providerType: String, @NotNull adList: List) {}
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeExpress2ViewListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeExpress2ViewListener.kt
new file mode 100644
index 0000000..d9aca05
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeExpress2ViewListener.kt
@@ -0,0 +1,37 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+
+/**
+ * 原生自渲染广告曝光和点击的监听
+ *
+ * Created by Matthew Chen on 2020/5/27.
+ */
+interface NativeExpress2ViewListener {
+
+ /**
+ * 广告曝光了
+ */
+ fun onAdExposed(@NotNull providerType: String) {}
+
+ /**
+ * 广告被点击了
+ */
+ fun onAdClicked(@NotNull providerType: String) {}
+
+ /**
+ * 广告模板渲染成功了
+ */
+ fun onAdRenderSuccess(@NotNull providerType: String) {}
+
+ /**
+ * 广告模板渲染失败了
+ */
+ fun onAdRenderFailed(@NotNull providerType: String) {}
+
+ /**
+ * 广告模板被关闭了
+ */
+ fun onAdClose(@NotNull providerType: String) {}
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeExpressListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeExpressListener.kt
new file mode 100644
index 0000000..3670647
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeExpressListener.kt
@@ -0,0 +1,36 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+import org.jetbrains.annotations.Nullable
+
+
+/**
+ * Created by Matthew Chen on 2020-04-20.
+ */
+interface NativeExpressListener : NativeExpress2Listener {
+
+ /**
+ * 广告被点击了
+ */
+ fun onAdClicked(@NotNull providerType: String, @Nullable adObject: Any?) {}
+
+ /**
+ * 广告展示了
+ */
+ fun onAdShow(@NotNull providerType: String, @Nullable adObject: Any?) {}
+
+ /**
+ * 广告模板渲染成功
+ */
+ fun onAdRenderSuccess(@NotNull providerType: String, @Nullable adObject: Any?) {}
+
+ /**
+ * 广告模板渲染失败了
+ */
+ fun onAdRenderFail(@NotNull providerType: String, @Nullable adObject: Any?) {}
+
+ /**
+ * 广告模板被关闭了
+ */
+ fun onAdClosed(@NotNull providerType: String, @Nullable adObject: Any?) {}
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeListener.kt
new file mode 100644
index 0000000..c982ef2
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeListener.kt
@@ -0,0 +1,16 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+
+/**
+ * Created by Matthew Chen on 2020-04-20.
+ */
+interface NativeListener : BaseListener {
+
+ /**
+ * 请求到了广告
+ */
+ fun onAdLoaded(@NotNull providerType: String, @NotNull adList: List) {}
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeViewListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeViewListener.kt
new file mode 100644
index 0000000..f58d78a
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/NativeViewListener.kt
@@ -0,0 +1,23 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+
+/**
+ * 原生自渲染广告曝光和点击的监听
+ *
+ * Created by Matthew Chen on 2020/5/27.
+ */
+interface NativeViewListener {
+
+ /**
+ * 广告曝光了
+ */
+ fun onAdExposed(@NotNull providerType: String) {}
+
+ /**
+ * 广告被点击了
+ */
+ fun onAdClicked(@NotNull providerType: String) {}
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/RewardListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/RewardListener.kt
new file mode 100644
index 0000000..f1cf3e3
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/RewardListener.kt
@@ -0,0 +1,51 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+
+/**
+ * Created by Matthew Chen on 2020-04-22.
+ */
+interface RewardListener : BaseListener {
+
+ /**
+ * 请求到了广告
+ */
+ fun onAdLoaded(@NotNull providerType: String) {}
+
+ /**
+ * 广告被点击了
+ */
+ fun onAdClicked(@NotNull providerType: String) {}
+
+ /**
+ * 广告展示了
+ */
+ fun onAdShow(@NotNull providerType: String) {}
+
+ /**
+ * 广告曝光了( 和 onAdShow 的区别是展示不一定曝光,曝光一定展示,需要展示一定的时间才会曝光,曝光的条件是提供商规定的 )
+ */
+ fun onAdExpose(@NotNull providerType: String) {}
+
+ /**
+ * 视频广告播放完成
+ */
+ fun onAdVideoComplete(@NotNull providerType: String) {}
+
+ /**
+ * 视频缓存完成
+ */
+ fun onAdVideoCached(@NotNull providerType: String) {}
+
+ /**
+ * 奖励被验证
+ */
+ fun onAdRewardVerify(@NotNull providerType: String) {}
+
+ /**
+ * 广告被关闭了
+ */
+ fun onAdClose(@NotNull providerType: String) {}
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/listener/SplashListener.kt b/core/src/main/java/com/ifmvo/togetherad/core/listener/SplashListener.kt
new file mode 100644
index 0000000..f52a449
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/listener/SplashListener.kt
@@ -0,0 +1,33 @@
+package com.ifmvo.togetherad.core.listener
+
+import org.jetbrains.annotations.NotNull
+
+
+/**
+ * 通用的监听器
+ *
+ * Created by Matthew Chen on 2020-04-03.
+ */
+interface SplashListener : BaseListener {
+
+ /**
+ * 请求到了广告
+ */
+ fun onAdLoaded(@NotNull providerType: String) {}
+
+ /**
+ * 广告被点击了
+ */
+ fun onAdClicked(@NotNull providerType: String) {}
+
+ /**
+ * 广告曝光了
+ */
+ fun onAdExposure(@NotNull providerType: String) {}
+
+ /**
+ * 广告消失了( 点击跳过或者倒计时结束 )
+ */
+ fun onAdDismissed(@NotNull providerType: String) {}
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/provider/BaseAdProvider.kt b/core/src/main/java/com/ifmvo/togetherad/core/provider/BaseAdProvider.kt
new file mode 100644
index 0000000..9702d01
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/provider/BaseAdProvider.kt
@@ -0,0 +1,389 @@
+package com.ifmvo.togetherad.core.provider
+
+import android.os.Handler
+import android.os.Looper
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.listener.*
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import org.jetbrains.annotations.NotNull
+import org.jetbrains.annotations.Nullable
+
+/*
+ * Created by Matthew Chen on 2020-04-03.
+ */
+abstract class BaseAdProvider : IAdProvider {
+
+ protected val tag: String? = this.javaClass.simpleName
+
+ /**
+ * --------------------------- 开屏 ---------------------------
+ */
+ protected fun callbackSplashStartRequest(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: SplashListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 开始请求".logi()
+ listener.onAdStartRequest(adProviderType)
+ TogetherAd.allAdListener?.onAdStartRequest(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackSplashLoaded(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: SplashListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求成功了".logi()
+ listener.onAdLoaded(adProviderType)
+ TogetherAd.allAdListener?.onAdLoaded(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackSplashClicked(@NotNull adProviderType: String, @NotNull listener: SplashListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 点击了".logi()
+ listener.onAdClicked(adProviderType)
+ }
+ }
+
+ protected fun callbackSplashExposure(@NotNull adProviderType: String, @NotNull listener: SplashListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 曝光了".logi()
+ listener.onAdExposure(adProviderType)
+ }
+ }
+
+ protected fun callbackSplashFailed(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: SplashListener, errorCode: Int?, errorMsg: String?) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求失败了:$errorCode $errorMsg".loge()
+ listener.onAdFailed(adProviderType, errorMsg)
+ TogetherAd.allAdListener?.onAdFailed(adProviderType, alias, errorMsg)
+ }
+ }
+
+ protected fun callbackSplashDismiss(@NotNull adProviderType: String, @NotNull listener: SplashListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 消失了".logi()
+ listener.onAdDismissed(adProviderType)
+ }
+ }
+
+ /**
+ * --------------------------- 原生信息流 ---------------------------
+ */
+ protected fun callbackNativeStartRequest(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: NativeListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 开始请求".logi()
+ listener.onAdStartRequest(adProviderType)
+ TogetherAd.allAdListener?.onAdStartRequest(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackNativeLoaded(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: NativeListener, @NotNull adList: List) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求成功了, 请求到${adList.size}个广告".logi()
+ listener.onAdLoaded(adProviderType, adList)
+ TogetherAd.allAdListener?.onAdLoaded(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackNativeFailed(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: NativeListener, errorCode: Int?, errorMsg: String?) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求失败了:$errorCode $errorMsg".loge()
+ listener.onAdFailed(adProviderType, errorMsg)
+ TogetherAd.allAdListener?.onAdFailed(adProviderType, alias, errorMsg)
+ }
+ }
+
+ /**
+ * --------------------------- 原生信息流模板 ---------------------------
+ */
+ protected fun callbackNativeExpressStartRequest(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: NativeExpress2Listener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 开始请求".logi()
+ listener.onAdStartRequest(adProviderType)
+ TogetherAd.allAdListener?.onAdStartRequest(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackNativeExpressLoaded(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: NativeExpress2Listener, @NotNull adList: List) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求成功了, 请求到${adList.size}个广告".logi()
+ listener.onAdLoaded(adProviderType, adList)
+ TogetherAd.allAdListener?.onAdLoaded(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackNativeExpressFailed(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: NativeExpress2Listener, errorCode: Int?, errorMsg: String?) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求失败了:$errorCode $errorMsg".loge()
+ listener.onAdFailed(adProviderType, errorMsg)
+ TogetherAd.allAdListener?.onAdFailed(adProviderType, alias, errorMsg)
+ }
+ }
+
+ protected fun callbackNativeExpressClicked(@NotNull adProviderType: String, @Nullable adObject: Any?, @NotNull listener: NativeExpressListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 点击了".logi()
+ listener.onAdClicked(adProviderType, adObject)
+ }
+ }
+
+ protected fun callbackNativeExpressShow(@NotNull adProviderType: String, @Nullable adObject: Any?, @NotNull listener: NativeExpressListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 展示了".logi()
+ listener.onAdShow(adProviderType, adObject)
+ }
+ }
+
+ protected fun callbackNativeExpressRenderSuccess(@NotNull adProviderType: String, @Nullable adObject: Any?, @NotNull listener: NativeExpressListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 渲染成功".logi()
+ listener.onAdRenderSuccess(adProviderType, adObject)
+ }
+ }
+
+ protected fun callbackNativeExpressRenderFail(@NotNull adProviderType: String, @Nullable adObject: Any?, @NotNull listener: NativeExpressListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 渲染失败了".loge()
+ listener.onAdRenderFail(adProviderType, adObject)
+ }
+ }
+
+ protected fun callbackNativeExpressClosed(@NotNull adProviderType: String, @Nullable adObject: Any?, @NotNull listener: NativeExpressListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 关闭了".logi()
+ listener.onAdClosed(adProviderType, adObject)
+ }
+ }
+
+ /**
+ * --------------------------- 激励广告 ---------------------------
+ */
+ protected fun callbackRewardStartRequest(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: RewardListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 开始请求".logi()
+ listener.onAdStartRequest(adProviderType)
+ TogetherAd.allAdListener?.onAdStartRequest(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackRewardLoaded(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: RewardListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求成功了".logi()
+ listener.onAdLoaded(adProviderType)
+ TogetherAd.allAdListener?.onAdLoaded(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackRewardFailed(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: RewardListener, errorCode: Int?, errorMsg: String?) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求失败了:$errorCode $errorMsg".loge()
+ listener.onAdFailed(adProviderType, errorMsg)
+ TogetherAd.allAdListener?.onAdFailed(adProviderType, alias, errorMsg)
+ }
+ }
+
+ protected fun callbackRewardClicked(@NotNull adProviderType: String, @NotNull listener: RewardListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 点击了".logi()
+ listener.onAdClicked(adProviderType)
+ }
+ }
+
+ protected fun callbackRewardShow(@NotNull adProviderType: String, @NotNull listener: RewardListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 展示了".logi()
+ listener.onAdShow(adProviderType)
+ }
+ }
+
+ protected fun callbackRewardExpose(@NotNull adProviderType: String, @NotNull listener: RewardListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 曝光了".logi()
+ listener.onAdExpose(adProviderType)
+ }
+ }
+
+ protected fun callbackRewardVideoComplete(@NotNull adProviderType: String, @NotNull listener: RewardListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 播放完成".logi()
+ listener.onAdVideoComplete(adProviderType)
+ }
+ }
+
+ protected fun callbackRewardVideoCached(@NotNull adProviderType: String, @NotNull listener: RewardListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 视频已缓存".logi()
+ listener.onAdVideoCached(adProviderType)
+ }
+ }
+
+ protected fun callbackRewardVerify(@NotNull adProviderType: String, @NotNull listener: RewardListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 激励验证".logi()
+ listener.onAdRewardVerify(adProviderType)
+ }
+ }
+
+ protected fun callbackRewardClosed(@NotNull adProviderType: String, @NotNull listener: RewardListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 关闭了".logi()
+ listener.onAdClose(adProviderType)
+ }
+ }
+
+ /**
+ * --------------------------- 全屏视频广告 ---------------------------
+ */
+ protected fun callbackFullVideoStartRequest(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: FullVideoListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 开始请求".logi()
+ listener.onAdStartRequest(adProviderType)
+ TogetherAd.allAdListener?.onAdStartRequest(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackFullVideoLoaded(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: FullVideoListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求成功了".logi()
+ listener.onAdLoaded(adProviderType)
+ TogetherAd.allAdListener?.onAdLoaded(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackFullVideoFailed(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: FullVideoListener, errorCode: Int?, errorMsg: String?) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求失败了:$errorCode $errorMsg".loge()
+ listener.onAdFailed(adProviderType, errorMsg)
+ TogetherAd.allAdListener?.onAdFailed(adProviderType, alias, errorMsg)
+ }
+ }
+
+ protected fun callbackFullVideoClicked(@NotNull adProviderType: String, @NotNull listener: FullVideoListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 点击了".logi()
+ listener.onAdClicked(adProviderType)
+ }
+ }
+
+ protected fun callbackFullVideoShow(@NotNull adProviderType: String, @NotNull listener: FullVideoListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 展示了".logi()
+ listener.onAdShow(adProviderType)
+ }
+ }
+
+ protected fun callbackFullVideoCached(@NotNull adProviderType: String, @NotNull listener: FullVideoListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 视频已缓存".logi()
+ listener.onAdVideoCached(adProviderType)
+ }
+ }
+
+ protected fun callbackFullVideoClosed(@NotNull adProviderType: String, @NotNull listener: FullVideoListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 关闭了".logi()
+ listener.onAdClose(adProviderType)
+ }
+ }
+
+ protected fun callbackFullVideoComplete(@NotNull adProviderType: String, @NotNull listener: FullVideoListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 视频播放完成了".logi()
+ listener.onAdVideoComplete(adProviderType)
+ }
+ }
+
+ /**
+ * --------------------------- Banner 横幅广告 ---------------------------
+ */
+ protected fun callbackBannerStartRequest(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: BannerListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 开始请求".logi()
+ listener.onAdStartRequest(adProviderType)
+ TogetherAd.allAdListener?.onAdStartRequest(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackBannerLoaded(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: BannerListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求成功了".logi()
+ listener.onAdLoaded(adProviderType)
+ TogetherAd.allAdListener?.onAdLoaded(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackBannerFailed(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: BannerListener, errorCode: Int?, errorMsg: String?) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求失败了:$errorCode $errorMsg".loge()
+ listener.onAdFailed(adProviderType, errorMsg)
+ TogetherAd.allAdListener?.onAdFailed(adProviderType, alias, errorMsg)
+ }
+ }
+
+ protected fun callbackBannerClosed(@NotNull adProviderType: String, @NotNull listener: BannerListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 关闭了".logi()
+ listener.onAdClose(adProviderType)
+ }
+ }
+
+ protected fun callbackBannerExpose(@NotNull adProviderType: String, @NotNull listener: BannerListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 曝光了".logi()
+ listener.onAdExpose(adProviderType)
+ }
+ }
+
+ protected fun callbackBannerClicked(@NotNull adProviderType: String, @NotNull listener: BannerListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 点击了".logi()
+ listener.onAdClicked(adProviderType)
+ }
+ }
+
+ /**
+ * --------------------------- Interaction 插屏广告 ---------------------------
+ */
+ protected fun callbackInterStartRequest(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: InterListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 开始请求".logi()
+ listener.onAdStartRequest(adProviderType)
+ TogetherAd.allAdListener?.onAdStartRequest(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackInterLoaded(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: InterListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求成功了".logi()
+ listener.onAdLoaded(adProviderType)
+ TogetherAd.allAdListener?.onAdLoaded(adProviderType, alias)
+ }
+ }
+
+ protected fun callbackInterFailed(@NotNull adProviderType: String, @NotNull alias: String, @NotNull listener: InterListener, errorCode: Int?, errorMsg: String?) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 请求失败了:$errorCode $errorMsg".loge()
+ listener.onAdFailed(adProviderType, errorMsg)
+ TogetherAd.allAdListener?.onAdFailed(adProviderType, alias, errorMsg)
+ }
+ }
+
+ protected fun callbackInterClosed(@NotNull adProviderType: String, @NotNull listener: InterListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 关闭了".logi()
+ listener.onAdClose(adProviderType)
+ }
+ }
+
+ protected fun callbackInterExpose(@NotNull adProviderType: String, @NotNull listener: InterListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 曝光了".logi()
+ listener.onAdExpose(adProviderType)
+ }
+ }
+
+ protected fun callbackInterClicked(@NotNull adProviderType: String, @NotNull listener: InterListener) {
+ Handler(Looper.getMainLooper()).post {
+ "${adProviderType}: 点击了".logi()
+ listener.onAdClicked(adProviderType)
+ }
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/provider/IAdProvider.kt b/core/src/main/java/com/ifmvo/togetherad/core/provider/IAdProvider.kt
new file mode 100644
index 0000000..a050a48
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/provider/IAdProvider.kt
@@ -0,0 +1,155 @@
+package com.ifmvo.togetherad.core.provider
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.listener.*
+import org.jetbrains.annotations.NotNull
+
+/*
+ * Created by Matthew Chen on 2020-04-03.
+ */
+interface IAdProvider {
+
+ /**
+ * -----------------------------------开屏广告-----------------------------------
+ */
+ fun loadAndShowSplashAd(
+ @NotNull activity: Activity,//由于百度必须使用 Activity,所以这里统一传
+ @NotNull adProviderType: String,
+ @NotNull alias: String,//当前广告位的别名
+ @NotNull container: ViewGroup,//开屏广告的容器,开屏广告请求到之后会自动添加进去
+ @NotNull listener: SplashListener//回调
+ )
+
+ //开屏广告仅请求
+ fun loadOnlySplashAd(
+ @NotNull activity: Activity,//由于百度必须使用 Activity,所以这里统一传
+ @NotNull adProviderType: String,
+ @NotNull alias: String,//当前广告位的别名
+ @NotNull listener: SplashListener//回调
+ )
+
+ //展示开屏广告
+ fun showSplashAd(
+ @NotNull container: ViewGroup
+ ): Boolean
+
+ /**
+ * -----------------------------------Banner 广告-----------------------------------
+ */
+ fun showBannerAd(
+ @NotNull activity: Activity,
+ @NotNull adProviderType: String,
+ @NotNull alias: String,
+ @NotNull container: ViewGroup,
+ @NotNull listener: BannerListener
+ )
+
+ //销毁 Banner 广告
+ fun destroyBannerAd()
+
+ /**
+ * -----------------------------------插屏-----------------------------------
+ */
+ fun requestInterAd(
+ @NotNull activity: Activity,
+ @NotNull adProviderType: String,
+ @NotNull alias: String,
+ @NotNull listener: InterListener
+ )
+
+ //展示插屏广告
+ fun showInterAd(
+ @NotNull activity: Activity
+ )
+
+ //销毁插屏广告
+ fun destroyInterAd()
+
+ /**
+ * -----------------------------------获取自渲染信息流-----------------------------------
+ */
+ fun getNativeAdList(
+ @NotNull activity: Activity,
+ @NotNull adProviderType: String,
+ @NotNull alias: String,
+ maxCount: Int,
+ @NotNull listener: NativeListener
+ )
+
+ //判断原生广告对象是否属于这个提供商
+ fun nativeAdIsBelongTheProvider(@NotNull adObject: Any): Boolean
+
+ //控制原生自渲染的生命周期
+ fun resumeNativeAd(@NotNull adObject: Any)
+
+ //控制原生自渲染的生命周期
+ fun pauseNativeAd(@NotNull adObject: Any)
+
+ //控制原生自渲染的生命周期
+ fun destroyNativeAd(@NotNull adObject: Any)
+
+ /**
+ * -----------------------------------获取原生模板列表-----------------------------------
+ */
+ fun getNativeExpressAdList(
+ @NotNull activity: Activity,
+ @NotNull adProviderType: String,
+ @NotNull alias: String,
+ adCount: Int,
+ @NotNull listener: NativeExpressListener
+ )
+
+ //控制原生模板的生命周期
+ fun destroyNativeExpressAd(adObject: Any)
+
+ //判断模板广告对象是否属于这个提供商
+ fun nativeExpressAdIsBelongTheProvider(adObject: Any): Boolean
+
+ /**
+ * -----------------------------------获取原生模板2.0列表-----------------------------------
+ */
+
+ fun getNativeExpress2AdList(
+ @NotNull activity: Activity,
+ @NotNull adProviderType: String,
+ @NotNull alias: String,
+ adCount: Int,
+ @NotNull listener: NativeExpress2Listener
+ )
+
+ //控制原生模板的生命周期
+ fun destroyNativeExpress2Ad(adObject: Any)
+
+ //判断模板广告对象是否属于这个提供商
+ fun nativeExpress2AdIsBelongTheProvider(adObject: Any): Boolean
+
+ /**
+ * -----------------------------------请求激励广告 -----------------------------------
+ */
+ fun requestRewardAd(
+ @NotNull activity: Activity,
+ @NotNull adProviderType: String,
+ @NotNull alias: String,
+ @NotNull listener: RewardListener
+ )
+
+ //展示激励广告
+ fun showRewardAd(
+ @NotNull activity: Activity
+ ): Boolean
+
+ /**
+ * -----------------------------------请求全屏视频广告 -----------------------------------
+ */
+ fun requestFullVideoAd(
+ @NotNull activity: Activity,
+ @NotNull adProviderType: String,
+ @NotNull alias: String,
+ @NotNull listener: FullVideoListener
+ )
+
+ fun showFullVideoAd(
+ @NotNull activity: Activity
+ ): Boolean
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/utils/DispatchUtil.kt b/core/src/main/java/com/ifmvo/togetherad/core/utils/DispatchUtil.kt
new file mode 100644
index 0000000..9749e00
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/utils/DispatchUtil.kt
@@ -0,0 +1,137 @@
+package com.ifmvo.togetherad.core.utils
+
+import com.ifmvo.togetherad.core.DispatchType
+import com.ifmvo.togetherad.core.TogetherAd
+import org.jetbrains.annotations.NotNull
+
+
+/**
+ * 参数 configStr : "baidu:1,gdt:4,csj:4"
+ *
+ * 按照 2 :8 的比例随机返回 BAIDU or GDT or CSJ
+ *
+ * return AdNameType.BAIDU || AdNameType.GDT || AdNameType.CSJ
+ *
+ * Created by Matthew_Chen on 2018/8/24.
+ */
+object DispatchUtil {
+
+ /**
+ * ratioMap: mapOf("baidu" to 3, "gdt" to 7, "csj" to 7)
+ */
+ fun getAdProvider(@NotNull alias: String, @NotNull ratioMap: LinkedHashMap): String? {
+ return when (TogetherAd.mDispatchTypeMap[alias] ?: TogetherAd.dispatchType) {
+ DispatchType.Priority -> {
+ getAdProviderPriority(ratioMap)
+ }
+ DispatchType.Random -> {
+ getAdProviderRandom(ratioMap)
+ }
+ }
+ }
+
+ /**
+ * ratioMap: linkedMapOf("baidu" to 3, "gdt" to 7, "csj" to 7)
+ *
+ * 取权重最高的那个
+ */
+ private fun getAdProviderPriority(@NotNull ratioMap: HashMap): String? {
+ "提供商权重:$ratioMap".logi()
+ val sortedList = ratioMap.entries.filter { it.value != 0 }.sortedByDescending { it.value }
+ val selectedKey = sortedList.getOrNull(0)?.key
+ "权重最高的是: $selectedKey".logi()
+ return selectedKey
+ }
+
+ /**
+ * ratioMap: mapOf("baidu" to 3, "gdt" to 7, "csj" to 7)
+ *
+ * 按照权重随机取
+ */
+ private fun getAdProviderRandom(@NotNull ratioMap: LinkedHashMap): String? {
+
+ val ratio = StringBuilder()
+ val list = mutableListOf()
+
+ ratioMap.entries.forEach { entry ->
+ ratio.append("${entry.key}:${entry.value}")
+ ratio.append(",")
+ repeat(entry.value) {
+ list.add(entry.key)
+ }
+ }
+
+ "提供商权重:$ratio".logi()
+
+ //没有匹配的
+ if (list.isEmpty()) return null
+ //在list里面随机选择一个
+ val adNameType = list[(0 until list.size).random()]
+ "随机到的广告: $adNameType".logi()
+ return adNameType
+ }
+
+ /**
+ * ratio : "baidu:3,gdt:7,csj:7"
+ * return AdNameType.BAIDU || AdNameType.GDT || AdNameType.CSJ
+ */
+ private fun getAdProviderRandom(@NotNull ratio: String): String? {
+ "提供商权重:$ratio".logi()
+ val list = mutableListOf()
+ //{baidu:2},{gdt:8}
+ val split = ratio.split(",")
+ for (itemStr in split) {
+ //不能为空
+ if (itemStr.isEmpty()) break
+ val splitKeyValue = itemStr.split(":")
+ //必须分割两份才正确
+ if (splitKeyValue.size != 2) break
+ //"baidu:2"
+ val keyStr = splitKeyValue[0]
+ val valueStr = splitKeyValue[1]
+ //都不能为空
+ if (keyStr.isEmpty() || valueStr.isEmpty()) break
+ //加到 list 里面 2 个 "baidu"
+ repeat(valueStr.toIntOrNull() ?: 0) {
+ list.add(keyStr)
+ }
+ }
+ //没有匹配的
+ if (list.size == 0) return null
+ //在list里面随机选择一个
+ val adNameType = list[(0 until list.size).random()]
+ "随机到的广告: $adNameType".logi()
+ return adNameType
+ }
+}
+
+
+/**
+ * 测试工具
+ */
+//fun main() {
+//
+// var a = 0
+// var b = 0
+// var c = 0
+// var d = 0
+//
+// val ratioMap = linkedMapOf()
+// ratioMap["d"] = 1
+// ratioMap["a"] = 2
+// ratioMap["c"] = 3
+// ratioMap["b"] = 4
+//
+// val startTime = System.currentTimeMillis()
+// repeat(100000) {
+// when (AdRandomUtil.getAdProviderPriority(ratioMap)) {
+// "a" -> a++
+// "b" -> b++
+// "c" -> c++
+// "d" -> d++
+// }
+// }
+// val endTime = System.currentTimeMillis()
+// //main函数执行的代码不能打log,要把log删除
+// println("a: $a, b: $b, c: $c, d: $d, 耗时: ${endTime - startTime}")
+//}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/utils/LogExt.kt b/core/src/main/java/com/ifmvo/togetherad/core/utils/LogExt.kt
new file mode 100644
index 0000000..f773216
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/utils/LogExt.kt
@@ -0,0 +1,32 @@
+package com.ifmvo.togetherad.core.utils
+
+import android.util.Log
+import com.ifmvo.togetherad.core.TogetherAd
+
+/*
+ * Created by Matthew_Chen on 2018/12/24.
+ */
+fun String.logv(tag: String? = "TogetherAd") {
+ if (TogetherAd.printLogEnable)
+ Log.v(tag, this)
+}
+
+fun String.logd(tag: String? = "TogetherAd") {
+ if (TogetherAd.printLogEnable)
+ Log.d(tag, this)
+}
+
+fun String.logi(tag: String? = "TogetherAd") {
+ if (TogetherAd.printLogEnable)
+ Log.i(tag, this)
+}
+
+fun String.logw(tag: String? = "TogetherAd") {
+ if (TogetherAd.printLogEnable)
+ Log.w(tag, this)
+}
+
+fun String.loge(tag: String? = "TogetherAd") {
+ if (TogetherAd.printLogEnable)
+ Log.e(tag, this)
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/utils/ProxyHandler.kt b/core/src/main/java/com/ifmvo/togetherad/core/utils/ProxyHandler.kt
new file mode 100644
index 0000000..713c64c
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/utils/ProxyHandler.kt
@@ -0,0 +1,19 @@
+//package com.ifmvo.togetherad.core.utils
+//
+//import java.lang.reflect.InvocationHandler
+//import java.lang.reflect.Method
+//
+//
+///**
+// *
+// * Created by Matthew Chen on 2020/8/27.
+// */
+//class ProxyHandler(proxy: Any?) : InvocationHandler {
+//
+// private var mProxy = proxy
+//
+// override fun invoke(proxy: Any?, method: Method?, args: Array?): Any? {
+// method?.invoke(mProxy, args)
+// return null
+// }
+//}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/utils/ScreenUtil.kt b/core/src/main/java/com/ifmvo/togetherad/core/utils/ScreenUtil.kt
new file mode 100644
index 0000000..dedbdb2
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/utils/ScreenUtil.kt
@@ -0,0 +1,19 @@
+package com.ifmvo.togetherad.core.utils
+
+import android.content.Context
+
+/*
+ *
+ *
+ * Created by Matthew Chen on 2020-05-15.
+ */
+object ScreenUtil {
+
+ fun getDisplayMetricsWidth(context: Context): Int {
+ return context.applicationContext.resources.displayMetrics.widthPixels
+ }
+
+ fun getDisplayMetricsHeight(context: Context): Int {
+ return context.applicationContext.resources.displayMetrics.heightPixels
+ }
+}
\ No newline at end of file
diff --git a/core/src/main/java/com/ifmvo/togetherad/core/utils/SizeExt.kt b/core/src/main/java/com/ifmvo/togetherad/core/utils/SizeExt.kt
new file mode 100644
index 0000000..57561bd
--- /dev/null
+++ b/core/src/main/java/com/ifmvo/togetherad/core/utils/SizeExt.kt
@@ -0,0 +1,26 @@
+package com.ifmvo.togetherad.core.utils
+
+import android.content.Context
+import android.content.res.Resources
+import android.util.TypedValue
+import org.jetbrains.annotations.NotNull
+
+/**
+ *
+ * Created by Matthew Chen on 2020/9/9.
+ */
+val Float.dp get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics)
+
+/**
+ * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
+ */
+fun px2dp(@NotNull context: Context, px: Int): Float {
+ val scale = context.applicationContext.resources.displayMetrics.density
+ return px / scale + 0.5f
+}
+
+fun dpToPx(context: Context, dp: Int): Int {
+ val r: Resources = context.applicationContext.resources
+ val px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp.toFloat(), r.displayMetrics)
+ return px.toInt()
+}
\ No newline at end of file
diff --git a/core/src/main/res/drawable/shape_pre_movie_time.xml b/core/src/main/res/drawable/shape_pre_movie_time.xml
new file mode 100644
index 0000000..218eb81
--- /dev/null
+++ b/core/src/main/res/drawable/shape_pre_movie_time.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/main/res/drawable/shape_splash_skip_view_custom_bg.xml b/core/src/main/res/drawable/shape_splash_skip_view_custom_bg.xml
new file mode 100644
index 0000000..1126dab
--- /dev/null
+++ b/core/src/main/res/drawable/shape_splash_skip_view_custom_bg.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/main/res/layout/layout_splash_skip_view_simple1.xml b/core/src/main/res/layout/layout_splash_skip_view_simple1.xml
new file mode 100644
index 0000000..218c860
--- /dev/null
+++ b/core/src/main/res/layout/layout_splash_skip_view_simple1.xml
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/core/src/main/res/layout/layout_splash_skip_view_simple2.xml b/core/src/main/res/layout/layout_splash_skip_view_simple2.xml
new file mode 100644
index 0000000..d3f88bc
--- /dev/null
+++ b/core/src/main/res/layout/layout_splash_skip_view_simple2.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/main/res/layout/layout_splash_skip_view_simple3.xml b/core/src/main/res/layout/layout_splash_skip_view_simple3.xml
new file mode 100644
index 0000000..5714108
--- /dev/null
+++ b/core/src/main/res/layout/layout_splash_skip_view_simple3.xml
@@ -0,0 +1,14 @@
+
+
\ No newline at end of file
diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..da4478e
--- /dev/null
+++ b/core/src/main/res/values/attrs.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
new file mode 100644
index 0000000..eeae768
--- /dev/null
+++ b/core/src/main/res/values/strings.xml
@@ -0,0 +1,16 @@
+
+ 配置中的广告全部加载失败,或配置中没有匹配的广告
+ 超时了
+ 曝光成功了
+ 准备好了
+ 展示了
+ 点击了
+ 消失了
+
+
+ 不喜欢
+
+ 未初始化,请根据文档进行初始化:https://github.com/ifmvo/TogetherAd/blob/master/doc/prepare.md
+
+ 没有任何分配广告
+
diff --git a/csj/.gitignore b/csj/.gitignore
new file mode 100644
index 0000000..107ef7c
--- /dev/null
+++ b/csj/.gitignore
@@ -0,0 +1,53 @@
+# Copy from Alibaba open source
+
+# Built application files
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+# local.properties
+.classpath
+.project
+.settings/
+
+# Proguard folder generated by Eclipse
+proguard/
+
+#Log Files
+*.log
+
+# OS X
+.DS_Store
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.war
+*.ear
+*.iml
+
+# IDEA Files
+.idea/
+.svn/
+out/
+
+# MAVEN COMPILE Files
+target/
+lint.xml
+
+deploy.gradle
+jcenterDeploy.gradle
+jcenterInstall.gradle
\ No newline at end of file
diff --git a/csj/build.gradle b/csj/build.gradle
new file mode 100644
index 0000000..0b24e12
--- /dev/null
+++ b/csj/build.gradle
@@ -0,0 +1,41 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'com.kezong.fat-aar'
+
+// JitPack Maven
+apply plugin: 'com.github.dcendents.android-maven'
+// Your Group
+group = 'com.github.ifmvo'
+
+android {
+ compileSdkVersion 28
+
+ defaultConfig {
+ minSdkVersion 16
+ targetSdkVersion 28
+ versionCode 1
+ versionName "5.0.3"
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ buildTypes {
+ release {
+ consumerProguardFiles 'proguard-rules.pro'
+ }
+ }
+
+ repositories { flatDir { dirs 'libs' } }
+
+}
+
+dependencies {
+ api fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+// embed(name: 'open_ad_sdk', ext: 'aar')
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+
+ api project(':core')
+}
\ No newline at end of file
diff --git a/csj/libs/open_ad_sdk.aar b/csj/libs/open_ad_sdk.aar
new file mode 100644
index 0000000..f1aaddc
Binary files /dev/null and b/csj/libs/open_ad_sdk.aar differ
diff --git a/csj/proguard-rules.pro b/csj/proguard-rules.pro
new file mode 100644
index 0000000..ee1687c
--- /dev/null
+++ b/csj/proguard-rules.pro
@@ -0,0 +1,31 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+
+#------------------------穿山甲的混淆---------------------------#
+-keep class com.bytedance.** { *; }
+-keep class com.ss.** { *; }
+-keep public interface com.bytedance.sdk.openadsdk.downloadnew.** {*;}
+-keep class com.pgl.sys.ces.** {*;}
+-keep class com.bytedance.embed_dr.** {*;}
+-keep class com.bytedance.embedapplog.** {*;}
+
+-keep class com.ifmvo.togetherad.csj.** { *; }
diff --git a/csj/src/main/AndroidManifest.xml b/csj/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..4bd9a3a
--- /dev/null
+++ b/csj/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/TogetherAdCsj.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/TogetherAdCsj.kt
new file mode 100644
index 0000000..2f26ead
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/TogetherAdCsj.kt
@@ -0,0 +1,124 @@
+package com.ifmvo.togetherad.csj
+
+import android.content.Context
+import com.bytedance.sdk.component.adnet.face.IHttpStack
+import com.bytedance.sdk.openadsdk.*
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.entity.AdProviderEntity
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+import org.jetbrains.annotations.NotNull
+
+/**
+ * 初始化穿山甲
+ *
+ * Created by Matthew Chen on 2020-04-17.
+ */
+object TogetherAdCsj {
+
+ // 必须设置,穿山甲的广告位ID
+ var idMapCsj = mutableMapOf()
+
+ // 可选参数,需在初始化之前,设置是否使用texture播放视频:true使用、false不使用。默认为false不使用(使用的是surface)
+ var useTextureView: Boolean = false
+
+ // 可选参数,设置主题类型,0:正常模式;1:夜间模式;默认为0;传非法值,按照0处理
+ var themeStatus: Int = 0
+
+ // 可选参数,需在初始化之前,设置落地页主题,默认为TTAdConstant#TITLE_BAR_THEME_LIGHT
+ var titleBarTheme: Int = TTAdConstant.TITLE_BAR_THEME_LIGHT
+
+ // 可选参数,需在初始化之前,设置是否允许SDK弹出通知:true允许、false禁止。默认为true允许
+ var allowShowNotify: Boolean = true
+
+ // 可选参数,需在初始化之前,是否打开debug调试信息输出:true打开、false关闭。默认false关闭
+ var debug: Boolean = false
+
+ // 可选参数,需在初始化之前,哪些网络情况下允许直接下载
+ var directDownloadNetworkType = TTAdConstant.NETWORK_STATE_WIFI or TTAdConstant.NETWORK_STATE_4G
+
+ // 可选参数,需在初始化之前,设置是否支持多进程:true支持、false不支持。默认为false不支持
+ var supportMultiProcess: Boolean = false
+
+ // 可选参数,需在初始化之前,设置外部网络请求,默认为 urlconnection
+ var httpStack: IHttpStack? = null
+
+ // 可选参数,需在初始化之前,设置是否为计费用户:true计费用户、false非计费用户。默认为false非计费用户。须征得用户同意才可传入该参数
+ var isPaid: Boolean = false
+
+ // 可选参数,需在初始化之前,设置用户画像的关键词列表 **不能超过为1000个字符**。须征得用户同意才可传入该参数
+ var keywords: String? = null
+
+ // 可选参数,需在初始化之前,设置额外的用户信息 **不能超过为1000个字符**
+ var data: String? = null
+
+ // 可选参数,需在初始化之前,是否异步初始化
+ @Deprecated(message = "穿山甲改变了异步初始化的方式, 使用 initCallback 替换", replaceWith = ReplaceWith(expression = "initCallback", imports = ["com.ifmvo.togetherad.csj"]), level = DeprecationLevel.WARNING)
+ var isAsyncInit: Boolean = false
+
+ // 可选参数,需在初始化之前,可以设置隐私信息控制开关
+ var customController: TTCustomController? = null
+
+ // 可选参数,异步初始化回调
+ var initCallback: TTAdSdk.InitCallback? = null
+
+ // 判断穿山甲SDK是否初始化成功
+ var isInitSuccess = TTAdSdk.isInitSuccess()
+
+ //全局使用的 TTAdManager
+ var mTTAdManager = TTAdSdk.getAdManager()
+ private set
+
+ /**
+ * 简单初始化
+ */
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull csjAdAppId: String, @NotNull appName: String) {
+ init(context, adProviderType, csjAdAppId, appName, null, null)
+ }
+
+ /**
+ * 自定义Provider初始化
+ */
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull csjAdAppId: String, @NotNull appName: String, providerClassPath: String? = null) {
+ init(context, adProviderType, csjAdAppId, appName, null, providerClassPath)
+ }
+
+ /**
+ * 广告位ID 初始化
+ */
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull csjAdAppId: String, @NotNull appName: String, csjIdMap: Map? = null) {
+ init(context, adProviderType, csjAdAppId, appName, csjIdMap, null)
+ }
+
+ /**
+ * 自定义Provider + 广告位ID 一起初始化
+ */
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull csjAdAppId: String, @NotNull appName: String, csjIdMap: Map? = null, providerClassPath: String?) {
+ TogetherAd.addProvider(AdProviderEntity(adProviderType, if (providerClassPath?.isEmpty() != false) CsjProvider::class.java.name else providerClassPath))
+
+ csjIdMap?.let { idMapCsj.putAll(it) }
+
+ //强烈建议在应用对应的Application#onCreate()方法中调用,避免出现content为null的异常
+ val ttAdConfig = TTAdConfig.Builder()
+ ttAdConfig.appId(csjAdAppId)
+ ttAdConfig.appName(appName)
+ ttAdConfig.themeStatus(themeStatus)//设置是否为夜间模式
+ ttAdConfig.useTextureView(useTextureView) //使用TextureView控件播放视频,默认为SurfaceView,当有SurfaceView冲突的场景,可以使用TextureView
+ ttAdConfig.titleBarTheme(titleBarTheme)
+ ttAdConfig.allowShowNotify(allowShowNotify) //是否允许sdk展示通知栏提示
+ ttAdConfig.debug(debug) //测试阶段打开,可以通过日志排查问题,上线时去除该调用
+ ttAdConfig.directDownloadNetworkType(directDownloadNetworkType) //允许直接下载的网络状态集合
+ ttAdConfig.supportMultiProcess(supportMultiProcess) //是否支持多进程,true支持
+ ttAdConfig.paid(isPaid)
+ ttAdConfig.asyncInit(isAsyncInit)
+ keywords?.let { ttAdConfig.keywords(it) }
+ data?.let { ttAdConfig.data(it) }
+ httpStack?.let { ttAdConfig.httpStack(it) } //自定义网络库,demo中给出了okhttp3版本的样例,其余请自行开发或者咨询工作人员。
+ customController?.let { ttAdConfig.customController(it) }
+ //初始化
+ if (initCallback == null) {
+ TTAdSdk.init(context, ttAdConfig.build())
+ } else {
+ TTAdSdk.init(context, ttAdConfig.build(), initCallback)
+ }
+ }
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/native_/express/NativeExpress2ViewCsj.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/express/NativeExpress2ViewCsj.kt
new file mode 100644
index 0000000..c77643c
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/express/NativeExpress2ViewCsj.kt
@@ -0,0 +1,69 @@
+package com.ifmvo.togetherad.csj.native_.express
+
+import android.app.Activity
+import android.view.View
+import android.view.ViewGroup
+import com.bytedance.sdk.openadsdk.TTAdConstant
+import com.bytedance.sdk.openadsdk.TTAdDislike
+import com.bytedance.sdk.openadsdk.TTAppDownloadListener
+import com.bytedance.sdk.openadsdk.TTNativeExpressAd
+import com.ifmvo.togetherad.core.custom.express2.BaseNativeExpress2View
+import com.ifmvo.togetherad.core.listener.NativeExpress2ViewListener
+
+/**
+ * Created by Matthew Chen on 2020/11/25.
+ */
+class NativeExpress2ViewCsj : BaseNativeExpress2View() {
+
+ override fun showNativeExpress2(activity: Activity, adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeExpress2ViewListener?) {
+ if (adObject !is TTNativeExpressAd) return
+
+ container.removeAllViews()
+
+ adObject.setExpressInteractionListener(object : TTNativeExpressAd.ExpressAdInteractionListener {
+ override fun onAdClicked(view: View?, type: Int) {
+ listener?.onAdClicked(adProviderType)
+ }
+
+ override fun onAdShow(view: View?, type: Int) {
+ listener?.onAdExposed(adProviderType)
+ }
+
+ override fun onRenderSuccess(view: View?, width: Float, height: Float) {
+ listener?.onAdRenderSuccess(adProviderType)
+ }
+
+ override fun onRenderFail(view: View?, errorMsg: String?, errorCode: Int) {
+ listener?.onAdRenderFailed(adProviderType)
+ }
+ })
+
+ adObject.setDislikeCallback(activity, object : TTAdDislike.DislikeInteractionCallback {
+ override fun onSelected(position: Int, value: String?, enforce: Boolean) {
+ container.removeAllViews()
+ listener?.onAdClose(adProviderType)
+ }
+
+ override fun onCancel() {}
+ override fun onShow() {}
+ })
+
+ if (adObject.interactionType == TTAdConstant.INTERACTION_TYPE_DOWNLOAD) {
+ adObject.setDownloadListener(object : TTAppDownloadListener {
+ override fun onIdle() {}
+ override fun onDownloadPaused(p0: Long, p1: Long, p2: String?, p3: String?) {}
+ override fun onDownloadFailed(p0: Long, p1: Long, p2: String?, p3: String?) {}
+ override fun onDownloadActive(p0: Long, p1: Long, p2: String?, p3: String?) {}
+ override fun onDownloadFinished(p0: Long, p1: String?, p2: String?) {}
+ override fun onInstalled(p0: String?, p1: String?) {}
+ })
+ }
+ adObject.render()
+ val parent = adObject.expressAdView?.parent
+ if (parent is ViewGroup) {
+ parent.removeAllViews()
+ }
+ container.addView(adObject.expressAdView)
+ }
+
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/BaseNativeViewCsj.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/BaseNativeViewCsj.kt
new file mode 100644
index 0000000..20d984b
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/BaseNativeViewCsj.kt
@@ -0,0 +1,161 @@
+package com.ifmvo.togetherad.csj.native_.view
+
+import android.view.View
+import android.view.ViewGroup
+import com.bytedance.sdk.openadsdk.TTAdConstant
+import com.bytedance.sdk.openadsdk.TTAppDownloadListener
+import com.bytedance.sdk.openadsdk.TTFeedAd
+import com.bytedance.sdk.openadsdk.TTNativeAd
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+
+/**
+ *
+ * Created by Matthew Chen on 2020/9/27.
+ */
+abstract class BaseNativeViewCsj(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeViewCsjFeed(onClose) {
+
+ //关闭按钮的回调
+ private var mOnClose = onClose
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+
+ if (adObject is TTFeedAd) {
+ super.showNative(adProviderType, adObject, container, listener)
+ return
+ }
+
+ if (adObject !is TTNativeAd) {
+ return
+ }
+
+ container.removeAllViews()
+
+ //findView
+ rootView = View.inflate(container.context, getLayoutRes(), container)
+
+ //AdLogo
+ getAdLogoImageView()?.setImageBitmap(adObject.adLogo)
+
+ //Icon
+ getIconImageView()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, adObject.icon.imageUrl)
+ }
+
+ //CloseBtn
+ getCloseButton()?.visibility = if (mOnClose == null) View.GONE else View.VISIBLE
+ getCloseButton()?.setOnClickListener {
+ mOnClose?.invoke(adProviderType)
+ }
+
+ //标题和描述
+ getTitleTextView()?.text = adObject.title
+ getDescTextView()?.text = adObject.description
+ getSourceTextView()?.text = if (adObject.source?.isNotEmpty() == true) adObject.source else "广告来源"
+ getActionButton()?.text = getActionBtnText(adObject)
+
+ adObject.setDownloadListener(object : TTAppDownloadListener {
+ override fun onIdle() {
+ getActionButton()?.text = "开始下载"
+ }
+
+ override fun onDownloadPaused(totalBytes: Long, currBytes: Long, fileName: String?, appName: String?) {
+ getActionButton()?.text = "下载暂停"
+ }
+
+ override fun onDownloadFailed(totalBytes: Long, currBytes: Long, fileName: String?, appName: String?) {
+ getActionButton()?.text = "重新下载"
+ }
+
+ override fun onDownloadActive(p0: Long, p1: Long, p2: String?, p3: String?) {
+ getActionButton()?.text = "下载中"
+ }
+
+ override fun onDownloadFinished(totalBytes: Long, fileName: String?, appName: String?) {
+ getActionButton()?.text = "点击安装"
+ }
+
+ override fun onInstalled(fileName: String?, appName: String?) {
+ getActionButton()?.text = "点击打开"
+ }
+ })
+
+ // 注册普通点击区域,创意点击区域。重要! 这个涉及到广告计费及交互,必须正确调用。convertView必须使用ViewGroup。
+ adObject.registerViewForInteraction(
+ rootView as ViewGroup,
+ getClickableViews() ?: mutableListOf(),
+ getCreativeViews() ?: mutableListOf(),
+ object : TTNativeAd.AdInteractionListener {
+ override fun onAdClicked(view: View, ad: TTNativeAd) {
+ // 点击普通区域的回调
+ }
+
+ override fun onAdCreativeClick(view: View, ad: TTNativeAd) {
+ // 点击创意区域的回调
+ listener?.onAdClicked(adProviderType)
+ }
+
+ override fun onAdShow(ad: TTNativeAd) {
+ // 广告曝光展示的回调
+ listener?.onAdExposed(adProviderType)
+ }
+ })
+
+ when (adObject.imageMode) {
+ //视频类型
+ TTAdConstant.IMAGE_MODE_VIDEO, TTAdConstant.IMAGE_MODE_VIDEO_VERTICAL -> {
+ getImageContainer()?.visibility = View.VISIBLE
+ getVideoContainer()?.visibility = View.GONE
+ getMainImageView_2()?.visibility = View.GONE
+ getMainImageView_3()?.visibility = View.GONE
+ val videoCoverImage = adObject.videoCoverImage
+
+ //信息流如果是视频的话,就只展示视频封面
+ if (videoCoverImage != null && videoCoverImage.imageUrl != null) {
+ getMainImageView_1()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, videoCoverImage.imageUrl)
+ }
+ }
+ }
+ //单个图片的类型
+ TTAdConstant.IMAGE_MODE_LARGE_IMG, TTAdConstant.IMAGE_MODE_SMALL_IMG, TTAdConstant.IMAGE_MODE_VERTICAL_IMG -> {
+ getImageContainer()?.visibility = View.VISIBLE
+ getVideoContainer()?.visibility = View.GONE
+ getMainImageView_2()?.visibility = View.GONE
+ getMainImageView_3()?.visibility = View.GONE
+ val imageList = adObject.imageList
+
+ if (imageList.isNotEmpty() && imageList[0] != null && imageList[0].isValid) {
+ getMainImageView_1()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, imageList[0].imageUrl)
+ }
+ }
+ }
+ //多个图片的类型
+ TTAdConstant.IMAGE_MODE_GROUP_IMG -> {
+ getImageContainer()?.visibility = View.VISIBLE
+ getVideoContainer()?.visibility = View.GONE
+ getMainImageView_2()?.visibility = View.VISIBLE
+ getMainImageView_3()?.visibility = View.VISIBLE
+ val imageList = adObject.imageList
+
+ if (imageList.isNotEmpty() && imageList[0] != null && imageList[0].isValid) {
+ getMainImageView_1()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, imageList[0].imageUrl)
+ }
+ }
+ if (imageList.isNotEmpty() && imageList.size > 1 && imageList[1] != null && imageList[1].isValid) {
+ getMainImageView_2()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, imageList[1].imageUrl)
+ }
+ }
+ if (imageList.isNotEmpty() && imageList.size > 2 && imageList[2].isValid) {
+ getMainImageView_3()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, imageList[2].imageUrl)
+ }
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/BaseNativeViewCsjFeed.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/BaseNativeViewCsjFeed.kt
new file mode 100644
index 0000000..23589bf
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/BaseNativeViewCsjFeed.kt
@@ -0,0 +1,256 @@
+package com.ifmvo.togetherad.csj.native_.view
+
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.ImageView
+import android.widget.TextView
+import com.bytedance.sdk.openadsdk.TTAdConstant
+import com.bytedance.sdk.openadsdk.TTAppDownloadListener
+import com.bytedance.sdk.openadsdk.TTFeedAd
+import com.bytedance.sdk.openadsdk.TTNativeAd
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeView
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.csj.R
+
+/**
+ *
+ * Created by Matthew Chen on 2020/9/27.
+ */
+abstract class BaseNativeViewCsjFeed(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeView() {
+
+ var rootView: View? = null
+
+ //关闭按钮的回调
+ private var mOnClose = onClose
+
+ open fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_csj
+ }
+
+ //广告Logo
+ open fun getAdLogoImageView(): ImageView? {
+ return rootView?.findViewById(R.id.csj_ad_logo)
+ }
+
+ //标题文字
+ open fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.csj_tv_title)
+ }
+
+ //描述文字
+ open fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.csj_tv_desc)
+ }
+
+ //描述文字
+ open fun getSourceTextView(): TextView? {
+ return rootView?.findViewById(R.id.csj_tv_source)
+ }
+
+ //icon 图
+ open fun getIconImageView(): ImageView? {
+ return rootView?.findViewById(R.id.csj_img_logo)
+ }
+
+ //主图1
+ open fun getMainImageView_1(): ImageView? {
+ return rootView?.findViewById(R.id.csj_img_poster1)
+ }
+
+ //主图2
+ open fun getMainImageView_2(): ImageView? {
+ return rootView?.findViewById(R.id.csj_img_poster2)
+ }
+
+ //主图3
+ open fun getMainImageView_3(): ImageView? {
+ return rootView?.findViewById(R.id.csj_img_poster2)
+ }
+
+ //视频容器
+ open fun getVideoContainer(): ViewGroup? {
+ return rootView?.findViewById(R.id.csj_video_container)
+ }
+
+ //图片容器
+ open fun getImageContainer(): ViewGroup? {
+ return rootView?.findViewById(R.id.csj_img_container)
+ }
+
+ //广告创意按钮
+ open fun getActionButton(): Button? {
+ return rootView?.findViewById(R.id.csj_btn_action)
+ }
+
+ //关闭按钮,可以重写为任意类型的View
+ open fun getCloseButton(): View? {
+ return rootView?.findViewById(R.id.csj_btn_close)
+ }
+
+ //可点击ViewList,可重写
+ open fun getClickableViews(): List? {
+ // 可以被点击的view, 也可以把convertView放进来意味整个item可被点击,点击会跳转到落地页
+ val clickViewList = mutableListOf()
+ clickViewList.add(rootView!!)
+ return clickViewList
+ }
+
+ // 创意点击区域的view 点击根据不同的创意进行下载或拨打电话动作
+ //如果需要点击图文区域也能进行下载或者拨打电话动作,请将图文区域的view传入creativeViewList
+ open fun getCreativeViews(): List? {
+ val creativeViewList = mutableListOf()
+ getActionButton()?.let { creativeViewList.add(it) }
+ return creativeViewList
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ if (adObject !is TTFeedAd) {
+ return
+ }
+
+ container.removeAllViews()
+
+ //findView
+ rootView = View.inflate(container.context, getLayoutRes(), container)
+
+ //AdLogo
+ getAdLogoImageView()?.setImageBitmap(adObject.adLogo)
+
+ //Icon
+ getIconImageView()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, adObject.icon.imageUrl)
+ }
+
+ //CloseBtn
+ getCloseButton()?.visibility = if (mOnClose == null) View.GONE else View.VISIBLE
+ getCloseButton()?.setOnClickListener {
+ mOnClose?.invoke(adProviderType)
+ }
+
+ //标题和描述
+ getTitleTextView()?.text = adObject.title
+ getDescTextView()?.text = adObject.description
+ getSourceTextView()?.text = if (adObject.source?.isNotEmpty() == true) adObject.source else "广告来源"
+ getActionButton()?.text = getActionBtnText(adObject)
+
+ adObject.setDownloadListener(object : TTAppDownloadListener {
+ override fun onIdle() {
+ getActionButton()?.text = "开始下载"
+ }
+
+ override fun onDownloadPaused(totalBytes: Long, currBytes: Long, fileName: String?, appName: String?) {
+ getActionButton()?.text = "下载暂停"
+ }
+
+ override fun onDownloadFailed(totalBytes: Long, currBytes: Long, fileName: String?, appName: String?) {
+ getActionButton()?.text = "重新下载"
+ }
+
+ override fun onDownloadActive(p0: Long, p1: Long, p2: String?, p3: String?) {
+ getActionButton()?.text = "下载中"
+ }
+
+ override fun onDownloadFinished(totalBytes: Long, fileName: String?, appName: String?) {
+ getActionButton()?.text = "点击安装"
+ }
+
+ override fun onInstalled(fileName: String?, appName: String?) {
+ getActionButton()?.text = "点击打开"
+ }
+ })
+
+ // 注册普通点击区域,创意点击区域。重要! 这个涉及到广告计费及交互,必须正确调用。convertView必须使用ViewGroup。
+ adObject.registerViewForInteraction(
+ rootView as ViewGroup,
+ getClickableViews() ?: mutableListOf(),
+ getCreativeViews() ?: mutableListOf(),
+ object : TTNativeAd.AdInteractionListener {
+ override fun onAdClicked(view: View, ad: TTNativeAd) {
+ // 点击普通区域的回调
+ }
+
+ override fun onAdCreativeClick(view: View, ad: TTNativeAd) {
+ // 点击创意区域的回调
+ listener?.onAdClicked(adProviderType)
+ }
+
+ override fun onAdShow(ad: TTNativeAd) {
+ // 广告曝光展示的回调
+ listener?.onAdExposed(adProviderType)
+ }
+ })
+
+ when (adObject.imageMode) {
+ //视频类型
+ TTAdConstant.IMAGE_MODE_VIDEO, TTAdConstant.IMAGE_MODE_VIDEO_VERTICAL -> {
+ getImageContainer()?.visibility = View.GONE
+ getVideoContainer()?.visibility = View.VISIBLE
+ getMainImageView_1()?.visibility = View.GONE
+ getMainImageView_2()?.visibility = View.GONE
+ getMainImageView_3()?.visibility = View.GONE
+ getVideoContainer()?.addView(adObject.adView)
+ }
+ //单个图片的类型
+ TTAdConstant.IMAGE_MODE_LARGE_IMG, TTAdConstant.IMAGE_MODE_SMALL_IMG, TTAdConstant.IMAGE_MODE_VERTICAL_IMG -> {
+ getImageContainer()?.visibility = View.VISIBLE
+ getVideoContainer()?.visibility = View.GONE
+ getMainImageView_2()?.visibility = View.GONE
+ getMainImageView_3()?.visibility = View.GONE
+ val imageList = adObject.imageList
+
+ if (imageList.isNotEmpty() && imageList[0] != null && imageList[0].isValid) {
+ getMainImageView_1()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, imageList[0].imageUrl)
+ }
+ }
+ }
+ //多个图片的类型
+ TTAdConstant.IMAGE_MODE_GROUP_IMG -> {
+ getImageContainer()?.visibility = View.VISIBLE
+ getVideoContainer()?.visibility = View.GONE
+ getMainImageView_2()?.visibility = View.VISIBLE
+ getMainImageView_3()?.visibility = View.VISIBLE
+ val imageList = adObject.imageList
+
+ if (imageList.isNotEmpty() && imageList[0] != null && imageList[0].isValid) {
+ getMainImageView_1()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, imageList[0].imageUrl)
+ }
+ }
+ if (imageList.isNotEmpty() && imageList.size > 1 && imageList[1] != null && imageList[1].isValid) {
+ getMainImageView_2()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, imageList[1].imageUrl)
+ }
+ }
+ if (imageList.isNotEmpty() && imageList.size > 2 && imageList[2].isValid) {
+ getMainImageView_3()?.let {
+ TogetherAd.mImageLoader?.loadImage(container.context, it, imageList[2].imageUrl)
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * 根据广告的状态返回按钮应该展示的文字
+ */
+ open fun getActionBtnText(ad: TTNativeAd): String {
+ return when (ad.interactionType) {
+ TTAdConstant.INTERACTION_TYPE_DOWNLOAD -> {
+ "下载"
+ }
+ TTAdConstant.INTERACTION_TYPE_DIAL -> {
+ "立即拨打"
+ }
+ TTAdConstant.INTERACTION_TYPE_LANDING_PAGE, TTAdConstant.INTERACTION_TYPE_BROWSER -> {
+ "查看详情"
+ }
+ else -> {
+ "查看详情"
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple1.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple1.kt
new file mode 100644
index 0000000..cd8b3fa
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple1.kt
@@ -0,0 +1,54 @@
+package com.ifmvo.togetherad.csj.native_.view
+
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.csj.R
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewCsjSimple1 : BaseNativeViewCsj() {
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_csj_simple_1
+ }
+
+ override fun getImageContainer(): ViewGroup? {
+ return rootView?.findViewById(R.id.ll_ad_container)
+ }
+
+ override fun getMainImageView_1(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster1)
+ }
+
+ override fun getMainImageView_2(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster2)
+ }
+
+ override fun getMainImageView_3(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster3)
+ }
+
+ override fun getVideoContainer(): ViewGroup? {
+ return rootView?.findViewById(R.id.fl_ad_container)
+ }
+
+ override fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_title)
+ }
+
+ override fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_desc)
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+
+ getImageContainer()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+ getVideoContainer()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+ }
+
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple2.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple2.kt
new file mode 100644
index 0000000..118601f
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple2.kt
@@ -0,0 +1,53 @@
+package com.ifmvo.togetherad.csj.native_.view
+
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.csj.R
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewCsjSimple2 : BaseNativeViewCsj() {
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_csj_simple_2
+ }
+
+ override fun getImageContainer(): ViewGroup? {
+ return rootView?.findViewById(R.id.ll_ad_container)
+ }
+
+ override fun getMainImageView_1(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster1)
+ }
+
+ override fun getMainImageView_2(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster2)
+ }
+
+ override fun getMainImageView_3(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster3)
+ }
+
+ override fun getVideoContainer(): ViewGroup? {
+ return rootView?.findViewById(R.id.fl_ad_container)
+ }
+
+ override fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_title)
+ }
+
+ override fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_desc)
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+
+ getImageContainer()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) / 3 * 9 / 16)
+ getVideoContainer()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) / 3 * 9 / 16)
+ }
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple3.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple3.kt
new file mode 100644
index 0000000..517f7d0
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple3.kt
@@ -0,0 +1,81 @@
+package com.ifmvo.togetherad.csj.native_.view
+
+import android.os.CountDownTimer
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.ifmvo.togetherad.core.custom.splashSkip.SplashSkipViewSimple2
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.csj.R
+import kotlin.math.roundToInt
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewCsjSimple3(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeViewCsj() {
+
+ private var mOnClose = onClose
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_csj_simple_3
+ }
+
+ override fun getImageContainer(): ViewGroup? {
+ return rootView?.findViewById(R.id.ll_ad_container)
+ }
+
+ override fun getMainImageView_1(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster1)
+ }
+
+ override fun getMainImageView_2(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster2)
+ }
+
+ override fun getMainImageView_3(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster3)
+ }
+
+ override fun getVideoContainer(): ViewGroup? {
+ return rootView?.findViewById(R.id.fl_ad_container)
+ }
+
+ override fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_title)
+ }
+
+ override fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_desc)
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+
+ //添加跳过按钮
+ val customSkipView = SplashSkipViewSimple2()
+ val skipView = customSkipView.onCreateSkipView(container.context)
+ skipView.run {
+ container.addView(this, customSkipView.getLayoutParams())
+ setOnClickListener {
+ mTimer?.cancel()
+ mOnClose?.invoke(adProviderType)
+ }
+ }
+
+ //开始倒计时
+ mTimer?.cancel()
+ mTimer = object : CountDownTimer(5000, 1000) {
+ override fun onFinish() {
+ mOnClose?.invoke(adProviderType)
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ val second = (millisUntilFinished / 1000f).roundToInt()
+ customSkipView.handleTime(second)
+ }
+ }
+ mTimer?.start()
+ }
+
+ private var mTimer: CountDownTimer? = null
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple4.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple4.kt
new file mode 100644
index 0000000..50c3a27
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple4.kt
@@ -0,0 +1,85 @@
+package com.ifmvo.togetherad.csj.native_.view
+
+import android.os.CountDownTimer
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.ifmvo.togetherad.core.custom.splashSkip.SplashSkipViewSimple3
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.csj.R
+import kotlin.math.roundToInt
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewCsjSimple4(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeViewCsj() {
+
+ private var mOnClose = onClose
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_csj_simple_4
+ }
+
+ override fun getImageContainer(): ViewGroup? {
+ return rootView?.findViewById(R.id.ll_ad_container)
+ }
+
+ override fun getMainImageView_1(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster1)
+ }
+
+ override fun getMainImageView_2(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster2)
+ }
+
+ override fun getMainImageView_3(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster3)
+ }
+
+ override fun getVideoContainer(): ViewGroup? {
+ return rootView?.findViewById(R.id.fl_ad_container)
+ }
+
+ override fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_title)
+ }
+
+ override fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_desc)
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+
+ getImageContainer()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+ getVideoContainer()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+
+ //添加跳过按钮
+ val customSkipView = SplashSkipViewSimple3()
+ val skipView = customSkipView.onCreateSkipView(container.context)
+ skipView.run {
+ container.addView(this, customSkipView.getLayoutParams())
+ setOnClickListener {
+ mTimer?.cancel()
+ mOnClose?.invoke(adProviderType)
+ }
+ }
+
+ //开始倒计时
+ mTimer?.cancel()
+ mTimer = object : CountDownTimer(5000, 1000) {
+ override fun onFinish() {
+ mOnClose?.invoke(adProviderType)
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ val second = (millisUntilFinished / 1000f).roundToInt()
+ customSkipView.handleTime(second)
+ }
+ }
+ mTimer?.start()
+ }
+
+ private var mTimer: CountDownTimer? = null
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple5.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple5.kt
new file mode 100644
index 0000000..254a506
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/native_/view/NativeViewCsjSimple5.kt
@@ -0,0 +1,20 @@
+package com.ifmvo.togetherad.csj.native_.view
+
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.csj.native_.view.BaseNativeViewCsj
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewCsjSimple5(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeViewCsj(onClose){
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+
+ getImageContainer()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+ getVideoContainer()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+ }
+
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProvider.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProvider.kt
new file mode 100644
index 0000000..79f7cbe
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProvider.kt
@@ -0,0 +1,179 @@
+package com.ifmvo.togetherad.csj.provider
+
+import com.bytedance.sdk.openadsdk.TTAdConstant
+import com.ifmvo.togetherad.core.custom.splashSkip.BaseSplashSkipView
+
+/**
+ * 广告提供商:穿山甲
+ *
+ * Created by Matthew Chen on 2020-04-03.
+ */
+open class CsjProvider : CsjProviderSplash() {
+
+ /**
+ * --------------------------- 开屏 ---------------------------
+ */
+ object Splash {
+
+ //是否模板类型广告请求
+ var isExpress = false
+
+ //超时时间
+ var maxFetchDelay = 4000
+
+ //自定义按钮
+ var customSkipView: BaseSplashSkipView? = null
+
+ //图片的宽高
+ internal var imageAcceptedSizeWidth = 1080
+
+ internal var imageAcceptedSizeHeight = 1920
+
+ fun setImageAcceptedSize(width: Int, height: Int) {
+ imageAcceptedSizeWidth = width
+ imageAcceptedSizeHeight = height
+ }
+ }
+
+ /**
+ * --------------------------- 横幅Banner ---------------------------
+ */
+ object Banner {
+
+ var supportDeepLink: Boolean = true
+
+ //模板的宽高
+ internal var expressViewAcceptedSizeWidth = -1f
+
+ internal var expressViewAcceptedSizeHeight = -1f
+
+ fun setExpressViewAcceptedSize(widthDp: Float, heightDp: Float) {
+ expressViewAcceptedSizeWidth = widthDp
+ expressViewAcceptedSizeHeight = heightDp
+ }
+
+ //Banner 刷新间隔时间
+ var slideIntervalTime = 30 * 1000
+ }
+
+ /**
+ * --------------------------- 插屏 ---------------------------
+ */
+ object Inter {
+
+ var supportDeepLink: Boolean = true
+
+ //图片的宽高
+ internal var expressViewAcceptedSizeWidth = -1f
+
+ internal var expressViewAcceptedSizeHeight = -1f
+
+ /**
+ * 说明:插屏在请求过程中,需要按照所选比例的实际尺寸请求,比如 1:1 的比例可以请求 600*600,2:3 的比例可以请求 600*900
+ */
+ fun setExpressViewAcceptedSize(width: Float, height: Float) {
+ expressViewAcceptedSizeWidth = width
+ expressViewAcceptedSizeHeight = height
+ }
+ }
+
+ /**
+ * --------------------------- 原生自渲染 ---------------------------
+ */
+ object Native {
+ //如果需要使用穿山甲的原生广告,必须在请求之前设置类型。
+ var nativeAdType = -1
+
+ var supportDeepLink: Boolean = true
+
+ //图片的宽高
+ internal var imageAcceptedSizeWidth = 1080
+
+ internal var imageAcceptedSizeHeight = 1080 * 9 / 16
+
+ fun setImageAcceptedSize(width: Int, height: Int) {
+ imageAcceptedSizeWidth = width
+ imageAcceptedSizeHeight = height
+ }
+ }
+
+ /**
+ * --------------------------- 原生自渲染模板 ---------------------------
+ */
+ object NativeExpress {
+
+ var supportDeepLink: Boolean = true
+
+ //期望模板广告view的size,单位dp
+ internal var expressViewAcceptedSizeWidth = 0f
+
+ //高度设置为0, 则高度会自适应
+ internal var expressViewAcceptedSizeHeight = 0f
+
+ /**
+ * 期望模板广告view的size, 单位dp
+ */
+ fun setExpressViewAcceptedSize(widthDp: Float, heightDp: Float) {
+ expressViewAcceptedSizeWidth = widthDp
+ expressViewAcceptedSizeHeight = heightDp
+ }
+ }
+
+ /**
+ * --------------------------- 激励 ---------------------------
+ */
+ object Reward {
+
+ //是否模板类型广告请求
+ var isExpress = true
+
+ //表来标识应用侧唯一用户;若非服务器回调模式或不需sdk透传,可设置为空字符串
+ var userID: String? = null
+
+ var supportDeepLink: Boolean = true
+
+ //奖励的名称
+ var rewardName: String? = null
+
+ //奖励的数量
+ var rewardAmount: Int = -1
+
+ //设置期望视频播放的方向,为TTAdConstant.HORIZONTAL或TTAdConstant.VERTICAL
+ var orientation: Int = TTAdConstant.VERTICAL
+
+ //用户透传的信息,可不传
+ var mediaExtra: String? = null
+
+ //设置是否在视频播放页面展示下载bar
+ var showDownLoadBar: Boolean = true
+
+ /**
+ * onAdRewardVerify 回调中用于判断校验结果( 后台校验中用到 )
+ */
+ var rewardVerify: Boolean = false
+ internal set
+
+ var errorCode: Int = 0
+ internal set
+
+ var errorMsg: String? = null
+ internal set
+ }
+
+ /**
+ * --------------------------- 全屏视频 ---------------------------
+ */
+ object FullVideo {
+
+ //是否模板类型广告请求
+ var isExpress = true
+
+ var supportDeepLink: Boolean = true
+
+ //设置期望视频播放的方向,为TTAdConstant.HORIZONTAL或TTAdConstant.VERTICAL
+ var orientation: Int = TTAdConstant.VERTICAL
+
+ var ritScenes: TTAdConstant.RitScenes? = null
+
+ }
+}
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderBanner.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderBanner.kt
new file mode 100644
index 0000000..d8cf0cc
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderBanner.kt
@@ -0,0 +1,85 @@
+package com.ifmvo.togetherad.csj.provider
+
+import android.app.Activity
+import android.view.View
+import android.view.ViewGroup
+import com.bytedance.sdk.openadsdk.*
+import com.ifmvo.togetherad.core.listener.BannerListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.csj.TogetherAdCsj
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/2.
+ */
+abstract class CsjProviderBanner : BaseAdProvider() {
+
+ override fun showBannerAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: BannerListener) {
+ destroyBannerAd()
+
+ callbackBannerStartRequest(adProviderType, alias, listener)
+
+ val adSlot = AdSlot.Builder()
+ .setCodeId(TogetherAdCsj.idMapCsj[alias]) //广告位id
+ .setSupportDeepLink(CsjProvider.Banner.supportDeepLink)
+ .setAdCount(1) //请求广告数量为1到3条
+ .setExpressViewAcceptedSize(CsjProvider.Banner.expressViewAcceptedSizeWidth, CsjProvider.Banner.expressViewAcceptedSizeHeight)
+ .setImageAcceptedSize(640, 320)//这个参数设置即可,不影响个性化模板广告的size
+ .build()
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadBannerExpressAd(adSlot, object : TTAdNative.NativeExpressAdListener {
+ override fun onNativeExpressAdLoad(adList: MutableList?) {
+ if (adList.isNullOrEmpty()) {
+ callbackBannerFailed(adProviderType, alias, listener, null, "请求成功,但是返回的list为空")
+ return
+ }
+
+ mTTNativeExpressBannerAd = adList[0]
+ mTTNativeExpressBannerAd?.setSlideIntervalTime(CsjProvider.Banner.slideIntervalTime)
+ mTTNativeExpressBannerAd?.setExpressInteractionListener(object : TTNativeExpressAd.ExpressAdInteractionListener {
+ override fun onAdClicked(p0: View?, p1: Int) {
+ callbackBannerClicked(adProviderType, listener)
+ }
+
+ override fun onAdShow(view: View?, p1: Int) {
+ callbackBannerExpose(adProviderType, listener)
+ }
+
+ override fun onRenderSuccess(view: View?, p1: Float, p2: Float) {
+ callbackBannerLoaded(adProviderType, alias, listener)
+ container.addView(view)
+ }
+
+ override fun onRenderFail(view: View?, errorMsg: String?, errorCode: Int) {
+ destroyBannerAd()
+ callbackBannerFailed(adProviderType, alias, listener, errorCode, errorMsg)
+ }
+ })
+ mTTNativeExpressBannerAd?.setDislikeCallback(activity, object : TTAdDislike.DislikeInteractionCallback {
+ override fun onSelected(position: Int, value: String, enforce: Boolean) {
+ //用户选择不喜欢原因后,移除广告展示
+ container.removeAllViews()
+ destroyBannerAd()
+ callbackBannerClosed(adProviderType, listener)
+ }
+
+ override fun onCancel() {}
+ override fun onShow() {}
+ })
+ mTTNativeExpressBannerAd?.render()
+ }
+
+ override fun onError(errorCode: Int, errorMsg: String?) {
+ destroyBannerAd()
+ callbackBannerFailed(adProviderType, alias, listener, errorCode, errorMsg)
+ }
+ })
+ }
+
+ private var mTTNativeExpressBannerAd: TTNativeExpressAd? = null
+
+ override fun destroyBannerAd() {
+ mTTNativeExpressBannerAd?.destroy()
+ mTTNativeExpressBannerAd = null
+ }
+
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderFullVideo.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderFullVideo.kt
new file mode 100644
index 0000000..6021e8c
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderFullVideo.kt
@@ -0,0 +1,78 @@
+package com.ifmvo.togetherad.csj.provider
+
+import android.app.Activity
+import com.bytedance.sdk.openadsdk.AdSlot
+import com.bytedance.sdk.openadsdk.TTAdNative
+import com.bytedance.sdk.openadsdk.TTAdSdk
+import com.bytedance.sdk.openadsdk.TTFullScreenVideoAd
+import com.ifmvo.togetherad.core.listener.FullVideoListener
+import com.ifmvo.togetherad.csj.TogetherAdCsj
+
+/**
+ *
+ * Created by Matthew Chen on 2020/12/1.
+ */
+abstract class CsjProviderFullVideo : CsjProviderBanner() {
+
+ private var mFllScreenVideoAd: TTFullScreenVideoAd? = null
+ override fun requestFullVideoAd(activity: Activity, adProviderType: String, alias: String, listener: FullVideoListener) {
+
+ callbackFullVideoStartRequest(adProviderType, alias, listener)
+
+ val adSlotBuilder = AdSlot.Builder()
+ adSlotBuilder.setCodeId(TogetherAdCsj.idMapCsj[alias])
+ //模板广告需要设置期望个性化模板广告的大小,单位dp,激励视频场景,只要设置的值大于0即可且仅是模板渲染的代码位ID使用,非模板渲染代码位切勿使用
+ if (CsjProvider.FullVideo.isExpress) {
+ adSlotBuilder.setExpressViewAcceptedSize(500f, 500f)
+ }
+ adSlotBuilder.setSupportDeepLink(CsjProvider.FullVideo.supportDeepLink)
+ adSlotBuilder.setOrientation(CsjProvider.FullVideo.orientation)//必填参数,期望视频的播放方向:TTAdConstant.HORIZONTAL 或 TTAdConstant.VERTICAL
+
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadFullScreenVideoAd(adSlotBuilder.build(), object : TTAdNative.FullScreenVideoAdListener {
+ override fun onFullScreenVideoAdLoad(fullScreenVideoAd: TTFullScreenVideoAd?) {
+ mFllScreenVideoAd = fullScreenVideoAd
+
+ mFllScreenVideoAd?.setFullScreenVideoAdInteractionListener(object : TTFullScreenVideoAd.FullScreenVideoAdInteractionListener {
+ override fun onSkippedVideo() {}
+
+ override fun onAdShow() {
+ callbackFullVideoShow(adProviderType, listener)
+ }
+
+ override fun onAdVideoBarClick() {
+ callbackFullVideoClicked(adProviderType, listener)
+ }
+
+ override fun onVideoComplete() {
+ callbackFullVideoComplete(adProviderType, listener)
+ }
+
+ override fun onAdClose() {
+ callbackFullVideoClosed(adProviderType, listener)
+ }
+ })
+
+ callbackFullVideoLoaded(adProviderType, alias, listener)
+ }
+
+ override fun onFullScreenVideoCached() {
+ callbackFullVideoCached(adProviderType, listener)
+ }
+
+ override fun onError(errorCode: Int, errorMsg: String?) {
+ callbackFullVideoFailed(adProviderType, alias, listener, errorCode, errorMsg)
+ }
+ })
+ }
+
+ override fun showFullVideoAd(activity: Activity): Boolean {
+ val ritScenes = CsjProvider.FullVideo.ritScenes
+ if (ritScenes != null) {
+ mFllScreenVideoAd?.showFullScreenVideoAd(activity, ritScenes, null)
+ } else {
+ mFllScreenVideoAd?.showFullScreenVideoAd(activity)
+ }
+ mFllScreenVideoAd = null
+ return true
+ }
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderInter.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderInter.kt
new file mode 100644
index 0000000..6841a14
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderInter.kt
@@ -0,0 +1,80 @@
+package com.ifmvo.togetherad.csj.provider
+
+import android.app.Activity
+import android.view.View
+import com.bytedance.sdk.openadsdk.*
+import com.ifmvo.togetherad.core.listener.InterListener
+import com.ifmvo.togetherad.csj.TogetherAdCsj
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/2.
+ */
+abstract class CsjProviderInter : CsjProviderFullVideo() {
+
+ private var mTTNativeExpressInterAd: TTNativeExpressAd? = null
+
+ override fun requestInterAd(activity: Activity, adProviderType: String, alias: String, listener: InterListener) {
+ destroyInterAd()
+
+ callbackInterStartRequest(adProviderType, alias, listener)
+
+ val adSlotBuilder = AdSlot.Builder()
+ .setCodeId(TogetherAdCsj.idMapCsj[alias]) //广告位id
+ .setSupportDeepLink(CsjProvider.Inter.supportDeepLink)
+ .setExpressViewAcceptedSize(CsjProvider.Inter.expressViewAcceptedSizeWidth, CsjProvider.Inter.expressViewAcceptedSizeHeight)
+ .setImageAcceptedSize(640, 320)//这个参数设置即可,不影响个性化模板广告的size
+ .setAdCount(1) //请求广告数量为1到3条
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadInteractionExpressAd(adSlotBuilder.build(), object : TTAdNative.NativeExpressAdListener {
+ override fun onNativeExpressAdLoad(adList: MutableList?) {
+ if (adList.isNullOrEmpty()) {
+ callbackInterFailed(adProviderType, alias, listener, null, "请求成功,但是返回的list为空")
+ return
+ }
+ callbackInterLoaded(adProviderType, alias, listener)
+
+ mTTNativeExpressInterAd = adList[0]
+ mTTNativeExpressInterAd?.setExpressInteractionListener(object : TTNativeExpressAd.AdInteractionListener {
+ override fun onAdDismiss() {
+ callbackInterClosed(adProviderType, listener)
+ }
+
+ override fun onAdClicked(p0: View?, p1: Int) {
+ callbackInterClicked(adProviderType, listener)
+ }
+
+ override fun onAdShow(view: View?, p1: Int) {
+ callbackInterExpose(adProviderType, listener)
+ }
+
+ override fun onRenderSuccess(view: View?, p1: Float, p2: Float) {
+ mTTNativeExpressInterAd?.showInteractionExpressAd(activity)
+ }
+
+ override fun onRenderFail(view: View?, errorMsg: String?, errorCode: Int) {
+
+ }
+ })
+ mTTNativeExpressInterAd?.setDislikeCallback(activity, object : TTAdDislike.DislikeInteractionCallback {
+ override fun onSelected(p0: Int, p1: String?, enforce: Boolean) {}
+ override fun onCancel() {}
+ override fun onShow() {}
+ })
+ }
+
+ override fun onError(errorCode: Int, errorMsg: String?) {
+ callbackInterFailed(adProviderType, alias, listener, errorCode, errorMsg)
+ }
+ })
+ }
+
+ override fun showInterAd(activity: Activity) {
+ mTTNativeExpressInterAd?.render()
+ }
+
+ override fun destroyInterAd() {
+ mTTNativeExpressInterAd?.destroy()
+ mTTNativeExpressInterAd = null
+ }
+
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderNative.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderNative.kt
new file mode 100644
index 0000000..c119b06
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderNative.kt
@@ -0,0 +1,123 @@
+package com.ifmvo.togetherad.csj.provider
+
+import android.app.Activity
+import com.bytedance.sdk.openadsdk.*
+import com.ifmvo.togetherad.core.listener.NativeListener
+import com.ifmvo.togetherad.csj.TogetherAdCsj
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class CsjProviderNative : CsjProviderInter() {
+
+ override fun getNativeAdList(activity: Activity, adProviderType: String, alias: String, maxCount: Int, listener: NativeListener) {
+ if (CsjProvider.Native.nativeAdType == -1) {
+ throw IllegalArgumentException(
+ """
+ |--------------------------------------------------------------------------------------
+ | 必须在每次请求穿山甲的原生广告之前设置类型。
+ | 设置方式:
+ | CsjProvider.Native.nativeAdType = AdSlot.TYPE_XXX(类型和你的广告位ID一致)。
+ | CsjProvider.Native.nativeAdType = AdSlot.TYPE_FEED
+ | CsjProvider.Native.nativeAdType = AdSlot.TYPE_INTERACTION_AD
+ | CsjProvider.Native.nativeAdType = AdSlot.TYPE_BANNER
+ | CsjProvider.Native.nativeAdType = AdSlot.TYPE_CACHED_SPLASH
+ | CsjProvider.Native.nativeAdType = AdSlot.TYPE_DRAW_FEED
+ | CsjProvider.Native.nativeAdType = AdSlot.TYPE_FULL_SCREEN_VIDEO
+ | CsjProvider.Native.nativeAdType = AdSlot.TYPE_REWARD_VIDEO
+ | CsjProvider.Native.nativeAdType = AdSlot.TYPE_SPLASH
+ | CsjProvider.Native.nativeAdType = AdSlot.TYPE_STREAM
+ | 任选其一
+ |--------------------------------------------------------------------------------------
+
+"""
+ )
+ }
+
+ //兼容穿山甲的 Stream 广告
+ if (CsjProvider.Native.nativeAdType == AdSlot.TYPE_STREAM) {
+ getStreamAdList(activity, adProviderType, alias, maxCount, listener)
+ return
+ }
+
+ callbackNativeStartRequest(adProviderType, alias, listener)
+
+ val adSlot = AdSlot.Builder()
+ .setCodeId(TogetherAdCsj.idMapCsj[alias])
+ .setSupportDeepLink(CsjProvider.Native.supportDeepLink)
+ .setImageAcceptedSize(CsjProvider.Native.imageAcceptedSizeWidth, CsjProvider.Native.imageAcceptedSizeHeight)
+ .setNativeAdType(CsjProvider.Native.nativeAdType)
+ .setAdCount(maxCount)
+ .build()
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadNativeAd(adSlot, object : TTAdNative.NativeAdListener {
+ override fun onNativeAdLoad(adList: MutableList?) {
+ if (adList.isNullOrEmpty()) {
+ callbackNativeFailed(adProviderType, alias, listener, null, "请求成功,但是返回的list为空")
+ return
+ }
+
+ callbackNativeLoaded(adProviderType, alias, listener, adList)
+ }
+
+ override fun onError(errorCode: Int, errorMsg: String?) {
+ callbackNativeFailed(adProviderType, alias, listener, errorCode, errorMsg)
+ }
+ })
+ }
+
+ private fun getStreamAdList(activity: Activity, adProviderType: String, alias: String, maxCount: Int, listener: NativeListener) {
+
+ callbackNativeStartRequest(adProviderType, alias, listener)
+
+ val adSlot = AdSlot.Builder()
+ .setCodeId(TogetherAdCsj.idMapCsj[alias])
+ .setImageAcceptedSize(CsjProvider.Native.imageAcceptedSizeWidth, CsjProvider.Native.imageAcceptedSizeHeight)
+ .setAdCount(maxCount)
+ .build()
+
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadStream(adSlot, object : TTAdNative.FeedAdListener {
+ override fun onFeedAdLoad(adList: MutableList?) {
+ if (adList.isNullOrEmpty()) {
+ callbackNativeFailed(adProviderType, alias, listener, null, "请求成功,但是返回的list为空")
+ return
+ }
+
+ callbackNativeLoaded(adProviderType, alias, listener, adList)
+ }
+
+ override fun onError(errorCode: Int, errorMsg: String?) {
+ callbackNativeFailed(adProviderType, alias, listener, errorCode, errorMsg)
+ }
+ })
+ }
+
+ override fun resumeNativeAd(adObject: Any) {
+ when (adObject) {
+ is TTNativeAd -> {
+
+ }
+ }
+ }
+
+ override fun pauseNativeAd(adObject: Any) {
+ when (adObject) {
+ is TTNativeAd -> {
+
+ }
+ }
+ }
+
+ override fun destroyNativeAd(adObject: Any) {
+ when (adObject) {
+ is TTNativeAd -> {
+ adObject.destroy()
+ }
+ }
+ }
+
+ override fun nativeAdIsBelongTheProvider(adObject: Any): Boolean {
+ return adObject is TTNativeAd
+ }
+
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderNativeExpress.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderNativeExpress.kt
new file mode 100644
index 0000000..daf61ed
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderNativeExpress.kt
@@ -0,0 +1,26 @@
+package com.ifmvo.togetherad.csj.provider
+
+import android.app.Activity
+import com.bytedance.sdk.openadsdk.TTNativeExpressAd
+import com.ifmvo.togetherad.core.listener.NativeExpressListener
+
+
+/**
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class CsjProviderNativeExpress : CsjProviderNative() {
+
+ override fun getNativeExpressAdList(activity: Activity, adProviderType: String, alias: String, adCount: Int, listener: NativeExpressListener) {
+ callbackNativeExpressStartRequest(adProviderType, alias, listener)
+ callbackNativeExpressFailed(adProviderType, alias, listener, null, "穿山甲不支持模板1.0")
+ }
+
+ override fun destroyNativeExpressAd(adObject: Any) {
+ if (adObject !is TTNativeExpressAd) return
+ adObject.destroy()
+ }
+
+ override fun nativeExpressAdIsBelongTheProvider(adObject: Any): Boolean {
+ return adObject is TTNativeExpressAd
+ }
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderNativeExpress2.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderNativeExpress2.kt
new file mode 100644
index 0000000..10c5c6b
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderNativeExpress2.kt
@@ -0,0 +1,52 @@
+package com.ifmvo.togetherad.csj.provider
+
+import android.app.Activity
+import com.bytedance.sdk.openadsdk.AdSlot
+import com.bytedance.sdk.openadsdk.TTAdNative
+import com.bytedance.sdk.openadsdk.TTAdSdk
+import com.bytedance.sdk.openadsdk.TTNativeExpressAd
+import com.ifmvo.togetherad.core.listener.NativeExpress2Listener
+import com.ifmvo.togetherad.csj.TogetherAdCsj
+
+
+/**
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class CsjProviderNativeExpress2 : CsjProviderNativeExpress() {
+
+ override fun getNativeExpress2AdList(activity: Activity, adProviderType: String, alias: String, adCount: Int, listener: NativeExpress2Listener) {
+
+ callbackNativeExpressStartRequest(adProviderType, alias, listener)
+
+ val adSlot = AdSlot.Builder()
+ .setCodeId(TogetherAdCsj.idMapCsj[alias]) //广告位id
+ .setSupportDeepLink(CsjProvider.NativeExpress.supportDeepLink)
+ .setAdCount(adCount)//请求广告数量为1到3条
+ .setExpressViewAcceptedSize(CsjProvider.NativeExpress.expressViewAcceptedSizeWidth, CsjProvider.NativeExpress.expressViewAcceptedSizeHeight)//期望模板广告view的size,单位dp
+ .build()
+
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadNativeExpressAd(adSlot, object : TTAdNative.NativeExpressAdListener {
+ override fun onNativeExpressAdLoad(ads: MutableList?) {
+ if (ads.isNullOrEmpty()) {
+ callbackNativeExpressFailed(adProviderType, alias, listener, null, "请求成功,但是返回的list为空")
+ return
+ }
+
+ callbackNativeExpressLoaded(adProviderType, alias, listener, ads)
+ }
+
+ override fun onError(errorCode: Int, errorMsg: String?) {
+ callbackNativeExpressFailed(adProviderType, alias, listener, errorCode, errorMsg)
+ }
+ })
+ }
+
+ override fun destroyNativeExpress2Ad(adObject: Any) {
+ if (adObject !is TTNativeExpressAd) return
+ adObject.destroy()
+ }
+
+ override fun nativeExpress2AdIsBelongTheProvider(adObject: Any): Boolean {
+ return adObject is TTNativeExpressAd
+ }
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderReward.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderReward.kt
new file mode 100644
index 0000000..b0f8ff4
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderReward.kt
@@ -0,0 +1,117 @@
+package com.ifmvo.togetherad.csj.provider
+
+import android.app.Activity
+import com.bytedance.sdk.openadsdk.*
+import com.ifmvo.togetherad.core.listener.RewardListener
+import com.ifmvo.togetherad.csj.TogetherAdCsj
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class CsjProviderReward : CsjProviderNativeExpress2() {
+
+ private var mttRewardVideoAd: TTRewardVideoAd? = null
+ override fun requestRewardAd(activity: Activity, adProviderType: String, alias: String, listener: RewardListener) {
+
+ callbackRewardStartRequest(adProviderType, alias, listener)
+
+ val adSlotBuilder = AdSlot.Builder()
+ .setCodeId(TogetherAdCsj.idMapCsj[alias])
+ .setSupportDeepLink(CsjProvider.Reward.supportDeepLink)
+ .setRewardAmount(if (CsjProvider.Reward.rewardAmount != -1) CsjProvider.Reward.rewardAmount else -1)
+ .setRewardName(if (CsjProvider.Reward.rewardName?.isNotEmpty() == true) CsjProvider.Reward.rewardName else "")
+ //必传参数,表来标识应用侧唯一用户;若非服务器回调模式或不需sdk透传,可设置为空字符串
+ .setUserID(if (CsjProvider.Reward.userID?.isNotEmpty() == true) CsjProvider.Reward.userID else "")
+ .setOrientation(CsjProvider.Reward.orientation) //设置期望视频播放的方向,为TTAdConstant.HORIZONTAL或TTAdConstant.VERTICAL
+
+ if (CsjProvider.Reward.mediaExtra?.isNotEmpty() == true) {
+ adSlotBuilder.setMediaExtra(CsjProvider.Reward.mediaExtra)
+ }
+
+ if (CsjProvider.Reward.isExpress) {
+ //模板广告需要设置期望个性化模板广告的大小,单位dp,激励视频场景,只要设置的值大于0即可
+ adSlotBuilder.setExpressViewAcceptedSize(500f, 500f)
+ }
+
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadRewardVideoAd(adSlotBuilder.build(), object : TTAdNative.RewardVideoAdListener {
+ override fun onError(code: Int, message: String?) {
+ callbackRewardFailed(adProviderType, alias, listener, code, message)
+ mttRewardVideoAd = null
+ }
+
+ //视频广告加载后的视频文件资源缓存到本地的回调
+ override fun onRewardVideoCached() {
+ callbackRewardVideoCached(adProviderType, listener)
+ }
+
+ //视频广告素材加载到,如title,视频url等,不包括视频文件
+ override fun onRewardVideoAdLoad(ad: TTRewardVideoAd) {
+
+ mttRewardVideoAd = ad
+ mttRewardVideoAd?.setShowDownLoadBar(CsjProvider.Reward.showDownLoadBar)
+ mttRewardVideoAd?.setRewardAdInteractionListener(object : TTRewardVideoAd.RewardAdInteractionListener {
+ override fun onSkippedVideo() {
+ }
+
+ override fun onVideoError() {
+ }
+
+ override fun onAdShow() {
+ callbackRewardShow(adProviderType, listener)
+ callbackRewardExpose(adProviderType, listener)
+ }
+
+ override fun onAdVideoBarClick() {
+ callbackRewardClicked(adProviderType, listener)
+ }
+
+ override fun onAdClose() {
+ callbackRewardClosed(adProviderType, listener)
+ mttRewardVideoAd = null
+ }
+
+ override fun onVideoComplete() {
+ callbackRewardVideoComplete(adProviderType, listener)
+ }
+
+ override fun onRewardVerify(rewardVerify: Boolean, rewardAmount: Int, rewardName: String?, errorCode: Int, errorMsg: String?) {
+ CsjProvider.Reward.rewardVerify = rewardVerify
+ CsjProvider.Reward.rewardAmount = rewardAmount
+ CsjProvider.Reward.rewardName = rewardName
+ CsjProvider.Reward.errorCode = errorCode
+ CsjProvider.Reward.errorMsg = errorMsg
+ callbackRewardVerify(adProviderType, listener)
+ }
+ })
+ mttRewardVideoAd?.setDownloadListener(object : TTAppDownloadListener {
+ override fun onIdle() {
+ }
+
+ override fun onDownloadActive(totalBytes: Long, currBytes: Long, fileName: String?, appName: String?) {
+ }
+
+ override fun onDownloadPaused(totalBytes: Long, currBytes: Long, fileName: String?, appName: String?) {
+ }
+
+ override fun onDownloadFailed(totalBytes: Long, currBytes: Long, fileName: String?, appName: String?) {
+ }
+
+ override fun onDownloadFinished(totalBytes: Long, fileName: String?, appName: String?) {
+ }
+
+ override fun onInstalled(fileName: String?, appName: String?) {
+ }
+ })
+
+ callbackRewardLoaded(adProviderType, alias, listener)
+ }
+ })
+ }
+
+ override fun showRewardAd(activity: Activity): Boolean {
+ mttRewardVideoAd?.showRewardVideoAd(activity, TTAdConstant.RitScenes.CUSTOMIZE_SCENES, "scenes_test")
+ return true
+ }
+
+}
\ No newline at end of file
diff --git a/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderSplash.kt b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderSplash.kt
new file mode 100644
index 0000000..e5f9e3f
--- /dev/null
+++ b/csj/src/main/java/com/ifmvo/togetherad/csj/provider/CsjProviderSplash.kt
@@ -0,0 +1,218 @@
+package com.ifmvo.togetherad.csj.provider
+
+import android.app.Activity
+import android.os.CountDownTimer
+import android.view.View
+import android.view.ViewGroup
+import com.bytedance.sdk.openadsdk.AdSlot
+import com.bytedance.sdk.openadsdk.TTAdNative
+import com.bytedance.sdk.openadsdk.TTAdSdk
+import com.bytedance.sdk.openadsdk.TTSplashAd
+import com.ifmvo.togetherad.core.listener.SplashListener
+import com.ifmvo.togetherad.csj.TogetherAdCsj
+import kotlin.math.roundToInt
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class CsjProviderSplash : CsjProviderReward() {
+
+ private var mTimer: CountDownTimer? = null
+
+ private var mListener: SplashListener? = null
+ private var mAdProviderType: String? = null
+
+ private var mSplashAd: TTSplashAd? = null
+ override fun loadOnlySplashAd(activity: Activity, adProviderType: String, alias: String, listener: SplashListener) {
+
+ mListener = listener
+ mAdProviderType = adProviderType
+
+ callbackSplashStartRequest(adProviderType, alias, listener)
+
+ val adSlotBuilder = AdSlot.Builder()
+ adSlotBuilder.setCodeId(TogetherAdCsj.idMapCsj[alias])
+ if (CsjProvider.Splash.isExpress) {
+ adSlotBuilder.setExpressViewAcceptedSize(CsjProvider.Splash.imageAcceptedSizeWidth.toFloat(), CsjProvider.Splash.imageAcceptedSizeHeight.toFloat())
+ } else {
+ adSlotBuilder.setImageAcceptedSize(CsjProvider.Splash.imageAcceptedSizeWidth, CsjProvider.Splash.imageAcceptedSizeHeight)
+ }
+
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadSplashAd(adSlotBuilder.build(), object : TTAdNative.SplashAdListener {
+ override fun onSplashAdLoad(splashAd: TTSplashAd?) {
+
+ if (splashAd == null) {
+ callbackSplashFailed(adProviderType, alias, listener, null, "请求成功,但是返回的广告为null")
+ return
+ }
+
+ callbackSplashLoaded(adProviderType, alias, listener)
+
+ mSplashAd = splashAd
+
+ mSplashAd?.setSplashInteractionListener(object : TTSplashAd.AdInteractionListener {
+ override fun onAdClicked(view: View?, p1: Int) {
+ callbackSplashClicked(adProviderType, listener)
+ }
+
+ override fun onAdSkip() {
+ CsjProvider.Splash.customSkipView = null
+ callbackSplashDismiss(adProviderType, listener)
+ }
+
+ override fun onAdShow(p0: View?, p1: Int) {
+ callbackSplashExposure(adProviderType, listener)
+ }
+
+ override fun onAdTimeOver() {
+ CsjProvider.Splash.customSkipView = null
+ callbackSplashDismiss(adProviderType, listener)
+ }
+ })
+ }
+
+ override fun onTimeout() {
+ callbackSplashFailed(adProviderType, alias, listener, null, "请求超时了")
+ }
+
+ override fun onError(errorCode: Int, errorMsg: String?) {
+ callbackSplashFailed(adProviderType, alias, listener, errorCode, errorMsg)
+ }
+ }, CsjProvider.Splash.maxFetchDelay)//超时时间,demo 为 3000
+ }
+
+ override fun showSplashAd(container: ViewGroup): Boolean {
+
+ if (mSplashAd?.splashView == null) {
+ return false
+ }
+
+ container.removeAllViews()
+ container.addView(mSplashAd!!.splashView)
+
+ val customSkipView = CsjProvider.Splash.customSkipView
+ val skipView = customSkipView?.onCreateSkipView(container.context)
+
+ if (customSkipView != null) {
+ mSplashAd?.setNotAllowSdkCountdown()
+ skipView?.run {
+ container.addView(this, customSkipView.getLayoutParams())
+ setOnClickListener {
+ mTimer?.cancel()
+ if (mAdProviderType != null && mListener != null) {
+ CsjProvider.Splash.customSkipView = null
+ callbackSplashDismiss(mAdProviderType!!, mListener!!)
+ }
+ }
+ }
+
+ //开始倒计时
+ mTimer?.cancel()
+ mTimer = object : CountDownTimer(5000, 1000) {
+ override fun onFinish() {
+ if (mAdProviderType != null && mListener != null) {
+ CsjProvider.Splash.customSkipView = null
+ callbackSplashDismiss(mAdProviderType!!, mListener!!)
+ }
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ val second = (millisUntilFinished / 1000f).roundToInt()
+ customSkipView.handleTime(second)
+ }
+ }
+ mTimer?.start()
+ }
+
+ return true
+ }
+
+ override fun loadAndShowSplashAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: SplashListener) {
+
+ callbackSplashStartRequest(adProviderType, alias, listener)
+
+ val customSkipView = CsjProvider.Splash.customSkipView
+ val skipView = customSkipView?.onCreateSkipView(activity)
+
+ val adSlotBuilder = AdSlot.Builder()
+ adSlotBuilder.setCodeId(TogetherAdCsj.idMapCsj[alias])
+ if (CsjProvider.Splash.isExpress) {
+ adSlotBuilder.setExpressViewAcceptedSize(CsjProvider.Splash.imageAcceptedSizeWidth.toFloat(), CsjProvider.Splash.imageAcceptedSizeHeight.toFloat())
+ } else {
+ adSlotBuilder.setImageAcceptedSize(CsjProvider.Splash.imageAcceptedSizeWidth, CsjProvider.Splash.imageAcceptedSizeHeight)
+ }
+
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadSplashAd(adSlotBuilder.build(), object : TTAdNative.SplashAdListener {
+ override fun onSplashAdLoad(splashAd: TTSplashAd?) {
+
+ if (splashAd == null) {
+ callbackSplashFailed(adProviderType, alias, listener, null, "请求成功,但是返回的广告为null")
+ return
+ }
+
+ callbackSplashLoaded(adProviderType, alias, listener)
+
+ container.removeAllViews()
+ container.addView(splashAd.splashView)
+
+ splashAd.setSplashInteractionListener(object : TTSplashAd.AdInteractionListener {
+ override fun onAdClicked(view: View?, p1: Int) {
+ callbackSplashClicked(adProviderType, listener)
+ }
+
+ override fun onAdSkip() {
+ CsjProvider.Splash.customSkipView = null
+ callbackSplashDismiss(adProviderType, listener)
+ }
+
+ override fun onAdShow(p0: View?, p1: Int) {
+ callbackSplashExposure(adProviderType, listener)
+ }
+
+ override fun onAdTimeOver() {
+ CsjProvider.Splash.customSkipView = null
+ callbackSplashDismiss(adProviderType, listener)
+ }
+ })
+
+ //自定义跳过按钮和计时逻辑
+ if (customSkipView != null) {
+ splashAd.setNotAllowSdkCountdown()
+ skipView?.run {
+ container.addView(this, customSkipView.getLayoutParams())
+ setOnClickListener {
+ mTimer?.cancel()
+ CsjProvider.Splash.customSkipView = null
+ callbackSplashDismiss(adProviderType, listener)
+ }
+ }
+
+ //开始倒计时
+ mTimer?.cancel()
+ mTimer = object : CountDownTimer(5000, 1000) {
+ override fun onFinish() {
+ CsjProvider.Splash.customSkipView = null
+ callbackSplashDismiss(adProviderType, listener)
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ val second = (millisUntilFinished / 1000f).roundToInt()
+ customSkipView.handleTime(second)
+ }
+ }
+ mTimer?.start()
+ }
+ }
+
+ override fun onTimeout() {
+ callbackSplashFailed(adProviderType, alias, listener, null, "请求超时了")
+ }
+
+ override fun onError(errorCode: Int, errorMsg: String?) {
+ callbackSplashFailed(adProviderType, alias, listener, errorCode, errorMsg)
+ }
+ }, CsjProvider.Splash.maxFetchDelay)//超时时间,demo 为 3000
+ }
+
+}
\ No newline at end of file
diff --git a/csj/src/main/res/layout/layout_native_view_csj.xml b/csj/src/main/res/layout/layout_native_view_csj.xml
new file mode 100644
index 0000000..43012e2
--- /dev/null
+++ b/csj/src/main/res/layout/layout_native_view_csj.xml
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/csj/src/main/res/layout/layout_native_view_csj_simple_1.xml b/csj/src/main/res/layout/layout_native_view_csj_simple_1.xml
new file mode 100644
index 0000000..5bc023d
--- /dev/null
+++ b/csj/src/main/res/layout/layout_native_view_csj_simple_1.xml
@@ -0,0 +1,107 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/csj/src/main/res/layout/layout_native_view_csj_simple_2.xml b/csj/src/main/res/layout/layout_native_view_csj_simple_2.xml
new file mode 100644
index 0000000..47e3a84
--- /dev/null
+++ b/csj/src/main/res/layout/layout_native_view_csj_simple_2.xml
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/csj/src/main/res/layout/layout_native_view_csj_simple_3.xml b/csj/src/main/res/layout/layout_native_view_csj_simple_3.xml
new file mode 100644
index 0000000..1a962a8
--- /dev/null
+++ b/csj/src/main/res/layout/layout_native_view_csj_simple_3.xml
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/csj/src/main/res/layout/layout_native_view_csj_simple_4.xml b/csj/src/main/res/layout/layout_native_view_csj_simple_4.xml
new file mode 100644
index 0000000..fe7d9e3
--- /dev/null
+++ b/csj/src/main/res/layout/layout_native_view_csj_simple_4.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/csj/src/main/res/values/strings.xml b/csj/src/main/res/values/strings.xml
new file mode 100644
index 0000000..6d5a695
--- /dev/null
+++ b/csj/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ TogetherAd
+
diff --git a/csj/src/main/res/xml/csj_file_paths.xml b/csj/src/main/res/xml/csj_file_paths.xml
new file mode 100644
index 0000000..4d30e3c
--- /dev/null
+++ b/csj/src/main/res/xml/csj_file_paths.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/.gitignore b/demo/.gitignore
new file mode 100644
index 0000000..107ef7c
--- /dev/null
+++ b/demo/.gitignore
@@ -0,0 +1,53 @@
+# Copy from Alibaba open source
+
+# Built application files
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+# local.properties
+.classpath
+.project
+.settings/
+
+# Proguard folder generated by Eclipse
+proguard/
+
+#Log Files
+*.log
+
+# OS X
+.DS_Store
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.war
+*.ear
+*.iml
+
+# IDEA Files
+.idea/
+.svn/
+out/
+
+# MAVEN COMPILE Files
+target/
+lint.xml
+
+deploy.gradle
+jcenterDeploy.gradle
+jcenterInstall.gradle
\ No newline at end of file
diff --git a/demo/TogetherAd.jks b/demo/TogetherAd.jks
new file mode 100644
index 0000000..1628d4e
Binary files /dev/null and b/demo/TogetherAd.jks differ
diff --git a/demo/build.gradle b/demo/build.gradle
new file mode 100644
index 0000000..72e8278
--- /dev/null
+++ b/demo/build.gradle
@@ -0,0 +1,76 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+
+android {
+ compileSdkVersion 28
+
+ defaultConfig {
+ applicationId "com.ifmvo.togetherad.demo"
+ minSdkVersion 16
+ targetSdkVersion 28
+ versionCode 1
+ versionName "5.0.3"
+ multiDexEnabled true
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ signingConfigs {
+ release {
+ keyAlias 'TogetherAd2020'
+ keyPassword 'TogetherAd2020'
+ storeFile file('TogetherAd.jks')
+ storePassword 'TogetherAd2020'
+ }
+ }
+
+ buildTypes {
+ release {
+ signingConfig signingConfigs.release
+ minifyEnabled true
+ shrinkResources true
+ zipAlignEnabled true
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ debug {
+ signingConfig signingConfigs.release
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ // 自定义APK文件名
+ applicationVariants.all { variant ->
+ variant.outputs.all {
+ outputFileName = "TogetherAdDemo_${releaseTime()}.apk"
+ }
+ }
+}
+
+//获取时间
+static def releaseTime() {
+ return new Date().format("yyyyMMdd", TimeZone.getTimeZone("UTC"))
+}
+
+dependencies {
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+ implementation 'com.android.support:recyclerview-v7:28.0.0'
+
+ //内存泄漏检测工具
+ debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4'
+
+// implementation 'com.github.ifmvo.TogetherAd:core:5.0.3'
+// implementation 'com.github.ifmvo.TogetherAd:gdt:5.0.3'
+// implementation 'com.github.ifmvo.TogetherAd:csj:5.0.3'
+// implementation 'com.github.ifmvo.TogetherAd:baidu:5.0.3'
+
+ //TogetherAd
+ implementation project(':csj')
+ implementation project(':gdt')
+ implementation project(':baidu')
+
+}
\ No newline at end of file
diff --git a/demo/proguard-rules.pro b/demo/proguard-rules.pro
new file mode 100644
index 0000000..05729a1
--- /dev/null
+++ b/demo/proguard-rules.pro
@@ -0,0 +1,194 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+#
+#-------------------------------------------基本不用动区域----------------------------------------------
+#
+#
+# -----------------------------基本 -----------------------------
+#
+
+# 指定代码的压缩级别 0 - 7(指定代码进行迭代优化的次数,在Android里面默认是5,这条指令也只有在可以优化时起作用。)
+-optimizationpasses 5
+# 混淆时不会产生形形色色的类名(混淆时不使用大小写混合类名)
+-dontusemixedcaseclassnames
+# 指定不去忽略非公共的库类(不跳过library中的非public的类)
+-dontskipnonpubliclibraryclasses
+# 指定不去忽略包可见的库类的成员
+-dontskipnonpubliclibraryclassmembers
+#不进行优化,建议使用此选项,
+-dontoptimize
+ # 不进行预校验,Android不需要,可加快混淆速度。
+-dontpreverify
+
+
+# 屏蔽警告
+-ignorewarnings
+# 指定混淆是采用的算法,后面的参数是一个过滤器
+# 这个过滤器是谷歌推荐的算法,一般不做更改
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+# 保护代码中的Annotation不被混淆
+-keepattributes *Annotation*
+# 避免混淆泛型, 这在JSON实体映射时非常重要
+-keepattributes Signature
+# 抛出异常时保留代码行号
+-keepattributes SourceFile,LineNumberTable
+ #优化时允许访问并修改有修饰符的类和类的成员,这可以提高优化步骤的结果。
+# 比如,当内联一个公共的getter方法时,这也可能需要外地公共访问。
+# 虽然java二进制规范不需要这个,要不然有的虚拟机处理这些代码会有问题。当有优化和使用-repackageclasses时才适用。
+#指示语:不能用这个指令处理库中的代码,因为有的类和类成员没有设计成public ,而在api中可能变成public
+-allowaccessmodification
+#当有优化和使用-repackageclasses时才适用。
+#-repackageclasses com.test
+
+ # 混淆时记录日志(打印混淆的详细信息)
+ # 这句话能够使我们的项目混淆后产生映射文件
+ # 包含有类名->混淆后类名的映射关系
+-verbose
+
+#
+# ----------------------------- 默认保留 -----------------------------
+#
+#----------------------------------------------------
+# 保持哪些类不被混淆
+#继承activity,application,service,broadcastReceiver,contentprovider....不进行混淆
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.support.multidex.MultiDexApplication
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class * extends android.view.View
+-keep class android.support.** {*;}## 保留support下的所有类及其内部类
+
+-keep public class com.google.vending.licensing.ILicensingService
+-keep public class com.android.vending.licensing.ILicensingService
+#表示不混淆上面声明的类,最后这两个类我们基本也用不上,是接入Google原生的一些服务时使用的。
+#----------------------------------------------------
+
+# 保留继承的
+-keep public class * extends android.support.v4.**
+-keep public class * extends android.support.v7.**
+-keep public class * extends android.support.annotation.**
+
+
+#表示不混淆任何包含native方法的类的类名以及native方法名,这个和我们刚才验证的结果是一致
+-keepclasseswithmembernames class * {
+ native ;
+}
+
+
+#这个主要是在layout 中写的onclick方法android:onclick="onClick",不进行混淆
+#表示不混淆Activity中参数是View的方法,因为有这样一种用法,在XML中配置android:onClick=”buttonClick”属性,
+#当用户点击该按钮时就会调用Activity中的buttonClick(View view)方法,如果这个方法被混淆的话就找不到了
+-keepclassmembers class * extends android.app.Activity{
+ public void *(android.view.View);
+}
+
+#表示不混淆枚举中的values()和valueOf()方法,枚举我用的非常少,这个就不评论了
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+#表示不混淆任何一个View中的setXxx()和getXxx()方法,
+#因为属性动画需要有相应的setter和getter的方法实现,混淆了就无法工作了。
+-keep public class * extends android.view.View{
+ *** get*();
+ void set*(***);
+ public (android.content.Context);
+ public (android.content.Context, android.util.AttributeSet);
+ public (android.content.Context, android.util.AttributeSet, int);
+}
+-keepclasseswithmembers class * {
+ public (android.content.Context, android.util.AttributeSet);
+ public (android.content.Context, android.util.AttributeSet, int);
+}
+
+#表示不混淆Parcelable实现类中的CREATOR字段,
+#毫无疑问,CREATOR字段是绝对不能改变的,包括大小写都不能变,不然整个Parcelable工作机制都会失败。
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
+# 这指定了继承Serizalizable的类的如下成员不被移除混淆
+-keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ private static final java.io.ObjectStreamField[] serialPersistentFields;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+# 保留R下面的资源
+-keep class **.R$* {
+ *;
+}
+#不混淆资源类下static的
+-keepclassmembers class **.R$* {
+ public static ;
+}
+
+
+
+# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
+-keepclassmembers class * {
+ void *(**On*Event);
+ void *(**On*Listener);
+}
+
+# 保留我们自定义控件(继承自View)不被混淆
+-keep public class * extends android.view.View{
+ *** get*();
+ void set*(***);
+ public (android.content.Context);
+ public (android.content.Context, android.util.AttributeSet);
+ public (android.content.Context, android.util.AttributeSet, int);
+}
+
+#
+#----------------------------- WebView(项目中没有可以忽略) -----------------------------
+#
+#webView需要进行特殊处理
+-keepclassmembers class fqcn.of.javascript.interface.for.Webview {
+ public *;
+}
+-keepclassmembers class * extends android.webkit.WebViewClient {
+ public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap);
+ public boolean *(android.webkit.WebView, java.lang.String);
+}
+-keepclassmembers class * extends android.webkit.WebViewClient {
+ public void *(android.webkit.WebView, jav.lang.String);
+}
+#在app中与HTML5的JavaScript的交互进行特殊处理
+#我们需要确保这些js要调用的原生方法不能够被混淆,于是我们需要做如下处理:
+-keepclassmembers class com.ljd.example.JSInterface {
+ ;
+}
+
+#(可选)避免Log打印输出
+-assumenosideeffects class android.util.Log {
+ public static *** v(...);
+ public static *** d(...);
+ public static *** i(...);
+ public static *** w(...);
+ }
\ No newline at end of file
diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..53d8e8a
--- /dev/null
+++ b/demo/src/main/AndroidManifest.xml
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/ic_launcher-playstore.png b/demo/src/main/ic_launcher-playstore.png
new file mode 100644
index 0000000..9b20e57
Binary files /dev/null and b/demo/src/main/ic_launcher-playstore.png differ
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/MainActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/MainActivity.kt
new file mode 100644
index 0000000..7545af2
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/MainActivity.kt
@@ -0,0 +1,53 @@
+package com.ifmvo.togetherad.demo
+
+import android.app.ListActivity
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.View
+import android.widget.ListView
+import android.widget.SimpleAdapter
+import android.widget.Toast
+import com.ifmvo.togetherad.demo.other.MainMenuHelper
+
+class MainActivity : ListActivity() {
+
+ private val menu by lazy { intent.getStringExtra("menu") ?: MainMenuHelper.menuMain }
+
+ private val menuList by lazy { MainMenuHelper.map[menu] }
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, MainActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ listAdapter = SimpleAdapter(this, menuList, R.layout.list_item_main, arrayOf("title", "desc"), intArrayOf(R.id.text1, R.id.text2))
+ }
+
+ override fun onListItemClick(l: ListView?, v: View?, position: Int, id: Long) {
+ if (menuList == null) return
+ val map = menuList!![position]
+ val classStr = map["class"]
+ if (classStr !is Class<*>) return
+ val intent = Intent(this, classStr)
+ intent.putExtra("menu", map["clickMenu"])
+ startActivity(intent)
+ }
+
+ private var lastClickTimeLong = 0L
+
+ override fun onBackPressed() {
+
+ if (System.currentTimeMillis() - lastClickTimeLong > 1000 && menu == MainMenuHelper.menuMain) {
+ lastClickTimeLong = System.currentTimeMillis()
+ Toast.makeText(this@MainActivity, "再点一次退出", Toast.LENGTH_SHORT).show()
+ return
+ }
+
+ super.onBackPressed()
+ }
+
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/app/ActLifecycleAppBase.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/app/ActLifecycleAppBase.kt
new file mode 100644
index 0000000..84a67a2
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/app/ActLifecycleAppBase.kt
@@ -0,0 +1,61 @@
+package com.ifmvo.togetherad.demo.app
+
+import android.app.Activity
+import android.app.Application
+import android.os.Bundle
+import com.ifmvo.togetherad.demo.splash.SplashActivity
+import com.ifmvo.togetherad.demo.splash.SplashHotActivity
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * 通过观察所有 Activity 的生命周期,实现热启动监听
+ *
+ * Created by Matthew_Chen on 2021.02.06.
+ */
+open class ActLifecycleAppBase : Application() {
+
+ //保存处于活跃状态的 Activity 个数
+ private val mActivityCount = AtomicInteger(0)
+
+ //应用退到后台的时间戳
+ private var mAppStopTimeMillis = 0L
+
+ override fun onCreate() {
+ super.onCreate()
+
+ registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
+
+ override fun onActivityStarted(activity: Activity?) {
+
+ activity ?: return
+
+ //热启动 && 应用退到后台时间超过10s
+ if (mActivityCount.get() == 0 && System.currentTimeMillis() - mAppStopTimeMillis > 10 * 1000 && activity !is SplashActivity) {
+ SplashHotActivity.action(activity)
+ }
+
+ //+1
+ mActivityCount.getAndAdd(1)
+ }
+
+ override fun onActivityStopped(activity: Activity?) {
+
+ activity ?: return
+
+ //-1
+ mActivityCount.getAndDecrement()
+
+ //退到后台,记录时间
+ if (mActivityCount.get() == 0) {
+ mAppStopTimeMillis = System.currentTimeMillis()
+ }
+ }
+
+ override fun onActivityPaused(activity: Activity?) {}
+ override fun onActivityResumed(activity: Activity?) {}
+ override fun onActivityDestroyed(activity: Activity?) {}
+ override fun onActivitySaveInstanceState(activity: Activity?, outState: Bundle?) {}
+ override fun onActivityCreated(activity: Activity?, savedInstanceState: Bundle?) {}
+ })
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/app/AdProviderType.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/app/AdProviderType.kt
new file mode 100644
index 0000000..39f201e
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/app/AdProviderType.kt
@@ -0,0 +1,19 @@
+package com.ifmvo.togetherad.demo.app
+
+/*
+ * 广告提供商枚举
+ *
+ * Created by Matthew_Chen on 2018/8/23.
+ */
+enum class AdProviderType(val type: String) {
+
+ //百度 Mob ( 百青藤 )
+ BAIDU("baidu"),
+
+ //腾讯的广点通( 优量汇 )
+ GDT("gdt"),
+
+ //穿山甲
+ CSJ("csj"),
+
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/app/App.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/app/App.kt
new file mode 100644
index 0000000..c7fee70
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/app/App.kt
@@ -0,0 +1,195 @@
+package com.ifmvo.togetherad.demo.app
+
+import com.ifmvo.togetherad.baidu.TogetherAdBaidu
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.csj.TogetherAdCsj
+import com.ifmvo.togetherad.demo.BuildConfig
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+
+/*
+ * Created by Matthew Chen on 2020-04-16.
+ */
+class App : ActLifecycleAppBase() {
+
+ override fun onCreate() {
+ super.onCreate()
+
+ /**
+ * 自定义穿山甲的初始化配置
+ * 可自行选择自定义穿山甲的配置,不配置就会使用穿山甲的默认值
+ */
+// // 可选参数,需在初始化之前,使用TextureView控件播放视频,默认为SurfaceView,当有SurfaceView冲突的场景,可以使用TextureView
+// TogetherAdCsj.useTextureView = false
+// // 可选参数,设置主题类型,0:正常模式;1:夜间模式;默认为0;传非法值,按照0处理
+// TogetherAdCsj.themeStatus = 1
+// // 可选参数,同上,区别在于这个随时可以调用
+// TogetherAdCsj.mTTAdManager.themeStatus = 1
+// // 可选参数,需在初始化之前,标题栏的主题色
+// TogetherAdCsj.titleBarTheme = TTAdConstant.TITLE_BAR_THEME_DARK
+// // 可选参数,需在初始化之前,是否允许sdk展示通知栏提示
+// TogetherAdCsj.allowShowNotify = true
+// // 可选参数,需在初始化之前,测试阶段打开,可以通过日志排查问题,上线时去除该调用
+// TogetherAdCsj.debug = true
+// // 可选参数,需在初始化之前,允许直接下载的网络状态集合
+// TogetherAdCsj.directDownloadNetworkType = TTAdConstant.NETWORK_STATE_WIFI or TTAdConstant.NETWORK_STATE_4G
+// // 可选参数,需在初始化之前,是否支持多进程,true支持
+// TogetherAdCsj.supportMultiProcess = false
+// // 可选参数,需在初始化之前,自定义网络库,demo中给出了okhttp3版本的样例,其余请自行开发或者咨询工作人员。
+// TogetherAdCsj.httpStack = object : IHttpStack { }
+// // 可选参数,需在初始化之前,设置是否为计费用户:true计费用户、false非计费用户。默认为false非计费用户。须征得用户同意才可传入该参数
+// TogetherAdCsj.isPaid = false
+// // 可选参数,需在初始化之前,是否一步初始化
+// TogetherAdCsj.isAsyncInit = false
+// // 可选参数,需在初始化之前,设置用户画像的关键词列表 **不能超过为1000个字符**。须征得用户同意才可传入该参数
+// TogetherAdCsj.keywords = ""
+// // 可选参数,需在初始化之前,设置额外的用户信息 **不能超过为1000个字符**
+// TogetherAdCsj.data = ""
+// // 可选参数,需在初始化之前,可以设置隐私信息控制开关,需要重写其方法
+// TogetherAdCsj.customController = object : TTCustomController() {}
+// // 可选参数,需在初始化之前,穿山甲初始化状态回调
+// TogetherAdCsj.initCallback = object : TTAdSdk.InitCallback {}
+
+ /**
+ * 自定义优量汇的初始化配置
+ */
+// //可参照 DownloadConfirmHelper 自定义下载确认的回调
+// TogetherAdGdt.downloadConfirmListener = DownloadConfirmHelper.DOWNLOAD_CONFIRM_LISTENER
+
+ //初始化穿山甲
+ TogetherAdCsj.init(context = this, adProviderType = AdProviderType.CSJ.type, csjAdAppId = "5001121", appName = this.getString(R.string.app_name))
+
+ //初始化广点通
+ TogetherAdGdt.init(context = this, adProviderType = AdProviderType.GDT.type, gdtAdAppId = "1101152570")
+ //初始化百青藤
+ TogetherAdBaidu.init(context = this, adProviderType = AdProviderType.BAIDU.type, baiduAdAppId = "e866cfb0")
+
+ /**
+ * 配置所有广告位ID
+ * 如果你的ID是服务器下发,也可以把配置ID放在其他位置,但是必须要在请求广告之前完成配置,否则无法加载广告
+ */
+ TogetherAdCsj.idMapCsj = mutableMapOf(
+ TogetherAdAlias.AD_SPLASH to "801121648",
+ TogetherAdAlias.AD_SPLASH_HOT to "801121648",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_SIMPLE to "901121134",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_RECYCLERVIEW to "901121125",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_SIMPLE to "",//不支持
+ TogetherAdAlias.AD_NATIVE_EXPRESS_RECYCLERVIEW to "",//不支持
+ TogetherAdAlias.AD_NATIVE_SIMPLE to "901121737",
+ TogetherAdAlias.AD_NATIVE_RECYCLERVIEW to "901121737",
+ TogetherAdAlias.AD_BANNER to "901121246",
+ TogetherAdAlias.AD_INTER to "945509693",
+ TogetherAdAlias.AD_REWARD to "901121365",
+ TogetherAdAlias.AD_FULL_VIDEO to "901121073",
+ TogetherAdAlias.AD_HYBRID_SPLASH to "901121737",//id是原生类型
+ TogetherAdAlias.AD_HYBRID_EXPRESS to "901121134",//id是原生模板2.0
+ TogetherAdAlias.AD_HYBRID_VERTICAL_PREMOVIE to "901121073"//id是全屏视频
+ )
+
+ TogetherAdGdt.idMapGDT = mutableMapOf(
+ TogetherAdAlias.AD_SPLASH to "8863364436303842593",
+ TogetherAdAlias.AD_SPLASH_HOT to "8863364436303842593",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_SIMPLE to "9061615683013706",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_RECYCLERVIEW to "9061615683013706",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_SIMPLE to "5060295460765937",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_RECYCLERVIEW to "5060295460765937",
+ TogetherAdAlias.AD_NATIVE_SIMPLE to "6040749702835933",
+ TogetherAdAlias.AD_NATIVE_RECYCLERVIEW to "6040749702835933",
+ TogetherAdAlias.AD_BANNER to "4080052898050840",
+ TogetherAdAlias.AD_INTER to "1050691202717808",
+ TogetherAdAlias.AD_REWARD to "2090845242931421",
+ TogetherAdAlias.AD_FULL_VIDEO to "9051949928507973",
+ TogetherAdAlias.AD_HYBRID_SPLASH to "8863364436303842593",//id是开屏类型
+ TogetherAdAlias.AD_HYBRID_EXPRESS to "5060295460765937",//id是原生模板1.0
+ TogetherAdAlias.AD_HYBRID_VERTICAL_PREMOVIE to "6040749702835933"
+ )
+
+ TogetherAdBaidu.idMapBaidu = mutableMapOf(
+ TogetherAdAlias.AD_SPLASH to "2058622",
+ TogetherAdAlias.AD_SPLASH_HOT to "2058622",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_SIMPLE to "",//不支持
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_RECYCLERVIEW to "",//不支持
+ TogetherAdAlias.AD_NATIVE_EXPRESS_SIMPLE to "",//不支持
+ TogetherAdAlias.AD_NATIVE_EXPRESS_RECYCLERVIEW to "",//不支持
+ TogetherAdAlias.AD_NATIVE_SIMPLE to "2058628",
+ TogetherAdAlias.AD_NATIVE_RECYCLERVIEW to "2058628",
+ TogetherAdAlias.AD_BANNER to "2015351",
+ TogetherAdAlias.AD_INTER to "2403633",
+ TogetherAdAlias.AD_REWARD to "5925490",
+ TogetherAdAlias.AD_FULL_VIDEO to "",
+ TogetherAdAlias.AD_HYBRID_SPLASH to "2058628",//id是原生类型
+ TogetherAdAlias.AD_HYBRID_EXPRESS to "",//不支持
+ TogetherAdAlias.AD_HYBRID_VERTICAL_PREMOVIE to ""//不支持
+ )
+
+ /**
+ * 配置全局的广告商权重。
+ * 如果在调用具体广告API时没有配置单次请求的权重,就会默认使用这个全局的权重
+ * 如果不配置,TogetherAd会默认所有初始化的广告商权重相同
+ *
+ * 也可以在请求广告前设置,实时生效
+ */
+ TogetherAd.setPublicProviderRatio(linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 0
+ ))
+
+ /**
+ * 自定义图片加载方式
+ * 用于自渲染类型的广告图片加载
+ * 如果不配置,TogetherAd 会使用默认的图片加载方式
+ * 不建议使用默认的 DefaultImageLoader 兼容性较差
+ * 主要考虑到:开发者可以自定义实现图片加载:渐变、占位图、错误图等
+ */
+// TogetherAd.setCustomImageLoader(object : AdImageLoader {
+// override fun loadImage(context: Context, imageView: ImageView, imgUrl: String) {
+// Glide.with(context).load(imgUrl).into(imageView)
+// }
+// })
+
+ /**
+ * 日志的开关
+ * 全局实时生效
+ */
+ TogetherAd.printLogEnable = BuildConfig.DEBUG
+
+ /**
+ * 是否失败切换 ( 当请求广告失败时,是否允许切换到其他广告提供商再次请求 )
+ * 全局实时生效
+ */
+// TogetherAd.failedSwitchEnable = true
+
+ /**
+ * 最大拉取延时时间 ms( 请求广告的超时时间 )
+ * 3000 ≤ value ≥ 10000( 小于3000时按3000计算,大于10000时按10000计算 )
+ * 全局实时生效
+ * 不设置或设置为0 -> 超时时间无限长
+ */
+// TogetherAd.maxFetchDelay = 8000
+
+ /**
+ * 所有广告商所有广告类型的广告都会回调这个监听器
+ * 主要是方便做统计:请求成功率、请求失败信息等
+ */
+// TogetherAd.allAdListener = object : AllAdListener {
+// override fun onAdStartRequest(providerType: String, alias: String) {
+// "开始请求: 提供商: $providerType, 广告位: $alias".logi("TogetherAd.allAdListener")
+// }
+//
+// override fun onAdFailed(providerType: String, alias: String, failedMsg: String?) {
+// "请求失败: 提供商: $providerType, 广告位: $alias, 错误信息: $failedMsg".loge("TogetherAd.allAdListener")
+// }
+//
+// override fun onAdLoaded(providerType: String, alias: String) {
+// "请求成功: 提供商: $providerType, 广告位: $alias".logi("TogetherAd.allAdListener")
+// }
+// }
+ /**
+ * 设置广告分发模式
+ * DispatchType.Priority 优先权重最高分发模式
+ * DispatchType.Random 按照权重随机分发模式
+ */
+// TogetherAd.dispatchType = DispatchType.Random
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/app/TogetherAdAlias.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/app/TogetherAdAlias.kt
new file mode 100644
index 0000000..4e6c526
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/app/TogetherAdAlias.kt
@@ -0,0 +1,59 @@
+package com.ifmvo.togetherad.demo.app
+
+/**
+ * 所有广告位的别名
+ *
+ * 列举你项目中的所有广告位,并给每个广告位起个名字
+ *
+ * 用于初始化广告位ID 以及 广告的请求
+ *
+ * Created by Matthew Chen on 2020-04-16.
+ */
+object TogetherAdAlias {
+
+ //开屏
+ const val AD_SPLASH = "ad_splash"
+
+ //热启动开屏
+ const val AD_SPLASH_HOT = "ad_splash_hot"
+
+ //原生模板2.0 简单使用
+ const val AD_NATIVE_EXPRESS_2_SIMPLE = "ad_native_express2_simple"
+
+ //原生模板2.0 在 RecyclerView 中使用
+ const val AD_NATIVE_EXPRESS_2_RECYCLERVIEW = "ad_native_express2_recyclerview"
+
+ //原生模板 简单使用
+ const val AD_NATIVE_EXPRESS_SIMPLE = "ad_native_express_simple"
+
+ //原生模板 在 RecyclerView 中使用
+ const val AD_NATIVE_EXPRESS_RECYCLERVIEW = "ad_native_express_recyclerview"
+
+ //原生 简单使用
+ const val AD_NATIVE_SIMPLE = "ad_native_simple"
+
+ //原生 在 RecyclerView 中使用
+ const val AD_NATIVE_RECYCLERVIEW = "ad_native_recyclerview"
+
+ //Banner
+ const val AD_BANNER = "ad_banner"
+
+ //插屏广告
+ const val AD_INTER = "ad_inter"
+
+ //激励广告
+ const val AD_REWARD = "ad_reward"
+
+ //全屏视频广告
+ const val AD_FULL_VIDEO = "ad_full_video"
+
+ //开屏混合使用
+ const val AD_HYBRID_SPLASH = "ad_splash_and_native"
+
+ //原生模板混合
+ const val AD_HYBRID_EXPRESS = "ad_hybrid_express"
+
+ //原生模板混合
+ const val AD_HYBRID_VERTICAL_PREMOVIE = "ad_hybrid_vertical_premovie"
+
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/banner/BannerActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/banner/BannerActivity.kt
new file mode 100644
index 0000000..0f2c85e
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/banner/BannerActivity.kt
@@ -0,0 +1,117 @@
+package com.ifmvo.togetherad.demo.banner
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.helper.AdHelperBanner
+import com.ifmvo.togetherad.core.listener.BannerListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.core.utils.px2dp
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import kotlinx.android.synthetic.main.activity_banner.*
+
+/**
+ * Banner 横幅广告
+ *
+ * Created by Matthew Chen on 2020/5/26.
+ */
+class BannerActivity : AppCompatActivity() {
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, BannerActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_banner)
+
+ btnRequestShow.setOnClickListener {
+ showBannerAd()
+ }
+
+ showBannerAd()
+ }
+
+ private fun showBannerAd() {
+
+ adContainer.removeAllViews()
+
+ val ratioMapBanner = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+ )
+
+ //设置 穿山甲 Banner 刷新间隔时间ms,可以不设置,默认为 30 * 1000 ms
+ CsjProvider.Banner.slideIntervalTime = 30 * 1000
+
+ //设置 穿山甲 Banner 尺寸
+ CsjProvider.Banner.setExpressViewAcceptedSize(px2dp(this, ScreenUtil.getDisplayMetricsWidth(this)), px2dp(this, ScreenUtil.getDisplayMetricsWidth(this) / 8))
+
+ AdHelperBanner.show(activity = this, alias = TogetherAdAlias.AD_BANNER, container = adContainer, /*ratioMap = ratioMapBanner,*/ listener = object : BannerListener {
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ addLog("\n开始请求了,$providerType")
+ /*
+ * 百度:设置'广告着陆页'动作栏的颜色主题,目前开放了七大主题:黑色、蓝色、咖啡色、绿色、藏青色、红色、白色(默认) 主题
+ */
+// if (providerType == AdProviderType.BAIDU.type) {
+// AppActivity.setActionBarColorTheme(AppActivity.ActionBarColorTheme.ACTION_BAR_RED_THEME)
+// }
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ //广告请求成功的回调,每次请求只回调一次
+ addLog("请求到了,$providerType")
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("单个广告请求失败, $providerType, $failedMsg")
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("全部请求失败了")
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //点击广告的回调
+ addLog("点击了,$providerType")
+ }
+
+ override fun onAdExpose(providerType: String) {
+ //广告展示曝光的回调;由于 Banner 广告存在自动刷新功能,所以曝光会回调多次,每次刷新都会回调
+ addLog("曝光了,$providerType")
+ }
+
+ override fun onAdClose(providerType: String) {
+ //广告被关闭的回调
+ addLog("关闭了,$providerType")
+ }
+ })
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ //销毁,避免内存泄漏
+ adContainer?.removeAllViews()//容器需要清空,否则广点通的Banner会一直请求( gdt的bug )
+ AdHelperBanner.destroy()
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/express/NativeExpressAdapter.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/express/NativeExpressAdapter.kt
new file mode 100644
index 0000000..b210e51
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/express/NativeExpressAdapter.kt
@@ -0,0 +1,71 @@
+package com.ifmvo.togetherad.demo.express
+
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.helper.AdHelperNativeExpress
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.other.ContentDataEntity
+import com.ifmvo.togetherad.demo.native_.template.NativeExpressTemplateSimple
+
+/**
+ * 一个普通的多类型列表的 Adapter
+ *
+ * Created by Matthew Chen on 2020/6/30.
+ */
+class NativeExpressAdapter(list: List) : RecyclerView.Adapter() {
+
+ companion object {
+ private const val ITEM_VIEW_TYPE_AD = 0
+ private const val ITEM_VIEW_TYPE_CONTENT = 1
+ }
+
+ private var mList: List = list
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return if (viewType == ITEM_VIEW_TYPE_CONTENT) {
+ ContentViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_native_content, parent, false))
+ } else {
+ AdViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_native_ad, parent, false))
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return mList.size
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (getItemViewType(position)) {
+ ITEM_VIEW_TYPE_CONTENT -> {
+ val contentViewHolder = holder as ContentViewHolder
+ val contentDataEntity = mList[position] as ContentDataEntity
+ contentViewHolder.imageView.layoutParams.height = ScreenUtil.getDisplayMetricsWidth(contentViewHolder.imageView.context) * 9 / 16
+ TogetherAd.mImageLoader?.loadImage(contentViewHolder.imageView.context, contentViewHolder.imageView, contentDataEntity.imgUrl)
+ contentViewHolder.textView.text = contentDataEntity.title
+ }
+ ITEM_VIEW_TYPE_AD -> {
+ val adViewHolder = holder as AdViewHolder
+ adViewHolder.adContainer.removeAllViews()
+ AdHelperNativeExpress.show(mList[position], adViewHolder.adContainer, NativeExpressTemplateSimple())
+ }
+ }
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return if (mList[position] is ContentDataEntity) ITEM_VIEW_TYPE_CONTENT else ITEM_VIEW_TYPE_AD
+ }
+
+ inner class AdViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ var adContainer: ViewGroup = itemView.findViewById(R.id.adContainer)
+ }
+
+ inner class ContentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ var imageView: ImageView = itemView.findViewById(R.id.img)
+ var textView: TextView = itemView.findViewById(R.id.txt)
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/express/NativeExpressRecyclerViewActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/express/NativeExpressRecyclerViewActivity.kt
new file mode 100644
index 0000000..26b025b
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/express/NativeExpressRecyclerViewActivity.kt
@@ -0,0 +1,133 @@
+package com.ifmvo.togetherad.demo.express
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.LinearLayoutManager
+import android.widget.Toast
+import com.ifmvo.togetherad.core.helper.AdHelperNativeExpress
+import com.ifmvo.togetherad.core.listener.NativeExpressListener
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.demo.other.ContentDataEntity
+import kotlinx.android.synthetic.main.activity_native_recyclerview.*
+
+
+/**
+ * 原生自渲染在 RecyclerView 中的用法
+ *
+ * Created by Matthew Chen on 2020-04-20.
+ */
+class NativeExpressRecyclerViewActivity : AppCompatActivity() {
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ private val ratioMapNativeExpressRecycler = mapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1
+ )
+
+ private val adHelperNativeExpressRv by lazy { AdHelperNativeExpress(this, TogetherAdAlias.AD_NATIVE_EXPRESS_RECYCLERVIEW, /*ratioMapNativeRecycler,*/ 3) }
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, NativeExpressRecyclerViewActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_native_recyclerview)
+
+ requestRvAd {
+ //使用 RecyclerView 展示合并后的数据
+ val allList = mergeContentAd(getContentData(), it)
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ recyclerView.adapter = NativeExpressAdapter(allList)
+ }
+ }
+
+ /**
+ * 请求广告List
+ */
+ private fun requestRvAd(onResult: (adList: List) -> Unit) {
+ adHelperNativeExpressRv.getExpressList(listener = object : NativeExpressListener {
+ override fun onAdStartRequest(providerType: String) {
+ //每个提供商请求之前都会回调
+ }
+
+ override fun onAdLoaded(providerType: String, adList: List) {
+ onResult(adList)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //单个提供商请求失败
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有的提供商都失败
+ onResult(mutableListOf())
+ }
+
+ override fun onAdClicked(providerType: String, adObject: Any?) {
+ }
+
+ override fun onAdShow(providerType: String, adObject: Any?) {
+ }
+
+ override fun onAdRenderSuccess(providerType: String, adObject: Any?) {
+ }
+
+ override fun onAdRenderFail(providerType: String, adObject: Any?) {
+ }
+
+ override fun onAdClosed(providerType: String, adObject: Any?) {
+ }
+ })
+ }
+
+ /**
+ * 把内容List和广告List合并
+ *
+ * 示例:第二条插入广告,之后每隔5条内容插入一条广告
+ *
+ * 具体逻辑按照自己的需求自行处理
+ */
+ private fun mergeContentAd(contentList: List, adList: List): List {
+
+ var nextAdPosition = 0
+ var lastUseAdPosition = 0
+
+ val multiItemList = mutableListOf()
+ repeat(contentList.size) {
+ multiItemList.add(contentList[it])
+ if (adList.isNotEmpty() && nextAdPosition == it) {
+ if (lastUseAdPosition > adList.size - 1) {
+ lastUseAdPosition = 0
+ }
+ multiItemList.add(adList[lastUseAdPosition])
+ lastUseAdPosition += 1
+ nextAdPosition += 5
+ }
+ }
+ return multiItemList
+ }
+
+ /**
+ * 模拟真实的内容数据List
+ */
+ private fun getContentData(): List {
+ val contentList = mutableListOf()
+ for (index in 1..15) {
+ val title = "正文内容序号:$index"
+ contentList.add(ContentDataEntity(title = title, imgUrl = "https://t8.baidu.com/it/u=2247852322,986532796&fm=79&app=86&size=h300&n=0&g=4n&f=jpeg?sec=1590128472&t=657ec840a5c6c658430135ea8b1d35f0"))
+ }
+ return contentList
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ adHelperNativeExpressRv.destroyAllExpressAd()
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/express/NativeExpressSimpleActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/express/NativeExpressSimpleActivity.kt
new file mode 100644
index 0000000..3410170
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/express/NativeExpressSimpleActivity.kt
@@ -0,0 +1,123 @@
+package com.ifmvo.togetherad.demo.express
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.helper.AdHelperNativeExpress
+import com.ifmvo.togetherad.core.listener.NativeExpressListener
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.demo.native_.template.NativeExpressTemplateSimple
+import kotlinx.android.synthetic.main.activity_native_express_simple.*
+
+/**
+ * Created by Matthew Chen on 2020/11/26.
+ */
+class NativeExpressSimpleActivity : AppCompatActivity() {
+
+ private val tag = "NativeExpressSimpleActivity"
+
+ private var mAdObject: Any? = null
+
+ private val adHelperNativeExpress by lazy {
+ val ratioMapNativeExpress = linkedMapOf(AdProviderType.GDT.type to 1)
+ AdHelperNativeExpress(this, TogetherAdAlias.AD_NATIVE_EXPRESS_SIMPLE, /*ratioMapNativeExpress,*/ 1)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_native_express_simple)
+
+ btnRequest.setOnClickListener {
+ requestAd()
+ }
+
+ btnShow.setOnClickListener {
+ showAd()
+ }
+ }
+
+ private fun requestAd() {
+ adHelperNativeExpress.getExpressList(object : NativeExpressListener {
+ override fun onAdLoaded(providerType: String, adList: List) {
+
+ mAdObject = adList[0]
+
+ //广告请求成功的回调,每次请求只回调一次
+ "onAdLoaded: $providerType, adList: ${adList.size}".logi(tag)
+ addLog("原生模板广告请求成功,$providerType")
+ }
+
+ override fun onAdClicked(providerType: String, adObject: Any?) {
+ //每次点击就会回调这里一次
+ addLog("原生模板广告点击了")
+ "onAdClicked".logi(tag)
+ }
+
+ override fun onAdShow(providerType: String, adObject: Any?) {
+ //每次展示就会回调这里一次
+ addLog("原生模板广告展示了")
+ "onAdShow".logi(tag)
+ }
+
+ override fun onAdRenderSuccess(providerType: String, adObject: Any?) {
+ //模板渲染成功了就会回调这里一次
+ addLog("模板渲染成功了")
+ "onAdRenderSuccess".logi(tag)
+ }
+
+ override fun onAdRenderFail(providerType: String, adObject: Any?) {
+ //模板渲染失败了就会回调这里一次
+ addLog("模板渲染失败了")
+ "onAdRenderFail".logi(tag)
+ }
+
+ override fun onAdClosed(providerType: String, adObject: Any?) {
+ //模板广告关闭了就会回调这里一次
+ addLog("模板广告关闭了")
+ "onAdClosed".logi(tag)
+ }
+
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ "onAdStartRequest: $providerType".logi(tag)
+ addLog("\n原生模板广告开始请求,$providerType")
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("原生模板广告全部请求失败了")
+ "onAdFailedAll".loge(tag)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("原生模板广告单个提供商请求失败了,$providerType, $failedMsg")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+ })
+ }
+
+ private fun showAd() {
+ AdHelperNativeExpress.show(mAdObject, adContainer, NativeExpressTemplateSimple())
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ adHelperNativeExpress.destroyAllExpressAd()
+ //或者
+// AdHelperNativeExpress.destroyExpressAd(mAdObject)
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2Adapter.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2Adapter.kt
new file mode 100644
index 0000000..e067dec
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2Adapter.kt
@@ -0,0 +1,95 @@
+package com.ifmvo.togetherad.demo.express2
+
+import android.app.Activity
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import android.widget.Toast
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.helper.AdHelperNativeExpress2
+import com.ifmvo.togetherad.core.listener.NativeExpress2ViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.other.ContentDataEntity
+import com.ifmvo.togetherad.demo.native_.template.NativeExpress2TemplateSimple
+import java.lang.ref.WeakReference
+
+/**
+ * 一个普通的多类型列表的 Adapter
+ *
+ * Created by Matthew Chen on 2020/6/30.
+ */
+class NativeExpress2Adapter(activity: Activity, list: List) : RecyclerView.Adapter() {
+
+ companion object {
+ private const val ITEM_VIEW_TYPE_AD = 0
+ private const val ITEM_VIEW_TYPE_CONTENT = 1
+ }
+
+ private var mList: List = list
+
+ private var mActivity: WeakReference = WeakReference(activity)
+
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return if (viewType == ITEM_VIEW_TYPE_CONTENT) {
+ ContentViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_native_content, parent, false))
+ } else {
+ AdViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_native_ad, parent, false))
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return mList.size
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (getItemViewType(position)) {
+ ITEM_VIEW_TYPE_CONTENT -> {
+ val contentViewHolder = holder as ContentViewHolder
+ val contentDataEntity = mList[position] as ContentDataEntity
+ contentViewHolder.imageView.layoutParams.height = ScreenUtil.getDisplayMetricsWidth(contentViewHolder.imageView.context) * 9 / 16
+ TogetherAd.mImageLoader?.loadImage(contentViewHolder.imageView.context, contentViewHolder.imageView, contentDataEntity.imgUrl)
+ contentViewHolder.textView.text = contentDataEntity.title
+ }
+ ITEM_VIEW_TYPE_AD -> {
+ val adViewHolder = holder as AdViewHolder
+ adViewHolder.adContainer.removeAllViews()
+ mActivity.get()?.let {
+ AdHelperNativeExpress2.show(it, mList[position], adViewHolder.adContainer, NativeExpress2TemplateSimple(), object : NativeExpress2ViewListener {
+ override fun onAdExposed(providerType: String) {
+ }
+
+ override fun onAdClicked(providerType: String) {
+ }
+
+ override fun onAdRenderSuccess(providerType: String) {
+ }
+
+ override fun onAdRenderFailed(providerType: String) {
+ }
+
+ override fun onAdClose(providerType: String) {
+ }
+ })
+ }
+ }
+ }
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return if (mList[position] is ContentDataEntity) ITEM_VIEW_TYPE_CONTENT else ITEM_VIEW_TYPE_AD
+ }
+
+ inner class AdViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ var adContainer: ViewGroup = itemView.findViewById(R.id.adContainer)
+ }
+
+ inner class ContentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ var imageView: ImageView = itemView.findViewById(R.id.img)
+ var textView: TextView = itemView.findViewById(R.id.txt)
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2RecyclerViewActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2RecyclerViewActivity.kt
new file mode 100644
index 0000000..3ca94e0
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2RecyclerViewActivity.kt
@@ -0,0 +1,118 @@
+package com.ifmvo.togetherad.demo.express2
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.LinearLayoutManager
+import android.widget.Toast
+import com.ifmvo.togetherad.core.helper.AdHelperNativeExpress2
+import com.ifmvo.togetherad.core.listener.NativeExpress2Listener
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.demo.other.ContentDataEntity
+import kotlinx.android.synthetic.main.activity_native_recyclerview.*
+
+
+/**
+ * 原生自渲染在 RecyclerView 中的用法
+ *
+ * Created by Matthew Chen on 2020-04-20.
+ */
+class NativeExpress2RecyclerViewActivity : AppCompatActivity() {
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ private val ratioMapNativeExpress2Recycler = mapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1
+ )
+
+ private val adHelperNativeExpress2Rv by lazy { AdHelperNativeExpress2(this, TogetherAdAlias.AD_NATIVE_EXPRESS_2_RECYCLERVIEW, /*ratioMapNativeRecycler,*/ 3) }
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, NativeExpress2RecyclerViewActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_native_recyclerview)
+
+ requestRvAd {
+ //使用 RecyclerView 展示合并后的数据
+ val allList = mergeContentAd(getContentData(), it)
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ recyclerView.adapter = NativeExpress2Adapter(this, allList)
+ }
+ }
+
+ /**
+ * 请求广告List
+ */
+ private fun requestRvAd(onResult: (adList: List) -> Unit) {
+ adHelperNativeExpress2Rv.getExpress2List(listener = object : NativeExpress2Listener {
+ override fun onAdStartRequest(providerType: String) {
+ //每个提供商请求之前都会回调
+ }
+
+ override fun onAdLoaded(providerType: String, adList: List) {
+ onResult(adList)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //单个提供商请求失败
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有的提供商都失败
+ onResult(mutableListOf())
+ }
+ })
+ }
+
+ /**
+ * 把内容List和广告List合并
+ *
+ * 示例:第二条插入广告,之后每隔5条内容插入一条广告
+ *
+ * 具体逻辑按照自己的需求自行处理
+ */
+ private fun mergeContentAd(contentList: List, adList: List): List {
+
+ var nextAdPosition = 0
+ var lastUseAdPosition = 0
+
+ val multiItemList = mutableListOf()
+ repeat(contentList.size) {
+ multiItemList.add(contentList[it])
+ if (adList.isNotEmpty() && nextAdPosition == it) {
+ if (lastUseAdPosition > adList.size - 1) {
+ lastUseAdPosition = 0
+ }
+ multiItemList.add(adList[lastUseAdPosition])
+ lastUseAdPosition += 1
+ nextAdPosition += 5
+ }
+ }
+ return multiItemList
+ }
+
+ /**
+ * 模拟真实的内容数据List
+ */
+ private fun getContentData(): List {
+ val contentList = mutableListOf()
+ for (index in 1..15) {
+ val title = "正文内容序号:$index"
+ contentList.add(ContentDataEntity(title = title, imgUrl = "https://t8.baidu.com/it/u=2247852322,986532796&fm=79&app=86&size=h300&n=0&g=4n&f=jpeg?sec=1590128472&t=657ec840a5c6c658430135ea8b1d35f0"))
+ }
+ return contentList
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ adHelperNativeExpress2Rv.destroyAllExpress2Ad()
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2SimpleActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2SimpleActivity.kt
new file mode 100644
index 0000000..24e10d0
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2SimpleActivity.kt
@@ -0,0 +1,126 @@
+package com.ifmvo.togetherad.demo.express2
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.helper.AdHelperNativeExpress2
+import com.ifmvo.togetherad.core.listener.NativeExpress2Listener
+import com.ifmvo.togetherad.core.listener.NativeExpress2ViewListener
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.demo.native_.template.NativeExpress2TemplateSimple
+import kotlinx.android.synthetic.main.activity_native_express_simple.*
+
+/**
+ * Created by Matthew Chen on 2020/11/26.
+ */
+class NativeExpress2SimpleActivity : AppCompatActivity() {
+
+ private val tag = "NativeExpress2SimpleActivity"
+
+ private var mAdObject: Any? = null
+
+ private val adHelperNativeExpress2 by lazy {
+ val ratioMapNativeExpress2 = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1
+ )
+ AdHelperNativeExpress2(this, TogetherAdAlias.AD_NATIVE_EXPRESS_2_SIMPLE, /*ratioMapNativeExpress2,*/ 1)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_native_express_simple)
+
+ btnRequest.setOnClickListener {
+ requestAd()
+ }
+
+ btnShow.setOnClickListener {
+ showAd()
+ }
+ }
+
+ private fun requestAd() {
+ adHelperNativeExpress2.getExpress2List(object : NativeExpress2Listener {
+ override fun onAdLoaded(providerType: String, adList: List) {
+ mAdObject = adList[0]
+
+ //广告请求成功的回调,每次请求只回调一次
+ "onAdLoaded: $providerType, adList: ${adList.size}".logi(tag)
+ addLog("原生模板广告请求成功,$providerType")
+ }
+
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ "onAdStartRequest: $providerType".logi(tag)
+ addLog("\n原生模板广告开始请求,$providerType")
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("原生模板广告全部请求失败了")
+ "onAdFailedAll".loge(tag)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("原生模板广告单个提供商请求失败了,$providerType, $failedMsg")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+ })
+ }
+
+ private fun showAd() {
+ AdHelperNativeExpress2.show(this, mAdObject, adContainer, NativeExpress2TemplateSimple(), object : NativeExpress2ViewListener {
+ override fun onAdExposed(providerType: String) {
+ //每次展示就会回调这里一次
+ addLog("原生模板广告展示了")
+ "onAdShow".logi(tag)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //每次点击就会回调这里一次
+ addLog("原生模板广告点击了")
+ "onAdClicked".logi(tag)
+ }
+
+ override fun onAdRenderSuccess(providerType: String) {
+ //模板渲染成功了就会回调这里一次
+ addLog("模板渲染成功了")
+ "onAdRenderSuccess".logi(tag)
+ }
+
+ override fun onAdRenderFailed(providerType: String) {
+ //模板渲染失败了就会回调这里一次
+ addLog("模板渲染失败了")
+ "onAdRenderFail".logi(tag)
+ }
+
+ override fun onAdClose(providerType: String) {
+ //模板广告关闭了就会回调这里一次
+ addLog("模板广告关闭了")
+ "onAdClosed".logi(tag)
+ }
+ })
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ adHelperNativeExpress2.destroyAllExpress2Ad()
+ //或者使用静态方法
+// AdHelperNativeExpress2.destroyExpress2Ad(mAdObject)
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/extend/CustomCsjProvider.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/extend/CustomCsjProvider.kt
new file mode 100644
index 0000000..59cc271
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/extend/CustomCsjProvider.kt
@@ -0,0 +1,97 @@
+package com.ifmvo.togetherad.demo.extend
+
+import android.app.Activity
+import android.view.View
+import android.view.ViewGroup
+import com.bytedance.sdk.openadsdk.*
+import com.ifmvo.togetherad.core.listener.BannerListener
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.csj.TogetherAdCsj
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+
+/**
+ *
+ * Created by Matthew Chen on 2020/10/23.
+ */
+class CustomCsjProvider : CsjProvider() {
+
+ object Banner {
+
+ var supportDeepLink: Boolean = true
+
+ //图片的宽高
+ internal var imageAcceptedSizeWidth = 600
+
+ internal var imageAcceptedSizeHeight = 257
+
+ fun setImageAcceptedSize(width: Int, height: Int) {
+ imageAcceptedSizeWidth = width
+ imageAcceptedSizeHeight = height
+ }
+
+ //Banner 刷新间隔时间
+ var slideIntervalTime = 30 * 1000
+ }
+
+ /**
+ * 这里只重写相应的方法即可
+ */
+ override fun showBannerAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: BannerListener) {
+ callbackBannerStartRequest(adProviderType, alias, listener)
+
+ destroyBannerAd()
+
+ val adSlot = AdSlot.Builder()
+ .setCodeId(TogetherAdCsj.idMapCsj[alias]) //广告位id
+ .setSupportDeepLink(Banner.supportDeepLink)
+ .setImageAcceptedSize(Banner.imageAcceptedSizeWidth, Banner.imageAcceptedSizeHeight)
+ .build()
+
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadBannerAd(adSlot, object : TTAdNative.BannerAdListener {
+ override fun onBannerAdLoad(bannerAd: TTBannerAd?) {
+ if (bannerAd == null) {
+ callbackBannerFailed(adProviderType, alias, listener, null, "请求成功,但是返回的 bannerAd 为空")
+ return
+ }
+
+ val bannerView = bannerAd.bannerView
+ if (bannerView == null) {
+ callbackBannerFailed(adProviderType, alias, listener, null, "请求成功,但是返回的 bannerView 为空")
+ return
+ }
+
+ callbackBannerLoaded(adProviderType, alias, listener)
+
+ bannerAd.setSlideIntervalTime(Banner.slideIntervalTime)
+ container.removeAllViews()
+ container.addView(bannerView)
+
+ bannerAd.setBannerInteractionListener(object : TTBannerAd.AdInteractionListener {
+ override fun onAdClicked(view: View?, type: Int) {
+ callbackBannerClicked(adProviderType, listener)
+ }
+
+ override fun onAdShow(view: View?, type: Int) {
+ callbackBannerExpose(adProviderType, listener)
+ }
+ })
+
+ bannerAd.setShowDislikeIcon(object : TTAdDislike.DislikeInteractionCallback {
+ override fun onSelected(position: Int, value: String?, enforce: Boolean) {
+ container.removeAllViews()
+ callbackBannerClosed(adProviderType, listener)
+ }
+
+ override fun onCancel() {}
+ override fun onShow() {}
+ })
+ }
+
+ override fun onError(errorCode: Int, errorMsg: String?) {
+ "onError".loge(tag)
+ callbackBannerFailed(adProviderType, alias, listener, errorCode, errorMsg)
+ }
+ })
+ }
+
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/extend/TogetherAdXiaomi.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/extend/TogetherAdXiaomi.kt
new file mode 100644
index 0000000..b04d2d5
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/extend/TogetherAdXiaomi.kt
@@ -0,0 +1,35 @@
+package com.ifmvo.togetherad.demo.extend
+
+import android.content.Context
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.entity.AdProviderEntity
+import org.jetbrains.annotations.NotNull
+
+/**
+ *
+ * Created by Matthew Chen on 2020/10/23.
+ */
+object TogetherAdXiaomi {
+
+ var idMapXiaomi = mutableMapOf()
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull xiaomiAdAppId: String) {
+ init(context, adProviderType, xiaomiAdAppId, null, null)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull xiaomiAdAppId: String, providerClassPath: String? = null) {
+ init(context, adProviderType, xiaomiAdAppId, null, providerClassPath)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull xiaomiAdAppId: String, xiaomiIdMap: Map? = null) {
+ init(context, adProviderType, xiaomiAdAppId, xiaomiIdMap, null)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull xiaomiAdAppId: String, xiaomiIdMap: Map? = null, providerClassPath: String? = null) {
+ TogetherAd.addProvider(AdProviderEntity(adProviderType, if (providerClassPath?.isEmpty() != false) XiaomiProvider::class.java.name else providerClassPath))
+ xiaomiIdMap?.let { idMapXiaomi.putAll(it) }
+
+ //小米SDK初始化
+ }
+
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/extend/XiaomiProvider.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/extend/XiaomiProvider.kt
new file mode 100644
index 0000000..fbdc143
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/extend/XiaomiProvider.kt
@@ -0,0 +1,74 @@
+package com.ifmvo.togetherad.demo.extend
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.listener.*
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+
+/**
+ * 自定义小米广告提供商
+ *
+ * 根据其他 Provider 可自行实现广告请求逻辑
+ *
+ * Created by Matthew Chen on 2020/10/23.
+ */
+class XiaomiProvider : BaseAdProvider() {
+
+ override fun loadOnlySplashAd(activity: Activity, adProviderType: String, alias: String, listener: SplashListener) {}
+
+ override fun showSplashAd(container: ViewGroup): Boolean {
+ return false
+ }
+
+ override fun loadAndShowSplashAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: SplashListener) {}
+
+ override fun showBannerAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: BannerListener) {}
+
+ override fun destroyBannerAd() {}
+
+ override fun requestInterAd(activity: Activity, adProviderType: String, alias: String, listener: InterListener) {}
+
+ override fun showInterAd(activity: Activity) {}
+
+ override fun destroyInterAd() {}
+
+ override fun getNativeAdList(activity: Activity, adProviderType: String, alias: String, maxCount: Int, listener: NativeListener) {}
+
+ override fun nativeAdIsBelongTheProvider(adObject: Any): Boolean {
+ return false
+ }
+
+ override fun resumeNativeAd(adObject: Any) {}
+
+ override fun pauseNativeAd(adObject: Any) {}
+
+ override fun destroyNativeAd(adObject: Any) {}
+
+ override fun getNativeExpressAdList(activity: Activity, adProviderType: String, alias: String, adCount: Int, listener: NativeExpressListener) {}
+
+ override fun destroyNativeExpressAd(adObject: Any) {}
+
+ override fun nativeExpressAdIsBelongTheProvider(adObject: Any): Boolean {
+ return false
+ }
+
+ override fun getNativeExpress2AdList(activity: Activity, adProviderType: String, alias: String, adCount: Int, listener: NativeExpress2Listener) {}
+
+ override fun destroyNativeExpress2Ad(adObject: Any) {}
+
+ override fun nativeExpress2AdIsBelongTheProvider(adObject: Any): Boolean {
+ return false
+ }
+
+ override fun requestRewardAd(activity: Activity, adProviderType: String, alias: String, listener: RewardListener) {}
+
+ override fun showRewardAd(activity: Activity): Boolean {
+ return false
+ }
+
+ override fun requestFullVideoAd(activity: Activity, adProviderType: String, alias: String, listener: FullVideoListener) {}
+
+ override fun showFullVideoAd(activity: Activity): Boolean {
+ return false
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/fullvideo/FullVideoActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/fullvideo/FullVideoActivity.kt
new file mode 100644
index 0000000..64b83cb
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/fullvideo/FullVideoActivity.kt
@@ -0,0 +1,124 @@
+package com.ifmvo.togetherad.demo.fullvideo
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.helper.AdHelperFullVideo
+import com.ifmvo.togetherad.core.listener.FullVideoListener
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import kotlinx.android.synthetic.main.activity_reward.*
+
+/**
+ *
+ * Created by Matthew Chen on 2020/12/2.
+ */
+class FullVideoActivity : AppCompatActivity() {
+
+ private val tag = "FullVideoActivity"
+
+ private lateinit var adHelperFullVideo: AdHelperFullVideo
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, FullVideoActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_full_video)
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ val ratioMapFullVideo = linkedMapOf(
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.GDT.type to 1
+ )
+
+ /**
+ * activity: 必传。
+ * alias: 必传。广告位的别名。初始化的时候是根据别名设置的广告ID,所以这里TogetherAd会根据别名查找对应的广告位ID。
+ * ratioMap: 非必传。广告商的权重。可以不传或传null,空的情况 TogetherAd 会自动使用初始化时 TogetherAd.setPublicProviderRatio 设置的全局通用权重。
+ * listener: 非必传。如果你不需要监听结果可以不传或传空。各个回调方法也可以选择性添加
+ */
+ adHelperFullVideo = AdHelperFullVideo(activity = this, alias = TogetherAdAlias.AD_FULL_VIDEO, /*ratioMap = ratioMapFullVideo,*/ listener = object : FullVideoListener {
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ addLog("\n开始请求: $providerType")
+ "onAdStartRequest: $providerType".logi(tag)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("请求失败: $providerType: $failedMsg")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("全部失败")
+ "onAdFailedAll".loge(tag)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //点击广告的回调
+ addLog("点击了: $providerType")
+ "onAdClicked: $providerType".logi(tag)
+ }
+
+ override fun onAdShow(providerType: String) {
+ //广告展示展示的回调
+ addLog("展示了: $providerType")
+ "onAdShow: $providerType".logi(tag)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ //广告请求成功的回调,每次请求只回调一次
+ addLog("请求到了: $providerType")
+ "onAdLoaded: $providerType".logi(tag)
+ }
+
+ override fun onAdVideoCached(providerType: String) {
+ //视频缓存完成的回调
+ addLog("视频已缓存: $providerType")
+ "onAdVideoCached: $providerType".logi(tag)
+ }
+
+ override fun onAdClose(providerType: String) {
+ //广告被关闭的回调
+ addLog("关闭了: $providerType")
+ "onAdClose: $providerType".logi(tag)
+ }
+
+ override fun onAdVideoComplete(providerType: String) {
+ //广告播放完成的回调
+ addLog("视频播放完成了: $providerType")
+ "onAdVideoComplete: $providerType".logi(tag)
+ }
+ })
+
+ btnRequest.setOnClickListener {
+ //开始请求广告
+ adHelperFullVideo.load()
+ }
+
+ btnShow.setOnClickListener {
+ //onAdLoaded 回调之后才能展示
+ adHelperFullVideo.show()
+ }
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/NativeExpressHybridActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/NativeExpressHybridActivity.kt
new file mode 100644
index 0000000..5697c19
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/NativeExpressHybridActivity.kt
@@ -0,0 +1,97 @@
+package com.ifmvo.togetherad.demo.hybrid
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.listener.NativeExpress2Listener
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.demo.hybrid.helper.AdHelperHybridExpress
+import kotlinx.android.synthetic.main.activity_native_express_simple.*
+
+/**
+ * Created by Matthew Chen on 2020/12/1.
+ */
+class NativeExpressHybridActivity : AppCompatActivity() {
+
+ private val tag = "NativeExpressHybridActivity"
+
+ private var mAdObject: Any? = null
+ private var mProviderType: String? = null
+
+ private val adHelperHybridExpress by lazy {
+ val ratioMapExpressHybrid = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1
+ )
+ AdHelperHybridExpress(this, TogetherAdAlias.AD_HYBRID_EXPRESS, /*ratioMapExpressHybrid,*/ 1)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_native_express_hybrid)
+
+ btnRequest.setOnClickListener {
+ requestAd()
+ }
+
+ btnShow.setOnClickListener {
+ showAd()
+ }
+ }
+
+ private fun requestAd() {
+ adHelperHybridExpress.getHybridExpressList(object : NativeExpress2Listener {
+ override fun onAdLoaded(providerType: String, adList: List) {
+
+ mAdObject = adList[0]
+ mProviderType = providerType
+
+ //广告请求成功的回调,每次请求只回调一次
+ "onAdLoaded: $providerType, adList: ${adList.size}".logi(tag)
+ addLog("原生模板广告请求成功,$providerType")
+ }
+
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ "onAdStartRequest: $providerType".logi(tag)
+ addLog("\n原生模板广告开始请求,$providerType")
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("原生模板广告全部请求失败了")
+ "onAdFailedAll".loge(tag)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("原生模板广告单个提供商请求失败了,$providerType, $failedMsg")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+ })
+ }
+
+ private fun showAd() {
+ AdHelperHybridExpress.show(mProviderType, this, mAdObject, adContainer)
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ adHelperHybridExpress.destroyAllHybridExpressAd()
+ //或者
+// AdHelperHybridExpress.destroyHybridExpressAd(mAdObject)
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/SplashHybridActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/SplashHybridActivity.kt
new file mode 100644
index 0000000..fd5c0a9
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/SplashHybridActivity.kt
@@ -0,0 +1,202 @@
+package com.ifmvo.togetherad.demo.hybrid
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.custom.splashSkip.SplashSkipViewSimple2
+import com.ifmvo.togetherad.core.listener.SplashListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.core.utils.dp
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.demo.hybrid.helper.AdHelperHybridSplash
+import com.ifmvo.togetherad.gdt.provider.GdtProvider
+import kotlinx.android.synthetic.main.activity_splash_pro.*
+
+/**
+ * 开屏 & 原生 混合使用
+ *
+ * Created by Matthew Chen on 2020-04-17.
+ */
+class SplashHybridActivity : AppCompatActivity() {
+
+ private val tag = "SplashHybridActivity"
+
+ private val adHelperSplashHybrid by lazy {
+ /**
+ * 使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ */
+ val ratioMapSplash = mapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+ )
+ /**
+ * activity: 必传。这里不是 Context,因为广点通必须传 Activity,所以统一传 Activity。
+ * alias: 必传。广告位的别名。初始化的时候是根据别名设置的广告ID,所以这里TogetherAd会根据别名查找对应的广告位ID。
+ * ratioMap: 非必传。广告商的权重。可以不传或传null,空的情况 TogetherAd 会自动使用初始化时 TogetherAd.setPublicProviderRatio 设置的全局通用权重。
+ */
+ AdHelperHybridSplash(
+ activity = this,
+ alias = TogetherAdAlias.AD_HYBRID_SPLASH /*, ratioMap = ratioMapSplash*/
+ )
+ }
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, SplashHybridActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_splash_pro)
+
+ btnLoad.setOnClickListener {
+ //开始请求开屏广告
+ requestSplashAd()
+ }
+
+ btnShow.setOnClickListener {
+ //展示广告
+ showSplashAd()
+ }
+
+ }
+
+ /**
+ * 请求开屏广告
+ */
+ private fun requestSplashAd() {
+
+ /**
+ * 设置 广点通 开屏广告 自定义跳过按钮
+ * TogetherAd 提供了两个简单的实例模板,同时只能设置一个,如果设置多个后面的生效
+ * 目前只有 优量汇(广点通) 支持自定义跳过按钮的样式,所以只会对 广点通 生效
+ */
+ GdtProvider.Splash.customSkipView = SplashSkipViewSimple2()
+ //GdtProvider.Splash.customSkipView = SplashSkipViewSimple1()
+ /**
+ * 给 穿山甲 设置可接受的图片尺寸,避免图片变形
+ * 一般设置容器的宽高即可
+ */
+ CsjProvider.Splash.setImageAcceptedSize(ScreenUtil.getDisplayMetricsWidth(this), ScreenUtil.getDisplayMetricsHeight(this) - 100f.dp.toInt())
+ /**
+ * 设置 穿山甲 开屏广告超时时间
+ * fetchDelay 参数,设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长)
+ * 如果不设置,默认值为 3000ms
+ */
+// CsjProvider.Splash.maxFetchDelay = 3000
+ /**
+ * 设置 优量汇 开屏广告超时时间
+ * 取值范围为[3000, 5000]ms。
+ * 如果不设置,会使用默认值
+ */
+// GdtProvider.Splash.maxFetchDelay = 3500
+
+ /**
+ * listener: 非必传。如果你不需要监听结果可以不传或传空。各个回调方法也可以选择性添加
+ */
+ adHelperSplashHybrid.loadOnly(listener = object : SplashListener {
+
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ addLog("\n开屏广告开始请求,$providerType")
+ "onAdStartRequest: $providerType".logi(tag)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ btnShow.isEnabled = true
+ //广告请求成功的回调,每次请求只回调一次
+ addLog("开屏广告请求好了,$providerType")
+ "onAdLoaded: $providerType".logi(tag)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //点击广告的回调
+ addLog("开屏广告被点击了,$providerType")
+ "onAdClicked: $providerType".logi(tag)
+ }
+
+ override fun onAdExposure(providerType: String) {
+ //广告展示曝光的回调
+ addLog("开屏广告曝光了,$providerType")
+ "onAdExposure: $providerType".logi(tag)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("开屏广告单个提供商请求失败了,$failedMsg, $providerType")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("全部请求失败了")
+ "onAdFailedAll".loge(tag)
+ actionHome(1000)
+ }
+
+ override fun onAdDismissed(providerType: String) {
+ //开屏广告消失了,点了跳过按钮或者倒计时结束之后会回调一次
+ //在这里跳转主界面,并关闭 Splash
+ addLog("开屏广告点了跳过或者倒计时结束, $providerType")
+ "onAdDismissed: $providerType".logi(tag)
+ actionHome(0)
+ }
+ })
+ //回调中的 providerType 是广告商类型
+ }
+
+ /**
+ * 展示开屏广告
+ */
+ private fun showSplashAd() {
+ //展示广告并返回是否展示成功
+ val showAdIsSuccess = adHelperSplashHybrid.showAd(adContainer)
+ //如果没有展示成功就直接跳走
+ if (!showAdIsSuccess) {
+ actionHome(1000)
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ adHelperSplashHybrid.resumeAd()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ adHelperSplashHybrid.pauseAd()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ adHelperSplashHybrid.destroyAd()
+ }
+
+ //不能手动返回
+ override fun onBackPressed() {}
+
+ private fun actionHome(delayMillis: Long) {
+ adContainer.postDelayed({
+ //在这里跳转到 Home 主界面
+ finish()
+ }, delayMillis)
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/VerticalPreMovieHybridActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/VerticalPreMovieHybridActivity.kt
new file mode 100644
index 0000000..3f07da2
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/VerticalPreMovieHybridActivity.kt
@@ -0,0 +1,106 @@
+package com.ifmvo.togetherad.demo.hybrid
+
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.demo.hybrid.helper.AdHelperHybridVerticalPreMovie
+import kotlinx.android.synthetic.main.activity_vertical_premovie.*
+
+/**
+ * Created by Matthew Chen on 2020/12/1.
+ */
+class VerticalPreMovieHybridActivity : AppCompatActivity() {
+
+ private val tag = "VerticalPreMovieHybridActivity"
+
+ private val adHelper by lazy {
+ val ratioMapVerticalPreMovie = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1
+ )
+ AdHelperHybridVerticalPreMovie(this, TogetherAdAlias.AD_HYBRID_VERTICAL_PREMOVIE, adContainer/*, ratioMapVerticalPreMovie*/)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_vertical_premovie)
+
+ btnRequestAndShow.setOnClickListener {
+ requestAd()
+ }
+ }
+
+ private fun requestAd() {
+
+ adHelper.loadAndShow(object : AdHelperHybridVerticalPreMovie.VerticalPreMovieListener {
+ override fun onAdLoaded(providerType: String) {
+ //广告请求成功的回调,每次请求只回调一次
+ "onAdLoaded: $providerType".logi(tag)
+ addLog("竖屏前贴广告请求成功,$providerType")
+ }
+
+ override fun onAdClicked(providerType: String) {
+ "onAdClicked: $providerType".logi(tag)
+ addLog("竖屏前贴广告点击了,$providerType")
+ }
+
+ override fun onAdExpose(providerType: String) {
+ "onAdExpose: $providerType".logi(tag)
+ addLog("竖屏前贴广告曝光了,$providerType")
+ }
+
+ override fun onAdClose(providerType: String) {
+ "onAdClose: $providerType".logi(tag)
+ addLog("竖屏前贴广告关闭了,$providerType")
+ }
+
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ "onAdStartRequest: $providerType".logi(tag)
+ addLog("\n竖屏前贴广告开始请求,$providerType")
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("竖屏前贴广告全部请求失败了")
+ "onAdFailedAll".loge(tag)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("竖屏前贴广告单个提供商请求失败了,$providerType, $failedMsg")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+ })
+
+ }
+
+ override fun onResume() {
+ super.onResume()
+ adHelper.onResume()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ adHelper.onPause()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ adHelper.onDestroy()
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/helper/AdHelperHybridExpress.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/helper/AdHelperHybridExpress.kt
new file mode 100644
index 0000000..9e8aa77
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/helper/AdHelperHybridExpress.kt
@@ -0,0 +1,235 @@
+package com.ifmvo.togetherad.demo.hybrid.helper
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.helper.AdHelperNativeExpress
+import com.ifmvo.togetherad.core.helper.AdHelperNativeExpress2
+import com.ifmvo.togetherad.core.helper.BaseHelper
+import com.ifmvo.togetherad.core.listener.NativeExpress2Listener
+import com.ifmvo.togetherad.core.listener.NativeExpress2ViewListener
+import com.ifmvo.togetherad.core.listener.NativeExpressListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.native_.template.NativeExpress2TemplateSimple
+import com.ifmvo.togetherad.demo.native_.template.NativeExpressTemplateSimple
+import org.jetbrains.annotations.NotNull
+import org.jetbrains.annotations.Nullable
+import java.lang.ref.WeakReference
+
+/**
+ *
+ * Created by Matthew Chen on 2020/12/1.
+ */
+class AdHelperHybridExpress(
+
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ ratioMap: LinkedHashMap? = null,
+ adCount: Int
+
+) : BaseHelper() {
+
+ private var mActivity: WeakReference = WeakReference(activity)
+ private var mAlias: String = alias
+ private var mRatioMap: LinkedHashMap? = ratioMap
+ private var mAdCount: Int = adCount
+ private var adProvider: BaseAdProvider? = null
+
+ //所有请求到的广告容器
+ private var mAdList = mutableListOf()
+
+ companion object {
+
+ private const val defaultAdCount = 1
+
+ fun show(@Nullable adProviderType: String?, @NotNull activity: Activity, @Nullable adObject: Any?, @Nullable container: ViewGroup?) {
+ if (adObject == null) {
+ return
+ }
+ if (container == null) {
+ return
+ }
+
+ when (adProviderType) {
+ AdProviderType.GDT.type -> {
+ AdHelperNativeExpress.show(adObject, container, NativeExpressTemplateSimple())
+ }
+ AdProviderType.CSJ.type -> {
+ AdHelperNativeExpress2.show(activity, adObject, container, NativeExpress2TemplateSimple(), object : NativeExpress2ViewListener {
+ override fun onAdExposed(providerType: String) {
+
+ }
+
+ override fun onAdClicked(providerType: String) {
+
+ }
+
+ override fun onAdRenderSuccess(providerType: String) {
+
+ }
+
+ override fun onAdRenderFailed(providerType: String) {
+
+ }
+
+ override fun onAdClose(providerType: String) {
+
+ }
+ })
+ }
+ }
+
+ }
+
+ fun destroyHybridExpressAd(@Nullable adObject: Any?) {
+ if (adObject == null) {
+ return
+ }
+ TogetherAd.mProviders.entries.forEach { entry ->
+ val adProvider = AdProviderLoader.loadAdProvider(entry.key)
+ adProvider?.destroyNativeExpressAd(adObject)
+ adProvider?.destroyNativeExpress2Ad(adObject)
+ }
+ }
+
+ fun destroyHybridExpressAd(@Nullable adObjectList: List?) {
+ if (adObjectList?.isEmpty() != false) {
+ return
+ }
+ adObjectList.forEach { destroyHybridExpressAd(it) }
+ }
+ }
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ adCount: Int
+ ) : this(activity, alias, null, adCount)
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String
+ ) : this(activity, alias, null, defaultAdCount)
+
+ fun getHybridExpressList(listener: NativeExpress2Listener? = null) {
+ val currentRatioMap = if (mRatioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else mRatioMap!!
+
+ startTimer(listener)
+ getHybridExpressListForMap(currentRatioMap, listener)
+ }
+
+ private fun getHybridExpressListForMap(@NotNull ratioMap: LinkedHashMap, listener: NativeExpress2Listener? = null) {
+
+ val currentAdCount = if (mAdCount <= 0) defaultAdCount else mAdCount
+
+ val adProviderType = DispatchUtil.getAdProvider(mAlias, ratioMap)
+
+ if (adProviderType?.isEmpty() != false || mActivity.get() == null) {
+ cancelTimer()
+ listener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${mActivity.get()?.getString(R.string.no_init)}".loge()
+ getHybridExpressListForMap(filterType(ratioMap, adProviderType), listener)
+ return
+ }
+
+ when (adProviderType) {
+ AdProviderType.GDT.type -> {
+ getHybridExpressList(adProviderType, currentAdCount, listener, ratioMap)
+ }
+ AdProviderType.CSJ.type -> {
+ getHybridExpress2List(adProviderType, currentAdCount, listener, ratioMap)
+ }
+ }
+ }
+
+ private fun getHybridExpressList(adProviderType: String, currentAdCount: Int, listener: NativeExpress2Listener?, ratioMap: LinkedHashMap) {
+ adProvider?.getNativeExpressAdList(mActivity.get()!!, adProviderType, mAlias, currentAdCount, object : NativeExpressListener {
+ override fun onAdStartRequest(providerType: String) {
+ listener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ getHybridExpressListForMap(filterType(ratioMap, adProviderType), listener)
+
+ listener?.onAdFailed(providerType, failedMsg)
+ }
+
+ override fun onAdLoaded(providerType: String, adList: List) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mAdList.addAll(adList)
+ listener?.onAdLoaded(providerType, adList)
+ }
+
+ override fun onAdClicked(providerType: String, adObject: Any?) {
+
+ }
+
+ override fun onAdShow(providerType: String, adObject: Any?) {
+
+ }
+
+ override fun onAdRenderSuccess(providerType: String, adObject: Any?) {
+
+ }
+
+ override fun onAdRenderFail(providerType: String, adObject: Any?) {
+
+ }
+
+ override fun onAdClosed(providerType: String, adObject: Any?) {
+
+ }
+ })
+ }
+
+ private fun getHybridExpress2List(adProviderType: String, currentAdCount: Int, listener: NativeExpress2Listener?, ratioMap: LinkedHashMap) {
+ adProvider?.getNativeExpress2AdList(mActivity.get()!!, adProviderType, mAlias, currentAdCount, object : NativeExpress2Listener {
+ override fun onAdLoaded(providerType: String, adList: List) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mAdList.addAll(adList)
+ listener?.onAdLoaded(providerType, adList)
+
+ }
+
+ override fun onAdStartRequest(providerType: String) {
+ listener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ getHybridExpressListForMap(filterType(ratioMap, adProviderType), listener)
+
+ listener?.onAdFailed(providerType, failedMsg)
+ }
+ })
+ }
+
+ /**
+ * 销毁所有请求到的广告
+ */
+ fun destroyAllHybridExpressAd() {
+ destroyHybridExpressAd(mAdList)
+ mAdList.clear()
+ }
+
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/helper/AdHelperHybridSplash.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/helper/AdHelperHybridSplash.kt
new file mode 100644
index 0000000..fe93e9a
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/helper/AdHelperHybridSplash.kt
@@ -0,0 +1,195 @@
+package com.ifmvo.togetherad.demo.hybrid.helper
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.bytedance.sdk.openadsdk.AdSlot
+import com.ifmvo.togetherad.core.R
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.helper.AdHelperNativePro
+import com.ifmvo.togetherad.core.helper.BaseHelper
+import com.ifmvo.togetherad.core.listener.NativeListener
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.listener.SplashListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.native_.template.NativeTemplateSimple3
+import org.jetbrains.annotations.NotNull
+import java.lang.ref.WeakReference
+
+/**
+ * 开屏广告
+ *
+ * Created by Matthew Chen on 2020-04-03.
+ */
+class AdHelperHybridSplash(
+
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ ratioMap: LinkedHashMap? = null
+
+) : BaseHelper() {
+
+ private var mActivity: WeakReference = WeakReference(activity)
+ private var mAlias: String = alias
+ private var mRatioMap: LinkedHashMap? = ratioMap
+ private var adProvider: BaseAdProvider? = null
+ private var mListener: SplashListener? = null
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String
+ ) : this(activity, alias, null)
+
+ //为了照顾 Java 调用的同学
+ fun loadOnly(listener: SplashListener? = null) {
+ destroyAd()
+
+ mListener = listener
+ val currentRatioMap = if (mRatioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else mRatioMap!!
+
+ startTimer(listener)
+ realLoadOnly(currentRatioMap)
+ }
+
+ private fun realLoadOnly(@NotNull ratioMap: LinkedHashMap) {
+
+ val adProviderType = DispatchUtil.getAdProvider(mAlias, ratioMap)
+
+ if (adProviderType?.isEmpty() != false || mActivity.get() == null) {
+ cancelTimer()
+ mListener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ mListener = null
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${mActivity.get()?.getString(R.string.no_init)}".loge()
+ realLoadOnly(filterType(ratioMap, adProviderType))
+ return
+ }
+
+ //可以在这里修改,哪种平台使用开屏,哪种平台使用原生
+ when (adProviderType) {
+ AdProviderType.GDT.type -> {
+ realLoadOnlySplash(ratioMap, adProviderType)
+ }
+ AdProviderType.BAIDU.type, AdProviderType.CSJ.type -> {
+ realLoadOnlyNative(ratioMap, adProviderType)
+ }
+ }
+
+ }
+
+ private var mAdObject: Any? = null
+ private fun realLoadOnlyNative(ratioMap: LinkedHashMap, adProviderType: String) {
+ CsjProvider.Native.nativeAdType = AdSlot.TYPE_FEED
+ adProvider?.getNativeAdList(activity = mActivity.get()!!, adProviderType = adProviderType, alias = mAlias, maxCount = 1, listener = object : NativeListener {
+ override fun onAdStartRequest(providerType: String) {
+ mListener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdLoaded(providerType: String, adList: List) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mListener?.onAdLoaded(providerType)
+
+ mAdObject = adList[0]
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ mListener?.onAdFailed(providerType, failedMsg)
+ val newRatioMap = filterType(ratioMap, adProviderType)
+ realLoadOnly(newRatioMap)
+ }
+ })
+ }
+
+ private fun realLoadOnlySplash(ratioMap: LinkedHashMap, adProviderType: String) {
+ adProvider?.loadOnlySplashAd(activity = mActivity.get()!!, adProviderType = adProviderType, alias = mAlias, listener = object : SplashListener {
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ mListener?.onAdFailed(providerType, failedMsg)
+ val newRatioMap = filterType(ratioMap, adProviderType)
+ realLoadOnly(newRatioMap)
+ }
+
+ override fun onAdStartRequest(providerType: String) {
+ mListener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mListener?.onAdLoaded(providerType)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ mListener?.onAdClicked(providerType)
+ }
+
+ override fun onAdExposure(providerType: String) {
+ mListener?.onAdExposure(providerType)
+ }
+
+ override fun onAdDismissed(providerType: String) {
+ mListener?.onAdDismissed(providerType)
+ mListener = null
+ }
+ })
+ }
+
+ fun showAd(@NotNull container: ViewGroup): Boolean {
+
+ if (mAdObject != null) {
+ fun onClose(adProviderType: String) {
+ mListener?.onAdDismissed(adProviderType)
+ destroyAd()
+ }
+
+ AdHelperNativePro.show(adObject = mAdObject, container = container, nativeTemplate = NativeTemplateSimple3(::onClose), listener = object : NativeViewListener {
+ override fun onAdExposed(providerType: String) {
+ mListener?.onAdExposure(providerType)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ mListener?.onAdClicked(providerType)
+ }
+ })
+ return true
+ } else {
+ return adProvider?.showSplashAd(container) ?: false
+ }
+ }
+
+ fun resumeAd() {
+ mAdObject?.run {
+ AdHelperNativePro.resumeAd(this)
+ }
+ }
+
+ fun pauseAd() {
+ mAdObject?.run {
+ AdHelperNativePro.pauseAd(this)
+ }
+ }
+
+ fun destroyAd() {
+ mAdObject?.run {
+ AdHelperNativePro.destroyAd(this)
+ mAdObject = null
+ mListener = null
+ }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/helper/AdHelperHybridVerticalPreMovie.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/helper/AdHelperHybridVerticalPreMovie.kt
new file mode 100644
index 0000000..dc0997f
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/helper/AdHelperHybridVerticalPreMovie.kt
@@ -0,0 +1,253 @@
+package com.ifmvo.togetherad.demo.hybrid.helper
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.bytedance.sdk.openadsdk.AdSlot
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.config.AdProviderLoader
+import com.ifmvo.togetherad.core.helper.AdHelperNativePro
+import com.ifmvo.togetherad.core.helper.BaseHelper
+import com.ifmvo.togetherad.core.listener.*
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.core.utils.DispatchUtil
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.native_.template.NativeTemplateSimple3
+import org.jetbrains.annotations.NotNull
+import java.lang.ref.WeakReference
+
+/**
+ * 广点通:激励、原生信息流
+ *
+ * 穿山甲:全屏视频
+ *
+ * Created by Matthew Chen on 2020/12/11.
+ */
+class AdHelperHybridVerticalPreMovie(
+
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ @NotNull container: ViewGroup,
+ ratioMap: LinkedHashMap? = null
+
+) : BaseHelper() {
+
+ private var mActivity: WeakReference = WeakReference(activity)
+ private var mAlias: String = alias
+ private var mContainer: ViewGroup = container
+ private var mRatioMap: LinkedHashMap? = ratioMap
+ private var mListener: VerticalPreMovieListener? = null
+ private var adProvider: BaseAdProvider? = null
+
+ //为了照顾 Java 调用的同学
+ constructor(
+ @NotNull activity: Activity,
+ @NotNull alias: String,
+ @NotNull container: ViewGroup
+ ) : this(activity, alias, container, null)
+
+ fun loadAndShow(listener: VerticalPreMovieListener? = null) {
+ onDestroy()
+
+ mListener = listener
+
+ val currentRatioMap: LinkedHashMap = if (mRatioMap?.isEmpty() != false) TogetherAd.getPublicProviderRatio() else mRatioMap!!
+
+ startTimer(mListener)
+ reload(currentRatioMap)
+ }
+
+ private fun reload(@NotNull ratioMap: LinkedHashMap) {
+
+ val adProviderType = DispatchUtil.getAdProvider(mAlias, ratioMap)
+
+ if (adProviderType?.isEmpty() != false || mActivity.get() == null) {
+ cancelTimer()
+ mListener?.onAdFailedAll(FailedAllMsg.failedAll_noDispatch)
+ return
+ }
+
+ adProvider = AdProviderLoader.loadAdProvider(adProviderType)
+
+ if (adProvider == null) {
+ "$adProviderType ${mActivity.get()?.getString(R.string.no_init)}".loge()
+ reload(filterType(ratioMap, adProviderType))
+ return
+ }
+
+ when (adProviderType) {
+ //广点通分为激励和原生
+ AdProviderType.GDT.type -> {
+// realLoadReward(adProviderType, ratioMap)
+ realLoadNative(adProviderType, ratioMap)
+ }
+ //穿山甲是全屏视频广告
+ AdProviderType.CSJ.type -> {
+ realLoadFullScreen(adProviderType, ratioMap)
+ }
+ }
+ }
+
+ private fun realLoadReward(adProviderType: String, ratioMap: LinkedHashMap) {
+ adProvider?.requestRewardAd(mActivity.get()!!, adProviderType, mAlias, object : RewardListener {
+ override fun onAdStartRequest(providerType: String) {
+ mListener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ reload(filterType(ratioMap, adProviderType))
+
+ mListener?.onAdFailed(providerType, failedMsg)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ mListener?.onAdClicked(providerType)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ if (isFetchOverTime) return
+
+ if (mActivity.get() == null) {
+ reload(filterType(ratioMap, adProviderType))
+ mListener?.onAdFailed(providerType, "Activity为空")
+ return
+ }
+ cancelTimer()
+ mListener?.onAdLoaded(providerType)
+
+ adProvider?.showRewardAd(mActivity.get()!!)
+ }
+
+ override fun onAdExpose(providerType: String) {
+ mListener?.onAdExpose(providerType)
+ }
+
+ override fun onAdClose(providerType: String) {
+ mListener?.onAdClose(providerType)
+ }
+ })
+ }
+
+ private fun realLoadFullScreen(adProviderType: String, ratioMap: LinkedHashMap) {
+ adProvider?.requestFullVideoAd(mActivity.get()!!, adProviderType, mAlias, object : FullVideoListener {
+ override fun onAdLoaded(providerType: String) {
+ if (isFetchOverTime) return
+
+ if (mActivity.get() == null) {
+ reload(filterType(ratioMap, adProviderType))
+ mListener?.onAdFailed(providerType, "Activity为空")
+ return
+ }
+
+ cancelTimer()
+ mListener?.onAdLoaded(providerType)
+
+ adProvider?.showFullVideoAd(mActivity.get()!!)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ mListener?.onAdClicked(providerType)
+ }
+
+ override fun onAdShow(providerType: String) {
+ mListener?.onAdExpose(providerType)
+ }
+
+ override fun onAdClose(providerType: String) {
+ mListener?.onAdClose(providerType)
+ }
+
+ override fun onAdStartRequest(providerType: String) {
+ mListener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ reload(filterType(ratioMap, adProviderType))
+
+ mListener?.onAdFailed(providerType, failedMsg)
+ }
+ })
+ }
+
+ private var mAdObject: Any? = null
+ private fun realLoadNative(adProviderType: String, ratioMap: LinkedHashMap) {
+ CsjProvider.Native.nativeAdType = AdSlot.TYPE_FEED
+ adProvider?.getNativeAdList(mActivity.get()!!, adProviderType, mAlias, 1, object : NativeListener {
+ override fun onAdLoaded(providerType: String, adList: List) {
+ if (isFetchOverTime) return
+
+ cancelTimer()
+ mListener?.onAdLoaded(providerType)
+
+ mAdObject = adList[0]
+ fun onClose(adProviderType: String) {
+ AdHelperNativePro.destroyAd(mAdObject)
+ mListener?.onAdClose(adProviderType)
+ }
+
+ AdHelperNativePro.show(adObject = mAdObject, container = mContainer, nativeTemplate = NativeTemplateSimple3(::onClose), listener = object : NativeViewListener {
+ override fun onAdExposed(providerType: String) {
+ mListener?.onAdExpose(providerType)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ mListener?.onAdClicked(providerType)
+ }
+ })
+ }
+
+ override fun onAdStartRequest(providerType: String) {
+ mListener?.onAdStartRequest(providerType)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ if (isFetchOverTime) return
+
+ reload(filterType(ratioMap, adProviderType))
+
+ mListener?.onAdFailed(providerType, failedMsg)
+ }
+ })
+ }
+
+ fun onResume() {
+ AdHelperNativePro.resumeAd(mAdObject)
+ }
+
+ fun onPause() {
+ AdHelperNativePro.pauseAd(mAdObject)
+ }
+
+ fun onDestroy() {
+ AdHelperNativePro.destroyAd(mAdObject)
+ }
+
+ interface VerticalPreMovieListener : BaseListener {
+ /**
+ * 请求到了广告
+ */
+ fun onAdLoaded(@NotNull providerType: String) {}
+
+ /**
+ * 广告被点击了
+ */
+ fun onAdClicked(@NotNull providerType: String) {}
+
+ /**
+ * 广告曝光了( 和 onAdShow 的区别是展示不一定曝光,曝光一定展示,需要展示一定的时间才会曝光,曝光的条件是提供商规定的 )
+ */
+ fun onAdExpose(@NotNull providerType: String) {}
+
+ /**
+ * 广告被关闭了
+ */
+ fun onAdClose(@NotNull providerType: String) {}
+
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/inter/InterActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/inter/InterActivity.kt
new file mode 100644
index 0000000..4c721f0
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/inter/InterActivity.kt
@@ -0,0 +1,104 @@
+package com.ifmvo.togetherad.demo.inter
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.helper.AdHelperInter
+import com.ifmvo.togetherad.core.listener.InterListener
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import kotlinx.android.synthetic.main.activity_inter.*
+
+/**
+ *
+ * Created by Matthew Chen on 2020/7/6.
+ */
+class InterActivity : AppCompatActivity() {
+
+ private var adHelperInter: AdHelperInter? = null
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, InterActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_inter)
+
+ //设置 穿山甲 Inter插屏广告 可接受图片尺寸,可以不设置,默认为 600 600
+ //CsjProvider.Inter.setImageAcceptedSize(600, 600)
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ val ratioMapInter = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+ )
+ adHelperInter = AdHelperInter(activity = this, alias = TogetherAdAlias.AD_INTER, /*ratioMap = ratioMapInter,*/ listener = object : InterListener {
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ addLog("\n开始请求了,$providerType")
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ //广告请求成功的回调,每次请求只回调一次
+ addLog("请求到了,$providerType")
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("单个广告请求失败, $providerType, $failedMsg")
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("全部请求失败了")
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //点击广告的回调
+ addLog("点击了,$providerType")
+ }
+
+ override fun onAdExpose(providerType: String) {
+ //广告展示曝光的回调;由于 Banner 广告存在自动刷新功能,所以曝光会回调多次,每次刷新都会回调
+ addLog("曝光了,$providerType")
+ }
+
+ override fun onAdClose(providerType: String) {
+ //广告被关闭的回调
+ addLog("关闭了,$providerType")
+ }
+ })
+
+ btnRequest.setOnClickListener {
+ //开始请求插屏广告
+ adHelperInter?.load()
+ }
+
+ btnShow.setOnClickListener {
+ //开始展示插屏广告,必须在 onAdLoaded 回调之后展示
+ adHelperInter?.show()
+ }
+
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ adHelperInter?.destroy()
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeAdapter.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeAdapter.kt
new file mode 100644
index 0000000..01d372d
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeAdapter.kt
@@ -0,0 +1,79 @@
+package com.ifmvo.togetherad.demo.native_
+
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import android.widget.Toast
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.helper.AdHelperNativePro
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.native_.template.NativeTemplateSimple5
+import com.ifmvo.togetherad.demo.other.ContentDataEntity
+
+/**
+ * 一个普通的多类型列表的 Adapter
+ *
+ * Created by Matthew Chen on 2020/6/30.
+ */
+class NativeAdapter(list: List) : RecyclerView.Adapter() {
+
+ companion object {
+ private const val ITEM_VIEW_TYPE_AD = 0
+ private const val ITEM_VIEW_TYPE_CONTENT = 1
+ }
+
+ private var mList: List = list
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
+ return if (viewType == ITEM_VIEW_TYPE_CONTENT) {
+ ContentViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_native_content, parent, false))
+ } else {
+ AdViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.list_item_native_ad, parent, false))
+ }
+ }
+
+ override fun getItemCount(): Int {
+ return mList.size
+ }
+
+ override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
+ when (getItemViewType(position)) {
+ ITEM_VIEW_TYPE_CONTENT -> {
+ val contentViewHolder = holder as ContentViewHolder
+ val contentDataEntity = mList[position] as ContentDataEntity
+ contentViewHolder.imageView.layoutParams.height = ScreenUtil.getDisplayMetricsWidth(contentViewHolder.imageView.context) * 9 / 16
+ TogetherAd.mImageLoader?.loadImage(contentViewHolder.imageView.context, contentViewHolder.imageView, contentDataEntity.imgUrl)
+ contentViewHolder.textView.text = contentDataEntity.title
+ }
+ ITEM_VIEW_TYPE_AD -> {
+ val adViewHolder = holder as AdViewHolder
+ AdHelperNativePro.show(mList[position], adViewHolder.adContainer, NativeTemplateSimple5(), object : NativeViewListener {
+ override fun onAdExposed(providerType: String) {
+ }
+
+ override fun onAdClicked(providerType: String) {
+ }
+ })
+ }
+ }
+ }
+
+ override fun getItemViewType(position: Int): Int {
+ return if (mList[position] is ContentDataEntity) ITEM_VIEW_TYPE_CONTENT else ITEM_VIEW_TYPE_AD
+ }
+
+ inner class AdViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ var adContainer: ViewGroup = itemView.findViewById(R.id.adContainer)
+ }
+
+ inner class ContentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
+ var imageView: ImageView = itemView.findViewById(R.id.img)
+ var textView: TextView = itemView.findViewById(R.id.txt)
+ }
+
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeRecyclerViewActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeRecyclerViewActivity.kt
new file mode 100644
index 0000000..fb5a5d7
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeRecyclerViewActivity.kt
@@ -0,0 +1,170 @@
+package com.ifmvo.togetherad.demo.native_
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.LinearLayoutManager
+import android.widget.Toast
+import com.bytedance.sdk.openadsdk.AdSlot
+import com.ifmvo.togetherad.core.helper.AdHelperNativePro
+import com.ifmvo.togetherad.core.listener.NativeListener
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.demo.other.ContentDataEntity
+import kotlinx.android.synthetic.main.activity_native_recyclerview.*
+
+
+/**
+ * 原生自渲染在 RecyclerView 中的用法
+ *
+ * Created by Matthew Chen on 2020-04-20.
+ */
+class NativeRecyclerViewActivity : AppCompatActivity() {
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ private val ratioMapNativeRecycler = mapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+ )
+
+ private val adHelperNativeRv by lazy { AdHelperNativePro(this, TogetherAdAlias.AD_NATIVE_RECYCLERVIEW, /*ratioMapNativeRecycler,*/ 3) }
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, NativeRecyclerViewActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_native_recyclerview)
+
+ requestRvAd {
+ //使用 RecyclerView 展示合并后的数据
+ val allList = mergeContentAd(getContentData(), it)
+ recyclerView.layoutManager = LinearLayoutManager(this)
+ recyclerView.adapter = NativeAdapter(allList)
+ }
+ }
+
+ /**
+ * 请求广告List
+ */
+ private fun requestRvAd(onResult: (adList: List) -> Unit) {
+ //--------------------------------------------------------------------------------------
+ // ( 必须设置 )如果需要使用穿山甲的原生广告,必须在请求之前设置类型。( 没用到穿山甲的请忽略 )
+ // 设置方式:CsjProvider.Native.nativeAdType = AdSlot.TYPE_XXX(类型和你的广告位ID一致)。
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_FEED
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_INTERACTION_AD
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_BANNER
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_CACHED_SPLASH
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_DRAW_FEED
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_FULL_SCREEN_VIDEO
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_REWARD_VIDEO
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_SPLASH
+ //--------------------------------------------------------------------------------------
+ CsjProvider.Native.nativeAdType = AdSlot.TYPE_FEED
+
+ //设置 穿山甲 图片可接受的尺寸 ( 建议设置,默认是 1080,607.5 )
+ //CsjProvider.Native.setImageAcceptedSize(ScreenUtil.getDisplayMetricsWidth(this), ScreenUtil.getDisplayMetricsWidth(this) * 9 / 16)
+
+ //指定普链广告点击后用于展示落地页的浏览器类型,可选项包括:InnerBrowser(APP 内置浏览器),Sys(系统浏览器),Default(默认,SDK 按照默认逻辑选择)
+ // ( 非必须设置,默认是:BrowserType.Default )
+ //GdtProvider.Native.browserType = BrowserType.Default
+
+ //指定点击 APP 广告后是否展示二次确认,可选项包括 Default(wifi 不展示,非 wifi 展示),NoConfirm(所有情况不展示)
+ // ( 非必须设置,默认是:DownAPPConfirmPolicy.Default )
+ //GdtProvider.Native.downAPPConfirmPolicy = DownAPPConfirmPolicy.Default
+
+ //设置返回视频广告的最大视频时长(闭区间,可单独设置),单位:秒,合法输入为:5<=maxVideoDuration<=60. 此设置会影响广告填充,请谨慎设置
+ // ( 非必须设置,默认是:60 )
+ //GdtProvider.Native.maxVideoDuration = 60
+
+ //设置返回视频广告的最小视频时长(闭区间,可单独设置),单位:秒 此设置会影响广告填充,请谨慎设置
+ // ( 非必须设置,默认是:5 )
+ //GdtProvider.Native.minVideoDuration = 5
+
+ //设置本次拉取的视频广告,从用户角度看到的视频播放策略;
+ // 可选项包括自VideoOption.VideoPlayPolicy.AUTO(在用户看来,视频广告是自动播放的)和VideoOption.VideoPlayPolicy.MANUAL(在用户看来,视频广告是手动播放的);
+ // 如果广告位支持视频,强烈建议调用此接口设置视频广告的播放策略,有助于提高eCPM值;如果广告位不支持视频,忽略本接口
+ // ( 默认是:VideoOption.VideoPlayPolicy.AUTO )
+ //GdtProvider.Native.videoPlayPolicy = VideoOption.VideoPlayPolicy.AUTO
+
+ adHelperNativeRv.getList(listener = object : NativeListener {
+ override fun onAdStartRequest(providerType: String) {
+ //每个提供商请求之前都会回调
+ }
+
+ override fun onAdLoaded(providerType: String, adList: List) {
+ onResult(adList)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //单个提供商请求失败
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有的提供商都失败
+ onResult(mutableListOf())
+ }
+ })
+ }
+
+ /**
+ * 把内容List和广告List合并
+ *
+ * 示例:第二条插入广告,之后每隔5条内容插入一条广告
+ *
+ * 具体逻辑按照自己的需求自行处理
+ */
+ private fun mergeContentAd(contentList: List, adList: List): List {
+
+ var nextAdPosition = 0
+ var lastUseAdPosition = 0
+
+ val multiItemList = mutableListOf()
+ repeat(contentList.size) {
+ multiItemList.add(contentList[it])
+ if (adList.isNotEmpty() && nextAdPosition == it) {
+ if (lastUseAdPosition > adList.size - 1) {
+ lastUseAdPosition = 0
+ }
+ multiItemList.add(adList[lastUseAdPosition])
+ lastUseAdPosition += 1
+ nextAdPosition += 5
+ }
+ }
+ return multiItemList
+ }
+
+ /**
+ * 模拟真实的内容数据List
+ */
+ private fun getContentData(): List {
+ val contentList = mutableListOf()
+ for (index in 1..15) {
+ val title = "正文内容序号:$index"
+ contentList.add(ContentDataEntity(title = title, imgUrl = "https://t8.baidu.com/it/u=2247852322,986532796&fm=79&app=86&size=h300&n=0&g=4n&f=jpeg?sec=1590128472&t=657ec840a5c6c658430135ea8b1d35f0"))
+ }
+ return contentList
+ }
+
+ override fun onResume() {
+ super.onResume()
+ adHelperNativeRv.resumeAllAd()
+ }
+
+ override fun onPause() {
+ super.onPause()
+ adHelperNativeRv.pauseAllAd()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ adHelperNativeRv.destroyAllAd()
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeSimpleActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeSimpleActivity.kt
new file mode 100644
index 0000000..8413918
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeSimpleActivity.kt
@@ -0,0 +1,200 @@
+package com.ifmvo.togetherad.demo.native_
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.bytedance.sdk.openadsdk.AdSlot
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeTemplate
+import com.ifmvo.togetherad.core.helper.AdHelperNativePro
+import com.ifmvo.togetherad.core.listener.NativeListener
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.demo.native_.template.NativeTemplateSimple1
+import com.ifmvo.togetherad.demo.native_.template.NativeTemplateSimple2
+import com.ifmvo.togetherad.demo.native_.template.NativeTemplateSimple4
+import com.ifmvo.togetherad.demo.native_.template.NativeTemplateSimple5
+import kotlinx.android.synthetic.main.activity_native_simple.*
+
+/**
+ * 原生自渲染的简单用法
+ *
+ * Created by Matthew Chen on 2020-04-20.
+ */
+class NativeSimpleActivity : AppCompatActivity() {
+
+ private val tag = "NativeSimpleActivity"
+
+ //声明
+ private var adHelperNative: AdHelperNativePro? = null
+
+ private var mAdObject: Any? = null
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, NativeSimpleActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_native_simple)
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ val ratioMapNativeSimple = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+ )
+
+ //初始化 maxCount: 返回广告的最大个数 ( 由于各个广告提供商返回的广告数量不等,所以只能控制返回广告的最大数量。例:maxCount = 4,返回的 1 ≤ List.size ≤ 4 )
+ adHelperNative = AdHelperNativePro(activity = this, alias = TogetherAdAlias.AD_NATIVE_SIMPLE, maxCount = 1/*, ratioMap = ratioMapNativeSimple*/)
+
+ btnRequest.setOnClickListener {
+ requestAd()
+ }
+
+ btnShow1.setOnClickListener {
+ showAd(adObject = mAdObject, nativeTemplate = NativeTemplateSimple1())
+ }
+
+ btnShow2.setOnClickListener {
+ showAd(adObject = mAdObject, nativeTemplate = NativeTemplateSimple2())
+ }
+
+ btnShow4.setOnClickListener {
+ showAd(adObject = mAdObject, nativeTemplate = NativeTemplateSimple4 {
+ adContainer.removeAllViews()
+ })
+ }
+
+ btnShow5.setOnClickListener {
+ showAd(adObject = mAdObject, nativeTemplate = NativeTemplateSimple5 {
+
+ })
+ }
+ }
+
+ /**
+ * 请求广告
+ */
+ private fun requestAd() {
+ //--------------------------------------------------------------------------------------
+ // ( 必须设置 )如果需要使用穿山甲的原生广告,必须在请求之前设置类型。( 没用到穿山甲的请忽略 )
+ // 设置方式:CsjProvider.Native.nativeAdType = AdSlot.TYPE_XXX(类型和你的广告位ID一致)。
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_FEED
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_INTERACTION_AD
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_BANNER
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_CACHED_SPLASH
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_DRAW_FEED
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_FULL_SCREEN_VIDEO
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_REWARD_VIDEO
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_SPLASH
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_STREAM
+ //--------------------------------------------------------------------------------------
+ CsjProvider.Native.nativeAdType = AdSlot.TYPE_FEED
+
+ //设置 穿山甲 图片可接受的尺寸 ( 建议设置,默认是 1080,607.5 )
+ //CsjProvider.Native.setImageAcceptedSize(ScreenUtil.getDisplayMetricsWidth(this), ScreenUtil.getDisplayMetricsWidth(this) * 9 / 16)
+
+ //指定普链广告点击后用于展示落地页的浏览器类型,可选项包括:InnerBrowser(APP 内置浏览器),Sys(系统浏览器),Default(默认,SDK 按照默认逻辑选择)
+ // ( 非必须设置,默认是:BrowserType.Default )
+ //GdtProvider.Native.browserType = BrowserType.Default
+
+ //指定点击 APP 广告后是否展示二次确认,可选项包括 Default(wifi 不展示,非 wifi 展示),NoConfirm(所有情况不展示)
+ // ( 非必须设置,默认是:DownAPPConfirmPolicy.Default )
+ //GdtProvider.Native.downAPPConfirmPolicy = DownAPPConfirmPolicy.Default
+
+ //设置返回视频广告的最大视频时长(闭区间,可单独设置),单位:秒,合法输入为:5<=maxVideoDuration<=60. 此设置会影响广告填充,请谨慎设置
+ // ( 非必须设置,默认是:60 )
+ //GdtProvider.Native.maxVideoDuration = 60
+
+ //设置返回视频广告的最小视频时长(闭区间,可单独设置),单位:秒 此设置会影响广告填充,请谨慎设置
+ // ( 非必须设置,默认是:5 )
+ //GdtProvider.Native.minVideoDuration = 5
+
+ //设置本次拉取的视频广告,从用户角度看到的视频播放策略;
+ // 可选项包括自VideoOption.VideoPlayPolicy.AUTO(在用户看来,视频广告是自动播放的)和VideoOption.VideoPlayPolicy.MANUAL(在用户看来,视频广告是手动播放的);
+ // 如果广告位支持视频,强烈建议调用此接口设置视频广告的播放策略,有助于提高eCPM值;如果广告位不支持视频,忽略本接口
+ // ( 默认是:VideoOption.VideoPlayPolicy.AUTO )
+ //GdtProvider.Native.videoPlayPolicy = VideoOption.VideoPlayPolicy.AUTO
+
+ adHelperNative?.getList(listener = object : NativeListener {
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ "onAdStartRequest: $providerType".logi(tag)
+ addLog("\n原生广告开始请求,$providerType")
+ }
+
+ override fun onAdLoaded(providerType: String, adList: List) {
+ //广告请求成功的回调,每次请求只回调一次
+ "onAdLoaded: $providerType, adList: ${adList.size}".logi(tag)
+ addLog("原生广告请求成功,$providerType")
+ mAdObject = adList[0]
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("原生广告单个提供商请求失败了,$providerType, $failedMsg")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("原生广告全部请求失败了")
+ "onAdFailedAll".loge(tag)
+ }
+ })
+ }
+
+ /**
+ * 展示广告
+ */
+ private fun showAd(adObject: Any?, nativeTemplate: BaseNativeTemplate) {
+ if (adObject == null) return
+
+ AdHelperNativePro.show(adObject = adObject, container = adContainer, nativeTemplate = nativeTemplate, listener = object : NativeViewListener {
+ override fun onAdExposed(providerType: String) {
+ //每次曝光就会回调这里一次
+ addLog("原生广告曝光了")
+ "onAdExposed".logi(tag)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //每次点击就会回调这里一次
+ addLog("原生广告点击了")
+ "onAdClicked".logi(tag)
+ }
+ })
+ }
+
+ override fun onPause() {
+ super.onPause()
+ adHelperNative?.pauseAllAd()
+ }
+
+ override fun onResume() {
+ super.onResume()
+ adHelperNative?.resumeAllAd()
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ adHelperNative?.destroyAllAd()
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeExpress2TemplateSimple.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeExpress2TemplateSimple.kt
new file mode 100644
index 0000000..0da46ab
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeExpress2TemplateSimple.kt
@@ -0,0 +1,28 @@
+package com.ifmvo.togetherad.demo.native_.template
+
+import com.ifmvo.togetherad.core.custom.express2.BaseNativeExpress2Template
+import com.ifmvo.togetherad.core.custom.express2.BaseNativeExpress2View
+import com.ifmvo.togetherad.csj.native_.express.NativeExpress2ViewCsj
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.gdt.native_.express2.NativeExpress2ViewGdt
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/27.
+ */
+class NativeExpress2TemplateSimple : BaseNativeExpress2Template() {
+
+ override fun getNativeExpress2View(adProviderType: String): BaseNativeExpress2View? {
+ return when (adProviderType) {
+ AdProviderType.CSJ.type -> {
+ NativeExpress2ViewCsj()
+ }
+ AdProviderType.GDT.type -> {
+ NativeExpress2ViewGdt()
+ }
+ else -> {
+ throw Exception("模板配置错误")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeExpressTemplateSimple.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeExpressTemplateSimple.kt
new file mode 100644
index 0000000..1a77350
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeExpressTemplateSimple.kt
@@ -0,0 +1,24 @@
+package com.ifmvo.togetherad.demo.native_.template
+
+import com.ifmvo.togetherad.core.custom.express.BaseNativeExpressTemplate
+import com.ifmvo.togetherad.core.custom.express.BaseNativeExpressView
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.gdt.native_.express.NativeExpressViewGdt
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/27.
+ */
+class NativeExpressTemplateSimple : BaseNativeExpressTemplate() {
+
+ override fun getNativeExpressView(adProviderType: String): BaseNativeExpressView? {
+ return when (adProviderType) {
+ AdProviderType.GDT.type -> {
+ NativeExpressViewGdt()
+ }
+ else -> {
+ throw Exception("模板配置错误")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple1.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple1.kt
new file mode 100644
index 0000000..71dce45
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple1.kt
@@ -0,0 +1,29 @@
+package com.ifmvo.togetherad.demo.native_.template
+
+import com.ifmvo.togetherad.baidu.native_.view.NativeViewBaiduSimple1
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeTemplate
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeView
+import com.ifmvo.togetherad.csj.native_.view.NativeViewCsjSimple1
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.gdt.native_.view.NativeViewGdtSimple1
+
+/*
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeTemplateSimple1 : BaseNativeTemplate() {
+
+ override fun getNativeView(adProviderType: String): BaseNativeView? {
+ return when (adProviderType) {
+ AdProviderType.BAIDU.type -> {
+ NativeViewBaiduSimple1()
+ }
+ AdProviderType.GDT.type -> {
+ NativeViewGdtSimple1()
+ }
+ AdProviderType.CSJ.type -> {
+ NativeViewCsjSimple1()
+ }
+ else -> throw Exception("模板配置错误")
+ }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple2.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple2.kt
new file mode 100644
index 0000000..b73bc6c
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple2.kt
@@ -0,0 +1,30 @@
+package com.ifmvo.togetherad.demo.native_.template
+
+import com.ifmvo.togetherad.baidu.native_.view.NativeViewBaiduSimple2
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeTemplate
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeView
+import com.ifmvo.togetherad.csj.native_.view.NativeViewCsjSimple2
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.gdt.native_.view.NativeViewGdtSimple2
+
+/**
+ *
+ * Created by Matthew Chen on 2020/8/28.
+ */
+class NativeTemplateSimple2 : BaseNativeTemplate() {
+
+ override fun getNativeView(adProviderType: String): BaseNativeView? {
+ return when (adProviderType) {
+ AdProviderType.GDT.type -> {
+ NativeViewGdtSimple2()
+ }
+ AdProviderType.CSJ.type -> {
+ NativeViewCsjSimple2()
+ }
+ AdProviderType.BAIDU.type -> {
+ NativeViewBaiduSimple2()
+ }
+ else -> throw Exception("模板配置错误")
+ }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple3.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple3.kt
new file mode 100644
index 0000000..8f9a327
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple3.kt
@@ -0,0 +1,31 @@
+package com.ifmvo.togetherad.demo.native_.template
+
+import com.ifmvo.togetherad.baidu.native_.view.NativeViewBaiduSimple3
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeTemplate
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeView
+import com.ifmvo.togetherad.csj.native_.view.NativeViewCsjSimple3
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.gdt.native_.view.NativeViewGdtSimple3
+
+/*
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeTemplateSimple3(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeTemplate() {
+
+ private var mOnClose = onClose
+
+ override fun getNativeView(adProviderType: String): BaseNativeView? {
+ return when (adProviderType) {
+ AdProviderType.GDT.type -> {
+ NativeViewGdtSimple3(mOnClose)
+ }
+ AdProviderType.CSJ.type -> {
+ NativeViewCsjSimple3(mOnClose)
+ }
+ AdProviderType.BAIDU.type -> {
+ NativeViewBaiduSimple3(mOnClose)
+ }
+ else -> throw Exception("模板配置错误")
+ }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple4.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple4.kt
new file mode 100644
index 0000000..30e3d8d
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple4.kt
@@ -0,0 +1,31 @@
+package com.ifmvo.togetherad.demo.native_.template
+
+import com.ifmvo.togetherad.baidu.native_.view.NativeViewBaiduSimple4
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeTemplate
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeView
+import com.ifmvo.togetherad.csj.native_.view.NativeViewCsjSimple4
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.gdt.native_.view.NativeViewGdtSimple4
+
+/*
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeTemplateSimple4(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeTemplate() {
+
+ private var mOnClose = onClose
+
+ override fun getNativeView(adProviderType: String): BaseNativeView? {
+ return when (adProviderType) {
+ AdProviderType.GDT.type -> {
+ NativeViewGdtSimple4(mOnClose)
+ }
+ AdProviderType.CSJ.type -> {
+ NativeViewCsjSimple4(mOnClose)
+ }
+ AdProviderType.BAIDU.type -> {
+ NativeViewBaiduSimple4(mOnClose)
+ }
+ else -> throw Exception("模板配置错误")
+ }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple5.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple5.kt
new file mode 100644
index 0000000..fffa381
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/native_/template/NativeTemplateSimple5.kt
@@ -0,0 +1,31 @@
+package com.ifmvo.togetherad.demo.native_.template
+
+import com.ifmvo.togetherad.baidu.native_.view.NativeViewBaiduSimple5
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeTemplate
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeView
+import com.ifmvo.togetherad.csj.native_.view.NativeViewCsjSimple5
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.gdt.native_.view.NativeViewGdtSimple5
+
+/*
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeTemplateSimple5(onClose: ((providerType: String) -> Unit)? = null) : BaseNativeTemplate() {
+
+ private var mOnClose = onClose
+
+ override fun getNativeView(adProviderType: String): BaseNativeView? {
+ return when (adProviderType) {
+ AdProviderType.GDT.type -> {
+ NativeViewGdtSimple5(mOnClose)
+ }
+ AdProviderType.CSJ.type -> {
+ NativeViewCsjSimple5(mOnClose)
+ }
+ AdProviderType.BAIDU.type -> {
+ NativeViewBaiduSimple5(mOnClose)
+ }
+ else -> throw Exception("模板配置错误")
+ }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/other/ContentDataEntity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/other/ContentDataEntity.kt
new file mode 100644
index 0000000..66a606e
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/other/ContentDataEntity.kt
@@ -0,0 +1,7 @@
+package com.ifmvo.togetherad.demo.other
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/30.
+ */
+class ContentDataEntity(val title: String, val imgUrl: String)
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/other/HelpActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/other/HelpActivity.kt
new file mode 100644
index 0000000..afc30a1
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/other/HelpActivity.kt
@@ -0,0 +1,78 @@
+package com.ifmvo.togetherad.demo.other
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import com.ifmvo.togetherad.demo.R
+import kotlinx.android.synthetic.main.activity_help.*
+
+/**
+ * 采坑指南
+ *
+ * Created by Matthew Chen on 2020/5/22.
+ */
+class HelpActivity : AppCompatActivity() {
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, HelpActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_help)
+
+ val txt = """
+
+广告法要求所有广告必须有广告的标示,否则会有风险。
+原生广告需要特别注意这一点,因为原生自渲染需要开发者自己写布局,而开屏、激励、Banner横幅、这类广告平台会自动添加广告标示。
+
+-------------------------------------------
+
+请求到的广告要尽量展示
+ ↓
+提高展示率、点击率
+ ↓
+提高 ecpm
+ ↓
+提高收入
+
+-------------------------------------------
+
+目前穿山甲和广点通的收入相对最好,建议搭配使用,如果两个平台给的量都比较少再用百度补充
+
+-------------------------------------------
+
+错误码: 2001, 错误信息:初始化错误,详细码:200102
+
+如果广点通返回这个错误信息,就是广点通的初始化出现问题,可能参数有问题、也可能项目混淆导致初始化异常
+
+-------------------------------------------
+
+由于会影响 ecpm,所以设置超时时间一定要慎重,尽量设置平台建议的时间范围或使用默认值
+
+-------------------------------------------
+
+错误码: 40029, 错误信息:两种情况:
+1. SDK版本低;使用的sdk版本过低,还不支持个性化模板渲染功能。解决办法:升级到平台最新版本sdk。
+2. 接口使用错误;创建的代码位类型是模板渲染/非模板渲染,但是请求方法是非模板渲染/模板渲染的方法。
+解决办法:使用模板渲染的方法去请求模板渲染类型或者使用非模板渲染的方法去请求非模板类型的广告,如果代码位在平台上是模板渲染,可以参考文档中个性化模板XX广告的部分,demo中参考带有express部分的代码。
+如果代码位不是模板渲染,则不要调用含有express字样的接口。参考文档:https://partner.oceanengine.com/doc?id=5dd0fe716b181e00112e3eb8
+
+如果穿山甲报这个错误,请及时联系我
+
+-------------------------------------------
+
+gdt: 请求失败了:错误码: 5004, 错误信息:没有广告
+
+优量汇报这个原因可能是请求太频繁,触发了优量汇的防刷量机制,可以等一个小时再试
+
+
+
+
+ """.trimIndent()
+ tvText.text = txt
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/other/MainMenuHelper.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/other/MainMenuHelper.kt
new file mode 100644
index 0000000..8f86d46
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/other/MainMenuHelper.kt
@@ -0,0 +1,165 @@
+package com.ifmvo.togetherad.demo.other
+
+import com.ifmvo.togetherad.demo.MainActivity
+import com.ifmvo.togetherad.demo.banner.BannerActivity
+import com.ifmvo.togetherad.demo.express.NativeExpressRecyclerViewActivity
+import com.ifmvo.togetherad.demo.express.NativeExpressSimpleActivity
+import com.ifmvo.togetherad.demo.express2.NativeExpress2RecyclerViewActivity
+import com.ifmvo.togetherad.demo.express2.NativeExpress2SimpleActivity
+import com.ifmvo.togetherad.demo.fullvideo.FullVideoActivity
+import com.ifmvo.togetherad.demo.hybrid.NativeExpressHybridActivity
+import com.ifmvo.togetherad.demo.hybrid.SplashHybridActivity
+import com.ifmvo.togetherad.demo.hybrid.VerticalPreMovieHybridActivity
+import com.ifmvo.togetherad.demo.inter.InterActivity
+import com.ifmvo.togetherad.demo.native_.NativeRecyclerViewActivity
+import com.ifmvo.togetherad.demo.native_.NativeSimpleActivity
+import com.ifmvo.togetherad.demo.reward.RewardActivity
+import com.ifmvo.togetherad.demo.splash.SplashActivity
+import com.ifmvo.togetherad.demo.splash.SplashHotActivity
+import com.ifmvo.togetherad.demo.splash.SplashProActivity
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/30.
+ */
+object MainMenuHelper {
+
+ const val menuMain = "menuMain"
+ private const val menuSplash = "menuSplash"
+ private const val menuNative = "menuNative"
+ private const val menuNativeExpress = "menuNativeExpress"
+ private const val menuHybrid = "menuHybrid"
+
+ private val menuMainList = arrayListOf(
+ mapOf(
+ "title" to "广告大全 5.0.3",
+ "desc" to "穿山甲3.6.1.1;优量汇4.351.1221;百度5.91"
+ ),
+ mapOf(
+ "title" to "开屏",
+ "desc" to "开屏广告以App启动作为曝光时机,提供5s的可感知广告展示。用户可以点击广告跳转到目标页面;或者点击右上角的“跳过”按钮,跳转到app内容首页",
+ "class" to MainActivity::class.java,
+ "clickMenu" to menuSplash
+ ),
+ mapOf(
+ "title" to "Banner 横幅",
+ "desc" to "Banner广告(横幅广告)位于app顶部、中部、底部任意一处,横向贯穿整个app页面;当用户与app互动时,Banner广告会停留在屏幕上,并可在一段时间后自动刷新",
+ "class" to BannerActivity::class.java
+ ),
+ mapOf(
+ "title" to "Interstitial 插屏广告",
+ "desc" to "在应用开启、暂停、退出时以半屏或全屏的形式弹出,展示时机巧妙避开用户对应用的正常体验。",
+ "class" to InterActivity::class.java
+ ),
+ mapOf(
+ "title" to "原生模板",
+ "desc" to "相比于Banner广告、插屏广告等,原生广告提供了更加灵活、多样化的广告样式选择",
+ "class" to MainActivity::class.java,
+ "clickMenu" to menuNativeExpress
+ ),
+ mapOf(
+ "title" to "原生自渲染",
+ "desc" to "Banner广告、插屏广告等,app会“收到”一个完整的view对象,开发者无法自定义广告view内部的组件布局(文字TextView、图片ImageView),而原生广告自渲染方式支持开发者自由拼合这些素材,最大程度的满足开发需求;与原生广告(模板方式)相比,自渲染方式更加自由灵活,开发者可以使用其为开发者的应用打造自定义的布局样式",
+ "class" to MainActivity::class.java,
+ "clickMenu" to menuNative
+ ),
+ mapOf(
+ "title" to "激励视频广告",
+ "desc" to "激励视频广告是指将短视频融入到app场景当中,成为app“任务”之一,用户观看短视频广告后可以得到一些应用内奖励",
+ "class" to RewardActivity::class.java
+ ),
+ mapOf(
+ "title" to "全屏视频广告",
+ "desc" to "对应的是优量汇的插屏全屏视频和穿山甲的全屏视频广告。全屏视频广告和激励视频广告比较像。差别在于全屏视频广告不需要完整的看完视频,就可以关闭广告。",
+ "class" to FullVideoActivity::class.java
+ ),
+ mapOf(
+ "title" to "混合使用",
+ "desc" to "混合使用就是将不同类型的广告展示在同一个广告位。可以解决一些问题或者可以提高收入,这里就举例一些常用的场景",
+ "class" to MainActivity::class.java,
+ "clickMenu" to menuHybrid
+ ),
+ mapOf(
+ "title" to "采坑指南",
+ "desc" to "持续更新...",
+ "class" to HelpActivity::class.java
+ )
+ )
+
+ private val menuSplashList = arrayListOf(
+ mapOf(
+ "title" to "请求并展示",
+ "desc" to "请求成功后立即自动展示",
+ "class" to SplashHotActivity::class.java
+ ),
+ mapOf(
+ "title" to "请求和展示分开",
+ "desc" to "请求成功后需手动调用展示。可实现预加载",
+ "class" to SplashProActivity::class.java
+ )
+ )
+
+ private val menuNativeList = arrayListOf(
+ mapOf(
+ "title" to "原生自渲染",
+ "desc" to "简单用法",
+ "class" to NativeSimpleActivity::class.java
+ ),
+ mapOf(
+ "title" to "原生自渲染",
+ "desc" to "在 RecyclerView 中使用",
+ "class" to NativeRecyclerViewActivity::class.java
+ )
+ )
+
+ private val menuNativeExpressList = arrayListOf(
+ mapOf(
+ "title" to "原生模板 2.0( 只支持优量汇、穿山甲 )",
+ "desc" to "简单用法",
+ "class" to NativeExpress2SimpleActivity::class.java
+ ),
+ mapOf(
+ "title" to "原生模板 2.0( 只支持优量汇、穿山甲 )",
+ "desc" to "在RecyclerView中的用法",
+ "class" to NativeExpress2RecyclerViewActivity::class.java
+ ),
+ mapOf(
+ "title" to "原生模板 1.0( 只支持优量汇 )",
+ "desc" to "简单用法",
+ "class" to NativeExpressSimpleActivity::class.java
+ ),
+ mapOf(
+ "title" to "原生模板 1.0( 只支持优量汇 )",
+ "desc" to "在RecyclerView中的用法",
+ "class" to NativeExpressRecyclerViewActivity::class.java
+ )
+ )
+
+ private val menuHybridList = arrayListOf(
+ mapOf(
+ "title" to "开屏和原生自渲染混合",
+ "desc" to "如果你的开屏ecpm比较低,就可以使用原生自渲染模拟开屏展示,以提高开屏广告位的收入",
+ "class" to SplashHybridActivity::class.java
+ ),
+ mapOf(
+ "title" to "原生模板1.0和原生模板2.0混合",
+ "desc" to "由于优量汇的原生模板2.0需要向平台申请,所以这里将优量汇的原生模板1.0和穿山甲的原生模板2.0混合使用",
+ "class" to NativeExpressHybridActivity::class.java
+ ),
+ mapOf(
+ "title" to "激励、全屏视频、原生自渲染 混合",
+ "desc" to "自定义需求",
+ "class" to VerticalPreMovieHybridActivity::class.java
+ )
+
+ )
+
+ val map = mapOf(
+ menuMain to menuMainList,
+ menuSplash to menuSplashList,
+ menuNative to menuNativeList,
+ menuNativeExpress to menuNativeExpressList,
+ menuHybrid to menuHybridList
+ )
+
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/reward/RewardActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/reward/RewardActivity.kt
new file mode 100644
index 0000000..279aa82
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/reward/RewardActivity.kt
@@ -0,0 +1,156 @@
+package com.ifmvo.togetherad.demo.reward
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.helper.AdHelperReward
+import com.ifmvo.togetherad.core.listener.RewardListener
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import kotlinx.android.synthetic.main.activity_reward.*
+
+/**
+ * 激励广告使用实例
+ *
+ * Created by Matthew Chen on 2020-04-22.
+ */
+class RewardActivity : AppCompatActivity() {
+
+ private val tag = "RewardActivity"
+
+ private lateinit var adHelperReward: AdHelperReward
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, RewardActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_reward)
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ val ratioMapReward = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+ )
+
+ /**
+ * 穿山甲请求激励广告可选参数
+ * 以下参数均为( 非必传 )
+ */
+// CsjProvider.Reward.userID = "userId_123"
+// CsjProvider.Reward.supportDeepLink = true//默认为true
+// CsjProvider.Reward.rewardName = "金币"//奖励名称
+// CsjProvider.Reward.rewardAmount = 30//奖励数量
+// CsjProvider.Reward.mediaExtra = "TogetherAd"//用户透传的信息
+// //设置期望视频播放的方向,为TTAdConstant.HORIZONTAL或TTAdConstant.VERTICAL。默认是TTAdConstant.VERTICAL
+// CsjProvider.Reward.orientation = TTAdConstant.VERTICAL//默认 TTAdConstant.VERTICAL
+// CsjProvider.Reward.showDownLoadBar = true//不设置默认为true
+
+ /**
+ * activity: 必传。
+ * alias: 必传。广告位的别名。初始化的时候是根据别名设置的广告ID,所以这里TogetherAd会根据别名查找对应的广告位ID。
+ * ratioMap: 非必传。广告商的权重。可以不传或传null,空的情况 TogetherAd 会自动使用初始化时 TogetherAd.setPublicProviderRatio 设置的全局通用权重。
+ * listener: 非必传。如果你不需要监听结果可以不传或传空。各个回调方法也可以选择性添加
+ */
+ adHelperReward = AdHelperReward(activity = this, alias = TogetherAdAlias.AD_REWARD, /*ratioMap = ratioMapReward,*/ listener = object : RewardListener {
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ addLog("\n开始请求: $providerType")
+ "onAdStartRequest: $providerType".logi(tag)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("请求失败: $providerType")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("全部失败")
+ "onAdFailedAll".loge(tag)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //点击广告的回调
+ addLog("点击了: $providerType")
+ "onAdClicked: $providerType".logi(tag)
+ }
+
+ override fun onAdShow(providerType: String) {
+ //广告展示展示的回调
+ addLog("展示了: $providerType")
+ "onAdShow: $providerType".logi(tag)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ //广告请求成功的回调,每次请求只回调一次
+ addLog("请求到了: $providerType")
+ "onAdLoaded: $providerType".logi(tag)
+ }
+
+ override fun onAdExpose(providerType: String) {
+ //广告展示曝光的回调
+ addLog("曝光了: $providerType")
+ "onAdExpose: $providerType".logi(tag)
+ }
+
+ override fun onAdVideoComplete(providerType: String) {
+ //视频播放完成的回调
+ addLog("视频播放完成: $providerType")
+ "onAdVideoComplete: $providerType".logi(tag)
+ }
+
+ override fun onAdVideoCached(providerType: String) {
+ //视频缓存完成的回调
+ addLog("视频已缓存: $providerType")
+ "onAdVideoCached: $providerType".logi(tag)
+ }
+
+ override fun onAdRewardVerify(providerType: String) {
+ //激励结果验证成功的回调
+ addLog("激励验证,$providerType")
+ "onAdRewardVerify,$providerType".logi(tag)
+
+// //如果 csj 使用到服务器到服务器回调功能,需要进行以下判断,gdt、baidu都不需要此判断
+// if (providerType == AdProviderType.CSJ.type && CsjProvider.Reward.rewardVerify) {
+// ... 验证成功后的操作
+// }
+ }
+
+ override fun onAdClose(providerType: String) {
+ //广告被关闭的回调
+ addLog("关闭了: $providerType")
+ "onAdClose: $providerType".logi(tag)
+ }
+ })
+
+ btnRequest.setOnClickListener {
+ //开始请求广告
+ adHelperReward.load()
+ }
+
+ btnShow.setOnClickListener {
+ //onAdLoaded 回调之后才能展示
+ adHelperReward.show()
+ }
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashActivity.kt
new file mode 100644
index 0000000..4f47ef4
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashActivity.kt
@@ -0,0 +1,184 @@
+package com.ifmvo.togetherad.demo.splash
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.custom.splashSkip.SplashSkipViewSimple2
+import com.ifmvo.togetherad.core.helper.AdHelperSplash
+import com.ifmvo.togetherad.core.listener.SplashListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.core.utils.dp
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+import com.ifmvo.togetherad.demo.MainActivity
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.gdt.provider.GdtProvider
+import kotlinx.android.synthetic.main.activity_splash.*
+
+/**
+ * 开屏广告使用示例
+ *
+ * Created by Matthew Chen on 2020-04-17.
+ */
+class SplashActivity : AppCompatActivity() {
+
+ private val tag = "SplashActivity"
+
+ //是否可以跳转,逻辑 copy from gdt demo
+ private var canJump = false
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, SplashActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_splash)
+
+ //开始请求开屏广告
+ requestSplashAd()
+ }
+
+ /**
+ * 请求开屏广告
+ */
+ private fun requestSplashAd() {
+
+ /**
+ * 设置 开屏广告 自定义跳过按钮
+ * TogetherAd 提供了两个简单的实例模板,同时只能设置一个,如果设置多个后面的生效
+ */
+ GdtProvider.Splash.customSkipView = SplashSkipViewSimple2()
+ //GdtProvider.Splash.customSkipView = SplashSkipViewSimple1()
+ CsjProvider.Splash.customSkipView = SplashSkipViewSimple2()
+ /**
+ * 设置 广点通 开屏广告超时时间
+ * fetchDelay 参数,设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),
+ * 取值范围为[3000, 5000]ms。
+ * 如果需要使用默认值,可以给 fetchDelay 设为0或者不设置。
+ */
+ //GdtProvider.Splash.maxFetchDelay = 0
+
+ /**
+ * 给 穿山甲 设置可接受的图片尺寸,避免图片变形
+ * 一般设置容器的宽高即可
+ */
+ CsjProvider.Splash.setImageAcceptedSize(ScreenUtil.getDisplayMetricsWidth(this), ScreenUtil.getDisplayMetricsHeight(this) - 100f.dp.toInt())
+
+ /**
+ * 设置 穿山甲 开屏广告超时时间
+ * fetchDelay 参数,设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),
+ * 如果不设置,默认值为 3000ms
+ */
+ //CsjProvider.Splash.maxFetchDelay = 3000
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ val ratioMapSplash = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+ )
+
+ /**
+ * activity: 必传。这里不是 Context,因为广点通必须传 Activity,所以统一传 Activity。
+ * alias: 必传。广告位的别名。初始化的时候是根据别名设置的广告ID,所以这里TogetherAd会根据别名查找对应的广告位ID。
+ * ratioMap: 非必传。广告商的权重。可以不传或传null,空的情况 TogetherAd 会自动使用初始化时 TogetherAd.setPublicProviderRatio 设置的全局通用权重。
+ * container: 必传。请求到广告之后会自动添加到 container 这个布局中展示。
+ * listener: 非必传。如果你不需要监听结果可以不传或传空。各个回调方法也可以选择性添加
+ */
+ AdHelperSplash.show(activity = this, alias = TogetherAdAlias.AD_SPLASH, /*ratioMap = ratioMapSplash,*/ container = adContainer, listener = object : SplashListener {
+
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ addLog("\n开屏广告开始请求,$providerType")
+ "onAdStartRequest: $providerType".logi(tag)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ //广告请求成功的回调,每次请求只回调一次
+ addLog("开屏广告请求好了,$providerType")
+ "onAdLoaded: $providerType".logi(tag)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //点击广告的回调
+ addLog("开屏广告被点击了,$providerType")
+ "onAdClicked: $providerType".logi(tag)
+ }
+
+ override fun onAdExposure(providerType: String) {
+ //广告展示曝光的回调
+ addLog("开屏广告曝光了,$providerType")
+ "onAdExposure: $providerType".logi(tag)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("开屏广告单个提供商请求失败了,$failedMsg, $providerType")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("全部请求失败了")
+ "onAdFailedAll".loge(tag)
+ actionHome(1000)
+ }
+
+ override fun onAdDismissed(providerType: String) {
+ //开屏广告消失了,点了跳过按钮或者倒计时结束之后会回调一次
+ //在这里跳转主界面,并关闭 Splash
+ addLog("开屏广告点了跳过或者倒计时结束, $providerType")
+ "onAdDismissed: $providerType".logi(tag)
+ actionHome()
+ }
+ })
+ //回调中的 providerType 是广告商类型
+ }
+
+ //不能手动返回
+ override fun onBackPressed() {}
+
+ override fun onResume() {
+ super.onResume()
+ if (canJump) {
+ actionHome()
+ }
+ canJump = true
+ }
+
+ override fun onPause() {
+ super.onPause()
+ canJump = false
+ }
+
+ private fun actionHome(delayMillis: Long = 0) {
+
+ if (!canJump) {
+ canJump = true
+ return
+ }
+
+ adContainer.postDelayed({
+ //在这里跳转到 Home 主界面
+ MainActivity.action(this)
+ finish()
+ }, delayMillis)
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashHotActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashHotActivity.kt
new file mode 100644
index 0000000..303cc2a
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashHotActivity.kt
@@ -0,0 +1,155 @@
+package com.ifmvo.togetherad.demo.splash
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.custom.splashSkip.SplashSkipViewSimple2
+import com.ifmvo.togetherad.core.helper.AdHelperSplash
+import com.ifmvo.togetherad.core.listener.SplashListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.core.utils.dp
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.gdt.provider.GdtProvider
+import kotlinx.android.synthetic.main.activity_splash.*
+
+class SplashHotActivity : AppCompatActivity() {
+
+ private val tag = "SplashActivity"
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, SplashHotActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_splash)
+
+ //开始请求开屏广告
+ requestSplashAd()
+ }
+
+ /**
+ * 请求开屏广告
+ */
+ private fun requestSplashAd() {
+
+ /**
+ * 设置 开屏广告 自定义跳过按钮
+ * TogetherAd 提供了两个简单的实例模板,同时只能设置一个,如果设置多个后面的生效
+ */
+ GdtProvider.Splash.customSkipView = SplashSkipViewSimple2()
+ //GdtProvider.Splash.customSkipView = SplashSkipViewSimple1()
+ CsjProvider.Splash.customSkipView = SplashSkipViewSimple2()
+ /**
+ * 设置 广点通 开屏广告超时时间
+ * fetchDelay 参数,设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),
+ * 取值范围为[3000, 5000]ms。
+ * 如果需要使用默认值,可以给 fetchDelay 设为0或者不设置。
+ */
+ //GdtProvider.Splash.maxFetchDelay = 0
+
+ /**
+ * 给 穿山甲 设置可接受的图片尺寸,避免图片变形
+ * 一般设置容器的宽高即可
+ */
+ CsjProvider.Splash.setImageAcceptedSize(ScreenUtil.getDisplayMetricsWidth(this), ScreenUtil.getDisplayMetricsHeight(this) - 100f.dp.toInt())
+
+ /**
+ * 设置 穿山甲 开屏广告超时时间
+ * fetchDelay 参数,设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),
+ * 如果不设置,默认值为 3000ms
+ */
+ //CsjProvider.Splash.maxFetchDelay = 3000
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ val ratioMapSplash = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+ )
+
+ /**
+ * activity: 必传。这里不是 Context,因为广点通必须传 Activity,所以统一传 Activity。
+ * alias: 必传。广告位的别名。初始化的时候是根据别名设置的广告ID,所以这里TogetherAd会根据别名查找对应的广告位ID。
+ * ratioMap: 非必传。广告商的权重。可以不传或传null,空的情况 TogetherAd 会自动使用初始化时 TogetherAd.setPublicProviderRatio 设置的全局通用权重。
+ * container: 必传。请求到广告之后会自动添加到 container 这个布局中展示。
+ * listener: 非必传。如果你不需要监听结果可以不传或传空。各个回调方法也可以选择性添加
+ */
+ AdHelperSplash.show(activity = this, alias = TogetherAdAlias.AD_SPLASH_HOT, /*ratioMap = ratioMapSplash,*/ container = adContainer, listener = object : SplashListener {
+
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ addLog("\n开屏广告开始请求,$providerType")
+ "onAdStartRequest: $providerType".logi(tag)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ //广告请求成功的回调,每次请求只回调一次
+ addLog("开屏广告请求好了,$providerType")
+ "onAdLoaded: $providerType".logi(tag)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //点击广告的回调
+ addLog("开屏广告被点击了,$providerType")
+ "onAdClicked: $providerType".logi(tag)
+ }
+
+ override fun onAdExposure(providerType: String) {
+ //广告展示曝光的回调
+ addLog("开屏广告曝光了,$providerType")
+ "onAdExposure: $providerType".logi(tag)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("开屏广告单个提供商请求失败了,$failedMsg, $providerType")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("全部请求失败了")
+ "onAdFailedAll".loge(tag)
+ actionHome(1000)
+ }
+
+ override fun onAdDismissed(providerType: String) {
+ //开屏广告消失了,点了跳过按钮或者倒计时结束之后会回调一次
+ //在这里跳转主界面,并关闭 Splash
+ addLog("开屏广告点了跳过或者倒计时结束, $providerType")
+ "onAdDismissed: $providerType".logi(tag)
+ actionHome(0)
+ }
+ })
+ //回调中的 providerType 是广告商类型
+ }
+
+ //不能手动返回
+ override fun onBackPressed() {}
+
+ private fun actionHome(delayMillis: Long) {
+ adContainer.postDelayed({
+ //在这里只关闭当前页即可
+ finish()
+ }, delayMillis)
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashProActivity.kt b/demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashProActivity.kt
new file mode 100644
index 0000000..ab3bd84
--- /dev/null
+++ b/demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashProActivity.kt
@@ -0,0 +1,183 @@
+package com.ifmvo.togetherad.demo.splash
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.view.View
+import com.ifmvo.togetherad.core.custom.splashSkip.SplashSkipViewSimple2
+import com.ifmvo.togetherad.core.helper.AdHelperSplashPro
+import com.ifmvo.togetherad.core.listener.SplashListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.core.utils.dp
+import com.ifmvo.togetherad.core.utils.loge
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.csj.provider.CsjProvider
+import com.ifmvo.togetherad.demo.R
+import com.ifmvo.togetherad.demo.app.AdProviderType
+import com.ifmvo.togetherad.demo.app.TogetherAdAlias
+import com.ifmvo.togetherad.gdt.provider.GdtProvider
+import kotlinx.android.synthetic.main.activity_splash_pro.*
+
+/**
+ * 开屏广告使用示例
+ *
+ * Created by Matthew Chen on 2020-04-17.
+ */
+class SplashProActivity : AppCompatActivity() {
+
+ private val tag = "SplashProActivity"
+
+ private val adHelperSplashPro by lazy {
+ /**
+ * 使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ */
+ val ratioMapSplash = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1
+ )
+ /**
+ * activity: 必传。这里不是 Context,因为广点通必须传 Activity,所以统一传 Activity。
+ * alias: 必传。广告位的别名。初始化的时候是根据别名设置的广告ID,所以这里TogetherAd会根据别名查找对应的广告位ID。
+ * ratioMap: 非必传。广告商的权重。可以不传或传null,空的情况 TogetherAd 会自动使用初始化时 TogetherAd.setPublicProviderRatio 设置的全局通用权重。
+ */
+ AdHelperSplashPro(activity = this, alias = TogetherAdAlias.AD_SPLASH/*, ratioMap = ratioMapSplash*/)
+ }
+
+ companion object {
+ fun action(context: Context) {
+ context.startActivity(Intent(context, SplashProActivity::class.java))
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_splash_pro)
+
+ btnLoad.setOnClickListener {
+ //开始请求开屏广告
+ requestSplashAd()
+ }
+
+ btnShow.setOnClickListener {
+ //展示广告
+ showSplashAd()
+ }
+
+ }
+
+ /**
+ * 请求开屏广告
+ */
+ private fun requestSplashAd() {
+
+ /**
+ * 设置 开屏广告 自定义跳过按钮
+ * TogetherAd 提供了两个简单的实例模板,同时只能设置一个,如果设置多个后面的生效
+ */
+ GdtProvider.Splash.customSkipView = SplashSkipViewSimple2()//广点通
+ CsjProvider.Splash.customSkipView = SplashSkipViewSimple2()//穿山甲
+ //GdtProvider.Splash.customSkipView = SplashSkipViewSimple1()
+ /**
+ * 给 穿山甲 设置可接受的图片尺寸,避免图片变形
+ * 一般设置容器的宽高即可
+ */
+ CsjProvider.Splash.setImageAcceptedSize(ScreenUtil.getDisplayMetricsWidth(this), ScreenUtil.getDisplayMetricsHeight(this) - 100f.dp.toInt())
+ /**
+ * 设置 穿山甲 开屏广告超时时间
+ * fetchDelay 参数,设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),
+ * 如果不设置,默认值为 4000ms
+ */
+ CsjProvider.Splash.maxFetchDelay = 4000
+ /**
+ * 设置 优量汇 开屏广告超时时间
+ * 取值范围为[3000, 5000]ms。
+ * 如果不设置,会使用默认值 4000ms
+ */
+ GdtProvider.Splash.maxFetchDelay = 4000
+
+ /**
+ * listener: 非必传。如果你不需要监听结果可以不传或传空。各个回调方法也可以选择性添加
+ */
+ adHelperSplashPro.loadOnly(listener = object : SplashListener {
+
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ addLog("\n开屏广告开始请求,$providerType")
+ "onAdStartRequest: $providerType".logi(tag)
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ btnShow.isEnabled = true
+ //广告请求成功的回调,每次请求只回调一次
+ addLog("开屏广告请求好了,$providerType")
+ "onAdLoaded: $providerType".logi(tag)
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //点击广告的回调
+ addLog("开屏广告被点击了,$providerType")
+ "onAdClicked: $providerType".logi(tag)
+ }
+
+ override fun onAdExposure(providerType: String) {
+ //广告展示曝光的回调
+ addLog("开屏广告曝光了,$providerType")
+ "onAdExposure: $providerType".logi(tag)
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ addLog("开屏广告单个提供商请求失败了,$failedMsg, $providerType")
+ "onAdFailed: $providerType: $failedMsg".loge(tag)
+ }
+
+ override fun onAdFailedAll(failedMsg: String?) {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ addLog("全部请求失败了")
+ "onAdFailedAll".loge(tag)
+ actionHome(1000)
+ }
+
+ override fun onAdDismissed(providerType: String) {
+ //开屏广告消失了,点了跳过按钮或者倒计时结束之后会回调一次
+ //在这里跳转主界面,并关闭 Splash
+ addLog("开屏广告点了跳过或者倒计时结束, $providerType")
+ "onAdDismissed: $providerType".logi(tag)
+ actionHome(0)
+ }
+ })
+ //回调中的 providerType 是广告商类型
+ }
+
+ /**
+ * 展示开屏广告
+ */
+ private fun showSplashAd() {
+ //展示广告并返回是否展示成功
+ val showAdIsSuccess = adHelperSplashPro.showAd(adContainer)
+ //如果没有展示成功就直接跳走
+ if (!showAdIsSuccess) {
+ actionHome(1000)
+ }
+ }
+
+ //不能手动返回
+ override fun onBackPressed() {}
+
+ private fun actionHome(delayMillis: Long) {
+ adContainer.postDelayed({
+ //在这里跳转到 Home 主界面
+ finish()
+ }, delayMillis)
+ }
+
+ private var logStr = "日志: \n"
+
+ private fun addLog(content: String?) {
+ logStr = logStr + content + "\n"
+ log.text = logStr
+
+ info.post { info.fullScroll(View.FOCUS_DOWN) }
+ }
+}
\ No newline at end of file
diff --git a/demo/src/main/res/drawable-v24/ic_launcher_foreground.xml b/demo/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..1f6bb29
--- /dev/null
+++ b/demo/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/src/main/res/drawable/ic_launcher_background.xml b/demo/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..0d025f9
--- /dev/null
+++ b/demo/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/src/main/res/drawable/ic_launcher_foreground.xml b/demo/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..8617672
--- /dev/null
+++ b/demo/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_banner.xml b/demo/src/main/res/layout/activity_banner.xml
new file mode 100644
index 0000000..d072bdf
--- /dev/null
+++ b/demo/src/main/res/layout/activity_banner.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_browser.xml b/demo/src/main/res/layout/activity_browser.xml
new file mode 100644
index 0000000..878c616
--- /dev/null
+++ b/demo/src/main/res/layout/activity_browser.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_full_video.xml b/demo/src/main/res/layout/activity_full_video.xml
new file mode 100644
index 0000000..b6a3ee0
--- /dev/null
+++ b/demo/src/main/res/layout/activity_full_video.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_help.xml b/demo/src/main/res/layout/activity_help.xml
new file mode 100644
index 0000000..baa7e7d
--- /dev/null
+++ b/demo/src/main/res/layout/activity_help.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_inter.xml b/demo/src/main/res/layout/activity_inter.xml
new file mode 100644
index 0000000..5ae9560
--- /dev/null
+++ b/demo/src/main/res/layout/activity_inter.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_native_express_hybrid.xml b/demo/src/main/res/layout/activity_native_express_hybrid.xml
new file mode 100644
index 0000000..ab73776
--- /dev/null
+++ b/demo/src/main/res/layout/activity_native_express_hybrid.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_native_express_simple.xml b/demo/src/main/res/layout/activity_native_express_simple.xml
new file mode 100644
index 0000000..ab73776
--- /dev/null
+++ b/demo/src/main/res/layout/activity_native_express_simple.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_native_recyclerview.xml b/demo/src/main/res/layout/activity_native_recyclerview.xml
new file mode 100644
index 0000000..5979cf7
--- /dev/null
+++ b/demo/src/main/res/layout/activity_native_recyclerview.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/demo/src/main/res/layout/activity_native_simple.xml b/demo/src/main/res/layout/activity_native_simple.xml
new file mode 100644
index 0000000..965343d
--- /dev/null
+++ b/demo/src/main/res/layout/activity_native_simple.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_reward.xml b/demo/src/main/res/layout/activity_reward.xml
new file mode 100644
index 0000000..f7856c5
--- /dev/null
+++ b/demo/src/main/res/layout/activity_reward.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_splash.xml b/demo/src/main/res/layout/activity_splash.xml
new file mode 100644
index 0000000..a361792
--- /dev/null
+++ b/demo/src/main/res/layout/activity_splash.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_splash_pro.xml b/demo/src/main/res/layout/activity_splash_pro.xml
new file mode 100644
index 0000000..a92fdd8
--- /dev/null
+++ b/demo/src/main/res/layout/activity_splash_pro.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/activity_vertical_premovie.xml b/demo/src/main/res/layout/activity_vertical_premovie.xml
new file mode 100644
index 0000000..8bd1b39
--- /dev/null
+++ b/demo/src/main/res/layout/activity_vertical_premovie.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/list_item_main.xml b/demo/src/main/res/layout/list_item_main.xml
new file mode 100644
index 0000000..df2f33b
--- /dev/null
+++ b/demo/src/main/res/layout/list_item_main.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/list_item_native_ad.xml b/demo/src/main/res/layout/list_item_native_ad.xml
new file mode 100644
index 0000000..30f97a6
--- /dev/null
+++ b/demo/src/main/res/layout/list_item_native_ad.xml
@@ -0,0 +1,5 @@
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/layout/list_item_native_content.xml b/demo/src/main/res/layout/list_item_native_content.xml
new file mode 100644
index 0000000..2cffbf4
--- /dev/null
+++ b/demo/src/main/res/layout/list_item_native_content.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/demo/src/main/res/mipmap-hdpi/ic_launcher.png b/demo/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..21dfab6
Binary files /dev/null and b/demo/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/demo/src/main/res/mipmap-hdpi/ic_launcher_round.png b/demo/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..49a1643
Binary files /dev/null and b/demo/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/demo/src/main/res/mipmap-mdpi/ic_launcher.png b/demo/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..495cae1
Binary files /dev/null and b/demo/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/demo/src/main/res/mipmap-mdpi/ic_launcher_round.png b/demo/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..d483e2a
Binary files /dev/null and b/demo/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/demo/src/main/res/mipmap-xhdpi/ic_launcher.png b/demo/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..3f8b1cf
Binary files /dev/null and b/demo/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..c494a78
Binary files /dev/null and b/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png b/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..14d4b00
Binary files /dev/null and b/demo/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..020e338
Binary files /dev/null and b/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..a5ea4b5
Binary files /dev/null and b/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..0c053a5
Binary files /dev/null and b/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/demo/src/main/res/values/colors.xml b/demo/src/main/res/values/colors.xml
new file mode 100644
index 0000000..69b2233
--- /dev/null
+++ b/demo/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #008577
+ #00574B
+ #D81B60
+
diff --git a/demo/src/main/res/values/ic_launcher_background.xml b/demo/src/main/res/values/ic_launcher_background.xml
new file mode 100644
index 0000000..c5d5899
--- /dev/null
+++ b/demo/src/main/res/values/ic_launcher_background.xml
@@ -0,0 +1,4 @@
+
+
+ #FFFFFF
+
\ No newline at end of file
diff --git a/demo/src/main/res/values/strings.xml b/demo/src/main/res/values/strings.xml
new file mode 100644
index 0000000..ef2a9f9
--- /dev/null
+++ b/demo/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ 广告大全
+
diff --git a/demo/src/main/res/values/styles.xml b/demo/src/main/res/values/styles.xml
new file mode 100644
index 0000000..13246c2
--- /dev/null
+++ b/demo/src/main/res/values/styles.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/doc/banner.md b/doc/banner.md
new file mode 100644
index 0000000..f41e637
--- /dev/null
+++ b/doc/banner.md
@@ -0,0 +1,7 @@
+# Banner 横幅广告
+
+Banner广告(横幅广告)位于app顶部、中部、底部任意一处,横向贯穿整个app页面;当用户与app互动时,Banner广告会停留在屏幕上,并可在一段时间后自动刷新
+
+—— 引自广点通文档
+
+详情可查看 Demo 中 [Banner横幅广告的示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/banner/BannerActivity.kt)
\ No newline at end of file
diff --git a/doc/express.md b/doc/express.md
new file mode 100644
index 0000000..dc69713
--- /dev/null
+++ b/doc/express.md
@@ -0,0 +1,7 @@
+# 原生模板广告
+
+使用方法和原生信息流差不多,直接看代码更好一点
+
+详情可查看 Demo 中 [原生模板2.0广告的简单用法示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2SimpleActivity.kt)
+
+详情可查看 Demo 中 [原生模板2.0广告在RecyclerView中使用示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/express2/NativeExpress2RecyclerViewActivity.kt)
\ No newline at end of file
diff --git a/doc/extend.md b/doc/extend.md
new file mode 100644
index 0000000..2c528b6
--- /dev/null
+++ b/doc/extend.md
@@ -0,0 +1,207 @@
+# 扩展
+
+### 扩展现有的 Provider
+[CsjProvider.kt](../csj/src/main/java/com/ifmvo/togetherad/csj/CsjProvider.kt)、[GdtProvider.kt](../gdt/src/main/java/com/ifmvo/togetherad/gdt/GdtProvider.kt)、[BaiduProvider.kt](../baidu/src/main/java/com/ifmvo/togetherad/baidu/BaiduProvider.kt)
+
+这三个文件分别是穿山甲、广点通、百青藤真正请求广告的代码,如果现有的Provider不符合你的需求,你可以通过``继承``的方式,按照自己的需求,对其他相应的方法进行``重写``。
+
+以 Csj 的 Banner 广告为例,目前穿山甲只允许创建模板类型的 Banner 广告,CsjProvider.kt 中使用的就是通过 loadBannerExpressAd 方法请求模板类型Banner。如果你想用原生类型Banner,可以通过以下方式进行自定义:
+
+```kotlin
+class CustomCsjProvider : CsjProvider() {
+
+ private val tag = "CustomCsjProvider"
+
+ object Banner {
+
+ var supportDeepLink: Boolean = true
+
+ //图片的宽高
+ internal var imageAcceptedSizeWidth = 600
+
+ internal var imageAcceptedSizeHeight = 257
+
+ fun setImageAcceptedSize(width: Int, height: Int) {
+ imageAcceptedSizeWidth = width
+ imageAcceptedSizeHeight = height
+ }
+
+ //Banner 刷新间隔时间
+ var slideIntervalTime = 30 * 1000
+ }
+
+ override fun showBannerAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: BannerListener) {
+ callbackBannerStartRequest(adProviderType, alias, listener)
+
+ destroyBannerAd()
+
+ val adSlot = AdSlot.Builder()
+ .setCodeId(TogetherAdCsj.idMapCsj[alias]) //广告位id
+ .setSupportDeepLink(Banner.supportDeepLink)
+ .setImageAcceptedSize(Banner.imageAcceptedSizeWidth, Banner.imageAcceptedSizeHeight)
+ .build()
+
+ TogetherAdCsj.mTTAdManager.createAdNative(activity).loadBannerAd(adSlot, object : TTAdNative.BannerAdListener {
+ override fun onBannerAdLoad(bannerAd: TTBannerAd?) {
+ if (bannerAd == null) {
+ callbackBannerFailed(adProviderType, alias, listener, "请求成功,但是返回的 bannerAd 为空")
+ return
+ }
+
+ val bannerView = bannerAd.bannerView
+ if (bannerView == null) {
+ callbackBannerFailed(adProviderType, alias, listener, "请求成功,但是返回的 bannerView 为空")
+ return
+ }
+
+ callbackBannerLoaded(adProviderType, alias, listener)
+
+ bannerAd.setSlideIntervalTime(Banner.slideIntervalTime)
+ container.removeAllViews()
+ container.addView(bannerView)
+
+ bannerAd.setBannerInteractionListener(object : TTBannerAd.AdInteractionListener {
+ override fun onAdClicked(view: View?, type: Int) {
+ callbackBannerClicked(adProviderType, listener)
+ }
+
+ override fun onAdShow(view: View?, type: Int) {
+ callbackBannerExpose(adProviderType, listener)
+ }
+ })
+
+ bannerAd.setShowDislikeIcon(object : TTAdDislike.DislikeInteractionCallback {
+ override fun onSelected(position: Int, value: String?) {
+ container.removeAllViews()
+ callbackBannerClosed(adProviderType, listener)
+ }
+
+ override fun onCancel() {}
+ override fun onRefuse() {}
+ })
+ }
+
+ override fun onError(errorCode: Int, errorMsg: String?) {
+ "onError".loge(tag)
+ callbackBannerFailed(adProviderType, alias, listener, "错误码:$errorCode, 错误信息:$errorMsg")
+ }
+ })
+ }
+
+}
+```
+
+然后 Application 中初始化时的代码修改:
+
+```kotlin
+TogetherAdCsj.init(context = this, adProviderType = AdProviderType.CSJ.type, csjAdAppId = "5001121", appName = this.getString(R.string.app_name), providerClassPath = CustomCsjProvider::class.java.name)
+```
+
+### 新增自定义 Provider
+
+同样的原理,如果穿山甲、广点通、百青藤这三个平台已经满足不了你,你还想再加一个其他的广告平台,那你就可以这样,自定义一个Provider:
+
+```Kotlin
+/**
+ * 自定义小米广告提供商
+ *
+ * 根据其他 Provider 可自行实现广告请求逻辑
+ *
+ * Created by Matthew Chen on 2020/10/23.
+ */
+class XiaomiProvider: BaseAdProvider() {
+
+ override fun showSplashAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: SplashListener) {}
+
+ override fun showBannerAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: BannerListener) {}
+
+ override fun destroyBannerAd() {}
+
+ override fun requestInterAd(activity: Activity, adProviderType: String, alias: String, listener: InterListener) {}
+
+ override fun showInterAd(activity: Activity) {}
+
+ override fun destroyInterAd() {}
+
+ override fun getNativeAdList(activity: Activity, adProviderType: String, alias: String, maxCount: Int, listener: NativeListener) {}
+
+ override fun nativeAdIsBelongTheProvider(adObject: Any): Boolean { return false }
+
+ override fun resumeNativeAd(adObject: Any) {}
+
+ override fun pauseNativeAd(adObject: Any) {}
+
+ override fun destroyNativeAd(adObject: Any) {}
+
+ override fun requestRewardAd(activity: Activity, adProviderType: String, alias: String, listener: RewardListener) {}
+
+ override fun showRewardAd(activity: Activity) {}
+}
+```
+
+再创建一个文件模仿 TogetherAdGdt 自定义小米的初始化
+
+```
+/**
+ * 自定义小米初始化
+ *
+ * Created by Matthew Chen on 2020/10/23.
+ */
+object TogetherAdXiaomi {
+
+ var idMapXiaomi = mapOf()
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull xiaomiAdAppId: String) {
+ init(context, adProviderType, xiaomiAdAppId, null, null)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull xiaomiAdAppId: String, providerClassPath: String? = null) {
+ init(context, adProviderType, xiaomiAdAppId, null, providerClassPath)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull xiaomiAdAppId: String, xiaomiIdMap: Map? = null) {
+ init(context, adProviderType, xiaomiAdAppId, xiaomiIdMap, null)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull xiaomiAdAppId: String, xiaomiIdMap: Map? = null, providerClassPath: String? = null) {
+ TogetherAd.addProvider(AdProviderEntity(adProviderType, if (providerClassPath?.isEmpty() != false) XiaomiProvider::class.java.name else providerClassPath))
+ xiaomiIdMap?.let { idMapXiaomi = it }
+
+ //小米SDK初始化
+ }
+
+}
+```
+
+枚举里面添加``XIAOMI``
+
+```kotlin
+/*
+ * 广告提供商枚举
+ *
+ * Created by Matthew_Chen on 2018/8/23.
+ */
+enum class AdProviderType(val type: String) {
+
+ //百度 Mob ( 百青藤 )
+ BAIDU("baidu"),
+
+ //腾讯的广点通( 优量汇 )
+ GDT("gdt"),
+
+ //穿山甲
+ CSJ("csj"),
+
+ //小米
+ XIAOMI("xiaomi")
+
+}
+```
+
+最后不要忘记再Application中初始化:
+
+```kotlin
+TogetherAdXiaomi.init(context = this, adProviderType = AdProviderType.XIAOMI.type, xiaomiAdAppId = "xxxxxxxx")
+```
+
+以上只是举例子,更多扩展同理。
\ No newline at end of file
diff --git a/doc/feature.md b/doc/feature.md
new file mode 100644
index 0000000..efd5106
--- /dev/null
+++ b/doc/feature.md
@@ -0,0 +1,27 @@
+## 特色功能
+
+### 1. 主流SDK随意搭配组合
+
+实际项目中,往往会接入多家广告SDK,以实现收益最大化的目的。
+
+``TogetherAd``帮助开发者将其集成在一起,开发者可以任选组合进行搭配使用
+
+### 2. 支持权重配置
+
+因为各个平台分发广告的量以及价格都是不一样的,所以需要动态配置请求的比例。
+
+例如:有三家广告平台 A、B、C,你认为 A 的单价和收入都是最高的,想要多展示一点。
+
+那么可以配置他们的权重:A:B:C = 2:1:1
+
+``TogetherAd`` 会根据配置的权重随机请求一家平台的广告,如果请求广告的总数是 40000 次。
+
+那么每家平台请求的次数就会趋近于:A: 20000, B:10000, C:10000
+
+### 3. 支持失败切换
+
+如果某个平台的广告请求失败或没有量,会自动在其他广告中随机出一种再次请求,这样可以尽可能多的展示广告,使收益最大化
+
+![](../img/TogetherAd.png)
+
+![](../img/TogetherAd_Feature.png)
\ No newline at end of file
diff --git a/doc/full_video.md b/doc/full_video.md
new file mode 100644
index 0000000..8edc087
--- /dev/null
+++ b/doc/full_video.md
@@ -0,0 +1,9 @@
+# 全屏视频广告
+
+全屏视频广告,该广告的效果播放全屏的视频,视频一定时间后可跳过,无需全程观看完。
+
+—— 引自穿山甲文档
+
+整体和激励广告差不多,只有穿山甲提供
+
+可查看 Demo 中 [全屏视频广告的示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/fullvideo/FullVideoActivity.kt)
\ No newline at end of file
diff --git a/doc/hybrid.md b/doc/hybrid.md
new file mode 100644
index 0000000..751831c
--- /dev/null
+++ b/doc/hybrid.md
@@ -0,0 +1,15 @@
+# 混合使用
+
+实际项目中我们可能遇到这样的情况:
+
+广点通的开屏广告ecpm很低,但是它的原生自渲染ecpm很高,那我们是不是可以使用原生自渲染伪装成开屏来代替广点通自己的开屏广告呢?这样收益岂不是更高!
+
+所以 TogetherAd 提供了混合使用的方案:
+
+调用开屏广告时,如果随机到csj和baidu就调用其开屏进行展示,如果随机到gdt就使用原生信息流伪装成开屏再进行展示。
+
+详情可查看 Demo 中 [开屏广告混合使用的示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/hybrid/SplashHybridActivity.kt)
+
+这里只举了一个开屏的例子,其他广告类型同理。
+
+**原生自渲染可以和任何类型的广告混合使用。**
\ No newline at end of file
diff --git a/doc/inter.md b/doc/inter.md
new file mode 100644
index 0000000..756ffe1
--- /dev/null
+++ b/doc/inter.md
@@ -0,0 +1,3 @@
+# Interstitial 插屏广告
+
+可查看 Demo 中 [Interstitial插屏广告的示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/inter/InterActivity.kt)
\ No newline at end of file
diff --git a/doc/native.md b/doc/native.md
new file mode 100644
index 0000000..485cb32
--- /dev/null
+++ b/doc/native.md
@@ -0,0 +1,137 @@
+# 原生自渲染广告
+
+原生广告自渲染方式支持开发者自由拼合素材,最大程度的满足开发需求;与原生广告(模板方式)相比,自渲染方式更加自由灵活,开发者可以使用其为开发者的应用打造自定义的布局样式
+
+—— 引自广点通文档
+
+### 声明并初始化
+
+```kotlin
+class NativeSimpleActivity : AppCompatActivity() {
+ //声明
+ private var adHelperNative: AdHelperNativePro? = null
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_flow_simple)
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ val ratioMapNativeSimple = linkedMapOf(
+ AdProviderType.GDT.type to 3,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+ )
+
+ //初始化 maxCount: 返回广告的最大个数 ( 由于各个广告提供商返回的广告数量不等,所以只能控制返回广告的最大数量。例:maxCount = 4,返回的 1 ≤ List.size ≤ 4 )
+ adHelperNative = AdHelperNativePro(activity = this, alias = TogetherAdAlias.AD_NATIVE_SIMPLE, maxCount = 1/*, ratioMap = ratioMapNativeSimple*/)
+ }
+}
+```
+
+### 请求
+
+```kotlin
+/**
+ * 请求广告
+ */
+private fun requestAd() {
+ //--------------------------------------------------------------------------------------
+ // ( 必须设置 )如果需要使用穿山甲的原生广告,必须在请求之前设置类型。( 没用到穿山甲的请忽略 )
+ // 设置方式:CsjProvider.Native.nativeAdType = AdSlot.TYPE_XXX(类型和你的广告位ID一致)。
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_FEED
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_INTERACTION_AD
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_BANNER
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_CACHED_SPLASH
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_DRAW_FEED
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_FULL_SCREEN_VIDEO
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_REWARD_VIDEO
+ // CsjProvider.Native.nativeAdType = AdSlot.TYPE_SPLASH
+ //--------------------------------------------------------------------------------------
+ CsjProvider.Native.nativeAdType = AdSlot.TYPE_FEED
+
+ //设置 穿山甲 图片可接受的尺寸 ( 建议设置,默认是 1080,607.5 )
+ //CsjProvider.Native.setImageAcceptedSize(ScreenUtil.getDisplayMetricsWidth(this), ScreenUtil.getDisplayMetricsWidth(this) * 9 / 16)
+
+ //指定普链广告点击后用于展示落地页的浏览器类型,可选项包括:InnerBrowser(APP 内置浏览器),Sys(系统浏览器),Default(默认,SDK 按照默认逻辑选择)
+ // ( 非必须设置,默认是:BrowserType.Default )
+ //GdtProvider.Native.browserType = BrowserType.Default
+
+ //指定点击 APP 广告后是否展示二次确认,可选项包括 Default(wifi 不展示,非 wifi 展示),NoConfirm(所有情况不展示)
+ // ( 非必须设置,默认是:DownAPPConfirmPolicy.Default )
+ //GdtProvider.Native.downAPPConfirmPolicy = DownAPPConfirmPolicy.Default
+
+ //设置返回视频广告的最大视频时长(闭区间,可单独设置),单位:秒,合法输入为:5<=maxVideoDuration<=60. 此设置会影响广告填充,请谨慎设置
+ // ( 非必须设置,默认是:60 )
+ //GdtProvider.Native.maxVideoDuration = 60
+
+ //设置返回视频广告的最小视频时长(闭区间,可单独设置),单位:秒 此设置会影响广告填充,请谨慎设置
+ // ( 非必须设置,默认是:5 )
+ //GdtProvider.Native.minVideoDuration = 5
+
+ //设置本次拉取的视频广告,从用户角度看到的视频播放策略;
+ // 可选项包括自VideoOption.VideoPlayPolicy.AUTO(在用户看来,视频广告是自动播放的)和VideoOption.VideoPlayPolicy.MANUAL(在用户看来,视频广告是手动播放的);
+ // 如果广告位支持视频,强烈建议调用此接口设置视频广告的播放策略,有助于提高eCPM值;如果广告位不支持视频,忽略本接口
+ // ( 默认是:VideoOption.VideoPlayPolicy.AUTO )
+ //GdtProvider.Native.videoPlayPolicy = VideoOption.VideoPlayPolicy.AUTO
+
+ adHelperNative?.getList(listener = object : NativeListener {
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ }
+
+ override fun onAdLoaded(providerType: String, adList: List) {
+ //广告请求成功的回调,每次请求只回调一次
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ }
+
+ override fun onAdFailedAll() {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ }
+ })
+}
+```
+
+### 展示
+
+```kotlin
+/**
+ * 展示广告
+ */
+private fun showAd(adObject: Any) {
+ AdHelperNativePro.show(adObject = adObject, container = adContainer, nativeTemplate = NativeTemplateSimple1(), listener = object : NativeViewListener {
+ override fun onAdExposed(providerType: String) {
+ //每次曝光就会回调这里一次
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //每次点击就会回调这里一次
+ }
+ })
+}
+```
+
+### 处理广告的生命周期
+
+```kotlin
+override fun onResume() {
+ super.onResume()
+ AdHelperNativePro.resumeAd(adObject)
+}
+
+override fun onPause() {
+ super.onPause()
+ AdHelperNativePro.pauseAd(adObject)
+}
+
+override fun onDestroy() {
+ super.onDestroy()
+ AdHelperNativePro.destroyAd(adObject)
+}
+```
+
+详情可查看 Demo 中 [原生自渲染广告的简单用法示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeSimpleActivity.kt)
+
+详情可查看 Demo 中 [原生自渲染广告在RecyclerView中使用示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/native_/NativeRecyclerViewActivity.kt)
\ No newline at end of file
diff --git a/doc/prepare.md b/doc/prepare.md
new file mode 100644
index 0000000..3b074a6
--- /dev/null
+++ b/doc/prepare.md
@@ -0,0 +1,332 @@
+# 准备工作
+### 1. 自行选择性添加权限到 AndroidManifest.xml 文件中
+
+**穿山甲的权限**
+
+```
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+```
+//建议在广告请求前,合适的时机调用SDK提供的方法
+//TTAdManager接口中的方法,context可以是Activity或Application
+void requestPermissionIfNecessary(Context context);
+```
+
+**优量汇的权限**
+
+优量汇 SDK 建议您在AndroidManifest.xml添加以下权限声明,若您的targetSDKVersion >= 23您还需要在运行时进行动态权限申请(可参考示例工程)
+
+```
+
+
+
+
+
+
+
+```
+
+注意:可选权限SDK不强制校验上述权限(即:无上述权限sdk也可正常工作),但建议您申请上述权限。针对单媒体的用户,允许获取权限的,投放定向广告;不允许获取权限的用户,投放通投广告。媒体可以选择是否把上述权限提供给优量汇,并承担相应广告填充和eCPM单价下降损失的结果。
+
+**百度的权限**
+
+```
+
+
+
+
+
+
+
+
+
+```
+
+### 2. 列举广告商类型
+
+新建一个枚举类 AdProviderType,列举你接入的广告商,任选1至3个,随意搭配
+
+```kotlin
+/*
+ * 广告提供商枚举
+ * 不需要的就删除,只保留需要的即可
+ */
+enum class AdProviderType(val type: String) {
+
+ //腾讯的广点通
+ GDT("gdt"),
+
+ //穿山甲
+ CSJ("csj"),
+
+ //百度 Mob
+ //BAIDU("baidu")
+
+}
+```
+
+### 3. 列举所有广告位
+
+新建一个 静态类,并列举你项目中的所有广告位,例如下面: 列举Demo 中所有的广告位别名
+
+```kotlin
+/**
+ * 所有广告位的别名
+ *
+ * 列举你项目中的所有广告位,并给每个广告位起个名字
+ *
+ * 用于初始化广告位ID 以及 广告的请求
+ *
+ * Created by Matthew Chen on 2020-04-16.
+ */
+object TogetherAdAlias {
+
+ //开屏
+ const val AD_SPLASH = "ad_splash"
+
+ //原生模板2.0 简单使用
+ const val AD_NATIVE_EXPRESS_2_SIMPLE = "ad_native_express2_simple"
+
+ //原生模板2.0 在 RecyclerView 中使用
+ const val AD_NATIVE_EXPRESS_2_RECYCLERVIEW = "ad_native_express2_recyclerview"
+
+ //原生模板 简单使用
+ const val AD_NATIVE_EXPRESS_SIMPLE = "ad_native_express_simple"
+
+ //原生模板 在 RecyclerView 中使用
+ const val AD_NATIVE_EXPRESS_RECYCLERVIEW = "ad_native_express_recyclerview"
+
+ //原生 简单使用
+ const val AD_NATIVE_SIMPLE = "ad_native_simple"
+
+ //原生 在 RecyclerView 中使用
+ const val AD_NATIVE_RECYCLERVIEW = "ad_native_recyclerview"
+
+ //Banner
+ const val AD_BANNER = "ad_banner"
+
+ //插屏广告
+ const val AD_INTER = "ad_inter"
+
+ //激励广告
+ const val AD_REWARD = "ad_reward"
+
+ //全屏视频广告
+ const val AD_FULL_VIDEO = "ad_full_video"
+
+ //开屏混合使用
+ const val AD_SPLASH_HYBRID = "ad_splash_and_native"
+
+ //原生模板混合
+ const val AD_EXPRESS_HYBRID = "ad_express_hybrid"
+
+}
+```
+
+### 4. 初始化
+
+在 Applicatioin 的 onCreate() 方法里面调用初始化方法
+
+同时需要配置所有 ``广告ID`` 和 ``广告位ID``
+
+示例代码中的 ``ID`` 是各个平台中 Demo 的测试 ``ID``
+
+```kotlin
+class App : Application() {
+
+ override fun onCreate() {
+ super.onCreate()
+
+ /**
+ * 自定义穿山甲的初始化配置
+ * 可自行选择自定义穿山甲的配置,不配置就会使用穿山甲的默认值
+ */
+// // 可选参数,需在初始化之前,使用TextureView控件播放视频,默认为SurfaceView,当有SurfaceView冲突的场景,可以使用TextureView
+// TogetherAdCsj.useTextureView = false
+// // 可选参数,需在初始化之前,标题栏的主题色
+// TogetherAdCsj.titleBarTheme = TTAdConstant.TITLE_BAR_THEME_DARK
+// // 可选参数,需在初始化之前,是否允许sdk展示通知栏提示
+// TogetherAdCsj.allowShowNotify = true
+// // 可选参数,需在初始化之前,测试阶段打开,可以通过日志排查问题,上线时去除该调用
+// TogetherAdCsj.debug = true
+// // 可选参数,需在初始化之前,允许直接下载的网络状态集合
+// TogetherAdCsj.directDownloadNetworkType = TTAdConstant.NETWORK_STATE_WIFI or TTAdConstant.NETWORK_STATE_4G
+// // 可选参数,需在初始化之前,是否支持多进程,true支持
+// TogetherAdCsj.supportMultiProcess = false
+// // 可选参数,需在初始化之前,自定义网络库,demo中给出了okhttp3版本的样例,其余请自行开发或者咨询工作人员。
+// TogetherAdCsj.httpStack = object : IHttpStack { }
+// // 可选参数,需在初始化之前,设置是否为计费用户:true计费用户、false非计费用户。默认为false非计费用户。须征得用户同意才可传入该参数
+// TogetherAdCsj.isPaid = false
+// // 可选参数,需在初始化之前,是否一步初始化
+// TogetherAdCsj.isAsyncInit = false
+// // 可选参数,需在初始化之前,设置用户画像的关键词列表 **不能超过为1000个字符**。须征得用户同意才可传入该参数
+// TogetherAdCsj.keywords = ""
+// // 可选参数,需在初始化之前,设置额外的用户信息 **不能超过为1000个字符**
+// TogetherAdCsj.data = ""
+// // 可选参数,需在初始化之前,可以设置隐私信息控制开关,需要重写其方法
+// TogetherAdCsj.customController = object : TTCustomController() {}
+// // 可选参数,需在初始化之前,穿山甲初始化状态回调
+// TogetherAdCsj.initCallback = object : TTAdSdk.InitCallback {}
+
+ /**
+ * 自定义优量汇的初始化配置
+ */
+// //可参照 DownloadConfirmHelper 自定义下载确认的回调
+// TogetherAdGdt.downloadConfirmListener = DownloadConfirmHelper.DOWNLOAD_CONFIRM_LISTENER
+
+ //初始化穿山甲
+ TogetherAdCsj.init(context = this, adProviderType = AdProviderType.CSJ.type, csjAdAppId = "5001121", appName = this.getString(R.string.app_name))
+
+ //初始化广点通
+ TogetherAdGdt.init(context = this, adProviderType = AdProviderType.GDT.type, gdtAdAppId = "1101152570")
+ //初始化百青藤
+ TogetherAdBaidu.init(context = this, adProviderType = AdProviderType.BAIDU.type, baiduAdAppId = "e866cfb0")
+
+ /**
+ * 配置所有广告位ID
+ * 如果你的ID是服务器下发,也可以把配置ID放在其他位置,但是必须要在请求广告之前完成配置,否则无法加载广告
+ */
+ TogetherAdCsj.idMapCsj = mutableMapOf(
+ TogetherAdAlias.AD_SPLASH to "801121648",
+ TogetherAdAlias.AD_SPLASH_HOT to "801121648",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_SIMPLE to "901121134",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_RECYCLERVIEW to "901121125",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_SIMPLE to "",//不支持
+ TogetherAdAlias.AD_NATIVE_EXPRESS_RECYCLERVIEW to "",//不支持
+ TogetherAdAlias.AD_NATIVE_SIMPLE to "901121737",
+ TogetherAdAlias.AD_NATIVE_RECYCLERVIEW to "901121737",
+ TogetherAdAlias.AD_BANNER to "901121246",
+ TogetherAdAlias.AD_INTER to "945509693",
+ TogetherAdAlias.AD_REWARD to "901121365",
+ TogetherAdAlias.AD_FULL_VIDEO to "901121073",
+ TogetherAdAlias.AD_HYBRID_SPLASH to "901121737",//id是原生类型
+ TogetherAdAlias.AD_HYBRID_EXPRESS to "901121134",//id是原生模板2.0
+ TogetherAdAlias.AD_HYBRID_VERTICAL_PREMOVIE to "901121073"//id是全屏视频
+ )
+
+ TogetherAdGdt.idMapGDT = mutableMapOf(
+ TogetherAdAlias.AD_SPLASH to "8863364436303842593",
+ TogetherAdAlias.AD_SPLASH_HOT to "8863364436303842593",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_SIMPLE to "9061615683013706",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_RECYCLERVIEW to "9061615683013706",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_SIMPLE to "5060295460765937",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_RECYCLERVIEW to "5060295460765937",
+ TogetherAdAlias.AD_NATIVE_SIMPLE to "6040749702835933",
+ TogetherAdAlias.AD_NATIVE_RECYCLERVIEW to "6040749702835933",
+ TogetherAdAlias.AD_BANNER to "4080052898050840",
+ TogetherAdAlias.AD_INTER to "1050691202717808",
+ TogetherAdAlias.AD_REWARD to "2090845242931421",
+ TogetherAdAlias.AD_FULL_VIDEO to "9051949928507973",
+ TogetherAdAlias.AD_HYBRID_SPLASH to "8863364436303842593",//id是开屏类型
+ TogetherAdAlias.AD_HYBRID_EXPRESS to "5060295460765937",//id是原生模板1.0
+ TogetherAdAlias.AD_HYBRID_VERTICAL_PREMOVIE to "6040749702835933"
+ )
+
+ TogetherAdBaidu.idMapBaidu = mutableMapOf(
+ TogetherAdAlias.AD_SPLASH to "2058622",
+ TogetherAdAlias.AD_SPLASH_HOT to "2058622",
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_SIMPLE to "",//不支持
+ TogetherAdAlias.AD_NATIVE_EXPRESS_2_RECYCLERVIEW to "",//不支持
+ TogetherAdAlias.AD_NATIVE_EXPRESS_SIMPLE to "",//不支持
+ TogetherAdAlias.AD_NATIVE_EXPRESS_RECYCLERVIEW to "",//不支持
+ TogetherAdAlias.AD_NATIVE_SIMPLE to "2058628",
+ TogetherAdAlias.AD_NATIVE_RECYCLERVIEW to "2058628",
+ TogetherAdAlias.AD_BANNER to "2015351",
+ TogetherAdAlias.AD_INTER to "2403633",
+ TogetherAdAlias.AD_REWARD to "5925490",
+ TogetherAdAlias.AD_FULL_VIDEO to "",
+ TogetherAdAlias.AD_HYBRID_SPLASH to "2058628",//id是原生类型
+ TogetherAdAlias.AD_HYBRID_EXPRESS to "",//不支持
+ TogetherAdAlias.AD_HYBRID_VERTICAL_PREMOVIE to ""//不支持
+ )
+
+ /**
+ * 配置全局的广告商权重。
+ * 如果在调用具体广告API时没有配置单次请求的权重,就会默认使用这个全局的权重
+ * 如果不配置,TogetherAd会默认所有初始化的广告商权重相同
+ *
+ * 也可以在请求广告前设置,实时生效
+ */
+ TogetherAd.setPublicProviderRatio(linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.BAIDU.type to 0,
+ AdProviderType.CSJ.type to 0
+ ))
+
+ /**
+ * 自定义图片加载方式
+ * 用于自渲染类型的广告图片加载
+ * 如果不配置,TogetherAd 会使用默认的图片加载方式
+ * 不建议使用默认的 DefaultImageLoader 兼容性较差
+ * 主要考虑到:开发者可以自定义实现图片加载:渐变、占位图、错误图等
+ */
+// TogetherAd.setCustomImageLoader(object : AdImageLoader {
+// override fun loadImage(context: Context, imageView: ImageView, imgUrl: String) {
+// Glide.with(context).load(imgUrl).into(imageView)
+// }
+// })
+
+ /**
+ * 日志的开关
+ * 全局实时生效
+ */
+ TogetherAd.printLogEnable = BuildConfig.DEBUG
+
+ /**
+ * 是否失败切换 ( 当请求广告失败时,是否允许切换到其他广告提供商再次请求 )
+ * 全局实时生效
+ */
+// TogetherAd.failedSwitchEnable = true
+
+ /**
+ * 最大拉取延时时间 ms( 请求广告的超时时间 )
+ * 3000 ≤ value ≥ 10000( 小于3000时按3000计算,大于10000时按10000计算 )
+ * 全局实时生效
+ * 不设置或设置为0 -> 超时时间无限长
+ */
+// TogetherAd.maxFetchDelay = 8000
+
+ /**
+ * 所有广告商所有广告类型的广告都会回调这个监听器
+ * 主要是方便做统计:请求成功率、请求失败信息等
+ */
+// TogetherAd.allAdListener = object : AllAdListener {
+// override fun onAdStartRequest(providerType: String, alias: String) {
+// "开始请求: 提供商: $providerType, 广告位: $alias".logi("TogetherAd.allAdListener")
+// }
+//
+// override fun onAdFailed(providerType: String, alias: String, failedMsg: String?) {
+// "请求失败: 提供商: $providerType, 广告位: $alias, 错误信息: $failedMsg".loge("TogetherAd.allAdListener")
+// }
+//
+// override fun onAdLoaded(providerType: String, alias: String) {
+// "请求成功: 提供商: $providerType, 广告位: $alias".logi("TogetherAd.allAdListener")
+// }
+// }
+ /**
+ * 设置广告分发模式
+ * DispatchType.Priority 优先权重最高分发模式
+ * DispatchType.Random 按照权重随机分发模式
+ */
+// TogetherAd.dispatchType = DispatchType.Random
+ }
+}
+```
\ No newline at end of file
diff --git a/doc/question.md b/doc/question.md
new file mode 100644
index 0000000..914ca5a
--- /dev/null
+++ b/doc/question.md
@@ -0,0 +1,15 @@
+## 常见问题
+
+### TogetherAd有没有Java版本?Java项目是否可以调用?
+
+没有Java版本,但是Java、Kotlin可以互相调用,Java项目完全可以使用。
+
+### 为什么要接入TogetherAd ?
+
+TogetherAd简洁的Api设计让接入广告更简单,避免项目中穿插大量的广告代码,尤其是项目中接入多家广告平台时,地狱般的回调大大降低了项目的可读性。TogetherAd由此而生
+
+### 接入TogetherAd后会不会被扣量?
+
+不会,该项目是开源项目,可以看到项目的所有源代码,没有任何的扣量逻辑
+
+### 不断完善中。。。
\ No newline at end of file
diff --git a/doc/reward.md b/doc/reward.md
new file mode 100644
index 0000000..0f288d3
--- /dev/null
+++ b/doc/reward.md
@@ -0,0 +1,107 @@
+# 激励广告
+
+激励视频广告是指将短视频融入到app场景当中,成为app“任务”之一,用户观看短视频广告后可以得到一些应用内奖励。
+
+激励视频广告是一种常见于游戏内的广告样式,多出现在游戏的复活、登录等位置,或者网服类app的一些增值服务场景。建议开发者在分析媒体属性和功能的基础上,判断是否前嵌入激励视频广告
+
+—— 引自广点通文档
+
+详情查看下面示例和注释:
+
+> 展示广告一定要在 onAdLoaded() 回调方法中执行
+
+```kotlin
+class RewardActivity : AppCompatActivity() {
+
+ private lateinit var adHelperReward: AdHelperReward
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_reward)
+
+ //使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+ val ratioMapReward = linkedMapOf(
+ AdProviderType.GDT.type to 3,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+ )
+
+ /**
+ * 穿山甲请求激励广告可选参数
+ * 以下参数均为( 非必传 )
+ */
+// CsjProvider.Reward.userID = "userId_123"
+// CsjProvider.Reward.supportDeepLink = true//默认为true
+// CsjProvider.Reward.rewardName = "金币"//奖励名称
+// CsjProvider.Reward.rewardAmount = 30//奖励数量
+// CsjProvider.Reward.mediaExtra = "TogetherAd"//用户透传的信息
+// //设置期望视频播放的方向,为TTAdConstant.HORIZONTAL或TTAdConstant.VERTICAL。默认是TTAdConstant.VERTICAL
+// CsjProvider.Reward.orientation = TTAdConstant.VERTICAL//默认 TTAdConstant.VERTICAL
+// CsjProvider.Reward.showDownLoadBar = true//不设置默认为true
+
+ /**
+ * activity: 必传。
+ * alias: 必传。广告位的别名。初始化的时候是根据别名设置的广告ID,所以这里TogetherAd会根据别名查找对应的广告位ID。
+ * ratioMap: 非必传。广告商的权重。可以不传或传null,空的情况 TogetherAd 会自动使用初始化时 TogetherAd.setPublicProviderRatio 设置的全局通用权重。
+ * listener: 非必传。如果你不需要监听结果可以不传或传空。各个回调方法也可以选择性添加
+ */
+ adHelperReward = AdHelperReward(activity = this, alias = TogetherAdAlias.AD_REWARD, ratioMap = ratioMapReward, listener = object : RewardListener {
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ }
+
+ override fun onAdFailedAll() {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //点击广告的回调
+ }
+
+ override fun onAdShow(providerType: String) {
+ //广告展示展示的回调
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ //广告请求成功的回调,每次请求只回调一次
+ //展示广告一定要在 onAdLoaded() 回调方法中执行
+ adHelperReward.show()
+
+// //如果 csj 使用到服务器到服务器回调功能,需要进行以下判断,gdt、baidu都不需要此判断
+// if (providerType == AdProviderType.CSJ.type && CsjProvider.Reward.rewardVerify) {
+// ... 验证成功后的操作
+// }
+ }
+
+ override fun onAdExpose(providerType: String) {
+ //广告展示曝光的回调
+ }
+
+ override fun onAdVideoComplete(providerType: String) {
+ //视频播放完成的回调
+ }
+
+ override fun onAdVideoCached(providerType: String) {
+ //视频缓存完成的回调
+ }
+
+ override fun onAdRewardVerify(providerType: String) {
+ //激励结果验证成功的回调
+ }
+
+ override fun onAdClose(providerType: String) {
+ //广告被关闭的回调
+ }
+ })
+
+ //开始请求广告
+ adHelperReward.load()
+ }
+}
+```
+
+可查看 Demo 中 [激励广告的示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/reward/RewardActivity.kt)
\ No newline at end of file
diff --git a/doc/splash.md b/doc/splash.md
new file mode 100644
index 0000000..afcdfc5
--- /dev/null
+++ b/doc/splash.md
@@ -0,0 +1,162 @@
+# 开屏广告
+
+开屏广告以App启动作为曝光时机,提供5s的可感知广告展示。用户可以点击广告跳转到目标页面,或者点击右上角的“跳过”按钮,跳转到app内容首页。
+
+—— 引自广点通文档
+
+### 调用姿势
+
+```kotlin
+/**
+ * 设置 gdt 开屏广告 自定义跳过按钮
+ * TogetherAd 提供了两个简单的实例模板,同时只能设置一个,如果设置多个后面的生效
+ * 目前只有 优量汇(广点通) 支持自定义跳过按钮的样式,所以只会对 广点通 生效
+ */
+GdtProvider.Splash.customSkipView = SplashSkipViewSimple2()
+//GdtProvider.Splash.customSkipView = SplashSkipViewSimple1()
+/**
+ * 设置 gdt 开屏广告超时时间
+ * fetchDelay 参数,设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),
+ * 取值范围为[3000, 5000]ms。
+ * 如果需要使用默认值,可以给 fetchDelay 设为0或者不设置。
+ */
+//GdtProvider.Splash.maxFetchDelay = 0
+
+/**
+ * 给 csj 设置可接受的图片尺寸,避免图片变形
+ * 一般设置容器的宽高即可
+ */
+CsjProvider.Splash.setImageAcceptedSize(ScreenUtil.getDisplayMetricsWidth(this), ScreenUtil.getDisplayMetricsHeight(this) - 100f.dp.toInt())
+
+/**
+ * 设置 csj 开屏广告超时时间
+ * fetchDelay 参数,设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),
+ * 如果不设置,默认值为 3000ms
+ */
+//CsjProvider.Splash.maxFetchDelay = 3000
+
+//使用 Map 配置广告商 权重,通俗的讲就是 随机请求的概率占比
+val ratioMapSplash = linkedMapOf(
+ AdProviderType.GDT.type to 1,
+ AdProviderType.CSJ.type to 1,
+ AdProviderType.BAIDU.type to 1
+)
+
+/**
+ * activity: 必传。这里不是 Context,因为广点通必须传 Activity,所以统一传 Activity。
+ * alias: 必传。广告位的别名。初始化的时候是根据别名设置的广告ID,所以这里TogetherAd会根据别名查找对应的广告位ID。
+ * ratioMap: 非必传。广告商的权重。可以不传或传null,空的情况 TogetherAd 会自动使用初始化时 TogetherAd.setPublicProviderRatio 设置的全局通用权重。
+ * container: 必传。请求到广告之后会自动添加到 container 这个布局中展示。
+ * listener: 非必传。如果你不需要监听结果可以不传或传空。各个回调方法也可以选择性添加
+ */
+AdHelperSplash.show(activity = this, alias = TogetherAdAlias.AD_SPLASH, ratioMap = ratioMapSplash, container = adContainer, listener = object : SplashListener {
+
+ override fun onAdStartRequest(providerType: String) {
+ //在开始请求之前会回调此方法,失败切换的情况会回调多次
+ }
+
+ override fun onAdLoaded(providerType: String) {
+ //广告请求成功的回调,每次请求只回调一次
+ }
+
+ override fun onAdClicked(providerType: String) {
+ //点击广告的回调
+ }
+
+ override fun onAdExposure(providerType: String) {
+ //广告展示曝光的回调
+ }
+
+ override fun onAdFailed(providerType: String, failedMsg: String?) {
+ //请求失败的回调,失败切换的情况会回调多次
+ }
+
+ override fun onAdFailedAll() {
+ //所有配置的广告商都请求失败了,只有在全部失败之后会回调一次
+ actionHome(1000)//跳转主页并finish开屏页
+ }
+
+ override fun onAdDismissed(providerType: String) {
+ //开屏广告消失了,点了跳过按钮或者倒计时结束之后会回调一次
+ //在这里跳转主界面,并关闭 Splash
+ actionHome(0)//跳转主页并finish开屏页
+ }
+})
+```
+
+> 回调中 ``providerType: String `` 是广告商的类型
+
+### 自定义广点通的跳过按钮
+
+TogetherAd 提供了两个简单的实例模板,只需要在请求广告之前进行如下配置即可:
+
+```kotlin
+/*
+ * 设置 gdt 开屏广告 自定义跳过按钮
+ * TogetherAd 提供了两个简单的实例模板,同时只能设置一个,如果设置多个后面的生效
+ * 目前只有 优量汇(广点通) 支持自定义跳过按钮的样式,所以只会对 广点通 生效
+ */
+GdtProvider.Splash.customSkipView = SplashSkipViewSimple2()
+//GdtProvider.Splash.customSkipView = SplashSkipViewSimple1()
+
+AdHelperSplash.show(activity = this, alias = TogetherAdAlias.AD_SPLASH, ratioMap = ratioMapSplash, container = adContainer, listener = object : SplashListener {
+ ...
+})
+```
+
+如果你觉得提供的两个模板都不满足你的需求,可以自定义样式:
+
+1. 首先需要创建一个类并继承 BaseSplashSkipView
+
+2. 然后模仿 ``SplashSkipViewSimple1`` 和 ``SplashSkipViewSimple2`` 来自定义想要的样式
+
+```kotlin
+class SplashSkipViewCustom : BaseSplashSkipView() {
+
+ private lateinit var tvTime: TextView
+
+ /**
+ * 创建跳过按钮的布局
+ */
+ override fun onCreateSkipView(context: Context): View {
+ val skipView = View.inflate(context, R.layout.layout_splash_skip_view_simple2, null)
+ tvTime = skipView.findViewById(R.id.time)
+ return skipView
+ }
+
+ /**
+ * 处理倒计时的展示,单位:秒
+ */
+ override fun handleTime(second: Int) {
+ tvTime.text = second.toString()
+ }
+
+ /**
+ * 获取布局参数,控制跳过按钮的位置
+ *
+ * 注意:LayoutParams 的类型取决于 请求开屏广告时 container 参数的类型。
+ * Demo 中是使用的 FrameLayout,所以这里就是 FrameLayout.LayoutParams;
+ * LayoutParams类型必须要一致,否则会崩溃
+ */
+ override fun getLayoutParams(): ViewGroup.LayoutParams {
+ val layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT)
+ layoutParams.gravity = Gravity.END or Gravity.TOP
+ layoutParams.topMargin = 50
+ layoutParams.rightMargin = 30
+ return layoutParams
+ }
+
+}
+```
+最后不要忘记修改配置:
+
+```kotlin
+GdtProvider.Splash.customSkipView = SplashSkipViewCustom()
+
+AdHelperSplash.show(activity = this, alias = TogetherAdAlias.AD_SPLASH, ratioMap = ratioMapSplash, container = adContainer, listener = object : SplashListener {
+ ...
+})
+```
+
+详情可查看 Demo 中 [开屏广告请求并展示的示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashActivity.kt)
+详情可查看 Demo 中 [开屏广告请求和展示分开的示例代码](../demo/src/main/java/com/ifmvo/togetherad/demo/splash/SplashProActivity.kt)
\ No newline at end of file
diff --git a/doc/update_log.md b/doc/update_log.md
new file mode 100644
index 0000000..82358da
--- /dev/null
+++ b/doc/update_log.md
@@ -0,0 +1,346 @@
+# 更新日志
+
+# 5.0.3
+
+2021.05.06
+
+1. 对应版本:穿山甲3.6.1.1;优量汇4.351.1221;百度5.91
+2. 更新了穿山甲
+3. 修复开启混淆后崩溃的问题[#36](https://github.com/ifmvo/TogetherAd/issues/36)
+
+## 5.0.2
+
+2021.04.26
+
+1. 对应版本:穿山甲3.6.1.0;优量汇4.351.1221;百度5.91
+2. 更新了穿山甲和优量汇的SDK
+3. 全屏视频广告添加了视频播放完成的回调 onVideoComplete
+
+## 5.0.1
+
+2021.04.19
+
+1. 对应版本:穿山甲3.6.0.0;优量汇4.333.1203;百度5.91
+2. 更新了穿山甲的SDK
+3. 优化 TTAdManager 的获取方式,全局使用一个,可以减少内存开支
+4. 新增可以设置夜间模式的接口 TogetherAdCsj.themeStatus = 1 或者 TogetherAdCsj.mTTAdManager.themeStatus = 1
+
+## 5.0.0
+
+2021.04.11
+
+1. 对应版本:穿山甲3.5.5.0;优量汇4.333.1203;百度5.91
+2. 项目远程仓库迁移到Jitpack,由于Jitpack不支持自定义groupId、artifactId和版本号规则,所以依赖路径有相应的变化,需要自行按照文档进行修改
+
+## 4.1.9
+
+2021.04.06
+
+1. 更新穿山甲SDK 3.5.5.0( 新增新插屏广告 )
+
+## 4.1.8
+
+2021.03.24
+
+1. 穿山甲的视频贴片广告合并到 AdHelperNativePro ( CsjProvider.Native.nativeAdType = AdSlot.TYPE_STREAM ),展示方式和原生自渲染一样
+
+## 4.1.7
+
+2021.03.22
+
+1. 优量汇原生自渲染可以自定义广告标识的位置( 重写 getLogoLayoutParams 方法 )
+
+## 4.1.5
+
+2021.03.16
+
+1. 原生自渲染广告支持快速添加关闭按钮
+
+## 4.1.4
+
+2021.03.15
+
+1. 新增穿山甲的自渲染贴片广告
+2. 优量汇支持了全屏视频广告
+3. 优量汇添加下载确认的弹窗,可自定义: TogetherAdGdt.downloadConfirmListener = DownloadConfirmHelper.DOWNLOAD_CONFIRM_LISTENER
+4. 更新穿山甲SDK到 v3.5.0.3
+5. 更新优量汇SDK到 v4.333.1203
+
+## 4.1.3
+
+2021.03.02
+
+1. 更新穿山甲SDK到 v3.5.0.1
+
+## 4.1.2
+
+2021.02.06
+
+1. 更新优量汇SDK到 v4.330.1202 ( 修复插屏全屏视频、激励视频、激励浏览可能遇到的崩溃问题 )
+2. 更新穿山甲SDK到 v3.4.5.0 ( https://bytedance.feishu.cn/docs/doccnhkyP8kSJZGDus7C5UsMdgc#l67FVr ) 【新增】SDK初始化增加异步初始化方式和初始化完成回调,且必须在主线程调用初始化方法;【优化】SDK初始化逻辑优化,同步初始化方式必须在主线程中调用;【废弃】TTAdConfig.Builder中asyncInit()方法废弃;
+3. TogetherAd 对穿山甲初始化API的变化进行了适配: TogetherAdCsj.initCallback
+4. 新增热启动开屏示例
+
+## 4.1.1
+
+2021.01.20
+
+1. 更新优量汇SDK到 v4.330.1200 ( 激励视频支持server to server通知、开屏支持预拉取,开屏支持滑动引导手势,激励视频、插屏全屏视频的倒计时和关闭按钮优化,视频广告支持动态营销挂件等功能。 )
+
+## 4.1.0
+
+2021.01.16
+
+1. 更新穿山甲SDK到 v3.4.1.2
+
+## 4.0.9
+
+2021.01.12
+
+1. 全部请求失败也返回错误日志: onAdFailedAll(failedMsg: String?)
+2. 更新穿山甲SDK到 v3.4.1.0
+
+## 4.0.7
+
+2020.12.23
+
+1. 每个广告位的分发方式可以单独设置: TogetherAd.mDispatchTypeMap[TogetherAdAlias.AD_SPLASH] = DispatchType.xxxxxx
+
+## 4.0.6
+
+2020.12.22
+
+1. 每个广告位的ID可以单独设置,例:TogetherAdCsj.idMapCsj[TogetherAdAlias.AD_SPLASH] = "xxxxxxxx"
+
+## 4.0.5
+
+2020.12.17
+
+1. 激励广告 show 方法新增返回值,是否展示成功
+2. 每个广告平台的开屏广告超时时间默认都改为 4000ms
+
+## 4.0.4
+
+2020.12.15
+
+1. 原生自渲染可自定义点击 List
+2. 原生自渲染的容器在展示前后自动removeAllViews
+
+## 4.0.3
+
+2020.12.09
+
+1. 更新优量汇版本到 4.310.1180( 新增开屏V+样式,支持视频边下边播,支持新游预约广告,插屏全屏视频支持试玩;提升开屏广告加载速度,修复其它已知问题 )
+
+## 4.0.2
+
+2020.12.03
+
+1. 支持穿山甲的全屏视频广告
+2. 添加 TogetherAd.allListener 方便做统计
+3. 添加广告分发优先级模式 TogetherAd.dispatchType = DispatchType.Priority
+
+## 4.0.1
+
+2020.12.01
+
+1. 穿山甲开屏广告支持自定义跳过按钮
+2. Banner 和 插屏广告改为模板的请求方式
+3. 新增原生模板1.0和原生模板2.0混合使用
+
+## 4.0.0
+
+2020.11.30
+
+1. 新增原生模板2.0、原生模板1.0
+2. Demo UI 调整
+
+## 3.2.6
+
+2020.11.24
+
+1. 更新优量汇版本到 4.294.1164( 修复开屏视频广告可能发生的崩溃问题 )
+2. 更新穿山甲版本到 3.3.0.3
+3. 新增 加载和展示分开的开屏广告 AdHelperSplashPro,可实现预加载
+
+## 3.2.5
+
+2020.11.05
+
+1. 更新优量汇版本到 4.291.1161( 修复开屏视频挂件在开屏结束后可能没有消失的问题;修复插屏 2.0 广告在Android8.x 系统中,当 Activity 使用透明主题时可能崩溃的问题。 )
+
+## 3.2.4
+
+2020.11.04
+
+1. 更新穿山甲版本到 3.3.0.1
+2. 更新优量汇版本到 4.290.1160
+
+## 3.2.3
+
+2020.10.28
+
+1. 修复部分机型DefaultImageLoader崩溃(#25)
+2. 原生自渲染参数可空
+3. 修复开启混淆后广点通初始化错误的问题(#24)
+
+## 3.2.1
+
+2020.10.23
+
+1. 穿山甲 loadBannerAd -> loadBannerExpressAd( 穿山甲目前只支持模板类型Banner,如果你还想继续使用loadBannerAd )[详情查看文档](doc/extend.md)
+2. 改为不设置ratioMap的情况下默认不展示广告
+3. 删除了所有 Deprecated.
+4. 将各个平台的 Provider 开放出来,如果现有的 Provider 不满足你的需求可以自定义扩展。[详情查看文档](doc/extend.md)
+
+## 3.2.0
+
+2020.10.13
+
+1. radio -> ratio ( 比例,英文单词拼写错误纠正 )
+
+## 3.1.9
+
+2020.09.28
+
+1. 封装原生信息流Base,自定义模板更简单
+
+## 3.1.8
+
+2020.09.15
+
+1. 更新SDK版本:穿山甲v3.2.5.1;广点通v4.270.1140;百青藤v5.91
+
+## 3.1.7
+
+2020.09.10
+
+1. 开屏广告:广点通和穿山甲支持自定义超时时间,另外穿山甲还支持设置图片尺寸避免变形 [详情查看文档](doc/splash.md)
+2. 原生自渲染:广点通支持自定义一些参数 [详情查看文档](doc/native.md)
+3. Banner横幅广告:穿山甲支持设置刷新时间、图片尺寸 [详情查看文档](doc/banner.md)
+4. Inter插屏广告:穿山甲支持设置图片尺寸 [详情查看文档](doc/inter.md)
+5. 初始化:穿山甲新增初始化参数 [详情查看文档](doc/prepare.md)
+
+## 3.1.6
+
+2020.09.07
+
+1. 激励广告支持穿山甲自定义请求参数 CsjProvider.Reward [详情查看文档](doc/reward.md)
+2. 穿山甲原生广告设置类型的Api变为:CsjProvider.Native.nativeAdType = xxxxxx。不建议继续使用:AdHelperNativePro.csjNativeAdType = xxxxxx
+
+## 3.1.5
+
+2020.09.01
+
+1. 新增原生自渲染的样例 NativeViewSimple1、NativeViewSimple2、NativeViewSimple3
+
+### 3.1.4
+
+2020.08.27
+
+1. 所有种类广告支持超时逻辑
+
+### 3.1.3
+
+2020.08.26
+
+1. 去掉所有库中 appcompat-v7 依赖
+
+### 3.1.2
+
+2020.08.25
+
+1. 开屏广告支持超时逻辑
+
+### 3.1.1
+
+2020.08.19
+
+1. 穿山甲原生广告需要设置类型 [详情查看文档](doc/native.md)
+
+### 3.1.0
+
+2020.08.12
+
+1. 新增失败切换的开关 TogetherAd.failedSwitchEnable( 默认开启 )
+2. Demo中提供混合使用的方案 [详情查看文档](doc/hybrid.md)
+3. 解决开屏不设置自定义跳过按钮时广点通崩溃的问题
+4. 处理 Demo 中一个内存泄漏的问题
+
+### 3.0.9
+
+2020.08.04
+
+1. Log 日志开关
+2. 由于设计缺陷 AdHelperNative 弃用,使用 AdHelperNativePro 替换
+3. 原生自渲染广告的生命周期处理 [详情查看文档](doc/native.md)
+4. 更新穿山甲SDK版本到3.1.0.1
+
+### 3.0.8
+
+2020.07.09
+
+1. 资源库自带混淆规则,无需手动添加
+
+### 3.0.7
+
+2020.07.08
+
+1. 添加插屏广告 && 修复穿山甲BannerBug && 激励Demo修改
+
+### 3.0.6
+
+2020.06.23
+
+1. 初始化时可以不配置广告位ID,并单独提供配置广告位ID的api( 考虑广告位ID由服务器下发的情况 )
+2. 修复其他已知bug
+
+2020.06.30
+
+1. 使用 RecyclerView.Adapter 演示 原生自渲染广告 在 RecyclerView 中的用法
+
+### 3.0.5
+
+2020.06.10
+
+1. 修复 INSTALL_FAILED_CONFLICTING_PROVIDER ( Baidu 的 FileProvider 冲突问题 )
+
+### 3.0.4
+
+2020.06.08
+
+1. 删除或替换项目中所有 androidx ( 为了兼容还在使用 Support 的项目 )
+2. 优化csj自定义初始化配置的方式
+3. 更新 百青藤v5.85,穿山甲v3.0.0.4
+
+### 3.0.3
+
+2020.05.27
+
+1. 添加 Banner 横幅广告
+2. 更新广点通的初始化方式
+3. 修复激励广告内存泄漏问题
+4. 添加踩坑指南
+5. Demo中添加各个平台的测试ID
+6. 提供 APK 预览体验
+7. 全部失败的回调 onAdFailedAll() 删除失败原因参数
+
+### 3.0.2
+
+2020.05.20
+
+1. 更新广点通SDK版本到 4.211.1081
+
+### 3.0.1
+
+2020.05.19
+
+1. 广告商SDK的aar文件打包到依赖中
+2. 简化接入 TogetherAd 的流程
+
+### 3.0.0
+
+2020.05.18
+
+1. 发布新版本 3.x
+2. 支持开屏、原生自渲染、激励广告
\ No newline at end of file
diff --git a/gdt/.gitignore b/gdt/.gitignore
new file mode 100644
index 0000000..107ef7c
--- /dev/null
+++ b/gdt/.gitignore
@@ -0,0 +1,53 @@
+# Copy from Alibaba open source
+
+# Built application files
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+# local.properties
+.classpath
+.project
+.settings/
+
+# Proguard folder generated by Eclipse
+proguard/
+
+#Log Files
+*.log
+
+# OS X
+.DS_Store
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.war
+*.ear
+*.iml
+
+# IDEA Files
+.idea/
+.svn/
+out/
+
+# MAVEN COMPILE Files
+target/
+lint.xml
+
+deploy.gradle
+jcenterDeploy.gradle
+jcenterInstall.gradle
\ No newline at end of file
diff --git a/gdt/build.gradle b/gdt/build.gradle
new file mode 100644
index 0000000..19bc0dc
--- /dev/null
+++ b/gdt/build.gradle
@@ -0,0 +1,41 @@
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'com.kezong.fat-aar'
+
+// JitPack Maven
+apply plugin: 'com.github.dcendents.android-maven'
+// Your Group
+group = 'com.github.ifmvo'
+
+android {
+ compileSdkVersion 28
+
+ defaultConfig {
+ minSdkVersion 16
+ targetSdkVersion 28
+ versionCode 1
+ versionName "5.0.3"
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+
+ buildTypes {
+ release {
+ consumerProguardFiles 'proguard-rules.pro'
+ }
+ }
+
+ repositories { flatDir { dirs 'libs' } }
+
+}
+
+dependencies {
+ api fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
+// embed(name: 'GDTSDK.unionNormal.4.351.1221', ext: 'aar')
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+
+ api project(':core')
+}
\ No newline at end of file
diff --git a/gdt/libs/GDTSDK.unionNormal.4.351.1221.aar b/gdt/libs/GDTSDK.unionNormal.4.351.1221.aar
new file mode 100644
index 0000000..9853770
Binary files /dev/null and b/gdt/libs/GDTSDK.unionNormal.4.351.1221.aar differ
diff --git a/gdt/proguard-rules.pro b/gdt/proguard-rules.pro
new file mode 100644
index 0000000..6c34b6a
--- /dev/null
+++ b/gdt/proguard-rules.pro
@@ -0,0 +1,64 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# 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 *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
+-keep class com.qq.e.** {
+ public protected *;
+}
+-keep class android.support.v4.**{
+ public *;
+}
+-keep class android.support.v7.**{
+ public *;
+}
+-keep class yaq.gdtadv{
+ *;
+}
+-keep class com.qq.e.** {
+ *;
+}
+-keep class com.tencent.** {
+ *;
+}
+-keep class cn.mmachina.JniClient {
+ *;
+}
+-keep class c.t.m.li.tsa.** {
+ *;
+}
+
+-keep class * extends java.lang.annotation.Annotation { *; }
+-keep interface * extends java.lang.annotation.Annotation { *; }
+
+-keep, allowobfuscation class com.qq.e.comm.plugin.services.SDKServerService {*;}
+-keepclassmembers, allowobfuscation class com.qq.e.comm.plugin.net.SecurePackager {
+ public *;
+}
+
+-keepclasseswithmembers,includedescriptorclasses class * {
+native ;
+}
+
+-keep class * extends com.qq.e.mediation.interfaces.BaseNativeUnifiedAd { *; }
+-keep class * extends com.qq.e.mediation.interfaces.BaseSplashAd { *; }
+-keep class * extends com.qq.e.mediation.interfaces.BaseRewardAd { *; }
+
+
+-keep class com.ifmvo.togetherad.gdt.** { *; }
\ No newline at end of file
diff --git a/gdt/src/main/AndroidManifest.xml b/gdt/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..ea7861e
--- /dev/null
+++ b/gdt/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/TogetherAdGdt.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/TogetherAdGdt.kt
new file mode 100644
index 0000000..8724cab
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/TogetherAdGdt.kt
@@ -0,0 +1,40 @@
+package com.ifmvo.togetherad.gdt
+
+import android.content.Context
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.entity.AdProviderEntity
+import com.ifmvo.togetherad.gdt.provider.GdtProvider
+import com.qq.e.comm.compliance.DownloadConfirmListener
+import com.qq.e.comm.managers.GDTADManager
+import org.jetbrains.annotations.NotNull
+
+/**
+ * 初始化广点通
+ *
+ * Created by Matthew Chen on 2020-04-04.
+ */
+object TogetherAdGdt {
+
+ var idMapGDT = mutableMapOf()
+
+ //下载确认的回调,可参考 DownloadConfirmHelper 进行自定义
+ var downloadConfirmListener: DownloadConfirmListener? = null
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull gdtAdAppId: String) {
+ init(context, adProviderType, gdtAdAppId, null, null)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull gdtAdAppId: String, providerClassPath: String? = null) {
+ init(context, adProviderType, gdtAdAppId, null, providerClassPath)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull gdtAdAppId: String, gdtIdMap: Map? = null) {
+ init(context, adProviderType, gdtAdAppId, gdtIdMap, null)
+ }
+
+ fun init(@NotNull context: Context, @NotNull adProviderType: String, @NotNull gdtAdAppId: String, gdtIdMap: Map? = null, providerClassPath: String? = null) {
+ TogetherAd.addProvider(AdProviderEntity(adProviderType, if (providerClassPath?.isEmpty() != false) GdtProvider::class.java.name else providerClassPath))
+ gdtIdMap?.let { idMapGDT.putAll(it) }
+ GDTADManager.getInstance().initWith(context, gdtAdAppId)
+ }
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/express/NativeExpressViewGdt.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/express/NativeExpressViewGdt.kt
new file mode 100644
index 0000000..f7d2e99
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/express/NativeExpressViewGdt.kt
@@ -0,0 +1,49 @@
+package com.ifmvo.togetherad.gdt.native_.express
+
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.custom.express.BaseNativeExpressView
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.qq.e.ads.nativ.NativeExpressADView
+import com.qq.e.ads.nativ.NativeExpressMediaListener
+import com.qq.e.comm.constants.AdPatternType
+import com.qq.e.comm.util.AdError
+
+/**
+ * Created by Matthew Chen on 2020/11/25.
+ */
+class NativeExpressViewGdt : BaseNativeExpressView() {
+
+ override fun showNativeExpress(adProviderType: String, adObject: Any, container: ViewGroup) {
+ if (adObject !is NativeExpressADView) return
+
+ TogetherAdGdt.downloadConfirmListener?.let {
+ adObject.setDownloadConfirmListener(it)
+ }
+
+ //设置下载确认
+ if (adObject.boundData.adPatternType == AdPatternType.NATIVE_VIDEO) {
+ adObject.setMediaListener(object : NativeExpressMediaListener {
+ override fun onVideoInit(adView: NativeExpressADView?) {}
+ override fun onVideoPageClose(adView: NativeExpressADView?) {}
+ override fun onVideoPause(adView: NativeExpressADView?) {}
+ override fun onVideoStart(adView: NativeExpressADView?) {}
+ override fun onVideoError(adView: NativeExpressADView?, adError: AdError?) {}
+ override fun onVideoPageOpen(adView: NativeExpressADView?) {}
+ override fun onVideoLoading(adView: NativeExpressADView?) {}
+ override fun onVideoReady(adView: NativeExpressADView?, time: Long) {}
+ override fun onVideoCached(adView: NativeExpressADView?) {}
+ override fun onVideoComplete(adView: NativeExpressADView?) {}
+ })
+ }
+
+ adObject.render()
+
+ if (container.childCount > 0) {
+ container.removeAllViews()
+ }
+
+ // 需要保证 View 被绘制的时候是可见的,否则将无法产生曝光和收益。
+ container.addView(adObject)
+ }
+
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/express2/NativeExpress2ViewGdt.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/express2/NativeExpress2ViewGdt.kt
new file mode 100644
index 0000000..879d2c8
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/express2/NativeExpress2ViewGdt.kt
@@ -0,0 +1,73 @@
+package com.ifmvo.togetherad.gdt.native_.express2
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.custom.express2.BaseNativeExpress2View
+import com.ifmvo.togetherad.core.listener.NativeExpress2ViewListener
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.qq.e.ads.nativ.express2.AdEventListener
+import com.qq.e.ads.nativ.express2.MediaEventListener
+import com.qq.e.ads.nativ.express2.NativeExpressADData2
+
+/**
+ * Created by Matthew Chen on 2020/11/25.
+ */
+class NativeExpress2ViewGdt : BaseNativeExpress2View() {
+
+ override fun showNativeExpress2(activity: Activity, adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeExpress2ViewListener?) {
+
+ if (adObject !is NativeExpressADData2) return
+
+ container.removeAllViews()
+
+ //设置下载确认
+ TogetherAdGdt.downloadConfirmListener?.let {
+ adObject.setDownloadConfirmListener(it)
+ }
+
+ adObject.setAdEventListener(object : AdEventListener {
+ override fun onClick() {
+ listener?.onAdClicked(adProviderType)
+ }
+
+ override fun onExposed() {
+ listener?.onAdExposed(adProviderType)
+ }
+
+ override fun onRenderSuccess() {
+ if (adObject.adView != null) {
+ val parent = adObject.adView?.parent
+ if (parent is ViewGroup) {
+ parent.removeAllViews()
+ }
+ container.addView(adObject.adView)
+ listener?.onAdRenderSuccess(adProviderType)
+ } else {
+ listener?.onAdRenderFailed(adProviderType)
+ }
+ }
+
+ override fun onAdClosed() {
+ container.removeAllViews()
+ adObject.destroy()
+ listener?.onAdClose(adProviderType)
+ }
+
+ override fun onRenderFail() {
+ listener?.onAdRenderFailed(adProviderType)
+ }
+ })
+
+ adObject.setMediaListener(object : MediaEventListener {
+ override fun onVideoCache() {}
+ override fun onVideoPause() {}
+ override fun onVideoStart() {}
+ override fun onVideoComplete() {}
+ override fun onVideoError() {}
+ override fun onVideoResume() {}
+ })
+
+ adObject.render()
+
+ }
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/BaseNativeViewGdt.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/BaseNativeViewGdt.kt
new file mode 100644
index 0000000..8fc02ac
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/BaseNativeViewGdt.kt
@@ -0,0 +1,283 @@
+package com.ifmvo.togetherad.gdt.native_.view
+
+import android.view.View
+import android.view.ViewGroup
+import android.widget.*
+import com.ifmvo.togetherad.core.TogetherAd
+import com.ifmvo.togetherad.core.custom.native_.BaseNativeView
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.gdt.R
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.qq.e.ads.cfg.VideoOption
+import com.qq.e.ads.nativ.MediaView
+import com.qq.e.ads.nativ.NativeADEventListener
+import com.qq.e.ads.nativ.NativeADMediaListener
+import com.qq.e.ads.nativ.NativeUnifiedADData
+import com.qq.e.ads.nativ.widget.NativeAdContainer
+import com.qq.e.comm.constants.AdPatternType
+import com.qq.e.comm.util.AdError
+
+
+/**
+ *
+ * Created by Matthew Chen on 2020/9/16.
+ */
+abstract class BaseNativeViewGdt(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeView() {
+
+ //设置视频广告在预览页自动播放时是否静音,默认为true,静音自动播放;
+ // 模板渲染视频、插屏2.0视频、自渲染2.0视频都可使用
+ var autoPlayMuted = true
+
+ //设置视频广告在预览页自动播放的网络条件:
+ // VideoOption.AutoPlayPolicy.WIFI 表示只在WiFi下自动播放;
+ // VideoOption.AutoPlayPolicy.ALWAYS 表示始终自动播放,不区分当前网络;
+ // VideoOption.AutoPlayPolicy.NEVER 表示始终都不自动播放,不区分当前网络,但在WiFi时会预下载视频资源;
+ // 默认为始终自动播放;模板渲染视频、插屏2.0视频、自渲染2.0视频都可使用
+ var autoPlayPolicy: Int = VideoOption.AutoPlayPolicy.ALWAYS
+
+ //设置视频广告在预览页未开始播放时是否显示封面图,默认为true,显示封面图;
+ // 只对自渲染2.0视频广告生效
+ var needCoverImage = true
+
+ //设置视频广告在在预览页播放过程中是否显示进度条,默认为true,显示进度条;
+ // 只对自渲染2.0视频广告生效
+ var needProgressBar = true
+
+ //设置是否允许用户在预览页点击视频播放器区域控制视频的暂停或播放,默认为false,用户点击时的表现与点击clickableViews一致;
+ // 如果为true,用户点击时将收到NativeADMediaListener.onVideoClicked回调,而不是NativeADEventListener.onADClicked回调,因为此时并不是广告点击。只对自渲染2.0视频广告生效
+ var enableUserControl = false
+
+ //用户在预览页点击clickableViews或视频区域(setEnableUserControl设置为false)时是否跳转到详情页,默认为true,跳转到详情页;只对自渲染2.0视频广告生效
+ var enableDetailPage = true
+
+ //设置视频详情页是否静音播放,默认值为false,即有声播放;模板渲染视频、插屏2.0视频、自渲染2.0视频都可使用
+ var detailPageMuted = false
+
+ var rootView: View? = null
+
+ //关闭按钮的回调
+ private var mOnClose = onClose
+
+ open fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_gdt
+ }
+
+ open fun getNativeAdContainer(): NativeAdContainer? {
+ return rootView?.findViewById(R.id.native_ad_container)
+ }
+
+ //icon 图
+ open fun getIconImageView(): ImageView? {
+ return rootView?.findViewById(R.id.img_logo)
+ }
+
+ //action 按钮( 下载、浏览、打电话。。。 )
+ open fun getActionButton(): Button? {
+ return rootView?.findViewById(R.id.btn_download)
+ }
+
+ //关闭按钮
+ open fun getCloseButton(): View? {
+ return rootView?.findViewById(R.id.btn_close)
+ }
+
+ //标题文字
+ open fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.text_title)
+ }
+
+ //描述文字
+ open fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.text_desc)
+ }
+
+ //视频控件
+ open fun getMediaView(): MediaView? {
+ return rootView?.findViewById(R.id.gdt_media_view)
+ }
+
+ //主图
+ open fun getMainImageView(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster)
+ }
+
+ //视频是否静音按钮
+ open fun getMuteCheckBox(): CheckBox? {
+ return rootView?.findViewById(R.id.btn_mute)
+ }
+
+ //视频播放按钮
+ open fun getPlayButton(): Button? {
+ return rootView?.findViewById(R.id.btn_play)
+ }
+
+ //视频暂停按钮
+ open fun getPauseButton(): Button? {
+ return rootView?.findViewById(R.id.btn_pause)
+ }
+
+ //视频停止按钮
+ open fun getStopButton(): Button? {
+ return rootView?.findViewById(R.id.btn_stop)
+ }
+
+ //可点击ViewList,可重写
+ open fun getClickableViews(): List? {
+ val clickableViews = mutableListOf()
+ getMainImageView()?.let { clickableViews.add(it) }
+ getIconImageView()?.let { clickableViews.add(it) }
+ return clickableViews
+ }
+
+ //自定义点击按钮,点击直接下载或跳转的按钮,详情看广点通文档
+ open fun getCustomClickableViews(): List? {
+ val customClickableViews = mutableListOf()
+ getActionButton()?.let { customClickableViews.add(it) }
+ return customClickableViews
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ if (adObject !is NativeUnifiedADData) {
+ return
+ }
+
+ container.removeAllViews()
+
+ //findView
+ rootView = View.inflate(container.context, getLayoutRes(), container)
+
+ //设置下载确认
+ TogetherAdGdt.downloadConfirmListener?.let {
+ adObject.setDownloadConfirmListener(it)
+ }
+
+ //Image
+ getIconImageView()?.let { TogetherAd.mImageLoader?.loadImage(container.context, it, adObject.iconUrl) }
+
+ //标题和描述
+ getTitleTextView()?.text = adObject.title
+ getDescTextView()?.text = adObject.desc
+
+ //图片还是视频
+ when (adObject.adPatternType) {
+ AdPatternType.NATIVE_1IMAGE_2TEXT, AdPatternType.NATIVE_2IMAGE_2TEXT, AdPatternType.NATIVE_3IMAGE -> {
+ getMediaView()?.visibility = View.GONE
+ getMainImageView()?.visibility = View.VISIBLE
+ getMainImageView()?.let { TogetherAd.mImageLoader?.loadImage(container.context, it, adObject.imgUrl) }
+ }
+ AdPatternType.NATIVE_VIDEO -> {
+ getMediaView()?.visibility = View.VISIBLE
+ getMainImageView()?.visibility = View.GONE
+ }
+ }
+
+ adObject.bindAdToView(container.context, getNativeAdContainer(), getLogoLayoutParams(), getClickableViews(), getCustomClickableViews())
+
+ //视频需要设置 静音、播放、暂停、停止按钮
+ if (adObject.adPatternType == AdPatternType.NATIVE_VIDEO) {
+
+ val videoOption = VideoOption.Builder()
+ .setAutoPlayPolicy(autoPlayPolicy)
+ .setAutoPlayMuted(autoPlayMuted)
+ .setDetailPageMuted(detailPageMuted)
+ .setNeedCoverImage(needCoverImage)
+ .setNeedProgressBar(needProgressBar)
+ .setEnableDetailPage(enableDetailPage)
+ .setEnableUserControl(enableUserControl)
+ .build()
+
+ adObject.bindMediaView(getMediaView(), videoOption, object : NativeADMediaListener {
+ override fun onVideoInit() {}
+ override fun onVideoStop() {}
+ override fun onVideoPause() {}
+ override fun onVideoStart() {}
+ override fun onVideoError(p0: AdError?) {}
+ override fun onVideoCompleted() {}
+ override fun onVideoLoading() {}
+ override fun onVideoReady() {}
+ override fun onVideoLoaded(p0: Int) {}
+ override fun onVideoClicked() {}
+ override fun onVideoResume() {}
+ })
+ getMuteCheckBox()?.visibility = View.VISIBLE
+ getPlayButton()?.visibility = View.VISIBLE
+ getPauseButton()?.visibility = View.VISIBLE
+ getStopButton()?.visibility = View.VISIBLE
+
+ getMuteCheckBox()?.isChecked = autoPlayMuted
+ getMuteCheckBox()?.setOnCheckedChangeListener { _, isChecked ->
+ adObject.setVideoMute(isChecked)
+ }
+
+ getPlayButton()?.setOnClickListener {
+ adObject.startVideo()
+ }
+
+ getPauseButton()?.setOnClickListener {
+ adObject.pauseVideo()
+ }
+
+ getStopButton()?.setOnClickListener {
+ adObject.stopVideo()
+ }
+ } else {
+ getMuteCheckBox()?.visibility = View.GONE
+ getPlayButton()?.visibility = View.GONE
+ getPauseButton()?.visibility = View.GONE
+ getStopButton()?.visibility = View.GONE
+ }
+
+ //广告的事件
+ adObject.setNativeAdEventListener(object : NativeADEventListener {
+ override fun onADStatusChanged() {
+ //根据广告的状态改变按钮的文字
+ getActionButton()?.let { it.text = getActionBtnText(adObject) }
+ }
+
+ override fun onADError(error: AdError?) {
+ }
+
+ override fun onADClicked() {
+ listener?.onAdClicked(adProviderType)
+ }
+
+ override fun onADExposed() {
+ listener?.onAdExposed(adProviderType)
+ }
+ })
+
+ //设置按钮的初始文字
+ getActionButton()?.let { it.text = getActionBtnText(adObject) }
+
+ //设置关闭按钮
+ getCloseButton()?.visibility = if (mOnClose == null) View.GONE else View.VISIBLE
+ getCloseButton()?.setOnClickListener {
+ mOnClose?.invoke(adProviderType)
+ }
+ }
+
+ /**
+ * 根据广告的状态返回按钮应该展示的文字
+ */
+ open fun getActionBtnText(ad: NativeUnifiedADData): String {
+ if (!ad.isAppAd) {
+ return "浏览"
+ }
+ return when (ad.appStatus) {
+ 0 -> "下载"
+ 1 -> "启动"
+ 2 -> "更新"
+ 4 -> ad.progress.toString() + "%"
+ 8 -> "安装"
+ 16 -> "下载失败,重新下载"
+ else -> "浏览"
+ }
+ }
+
+ /**
+ * 可以根据自己的情况重写,设置广告标示和logo的位置
+ */
+ open fun getLogoLayoutParams(): FrameLayout.LayoutParams? {
+ return null
+ }
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple1.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple1.kt
new file mode 100644
index 0000000..2e28afd
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple1.kt
@@ -0,0 +1,47 @@
+package com.ifmvo.togetherad.gdt.native_.view
+
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.gdt.R
+import com.qq.e.ads.nativ.MediaView
+import com.qq.e.ads.nativ.widget.NativeAdContainer
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewGdtSimple1 : BaseNativeViewGdt() {
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_gdt_simple_1
+ }
+
+ override fun getNativeAdContainer(): NativeAdContainer? {
+ return rootView?.findViewById(R.id.native_ad_container)
+ }
+
+ override fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_title)
+ }
+
+ override fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_desc)
+ }
+
+ override fun getMediaView(): MediaView? {
+ return rootView?.findViewById(R.id.gdt_media_view)
+ }
+
+ override fun getMainImageView(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster)
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+
+ getMainImageView()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+ getMediaView()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+ }
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple2.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple2.kt
new file mode 100644
index 0000000..acd6d39
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple2.kt
@@ -0,0 +1,48 @@
+package com.ifmvo.togetherad.gdt.native_.view
+
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.gdt.R
+import com.qq.e.ads.nativ.MediaView
+import com.qq.e.ads.nativ.widget.NativeAdContainer
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewGdtSimple2 : BaseNativeViewGdt() {
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_gdt_simple_2
+ }
+
+ override fun getNativeAdContainer(): NativeAdContainer? {
+ return rootView?.findViewById(R.id.native_ad_container)
+ }
+
+ override fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_title)
+ }
+
+ override fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_desc)
+ }
+
+ override fun getMediaView(): MediaView? {
+ return rootView?.findViewById(R.id.gdt_media_view)
+ }
+
+ override fun getMainImageView(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster)
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+
+ getMainImageView()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) / 3 * 9 / 16)
+ getMediaView()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) / 3 * 9 / 16)
+ }
+
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple3.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple3.kt
new file mode 100644
index 0000000..a21a918
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple3.kt
@@ -0,0 +1,78 @@
+package com.ifmvo.togetherad.gdt.native_.view
+
+import android.os.CountDownTimer
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.ifmvo.togetherad.core.custom.splashSkip.SplashSkipViewSimple2
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.gdt.R
+import com.qq.e.ads.nativ.MediaView
+import com.qq.e.ads.nativ.widget.NativeAdContainer
+import kotlin.math.roundToInt
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewGdtSimple3(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeViewGdt() {
+
+ private var mOnClose = onClose
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_gdt_simple_3
+ }
+
+ override fun getNativeAdContainer(): NativeAdContainer? {
+ return rootView?.findViewById(R.id.native_ad_container)
+ }
+
+ override fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_title)
+ }
+
+ override fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_desc)
+ }
+
+ override fun getMediaView(): MediaView? {
+ return rootView?.findViewById(R.id.gdt_media_view)
+ }
+
+ override fun getMainImageView(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster)
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+
+ //添加跳过按钮
+ val customSkipView = SplashSkipViewSimple2()
+ val skipView = customSkipView.onCreateSkipView(container.context)
+ skipView.run {
+ container.addView(this, customSkipView.getLayoutParams())
+ setOnClickListener {
+ mTimer?.cancel()
+ container.removeAllViews()
+ mOnClose?.invoke(adProviderType)
+ }
+ }
+
+ //开始倒计时
+ mTimer?.cancel()
+ mTimer = object : CountDownTimer(5000, 1000) {
+ override fun onFinish() {
+ container.removeAllViews()
+ mOnClose?.invoke(adProviderType)
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ val second = (millisUntilFinished / 1000f).roundToInt()
+ customSkipView.handleTime(second)
+ }
+ }
+ mTimer?.start()
+
+ }
+
+ private var mTimer: CountDownTimer? = null
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple4.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple4.kt
new file mode 100644
index 0000000..ab21931
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple4.kt
@@ -0,0 +1,81 @@
+package com.ifmvo.togetherad.gdt.native_.view
+
+import android.os.CountDownTimer
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import com.ifmvo.togetherad.core.custom.splashSkip.SplashSkipViewSimple3
+import com.ifmvo.togetherad.core.listener.NativeViewListener
+import com.ifmvo.togetherad.core.utils.ScreenUtil
+import com.ifmvo.togetherad.gdt.R
+import com.qq.e.ads.nativ.MediaView
+import com.qq.e.ads.nativ.widget.NativeAdContainer
+import kotlin.math.roundToInt
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewGdtSimple4(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeViewGdt() {
+
+ private var mOnClose = onClose
+
+ override fun getLayoutRes(): Int {
+ return R.layout.layout_native_view_gdt_simple_4
+ }
+
+ override fun getNativeAdContainer(): NativeAdContainer? {
+ return rootView?.findViewById(R.id.native_ad_container)
+ }
+
+ override fun getTitleTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_title)
+ }
+
+ override fun getDescTextView(): TextView? {
+ return rootView?.findViewById(R.id.tv_desc)
+ }
+
+ override fun getMediaView(): MediaView? {
+ return rootView?.findViewById(R.id.gdt_media_view)
+ }
+
+ override fun getMainImageView(): ImageView? {
+ return rootView?.findViewById(R.id.img_poster)
+ }
+
+ override fun showNative(adProviderType: String, adObject: Any, container: ViewGroup, listener: NativeViewListener?) {
+ super.showNative(adProviderType, adObject, container, listener)
+
+ getMainImageView()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+ getMediaView()?.layoutParams?.height = (ScreenUtil.getDisplayMetricsWidth(container.context) * 9 / 16)
+
+ //添加跳过按钮
+ val customSkipView = SplashSkipViewSimple3()
+ val skipView = customSkipView.onCreateSkipView(container.context)
+ skipView.run {
+ container.addView(this, customSkipView.getLayoutParams())
+ setOnClickListener {
+ mTimer?.cancel()
+ container.removeAllViews()
+ mOnClose?.invoke(adProviderType)
+ }
+ }
+
+ //开始倒计时
+ mTimer?.cancel()
+ mTimer = object : CountDownTimer(5000, 1000) {
+ override fun onFinish() {
+ container.removeAllViews()
+ mOnClose?.invoke(adProviderType)
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ val second = (millisUntilFinished / 1000f).roundToInt()
+ customSkipView.handleTime(second)
+ }
+ }
+ mTimer?.start()
+ }
+
+ private var mTimer: CountDownTimer? = null
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple5.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple5.kt
new file mode 100644
index 0000000..5602f70
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/native_/view/NativeViewGdtSimple5.kt
@@ -0,0 +1,20 @@
+package com.ifmvo.togetherad.gdt.native_.view
+
+import android.view.Gravity
+import android.widget.FrameLayout
+
+/**
+ * Created by Matthew Chen on 2020-04-21.
+ */
+class NativeViewGdtSimple5(onClose: ((adProviderType: String) -> Unit)? = null) : BaseNativeViewGdt(onClose) {
+
+ /**
+ * 重写该方法,可以设置广告Logo标识的位置
+ */
+ override fun getLogoLayoutParams(): FrameLayout.LayoutParams? {
+ val layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT)
+ layoutParams.gravity = Gravity.BOTTOM or Gravity.END
+ layoutParams.bottomMargin = 100
+ return layoutParams
+ }
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/DownloadApkConfirmDialog.java b/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/DownloadApkConfirmDialog.java
new file mode 100644
index 0000000..b6a0376
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/DownloadApkConfirmDialog.java
@@ -0,0 +1,238 @@
+package com.ifmvo.togetherad.gdt.other;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Configuration;
+import android.text.TextUtils;
+import android.text.util.Linkify;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Patterns;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.ifmvo.togetherad.gdt.R;
+import com.qq.e.comm.compliance.DownloadConfirmCallBack;
+
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.regex.Matcher;
+
+
+/*
+ * Copy from gdt demo.
+ */
+public class DownloadApkConfirmDialog extends Dialog implements View.OnClickListener {
+ private static final String TAG = "ConfirmDialog";
+ private Context context;
+ private int orientation;
+ private DownloadConfirmCallBack callBack;
+ private TextView textView;
+ private ImageView close;
+ private Button confirm;
+
+ private ViewGroup contentHolder;
+ private ProgressBar loadingBar;
+ private Button reloadButton;
+
+ private String url;
+
+ private static final String RELOAD_TEXT = "重新加载";
+ private static final String LOAD_ERROR_TEXT = "抱歉,应用信息获取失败";
+
+ public DownloadApkConfirmDialog(Context context, String infoUrl,
+ DownloadConfirmCallBack callBack) {
+ super(context, R.style.DownloadConfirmDialogFullScreen);//需要全屏显示,同时显示非窗口蒙版
+ this.context = context;
+ this.callBack = callBack;
+ this.url = infoUrl;
+ orientation = context.getResources().getConfiguration().orientation;
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setCanceledOnTouchOutside(true);
+ initView();
+ }
+
+ private void initView() {
+ setContentView(R.layout.download_confirm_dialog);
+ View root = findViewById(R.id.download_confirm_root);
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ root.setBackgroundResource(R.drawable.download_confirm_background_portrait);
+ } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ root.setBackgroundResource(R.drawable.download_confirm_background_landscape);
+ }
+ close = findViewById(R.id.download_confirm_close);
+ close.setOnClickListener(this);
+ reloadButton = findViewById(R.id.download_confirm_reload_button);
+ reloadButton.setOnClickListener(this);
+ confirm = findViewById(R.id.download_confirm_confirm);
+ confirm.setOnClickListener(this);
+ loadingBar = findViewById(R.id.download_confirm_progress_bar);
+ contentHolder = findViewById(R.id.download_confirm_content);
+ createTextView();
+ }
+
+ private void createTextView() {
+ FrameLayout layout = findViewById(R.id.download_confirm_holder);
+ textView = new TextView(context);
+ ScrollView sv = new ScrollView(context);
+ sv.addView(textView);
+ layout.addView(sv);
+ }
+
+ @Override
+ public void show() {
+ super.show();
+ try {
+ loadUrl(url);
+ } catch (Exception e) {
+ Log.e(DownloadApkConfirmDialog.TAG, "load error url:" + url, e);
+ }
+ }
+
+
+ private void loadUrl(String url) {
+ if (TextUtils.isEmpty(url)) {
+ loadingBar.setVisibility(View.GONE);
+ contentHolder.setVisibility(View.GONE);
+ reloadButton.setVisibility(View.VISIBLE);
+ reloadButton.setText(LOAD_ERROR_TEXT);
+ reloadButton.setEnabled(false);
+ return;
+ }
+ new NetworkRequestAsyncTask() {
+ @Override
+ protected void onPostExecute(String str) {
+ loadingBar.setVisibility(View.GONE);
+ reloadButton.setVisibility(View.GONE);
+ contentHolder.setVisibility(View.VISIBLE);
+
+ DownloadConfirmHelper.ApkInfo apkInfo = DownloadConfirmHelper.getAppInfoFromJson(str);
+ if (apkInfo == null) {
+ loadingBar.setVisibility(View.GONE);
+ reloadButton.setVisibility(View.VISIBLE);
+ contentHolder.setVisibility(View.GONE);
+ return;
+ }
+
+
+ textView.append("icon链接:\n");
+ textView.append(apkInfo.iconUrl);
+
+ textView.append("\n应用名:\n");
+ textView.append("\t" + apkInfo.appName);
+
+ textView.append("\n应用版本:\n");
+ textView.append("\t" + apkInfo.versionName);
+
+ textView.append("\n开发者:\n");
+ textView.append("\t" + apkInfo.authorName);
+
+ textView.append("\n应用大小:\n");
+ textView.append("\t" + readableFileSize(apkInfo.fileSize));
+
+ textView.append("\n更新时间:\n");
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
+ textView.append("\t" + sdf.format(new Date(apkInfo.apkPublishTime)));
+
+ textView.append("\n隐私条款链接:\n");
+ textView.append(apkInfo.privacyAgreementUrl);
+
+ textView.append("\n权限信息:\n");
+
+ for (String i : apkInfo.permissions) {
+ textView.append("\t" + i + "\n");
+ }
+ Linkify.TransformFilter filter = new Linkify.TransformFilter() {
+ public final String transformUrl(final Matcher match, String url) {
+ return match.group();
+ }
+ };
+ Linkify.addLinks(textView, Patterns.WEB_URL, null, null, filter);
+ loadingBar.setVisibility(View.GONE);
+ reloadButton.setVisibility(View.GONE);
+ contentHolder.setVisibility(View.VISIBLE);
+ }
+ }.execute(url);
+ }
+
+ @Override
+ protected void onStart() {
+ DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();
+ int height = dm.heightPixels;
+ int width = dm.widthPixels;
+ Window window = getWindow();
+ window.getDecorView().setPadding(0, 0, 0, 0);
+ WindowManager.LayoutParams layoutParams = window.getAttributes();
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
+ layoutParams.height = (int) (height * 0.6);
+ layoutParams.gravity = Gravity.BOTTOM;
+ layoutParams.windowAnimations = R.style.DownloadConfirmDialogAnimationUp;
+ } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ layoutParams.width = (int) (width * 0.5);
+ layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
+ layoutParams.gravity = Gravity.RIGHT;
+ layoutParams.windowAnimations = R.style.DownloadConfirmDialogAnimationRight;
+ }
+ //弹窗外区域蒙版50%透明度
+ layoutParams.dimAmount = 0.5f;
+
+ //resume后动画会重复,在显示出来后重置无动画
+ window.setAttributes(layoutParams);
+ setOnShowListener(new OnShowListener() {
+ @Override
+ public void onShow(DialogInterface dialog) {
+ try {
+ Window window = getWindow();
+ window.setWindowAnimations(0);
+ } catch (Throwable t) {
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == close) {
+ if (callBack != null) {
+ callBack.onCancel();
+ }
+ dismiss();
+ } else if (v == confirm) {
+ if (callBack != null) {
+ callBack.onConfirm();
+ }
+ dismiss();
+ } else if (v == reloadButton) {
+ loadUrl(url);
+ }
+
+ }
+
+ @Override
+ public void cancel() {
+ super.cancel();
+ if (callBack != null) {
+ callBack.onCancel();
+ }
+ }
+
+ public static String readableFileSize(long size) {
+ if (size <= 0) return "0";
+ final String[] units = new String[]{"B", "kB", "MB", "GB", "TB"};
+ int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
+ return new DecimalFormat("#,##0.##").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
+ }
+
+}
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/DownloadApkConfirmDialogWebView.java b/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/DownloadApkConfirmDialogWebView.java
new file mode 100644
index 0000000..b34b3f2
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/DownloadApkConfirmDialogWebView.java
@@ -0,0 +1,200 @@
+package com.ifmvo.togetherad.gdt.other;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.res.Configuration;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.webkit.WebResourceError;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+
+import com.ifmvo.togetherad.gdt.R;
+import com.qq.e.comm.compliance.DownloadConfirmCallBack;
+
+
+/*
+ * Copy from gdt demo.
+ */
+public class DownloadApkConfirmDialogWebView extends Dialog implements View.OnClickListener {
+ private static final String TAG = "ConfirmDialogWebView";
+ private Context context;
+ private int orientation;
+ private DownloadConfirmCallBack callBack;
+ private WebView webView;
+ private ImageView close;
+ private Button confirm;
+
+ private ViewGroup contentHolder;
+ private ProgressBar loadingBar;
+ private Button reloadButton;
+
+ private String url;
+ private boolean urlLoadError = false;
+
+ private static final String RELOAD_TEXT = "重新加载";
+ private static final String LOAD_ERROR_TEXT = "抱歉,应用信息获取失败";
+
+ public DownloadApkConfirmDialogWebView(Context context, String infoUrl, DownloadConfirmCallBack callBack) {
+ super(context, R.style.DownloadConfirmDialogFullScreen);//需要全屏显示,同时显示非窗口蒙版
+ this.context = context;
+ this.callBack = callBack;
+ this.url = infoUrl;
+ orientation = context.getResources().getConfiguration().orientation;
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ setCanceledOnTouchOutside(true);
+ initView();
+ }
+
+ private void initView() {
+ setContentView(R.layout.download_confirm_dialog);
+ View root = findViewById(R.id.download_confirm_root);
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ root.setBackgroundResource(R.drawable.download_confirm_background_portrait);
+ } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ root.setBackgroundResource(R.drawable.download_confirm_background_landscape);
+ }
+ close = findViewById(R.id.download_confirm_close);
+ close.setOnClickListener(this);
+ reloadButton = findViewById(R.id.download_confirm_reload_button);
+ reloadButton.setOnClickListener(this);
+ confirm = findViewById(R.id.download_confirm_confirm);
+ confirm.setOnClickListener(this);
+ loadingBar = findViewById(R.id.download_confirm_progress_bar);
+ contentHolder = findViewById(R.id.download_confirm_content);
+ createTextView();
+ }
+
+ private void createTextView() {
+ FrameLayout layout = findViewById(R.id.download_confirm_holder);
+ webView = new WebView(context);
+ webView.getSettings().setJavaScriptEnabled(true);
+ webView.setWebViewClient(new Client());
+ layout.addView(webView);
+ }
+
+ @Override
+ public void show() {
+ super.show();
+ try {
+ loadUrl(url);
+ } catch (Exception e) {
+ Log.e(DownloadApkConfirmDialogWebView.TAG, "load error url:" + url, e);
+ }
+ }
+
+
+ private void loadUrl(String url) {
+ if (TextUtils.isEmpty(url)) {
+ loadingBar.setVisibility(View.GONE);
+ contentHolder.setVisibility(View.GONE);
+ reloadButton.setVisibility(View.VISIBLE);
+ reloadButton.setText(LOAD_ERROR_TEXT);
+ reloadButton.setEnabled(false);
+ return;
+ }
+ urlLoadError = false;
+ Log.d(TAG, "download confirm load url:" + url);
+ webView.loadUrl(url);
+ }
+
+ @Override
+ protected void onStart() {
+ DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();
+ int height = dm.heightPixels;
+ int width = dm.widthPixels;
+ Window window = getWindow();
+ window.getDecorView().setPadding(0, 0, 0, 0);
+ WindowManager.LayoutParams layoutParams = window.getAttributes();
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+ layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
+ layoutParams.height = (int) (height * 0.6);
+ layoutParams.gravity = Gravity.BOTTOM;
+ layoutParams.windowAnimations = R.style.DownloadConfirmDialogAnimationUp;
+ } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+ layoutParams.width = (int) (width * 0.5);
+ layoutParams.height = WindowManager.LayoutParams.MATCH_PARENT;
+ layoutParams.gravity = Gravity.RIGHT;
+ layoutParams.windowAnimations = R.style.DownloadConfirmDialogAnimationRight;
+ }
+ //弹窗外区域蒙版50%透明度
+ layoutParams.dimAmount = 0.5f;
+
+ //resume后动画会重复,在显示出来后重置无动画
+ window.setAttributes(layoutParams);
+ setOnShowListener(new OnShowListener() {
+ @Override
+ public void onShow(DialogInterface dialog) {
+ try {
+ Window window = getWindow();
+ window.setWindowAnimations(0);
+ } catch (Throwable t) {
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v == close) {
+ if (callBack != null) {
+ callBack.onCancel();
+ }
+ dismiss();
+ } else if (v == confirm) {
+ if (callBack != null) {
+ callBack.onConfirm();
+ }
+ dismiss();
+ } else if (v == reloadButton) {
+ loadUrl(url);
+ }
+
+ }
+
+ @Override
+ public void cancel() {
+ super.cancel();
+ if (callBack != null) {
+ callBack.onCancel();
+ }
+ }
+
+ class Client extends WebViewClient {
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ if (!urlLoadError) {
+ loadingBar.setVisibility(View.GONE);
+ reloadButton.setVisibility(View.GONE);
+ contentHolder.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
+ super.onReceivedError(view, request, error);
+ Log.d(TAG, "doConfirmWithInfo onReceivedError:" + error + " " + request);
+ urlLoadError = true;
+ loadingBar.setVisibility(View.GONE);
+ contentHolder.setVisibility(View.GONE);
+ reloadButton.setVisibility(View.VISIBLE);
+ reloadButton.setText(RELOAD_TEXT);
+ reloadButton.setEnabled(true);
+ }
+ }
+
+
+}
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/DownloadConfirmHelper.java b/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/DownloadConfirmHelper.java
new file mode 100644
index 0000000..cb149e3
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/DownloadConfirmHelper.java
@@ -0,0 +1,109 @@
+package com.ifmvo.togetherad.gdt.other;
+
+import android.app.Activity;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.qq.e.comm.compliance.DownloadConfirmCallBack;
+import com.qq.e.comm.compliance.DownloadConfirmListener;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * Copy from gdt demo.
+ */
+public class DownloadConfirmHelper {
+ public static final String TAG = "DownloadConfirmHelper";
+
+ private static final String JSON_INFO_PARAMETER = "&resType=api";
+
+ private static final String JSON_RESULT_KEY = "ret";
+ private static final String JSON_DATA_KEY = "data";
+
+ private static final String ICON_URL_KEY = "iconUrl";//App Icon
+ private static final String APP_NAME_KEY = "appName";//App 名称
+ private static final String VERSION_NAME_KEY = "versionName";//版本号
+ private static final String AUTHOR_NAME_KEY = "authorName";//开发者
+ private static final String PERMISSIONS_KEY = "permissions";//权限列表(具体权限信息,非URL)
+ private static final String PRIVACY_AGREEMENT_KEY = "privacyAgreement";//隐私政策(URL)
+ private static final String UPDATE_TIME_KEY = "apkPublishTime";//版本更新时间
+ private static final String APK_FILE_SIZE_KEY = "fileSize";//apk文件大小,bytes
+
+ public static class ApkInfo {
+ public String iconUrl;
+ public String appName;
+ public String versionName;
+ public String authorName;
+ public List permissions;
+ public String privacyAgreementUrl;
+ public long apkPublishTime;
+ public long fileSize;
+ }
+
+ public static final DownloadConfirmListener DOWNLOAD_CONFIRM_LISTENER = new DownloadConfirmListener() {
+ @Override
+ public void onDownloadConfirm(Activity context, int scenes, String infoUrl, DownloadConfirmCallBack callBack) {
+ Log.d(TAG, "scenes:" + scenes + " info url:" + infoUrl);
+
+ //获取对应的json数据并自定义显示
+// new DownloadApkConfirmDialog(context, getApkJsonInfoUrl(infoUrl), callBack).show();
+
+ new DownloadApkConfirmDialogWebView(context, infoUrl, callBack).show();//使用webview显示
+ }
+ };
+
+ public static String getApkJsonInfoUrl(String infoUrl) {
+ return infoUrl + JSON_INFO_PARAMETER;
+ }
+
+ public static ApkInfo getAppInfoFromJson(String jsonStr) {
+ ApkInfo result = null;
+
+ if (TextUtils.isEmpty(jsonStr)) {
+// Log.d(TAG, "请求应用信息返回值为空");
+ return null;
+ }
+ try {
+ JSONObject json = new JSONObject(jsonStr);
+ int retCode = json.optInt(JSON_RESULT_KEY, -1);
+ if (retCode != 0) {
+ Log.d(TAG, "请求应用信息返回值错误");
+ return null;
+ }
+ JSONObject dataJson = json.optJSONObject(JSON_DATA_KEY);
+ if (dataJson == null) {
+ Log.d(TAG, "请求应用信息返回值错误" + JSON_DATA_KEY);
+ return null;
+ }
+
+ if (dataJson != null) {
+ result = new ApkInfo();
+ result.iconUrl = dataJson.optString(ICON_URL_KEY);
+ result.appName = dataJson.optString(APP_NAME_KEY);
+ result.versionName = dataJson.optString(VERSION_NAME_KEY);
+ result.authorName = dataJson.optString(AUTHOR_NAME_KEY);
+ JSONArray jsonPermissions = dataJson.optJSONArray(PERMISSIONS_KEY);
+ if (jsonPermissions != null) {
+ result.permissions = new ArrayList<>();
+ for (int i = 0; i < jsonPermissions.length(); i++) {
+ result.permissions.add(jsonPermissions.getString(i));
+ }
+ }
+ result.privacyAgreementUrl = dataJson.optString(PRIVACY_AGREEMENT_KEY);
+ //后台返回的时间可能是秒也可能是毫秒,这里需要统一下为毫秒
+ //2000年1月1日1时0分0秒对应的 秒是946688401 毫秒是 946688401000
+ long publicTime = dataJson.optLong(UPDATE_TIME_KEY);
+ result.apkPublishTime = publicTime > 946688401000L ? publicTime : publicTime * 1000;
+ result.fileSize = dataJson.optLong(APK_FILE_SIZE_KEY);//单位是字节
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return result;
+ }
+}
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/NetworkRequestAsyncTask.java b/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/NetworkRequestAsyncTask.java
new file mode 100644
index 0000000..e3a4ef7
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/other/NetworkRequestAsyncTask.java
@@ -0,0 +1,59 @@
+package com.ifmvo.togetherad.gdt.other;
+
+import android.os.AsyncTask;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+/*
+ * Copy from gdt demo.
+ */
+public class NetworkRequestAsyncTask extends AsyncTask {
+ public static final String TAG = "NetworkRequestAsyncTask";
+ public static final String REQUEST_METHOD = "GET";
+ public static final int READ_TIMEOUT = 15000;
+ public static final int CONNECTION_TIMEOUT = 15000;
+
+ @Override
+ protected String doInBackground(String... params) {
+ String stringUrl = params[0];
+
+ if (TextUtils.isEmpty(stringUrl)) {
+ return null;
+ }
+
+ String httpResult;
+ String inputLine;
+ Log.d(TAG, "开始请求应用信息:" + stringUrl);
+ try {
+ URL myUrl = new URL(stringUrl);
+ HttpURLConnection connection = (HttpURLConnection)
+ myUrl.openConnection();
+ connection.setRequestMethod(REQUEST_METHOD);
+ connection.setReadTimeout(READ_TIMEOUT);
+ connection.setConnectTimeout(CONNECTION_TIMEOUT);
+
+ connection.connect();
+ InputStreamReader streamReader = new
+ InputStreamReader(connection.getInputStream());
+ BufferedReader reader = new BufferedReader(streamReader);
+
+ StringBuilder stringBuilder = new StringBuilder();
+ while ((inputLine = reader.readLine()) != null) {
+ stringBuilder.append(inputLine);
+ }
+ reader.close();
+ streamReader.close();
+ httpResult = stringBuilder.toString();
+ } catch (IOException e) {
+ Log.e(TAG, "请求应用信息错误", e);
+ httpResult = null;
+ }
+ return httpResult;
+ }
+}
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProvider.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProvider.kt
new file mode 100644
index 0000000..8022c7d
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProvider.kt
@@ -0,0 +1,155 @@
+package com.ifmvo.togetherad.gdt.provider
+
+import com.ifmvo.togetherad.core.custom.splashSkip.BaseSplashSkipView
+import com.qq.e.ads.cfg.BrowserType
+import com.qq.e.ads.cfg.DownAPPConfirmPolicy
+import com.qq.e.ads.cfg.VideoOption
+import com.qq.e.ads.nativ.ADSize
+import com.qq.e.ads.nativ.express2.VideoOption2
+
+
+/**
+ * 广告提供商:优量汇(广点通)
+ *
+ * Created by Matthew Chen on 2020-04-03.
+ */
+open class GdtProvider : GdtProviderSplash() {
+
+ /**
+ * --------------------------- 开屏 ---------------------------
+ */
+ object Splash {
+
+ /**
+ * fetchDelay 参数,设置开屏广告从请求到展示所花的最大时长(并不是指广告曝光时长),
+ * 取值范围为[3000, 5000]ms。
+ * 如果需要使用默认值,可以给 fetchDelay 设为0。
+ */
+ var maxFetchDelay = 4000
+
+ //自定义按钮
+ var customSkipView: BaseSplashSkipView? = null
+
+ }
+
+ /**
+ * --------------------------- 激励 ---------------------------
+ */
+ object Reward {
+
+ //是否有声播放
+ var volumeOn = true
+
+ //如果开启了服务器验证,用来获取此次交易的信息
+ var verificationOption: Any? = null
+
+ }
+
+ /**
+ * --------------------------- 横幅 ---------------------------
+ */
+ object Banner {
+
+ //Banner 刷新间隔时间
+ var slideIntervalTime = 30 * 1000
+ }
+
+ /**
+ * --------------------------- 原生自渲染 ---------------------------
+ */
+ object Native {
+ //设置返回视频广告的最大视频时长(闭区间,可单独设置),单位:秒,合法输入为:5<=maxVideoDuration<=60. 此设置会影响广告填充,请谨慎设置
+ var maxVideoDuration = 60
+
+ //设置返回视频广告的最小视频时长(闭区间,可单独设置),单位:秒 此设置会影响广告填充,请谨慎设置
+ var minVideoDuration = 5
+
+ //指定普链广告点击后用于展示落地页的浏览器类型,可选项包括:InnerBrowser(APP 内置浏览器),Sys(系统浏览器),Default(默认,SDK 按照默认逻辑选择)
+ var browserType: BrowserType = BrowserType.Default
+
+ //指定点击 APP 广告后是否展示二次确认,可选项包括 Default(wifi 不展示,非 wifi 展示),NoConfirm(所有情况不展示)
+ var downAPPConfirmPolicy: DownAPPConfirmPolicy = DownAPPConfirmPolicy.Default
+
+ //测试性接口,不保证有效。传入 app 内类目信息
+ var categories: List? = null
+
+ //设置本次拉取的视频广告,从用户角度看到的视频播放策略;
+ // 可选项包括自VideoOption.VideoPlayPolicy.AUTO(在用户看来,视频广告是自动播放的)和VideoOption.VideoPlayPolicy.MANUAL(在用户看来,视频广告是手动播放的);
+ // 如果广告位支持视频,强烈建议调用此接口设置视频广告的播放策略,有助于提高eCPM值;如果广告位不支持视频,忽略本接口
+ var videoPlayPolicy: Int = VideoOption.VideoPlayPolicy.AUTO
+ }
+
+ /**
+ * --------------------------- 原生模板 ---------------------------
+ */
+ object NativeExpress {
+
+ // 自动播放时为静音
+ var autoPlayMuted = true
+
+ //视频详情页播放时默认不静音
+ var detailPageMuted = false
+
+ // WIFI 环境下可以自动播放视频( 模板2.0 )
+ var autoPlayPolicyVideoOption2: VideoOption2.AutoPlayPolicy = VideoOption2.AutoPlayPolicy.ALWAYS
+
+ // WIFI 环境下可以自动播放视频 ( 模板1.0 )
+ var autoPlayPolicy: Int = VideoOption.AutoPlayPolicy.ALWAYS
+
+ /**
+ * 如果广告位支持视频广告,强烈建议在调用loadData请求广告前调用setVideoPlayPolicy,有助于提高视频广告的eCPM值
+ * 如果广告位仅支持图文广告,则无需调用
+ * 设置本次拉取的视频广告,从用户角度看到的视频播放策略
+ * "用户角度"特指用户看到的情况,并非SDK是否自动播放,与自动播放策略AutoPlayPolicy的取值并非一一对应
+ * 如自动播放策略为AutoPlayPolicy.WIFI,但此时用户网络为4G环境,在用户看来就是手工播放的
+ */
+ var videoPlayPolicy = VideoOption.VideoPlayPolicy.AUTO
+
+ //视频最小时长
+ var minVideoDuration: Int = 0
+
+ //视频最大时长
+ var maxVideoDuration: Int = 0
+
+ //指定点击 APP 广告后是否展示二次确认,可选项包括 Default(wifi 不展示,非wifi 展示),NoConfirm(所有情况不展示)
+ var downAPPConfirmPolicy: DownAPPConfirmPolicy = DownAPPConfirmPolicy.Default
+
+ //指定普链广告点击后用于展示落地页的浏览器类型,可选项包括:InnerBrowser(APP 内置浏览器),Sys(系统浏览器),Default(默认),SDK 按照默认逻辑选择
+ var browserType: BrowserType = BrowserType.Default
+
+ //广告的宽高
+ internal var adWidth = ADSize.FULL_WIDTH
+ internal var adHeight = ADSize.AUTO_HEIGHT
+
+ fun setAdSize(widthDp: Int = ADSize.FULL_WIDTH, heightDp: Int = ADSize.AUTO_HEIGHT) {
+ adWidth = widthDp
+ adHeight = heightDp
+ }
+ }
+
+ /**
+ * --------------------------- 全屏视频 ---------------------------
+ */
+ object FullVideo {
+
+ // 自动播放时为静音
+ var autoPlayMuted = true
+
+ // WIFI 环境下可以自动播放视频
+ var autoPlayPolicy: Int = VideoOption.AutoPlayPolicy.ALWAYS
+
+ //视频最小时长
+ var minVideoDuration: Int = 0
+
+ //视频最大时长
+ var maxVideoDuration: Int = 0
+
+ /*
+ * 设置本次拉取的视频广告,从用户角度看到的视频播放策略;
+ * 可选项包括自VideoOption.VideoPlayPolicy.AUTO(在用户看来,视频广告是自动播放的)和VideoOption.VideoPlayPolicy.MANUAL(在用户看来,视频广告是手动播放的);
+ * 插屏全屏视频广告,强烈建议调用此接口设置视频广告的播放策略,有助于提高eCPM值
+ */
+ var videoPlayPolicy = VideoOption.VideoPlayPolicy.AUTO
+
+ }
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderBanner.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderBanner.kt
new file mode 100644
index 0000000..9a3c758
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderBanner.kt
@@ -0,0 +1,67 @@
+package com.ifmvo.togetherad.gdt.provider
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.listener.BannerListener
+import com.ifmvo.togetherad.core.provider.BaseAdProvider
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.qq.e.ads.banner2.UnifiedBannerADListener
+import com.qq.e.ads.banner2.UnifiedBannerView
+import com.qq.e.comm.util.AdError
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class GdtProviderBanner : BaseAdProvider() {
+
+ private var banner: UnifiedBannerView? = null
+ override fun showBannerAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: BannerListener) {
+ callbackBannerStartRequest(adProviderType, alias, listener)
+ destroyBannerAd()
+ banner = UnifiedBannerView(activity, TogetherAdGdt.idMapGDT[alias], object : UnifiedBannerADListener {
+ override fun onADCloseOverlay() {
+ }
+
+ override fun onADExposure() {
+ callbackBannerExpose(adProviderType, listener)
+ }
+
+ override fun onADClosed() {
+ destroyBannerAd()
+ callbackBannerClosed(adProviderType, listener)
+ }
+
+ override fun onADLeftApplication() {
+ }
+
+ override fun onADOpenOverlay() {
+ }
+
+ override fun onNoAD(adError: AdError?) {
+ destroyBannerAd()
+ callbackBannerFailed(adProviderType, alias, listener, adError?.errorCode, adError?.errorMsg)
+ }
+
+ override fun onADReceive() {
+ TogetherAdGdt.downloadConfirmListener?.let {
+ banner?.setDownloadConfirmListener(it)
+ }
+ callbackBannerLoaded(adProviderType, alias, listener)
+ }
+
+ override fun onADClicked() {
+ callbackBannerClicked(adProviderType, listener)
+ }
+ })
+ container.addView(banner)
+ banner?.setRefresh(GdtProvider.Banner.slideIntervalTime)
+ banner?.loadAD()
+ }
+
+ override fun destroyBannerAd() {
+ banner?.destroy()
+ banner = null
+ }
+
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderFullVideo.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderFullVideo.kt
new file mode 100644
index 0000000..e45bcab
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderFullVideo.kt
@@ -0,0 +1,89 @@
+package com.ifmvo.togetherad.gdt.provider
+
+import android.app.Activity
+import com.ifmvo.togetherad.core.listener.FullVideoListener
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.qq.e.ads.cfg.VideoOption
+import com.qq.e.ads.interstitial2.UnifiedInterstitialAD
+import com.qq.e.ads.interstitial2.UnifiedInterstitialADListener
+import com.qq.e.ads.interstitial2.UnifiedInterstitialMediaListener
+import com.qq.e.comm.util.AdError
+
+
+/**
+ * 全屏视频广告
+ *
+ * Created by Matthew Chen on 2020/12/2.
+ */
+abstract class GdtProviderFullVideo : GdtProviderBanner() {
+
+ private var fullVideoAd: UnifiedInterstitialAD? = null
+
+ override fun requestFullVideoAd(activity: Activity, adProviderType: String, alias: String, listener: FullVideoListener) {
+
+ callbackFullVideoStartRequest(adProviderType, alias, listener)
+
+ fullVideoAd = UnifiedInterstitialAD(activity, TogetherAdGdt.idMapGDT[alias], object : UnifiedInterstitialADListener {
+ override fun onADExposure() {
+ callbackFullVideoShow(adProviderType, listener)
+ }
+
+ override fun onVideoCached() {
+ callbackFullVideoCached(adProviderType, listener)
+ }
+
+ override fun onADOpened() {}
+
+ override fun onADClosed() {
+ callbackFullVideoClosed(adProviderType, listener)
+ }
+
+ override fun onADLeftApplication() {}
+
+ override fun onADReceive() {
+ TogetherAdGdt.downloadConfirmListener?.let {
+ fullVideoAd?.setDownloadConfirmListener(it)
+ }
+ callbackFullVideoLoaded(adProviderType, alias, listener)
+ }
+
+ override fun onNoAD(adError: AdError?) {
+ callbackFullVideoFailed(adProviderType, alias, listener, adError?.errorCode, adError?.errorMsg)
+ }
+
+ override fun onADClicked() {
+ callbackFullVideoClicked(adProviderType, listener)
+ }
+ })
+ val option = VideoOption.Builder()
+ .setAutoPlayMuted(GdtProvider.FullVideo.autoPlayMuted)
+ .setAutoPlayPolicy(GdtProvider.FullVideo.autoPlayPolicy)
+ .build()
+ fullVideoAd?.setVideoOption(option)
+ fullVideoAd?.setVideoPlayPolicy(GdtProvider.FullVideo.videoPlayPolicy)
+ fullVideoAd?.setMaxVideoDuration(GdtProvider.FullVideo.maxVideoDuration)
+ fullVideoAd?.setMaxVideoDuration(GdtProvider.FullVideo.minVideoDuration)
+ fullVideoAd?.setMediaListener(object :UnifiedInterstitialMediaListener {
+ override fun onVideoPageOpen() {}
+ override fun onVideoLoading() {}
+ override fun onVideoReady(p0: Long) {}
+ override fun onVideoInit() {}
+ override fun onVideoPause() {}
+ override fun onVideoPageClose() {}
+ override fun onVideoStart() {}
+ override fun onVideoComplete() {
+ callbackFullVideoComplete(adProviderType, listener)
+ }
+ override fun onVideoError(adError: AdError?) {}
+ })
+ fullVideoAd?.loadFullScreenAD()
+ }
+
+ override fun showFullVideoAd(activity: Activity): Boolean {
+ if (fullVideoAd?.isValid != true) {
+ return false
+ }
+ fullVideoAd?.showFullScreenAD(activity)
+ return true
+ }
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderInter.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderInter.kt
new file mode 100644
index 0000000..b41325f
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderInter.kt
@@ -0,0 +1,73 @@
+package com.ifmvo.togetherad.gdt.provider
+
+import android.app.Activity
+import com.ifmvo.togetherad.core.listener.InterListener
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.qq.e.ads.interstitial2.UnifiedInterstitialAD
+import com.qq.e.ads.interstitial2.UnifiedInterstitialADListener
+import com.qq.e.comm.util.AdError
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class GdtProviderInter : GdtProviderFullVideo() {
+
+ private var interAd: UnifiedInterstitialAD? = null
+ override fun requestInterAd(activity: Activity, adProviderType: String, alias: String, listener: InterListener) {
+
+ callbackInterStartRequest(adProviderType, alias, listener)
+
+ destroyInterAd()
+
+ interAd = UnifiedInterstitialAD(activity, TogetherAdGdt.idMapGDT[alias], object : UnifiedInterstitialADListener {
+ override fun onADExposure() {
+ callbackInterExpose(adProviderType, listener)
+ }
+
+ override fun onVideoCached() {
+ "onVideoCached".logi(tag)
+ }
+
+ override fun onADOpened() {
+ "onADOpened".logi(tag)
+ }
+
+ override fun onADClosed() {
+ callbackInterClosed(adProviderType, listener)
+ }
+
+ override fun onADLeftApplication() {
+ "onADLeftApplication".logi(tag)
+ }
+
+ override fun onADReceive() {
+ TogetherAdGdt.downloadConfirmListener?.let {
+ interAd?.setDownloadConfirmListener(it)
+ }
+ callbackInterLoaded(adProviderType, alias, listener)
+ }
+
+ override fun onNoAD(adError: AdError?) {
+ callbackInterFailed(adProviderType, alias, listener, adError?.errorCode, adError?.errorMsg)
+ }
+
+ override fun onADClicked() {
+ callbackInterClicked(adProviderType, listener)
+ }
+ })
+ interAd?.loadAD()
+ }
+
+ override fun showInterAd(activity: Activity) {
+ interAd?.show()
+ }
+
+ override fun destroyInterAd() {
+ interAd?.close()
+ interAd?.destroy()
+ interAd = null
+ }
+
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderNative.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderNative.kt
new file mode 100644
index 0000000..55f81f1
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderNative.kt
@@ -0,0 +1,75 @@
+package com.ifmvo.togetherad.gdt.provider
+
+import android.app.Activity
+import com.ifmvo.togetherad.core.listener.NativeListener
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.qq.e.ads.cfg.VideoOption
+import com.qq.e.ads.nativ.NativeADUnifiedListener
+import com.qq.e.ads.nativ.NativeUnifiedAD
+import com.qq.e.ads.nativ.NativeUnifiedADData
+import com.qq.e.comm.constants.AdPatternType
+import com.qq.e.comm.util.AdError
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class GdtProviderNative : GdtProviderInter() {
+
+ override fun getNativeAdList(activity: Activity, adProviderType: String, alias: String, maxCount: Int, listener: NativeListener) {
+
+ callbackNativeStartRequest(adProviderType, alias, listener)
+
+ val nativeADUnifiedListener = object : NativeADUnifiedListener {
+ override fun onADLoaded(adList: List?) {
+ //list是空的,按照错误来处理
+ if (adList?.isEmpty() != false) {
+ callbackNativeFailed(adProviderType, alias, listener, null, "请求成功,但是返回的list为空")
+ return
+ }
+
+ callbackNativeLoaded(adProviderType, alias, listener, adList)
+ }
+
+ override fun onNoAD(adError: AdError?) {
+ callbackNativeFailed(adProviderType, alias, listener, adError?.errorCode, adError?.errorMsg)
+ }
+ }
+
+ val mAdManager = NativeUnifiedAD(activity, TogetherAdGdt.idMapGDT[alias], nativeADUnifiedListener)
+ mAdManager.setBrowserType(GdtProvider.Native.browserType)
+ mAdManager.setDownAPPConfirmPolicy(GdtProvider.Native.downAPPConfirmPolicy)
+ GdtProvider.Native.categories?.let { mAdManager.setCategories(it) }
+ mAdManager.setMaxVideoDuration(GdtProvider.Native.maxVideoDuration)//有效值就是 5-60
+ mAdManager.setMinVideoDuration(GdtProvider.Native.minVideoDuration)
+ mAdManager.setVideoPlayPolicy(GdtProvider.Native.videoPlayPolicy)//本次拉回的视频广告,在用户看来是否为自动播放的
+ //视频播放前,用户看到的广告容器是由SDK渲染的.该接口已经废弃,仅支持sdk渲染,不再支持开发者自己渲染
+ mAdManager.setVideoADContainerRender(VideoOption.VideoADContainerRender.SDK)
+ mAdManager.loadData(maxCount)
+ }
+
+ override fun nativeAdIsBelongTheProvider(adObject: Any): Boolean {
+ return adObject is NativeUnifiedADData
+ }
+
+ override fun resumeNativeAd(adObject: Any) {
+ if (adObject !is NativeUnifiedADData) return
+ adObject.resume()
+ if (adObject.adPatternType == AdPatternType.NATIVE_VIDEO) {
+ adObject.resumeVideo()
+ }
+ }
+
+ override fun pauseNativeAd(adObject: Any) {
+ if (adObject !is NativeUnifiedADData) return
+ if (adObject.adPatternType == AdPatternType.NATIVE_VIDEO) {
+ adObject.pauseVideo()
+ }
+ }
+
+ override fun destroyNativeAd(adObject: Any) {
+ if (adObject !is NativeUnifiedADData) return
+ adObject.destroy()
+ }
+
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderNativeExpress.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderNativeExpress.kt
new file mode 100644
index 0000000..de1c6fc
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderNativeExpress.kt
@@ -0,0 +1,79 @@
+package com.ifmvo.togetherad.gdt.provider
+
+import android.app.Activity
+import com.ifmvo.togetherad.core.listener.NativeExpressListener
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.qq.e.ads.cfg.VideoOption
+import com.qq.e.ads.nativ.ADSize
+import com.qq.e.ads.nativ.NativeExpressAD
+import com.qq.e.ads.nativ.NativeExpressADView
+import com.qq.e.comm.util.AdError
+
+/**
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class GdtProviderNativeExpress : GdtProviderNative() {
+
+ override fun getNativeExpressAdList(activity: Activity, adProviderType: String, alias: String, adCount: Int, listener: NativeExpressListener) {
+
+ callbackNativeExpressStartRequest(adProviderType, alias, listener)
+
+ val nativeExpressADListener = object : NativeExpressAD.NativeExpressADListener {
+
+ override fun onADLoaded(ads: MutableList?) {
+ if (ads.isNullOrEmpty()) {
+ callbackNativeExpressFailed(adProviderType, alias, listener, null, "请求成功,但是返回的list为空")
+ return
+ }
+ callbackNativeExpressLoaded(adProviderType, alias, listener, ads)
+ }
+
+ override fun onNoAD(adError: AdError?) {
+ callbackNativeExpressFailed(adProviderType, alias, listener, adError?.errorCode, adError?.errorMsg)
+ }
+
+ override fun onRenderSuccess(adView: NativeExpressADView?) {
+ callbackNativeExpressRenderSuccess(adProviderType, adView, listener)
+ }
+
+ override fun onRenderFail(adView: NativeExpressADView?) {
+ callbackNativeExpressRenderFail(adProviderType, adView, listener)
+ }
+
+ override fun onADClicked(adView: NativeExpressADView?) {
+ callbackNativeExpressClicked(adProviderType, adView, listener)
+ }
+
+ override fun onADExposure(adView: NativeExpressADView?) {
+ callbackNativeExpressShow(adProviderType, adView, listener)
+ }
+
+ override fun onADClosed(adView: NativeExpressADView?) {
+ callbackNativeExpressClosed(adProviderType, adView, listener)
+ }
+
+ override fun onADCloseOverlay(adView: NativeExpressADView?) {}
+ override fun onADOpenOverlay(adView: NativeExpressADView?) {}
+ override fun onADLeftApplication(adView: NativeExpressADView?) {}
+ }
+
+ val nativeExpressAD = NativeExpressAD(activity, ADSize(GdtProvider.NativeExpress.adWidth, GdtProvider.NativeExpress.adHeight), TogetherAdGdt.idMapGDT[alias], nativeExpressADListener)
+ nativeExpressAD.setVideoOption(VideoOption.Builder()
+ .setAutoPlayPolicy(GdtProvider.NativeExpress.autoPlayPolicy)
+ .setAutoPlayMuted(GdtProvider.NativeExpress.autoPlayMuted)
+ .build())
+ nativeExpressAD.setVideoPlayPolicy(GdtProvider.NativeExpress.videoPlayPolicy)
+ nativeExpressAD.setMinVideoDuration(GdtProvider.NativeExpress.minVideoDuration)
+ nativeExpressAD.setMaxVideoDuration(GdtProvider.NativeExpress.maxVideoDuration)
+ nativeExpressAD.loadAD(adCount)
+ }
+
+ override fun destroyNativeExpressAd(adObject: Any) {
+ if (adObject !is NativeExpressADView) return
+ adObject.destroy()
+ }
+
+ override fun nativeExpressAdIsBelongTheProvider(adObject: Any): Boolean {
+ return adObject is NativeExpressADView
+ }
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderNativeExpress2.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderNativeExpress2.kt
new file mode 100644
index 0000000..d6ca516
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderNativeExpress2.kt
@@ -0,0 +1,66 @@
+package com.ifmvo.togetherad.gdt.provider
+
+import android.app.Activity
+import com.ifmvo.togetherad.core.listener.NativeExpress2Listener
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.qq.e.ads.nativ.express2.NativeExpressAD2
+import com.qq.e.ads.nativ.express2.NativeExpressADData2
+import com.qq.e.ads.nativ.express2.VideoOption2
+import com.qq.e.comm.util.AdError
+
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class GdtProviderNativeExpress2 : GdtProviderNativeExpress() {
+
+ override fun getNativeExpress2AdList(activity: Activity, adProviderType: String, alias: String, adCount: Int, listener: NativeExpress2Listener) {
+
+ callbackNativeExpressStartRequest(adProviderType, alias, listener)
+
+ val adLoaderListener = object : NativeExpressAD2.AdLoadListener {
+ override fun onLoadSuccess(ads: MutableList?) {
+ if (ads.isNullOrEmpty()) {
+ callbackNativeExpressFailed(adProviderType, alias, listener, null, "请求成功,但是返回的list为空")
+ return
+ }
+ callbackNativeExpressLoaded(adProviderType, alias, listener, ads)
+ }
+
+ override fun onNoAD(adError: AdError?) {
+ callbackNativeExpressFailed(adProviderType, alias, listener, adError?.errorCode, adError?.errorMsg)
+ }
+ }
+
+ val mNativeExpressAD2 = NativeExpressAD2(activity, TogetherAdGdt.idMapGDT[alias], adLoaderListener)
+ mNativeExpressAD2.setAdSize(GdtProvider.NativeExpress.adWidth, GdtProvider.NativeExpress.adHeight) // 单位dp
+ mNativeExpressAD2.setDownAPPConfirmPolicy(GdtProvider.NativeExpress.downAPPConfirmPolicy)
+ //指定普链广告点击后用于展示落地页的浏览器类型,可选项包括:InnerBrowser(APP 内置浏览器),Sys(系统浏览器),Default(默认),SDK 按照默认逻辑选择
+ mNativeExpressAD2.setBrowserType(GdtProvider.NativeExpress.browserType)
+ // 如果您在平台上新建原生模板广告位时,选择了支持视频,那么可以进行个性化设置(可选)
+ val builder = VideoOption2.Builder()
+ /**
+ * 如果广告位支持视频广告,强烈建议在调用loadData请求广告前设置setAutoPlayPolicy,有助于提高视频广告的eCPM值
+ * 如果广告位仅支持图文广告,则无需调用
+ */
+ builder.setAutoPlayPolicy(GdtProvider.NativeExpress.autoPlayPolicyVideoOption2) // WIFI 环境下可以自动播放视频
+ .setAutoPlayMuted(GdtProvider.NativeExpress.autoPlayMuted) // 自动播放时为静音
+ .setDetailPageMuted(GdtProvider.NativeExpress.detailPageMuted) // 视频详情页播放时不静音
+ .setMaxVideoDuration(GdtProvider.NativeExpress.maxVideoDuration) // 设置返回视频广告的最大视频时长(闭区间,可单独设置),单位:秒,默认为 0 代表无限制,合法输入为:5<=maxVideoDuration<=60. 此设置会影响广告填充,请谨慎设置
+ .setMinVideoDuration(GdtProvider.NativeExpress.minVideoDuration) // 设置返回视频广告的最小视频时长(闭区间,可单独设置),单位:秒,默认为 0 代表无限制, 此设置会影响广告填充,请谨慎设置
+
+ mNativeExpressAD2.setVideoOption2(builder.build())
+ mNativeExpressAD2.loadAd(adCount)
+
+ }
+
+ override fun destroyNativeExpress2Ad(adObject: Any) {
+ if (adObject !is NativeExpressADData2) return
+ adObject.destroy()
+ }
+
+ override fun nativeExpress2AdIsBelongTheProvider(adObject: Any): Boolean {
+ return adObject is NativeExpressADData2
+ }
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderReward.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderReward.kt
new file mode 100644
index 0000000..688c722
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderReward.kt
@@ -0,0 +1,92 @@
+package com.ifmvo.togetherad.gdt.provider
+
+import android.app.Activity
+import com.ifmvo.togetherad.core.listener.RewardListener
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.qq.e.ads.rewardvideo.RewardVideoAD
+import com.qq.e.ads.rewardvideo.RewardVideoADListener
+import com.qq.e.ads.rewardvideo.ServerSideVerificationOptions
+import com.qq.e.comm.util.AdError
+import com.qq.e.comm.util.VideoAdValidity
+
+
+/**
+ *
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class GdtProviderReward : GdtProviderNativeExpress2() {
+
+ private var rewardVideoAD: RewardVideoAD? = null
+ override fun requestRewardAd(activity: Activity, adProviderType: String, alias: String, listener: RewardListener) {
+
+ callbackRewardStartRequest(adProviderType, alias, listener)
+
+ rewardVideoAD = RewardVideoAD(activity, TogetherAdGdt.idMapGDT[alias], object : RewardVideoADListener {
+
+ override fun onADExpose() {
+ callbackRewardExpose(adProviderType, listener)
+ }
+
+ override fun onADClick() {
+ callbackRewardClicked(adProviderType, listener)
+ }
+
+ override fun onVideoCached() {
+ callbackRewardVideoCached(adProviderType, listener)
+ }
+
+ override fun onReward(map: MutableMap?) {
+ map?.let { GdtProvider.Reward.verificationOption = it[ServerSideVerificationOptions.TRANS_ID] }
+ callbackRewardVerify(adProviderType, listener)
+ }
+
+ override fun onADClose() {
+ callbackRewardClosed(adProviderType, listener)
+ rewardVideoAD = null
+ }
+
+ override fun onADLoad() {
+ TogetherAdGdt.downloadConfirmListener?.let {
+ rewardVideoAD?.setDownloadConfirmListener(it)
+ }
+ callbackRewardLoaded(adProviderType, alias, listener)
+ }
+
+ override fun onVideoComplete() {
+ callbackRewardVideoComplete(adProviderType, listener)
+ }
+
+ override fun onError(adError: AdError?) {
+ callbackRewardFailed(adProviderType, alias, listener, adError?.errorCode, adError?.errorMsg)
+ rewardVideoAD = null
+ }
+
+ override fun onADShow() {
+ callbackRewardShow(adProviderType, listener)
+ }
+
+ }, GdtProvider.Reward.volumeOn)
+
+ rewardVideoAD?.loadAD()
+ }
+
+ override fun showRewardAd(activity: Activity): Boolean {
+ //空的就展示失败
+ if (rewardVideoAD == null) {
+ return false
+ }
+
+ return when (rewardVideoAD!!.checkValidity()!!) {
+ //已经展示或过期
+ VideoAdValidity.SHOWED, VideoAdValidity.OVERDUE -> {
+ false
+ }
+ //有效或未缓存完成,直接展示
+ VideoAdValidity.VALID, VideoAdValidity.NONE_CACHE -> {
+ rewardVideoAD?.showAD()
+ true
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderSplash.kt b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderSplash.kt
new file mode 100644
index 0000000..e373c10
--- /dev/null
+++ b/gdt/src/main/java/com/ifmvo/togetherad/gdt/provider/GdtProviderSplash.kt
@@ -0,0 +1,176 @@
+package com.ifmvo.togetherad.gdt.provider
+
+import android.app.Activity
+import android.os.SystemClock
+import android.view.ViewGroup
+import com.ifmvo.togetherad.core.listener.SplashListener
+import com.ifmvo.togetherad.core.utils.logi
+import com.ifmvo.togetherad.core.utils.logv
+import com.ifmvo.togetherad.gdt.TogetherAdGdt
+import com.ifmvo.togetherad.gdt.other.DownloadConfirmHelper
+import com.qq.e.ads.splash.SplashAD
+import com.qq.e.ads.splash.SplashADListener
+import com.qq.e.comm.util.AdError
+import kotlin.math.roundToInt
+
+/**
+ * Created by Matthew Chen on 2020/11/25.
+ */
+abstract class GdtProviderSplash : GdtProviderReward() {
+
+ private var splashAd: SplashAD? = null
+ private var mExpireTimestamp = 0L//广告失效的时间戳
+ private var mContainer: ViewGroup? = null
+
+ override fun loadOnlySplashAd(activity: Activity, adProviderType: String, alias: String, listener: SplashListener) {
+ callbackSplashStartRequest(adProviderType, alias, listener)
+
+ val customSkipView = GdtProvider.Splash.customSkipView
+ val skipView = customSkipView?.onCreateSkipView(activity)
+
+ splashAd = SplashAD(activity, skipView, TogetherAdGdt.idMapGDT[alias], object : SplashADListener {
+
+ override fun onADDismissed() {
+ GdtProvider.Splash.customSkipView = null
+ mContainer = null
+ splashAd = null
+ callbackSplashDismiss(adProviderType, listener)
+ }
+
+ override fun onNoAD(adError: AdError?) {
+ GdtProvider.Splash.customSkipView = null
+ mContainer = null
+ splashAd = null
+ callbackSplashFailed(adProviderType, alias, listener, adError?.errorCode, adError?.errorMsg)
+ }
+
+ /**
+ * 广告成功展示时调用,成功展示不等于有效展示(比如广告容器高度不够)
+ */
+ override fun onADPresent() {
+ activity.runOnUiThread {
+ skipView?.run {
+ mContainer?.addView(this, customSkipView.getLayoutParams())
+ }
+ }
+ "${adProviderType}: 广告成功展示".logi(tag)
+ splashAd?.preLoad()
+ }
+
+ override fun onADClicked() {
+ callbackSplashClicked(adProviderType, listener)
+ }
+
+ override fun onADTick(millisUntilFinished: Long) {
+ val second = (millisUntilFinished / 1000f).roundToInt()
+ GdtProvider.Splash.customSkipView?.handleTime(second)
+ "${adProviderType}: 倒计时: $second".logv(tag)
+ }
+
+ override fun onADExposure() {
+ callbackSplashExposure(adProviderType, listener)
+ }
+
+ /**
+ * 广告加载成功的回调,在fetchAdOnly的情况下,表示广告拉取成功可以显示了。广告需要在SystemClock.elapsedRealtime = mExpireTimestamp) {
+ return false
+ }
+
+ mContainer = container
+ splashAd?.showAd(container)
+
+ return true
+ }
+
+ override fun loadAndShowSplashAd(activity: Activity, adProviderType: String, alias: String, container: ViewGroup, listener: SplashListener) {
+
+ callbackSplashStartRequest(adProviderType, alias, listener)
+
+ val customSkipView = GdtProvider.Splash.customSkipView
+ val skipView = customSkipView?.onCreateSkipView(container.context)
+
+ splashAd = SplashAD(activity, skipView, TogetherAdGdt.idMapGDT[alias], object : SplashADListener {
+
+ override fun onADDismissed() {
+ splashAd = null
+ GdtProvider.Splash.customSkipView = null
+ callbackSplashDismiss(adProviderType, listener)
+ }
+
+ override fun onNoAD(adError: AdError?) {
+ GdtProvider.Splash.customSkipView = null
+ splashAd = null
+ callbackSplashFailed(adProviderType, alias, listener, adError?.errorCode, adError?.errorMsg)
+ }
+
+ /**
+ * 广告成功展示时调用,成功展示不等于有效展示(比如广告容器高度不够)
+ */
+ override fun onADPresent() {
+ activity.runOnUiThread {
+ skipView?.run {
+ container.addView(this, customSkipView.getLayoutParams())
+ }
+ }
+ "${adProviderType}: 广告成功展示".logi(tag)
+ }
+
+ override fun onADClicked() {
+ callbackSplashClicked(adProviderType, listener)
+ }
+
+ override fun onADTick(millisUntilFinished: Long) {
+ val second = (millisUntilFinished / 1000f).roundToInt()
+ customSkipView?.handleTime(second)
+ "${adProviderType}: 倒计时: $second".logv(tag)
+ }
+
+ override fun onADExposure() {
+ callbackSplashExposure(adProviderType, listener)
+ }
+
+ /**
+ * 广告加载成功的回调,在fetchAdOnly的情况下,表示广告拉取成功可以显示了。广告需要在SystemClock.elapsedRealtime
+
+
+
+
\ No newline at end of file
diff --git a/gdt/src/main/res/anim/download_confirm_dialog_slide_up.xml b/gdt/src/main/res/anim/download_confirm_dialog_slide_up.xml
new file mode 100644
index 0000000..914107a
--- /dev/null
+++ b/gdt/src/main/res/anim/download_confirm_dialog_slide_up.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/gdt/src/main/res/drawable/download_confirm_background_confirm.xml b/gdt/src/main/res/drawable/download_confirm_background_confirm.xml
new file mode 100644
index 0000000..eb2bdf9
--- /dev/null
+++ b/gdt/src/main/res/drawable/download_confirm_background_confirm.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/gdt/src/main/res/drawable/download_confirm_background_landscape.xml b/gdt/src/main/res/drawable/download_confirm_background_landscape.xml
new file mode 100644
index 0000000..7a3bee2
--- /dev/null
+++ b/gdt/src/main/res/drawable/download_confirm_background_landscape.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/gdt/src/main/res/drawable/download_confirm_background_portrait.xml b/gdt/src/main/res/drawable/download_confirm_background_portrait.xml
new file mode 100644
index 0000000..148b739
--- /dev/null
+++ b/gdt/src/main/res/drawable/download_confirm_background_portrait.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/gdt/src/main/res/drawable/ic_download_confirm_close.xml b/gdt/src/main/res/drawable/ic_download_confirm_close.xml
new file mode 100644
index 0000000..f37d2a6
--- /dev/null
+++ b/gdt/src/main/res/drawable/ic_download_confirm_close.xml
@@ -0,0 +1,12 @@
+
+
+
diff --git a/gdt/src/main/res/layout/download_confirm_dialog.xml b/gdt/src/main/res/layout/download_confirm_dialog.xml
new file mode 100644
index 0000000..6fb6521
--- /dev/null
+++ b/gdt/src/main/res/layout/download_confirm_dialog.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gdt/src/main/res/layout/layout_native_view_gdt.xml b/gdt/src/main/res/layout/layout_native_view_gdt.xml
new file mode 100644
index 0000000..bf86de1
--- /dev/null
+++ b/gdt/src/main/res/layout/layout_native_view_gdt.xml
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gdt/src/main/res/layout/layout_native_view_gdt_simple_1.xml b/gdt/src/main/res/layout/layout_native_view_gdt_simple_1.xml
new file mode 100644
index 0000000..6d5a7f2
--- /dev/null
+++ b/gdt/src/main/res/layout/layout_native_view_gdt_simple_1.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdt/src/main/res/layout/layout_native_view_gdt_simple_2.xml b/gdt/src/main/res/layout/layout_native_view_gdt_simple_2.xml
new file mode 100644
index 0000000..6c3d97a
--- /dev/null
+++ b/gdt/src/main/res/layout/layout_native_view_gdt_simple_2.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdt/src/main/res/layout/layout_native_view_gdt_simple_3.xml b/gdt/src/main/res/layout/layout_native_view_gdt_simple_3.xml
new file mode 100644
index 0000000..ba83b8a
--- /dev/null
+++ b/gdt/src/main/res/layout/layout_native_view_gdt_simple_3.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gdt/src/main/res/layout/layout_native_view_gdt_simple_4.xml b/gdt/src/main/res/layout/layout_native_view_gdt_simple_4.xml
new file mode 100644
index 0000000..3046c57
--- /dev/null
+++ b/gdt/src/main/res/layout/layout_native_view_gdt_simple_4.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gdt/src/main/res/values/strings.xml b/gdt/src/main/res/values/strings.xml
new file mode 100644
index 0000000..6d5a695
--- /dev/null
+++ b/gdt/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ TogetherAd
+
diff --git a/gdt/src/main/res/values/styles.xml b/gdt/src/main/res/values/styles.xml
new file mode 100644
index 0000000..203ba3a
--- /dev/null
+++ b/gdt/src/main/res/values/styles.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
diff --git a/gdt/src/main/res/xml/gdt_file_path.xml b/gdt/src/main/res/xml/gdt_file_path.xml
new file mode 100644
index 0000000..d512ee9
--- /dev/null
+++ b/gdt/src/main/res/xml/gdt_file_path.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..f728e24
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,20 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
+# Kotlin code style for this project: "official" or "obsolete":
+kotlin.code.style=official
+org.gradle.daemon=true
+org.gradle.jvmargs=-Xmx4608m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+org.gradle.parallel=true
+org.gradle.configureondemand=true
+android.injected.testOnly=false
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f6b961f
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..cbdfc1c
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Thu Jan 31 16:39:40 CST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..d600acd
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,158 @@
+#!/usr/bin/env bash
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+
+yes | $ANDROID_HOME/tools/bin/sdkmanager "platforms;android-28"
+
+yes | $ANDROID_HOME/tools/bin/sdkmanager "build-tools;27.0.3"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..24d52e4
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,85 @@
+@if "%DEBUG%" == "" @echo off
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/img/QR-code.png b/img/QR-code.png
new file mode 100644
index 0000000..ac3a896
Binary files /dev/null and b/img/QR-code.png differ
diff --git a/img/TogetherAd.png b/img/TogetherAd.png
new file mode 100644
index 0000000..028c531
Binary files /dev/null and b/img/TogetherAd.png differ
diff --git a/img/TogetherAd_Feature.png b/img/TogetherAd_Feature.png
new file mode 100644
index 0000000..9d7b7de
Binary files /dev/null and b/img/TogetherAd_Feature.png differ
diff --git a/img/qrcode_for_gh_e66be0cfb1f0_258.jpeg b/img/qrcode_for_gh_e66be0cfb1f0_258.jpeg
new file mode 100644
index 0000000..de64c89
Binary files /dev/null and b/img/qrcode_for_gh_e66be0cfb1f0_258.jpeg differ
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000..7d1d55e
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,5 @@
+include ':core'
+include ':gdt'
+include ':csj'
+include ':baidu'
+include ':demo'
diff --git a/xmind/TogetherAd.xmind b/xmind/TogetherAd.xmind
new file mode 100644
index 0000000..6a535d7
Binary files /dev/null and b/xmind/TogetherAd.xmind differ
diff --git a/xmind/TogetherAd_Feature.xmind b/xmind/TogetherAd_Feature.xmind
new file mode 100644
index 0000000..a4912fa
Binary files /dev/null and b/xmind/TogetherAd_Feature.xmind differ
diff --git a/xmind/baidu.xmind b/xmind/baidu.xmind
new file mode 100644
index 0000000..2e21c6a
Binary files /dev/null and b/xmind/baidu.xmind differ
diff --git a/xmind/csj.xmind b/xmind/csj.xmind
new file mode 100644
index 0000000..d55ac90
Binary files /dev/null and b/xmind/csj.xmind differ
diff --git a/xmind/gdt.xmind b/xmind/gdt.xmind
new file mode 100644
index 0000000..ff83281
Binary files /dev/null and b/xmind/gdt.xmind differ