Browse Source

增加GroMore广告SDK

liuxiaolong 2 years ago
parent
commit
11b7610d1b
46 changed files with 1574 additions and 114 deletions
  1. 1 0
      app/build.gradle
  2. 5 2
      app/src/main/AndroidManifest.xml
  3. 3 1
      app/src/main/java/com/convenient/android/lib/ui/sample/ad/AdMainActivity.kt
  4. 5 0
      app/src/main/java/com/convenient/android/lib/ui/sample/ad/activity/AdFullScreenAdActivity.kt
  5. 3 1
      app/src/main/java/com/convenient/android/lib/ui/sample/ad/activity/AdNativeActivity.kt
  6. 4 3
      app/src/main/java/com/convenient/android/lib/ui/sample/ad/activity/AdNativeListActivity.kt
  7. 107 0
      app/src/main/java/com/convenient/android/lib/ui/sample/ad/activity/AdNativeTemplateActivity.kt
  8. 28 20
      app/src/main/java/com/convenient/android/lib/ui/sample/ad/adapter/NativeAdSampleListAdapter.kt
  9. 21 8
      app/src/main/java/com/convenient/android/lib/ui/sample/ad/model/Datas.kt
  10. 4 4
      app/src/main/java/com/convenient/android/lib/ui/sample/ad/page/AdHomePage.kt
  11. 10 8
      app/src/main/java/com/convenient/android/lib/ui/sample/ad/viewmodel/AdConfigViewModel.kt
  12. 82 0
      app/src/main/res/layout/activity_ad_native_template.xml
  13. 1 1
      app/src/main/res/layout/view_ad_native.xml
  14. 4 3
      app/src/main/res/layout/view_rv_ad_native_item.xml
  15. 33 0
      app/src/main/res/layout/view_rv_ad_native_template_item.xml
  16. 26 0
      lib_ad_core/src/main/java/com/composition/android/lib/ad/basic/AdType.kt
  17. 1 2
      lib_ad_core/src/main/java/com/composition/android/lib/ad/interfaces/AdLoader.kt
  18. 7 1
      lib_ad_core/src/main/java/com/composition/android/lib/ad/widget/NativeAdView.kt
  19. 1 0
      lib_ad_core/src/main/res/values/attr.xml
  20. 34 34
      lib_ad_csj/src/main/java/com/composition/android/ad/csj/load/CSJAdLoader.kt
  21. 2 3
      lib_ad_csj/src/main/java/com/composition/android/ad/csj/load/request/CSJBannerRequestImpl.kt
  22. 4 7
      lib_ad_csj/src/main/java/com/composition/android/ad/csj/load/request/CSJNativeRequestImpl.kt
  23. 1 0
      lib_ad_csj/src/main/java/com/composition/android/ad/csj/load/view/CSJBannerView.kt
  24. 13 16
      lib_ad_csj/src/main/java/com/composition/android/ad/csj/load/view/CSJNativeAdView.kt
  25. 1 0
      lib_ad_gromore/.gitignore
  26. 64 0
      lib_ad_gromore/build.gradle
  27. 0 0
      lib_ad_gromore/consumer-rules.pro
  28. BIN
      lib_ad_gromore/libs/open_ad_sdk.aar
  29. 156 0
      lib_ad_gromore/proguard-rules.pro
  30. 24 0
      lib_ad_gromore/src/androidTest/java/com/composition/android/ad/gromore/ExampleInstrumentedTest.kt
  31. 53 0
      lib_ad_gromore/src/main/AndroidManifest.xml
  32. 218 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/GroMoreAdLoader.kt
  33. 17 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/impl/GMBannerAdSize.kt
  34. 40 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/impl/GroMoreInitialize.kt
  35. 63 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/request/GMAppOpenRequestImpl.kt
  36. 67 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/request/GMBannerRequestImpl.kt
  37. 64 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/request/GMInterstitialRequestImpl.kt
  38. 67 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/request/GMNativeTemplateRequestImpl.kt
  39. 63 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/request/GMRewardRequestImpl.kt
  40. 51 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/util/GMAdExpan.kt
  41. 28 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/util/GMSettingConfig.kt
  42. 74 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/view/GMBannerView.kt
  43. 98 0
      lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/view/GMNativeTemplateAdView.kt
  44. 8 0
      lib_ad_gromore/src/main/res/layout/layout_gm_native_ad_view_root.xml
  45. 17 0
      lib_ad_gromore/src/test/java/com/composition/android/ad/gromore/ExampleUnitTest.kt
  46. 1 0
      settings.gradle

+ 1 - 0
app/build.gradle

@@ -53,6 +53,7 @@ dependencies {
     implementation project(':lib_ad_core')
     implementation project(':lib_ad_admob')
     implementation project(':lib_ad_csj')
+    implementation project(':lib_ad_gromore')
 
     //compose依赖
     implementation "androidx.compose.ui:ui:$compose_version"

+ 5 - 2
app/src/main/AndroidManifest.xml

@@ -8,7 +8,7 @@
     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
 
     <application
-        android:allowBackup="true"
+        android:allowBackup="false"
         android:name=".LibApplication"
         android:dataExtractionRules="@xml/data_extraction_rules"
         android:fullBackupContent="@xml/backup_rules"
@@ -19,6 +19,7 @@
         android:supportsRtl="true"
         android:usesCleartextTraffic="true"
         android:theme="@style/Theme.Lib"
+        tools:replace="android:allowBackup"
         tools:targetApi="31">
 
         <activity
@@ -30,7 +31,9 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
-
+        <activity
+            android:name=".ui.sample.ad.activity.AdNativeTemplateActivity"
+            android:exported="false" />
         <activity
             android:name=".ui.sample.ad.activity.AdAppOpenActivity"
             android:exported="false" />

+ 3 - 1
app/src/main/java/com/convenient/android/lib/ui/sample/ad/AdMainActivity.kt

@@ -11,6 +11,7 @@ import com.convenient.android.lib.ui.sample.ad.page.AdMainPage
 import com.convenient.android.lib.ui.theme.SampleTheme
 import com.composition.android.ad.admob.impl.AdmobInitialize
 import com.composition.android.ad.csj.impl.CSJInitialize
+import com.composition.android.ad.gromore.load.impl.GroMoreInitialize
 import com.composition.android.lib.ad.bean.AdUnitBean
 
 class AdMainActivity : AppCompatActivity() {
@@ -28,10 +29,11 @@ class AdMainActivity : AppCompatActivity() {
 
     private fun initAd(){
         AdManager.instance.init(applicationContext, true)
-        AdManager.instance.initAdvertisersSDK(applicationContext, AdmobInitialize(),CSJInitialize("5320990"))
+        AdManager.instance.initAdvertisersSDK(applicationContext, AdmobInitialize(),CSJInitialize("5320990"), GroMoreInitialize("5320990"))
         val list = mutableListOf<AdUnitBean>()
         list.addAll(Datas.AdmobAdUnitList)
         list.addAll(Datas.CSJAdUnitList)
+        list.addAll(Datas.GroMoreAdUnitList)
         AdUnitConfigManager.instance.setAdUnits(list)
         AdManager.instance.addGlobalAdShowListener {
             Log.e("广告全局展示监听", "广告位名称:${it.adSlotName}\n广告商:${it.advertisersName}\n广告id:${it.adUnitId}\n广告类型:${it.adType}")

+ 5 - 0
app/src/main/java/com/convenient/android/lib/ui/sample/ad/activity/AdFullScreenAdActivity.kt

@@ -3,9 +3,11 @@ package com.convenient.android.lib.ui.sample.ad.activity
 import android.os.Bundle
 import androidx.lifecycle.lifecycleScope
 import com.composition.android.lib.ad.AdLoad
+import com.composition.android.lib.ad.AdManager
 import com.composition.android.lib.ad.basic.AdResult
 import com.composition.android.lib.ad.basic.AdType
 import com.composition.android.lib.ad.impl.NormalAdListener
+import com.composition.android.lib.ad.util.adLogE
 import com.convenient.android.common.base.viewbinding.BaseBindingActivity
 import com.convenient.android.common.extension.setViewsClick
 import com.convenient.android.common.utils.ToastUtil
@@ -73,6 +75,9 @@ class AdFullScreenAdActivity : BaseBindingActivity<ActivityAdInterstitialBinding
                     adResult?.adObject = null
                     adResult = null
                 }
+                onAdRewarded {
+                    adLogE(AdManager.TAG, "获取到奖励")
+                }
             }
         }
     }

+ 3 - 1
app/src/main/java/com/convenient/android/lib/ui/sample/ad/activity/AdNativeActivity.kt

@@ -35,7 +35,9 @@ class AdNativeActivity : BaseBindingActivity<ActivityAdNativeBinding>(ActivityAd
         setViewsClick({
             when (it.id) {
                 R.id.btn_load_native_in_recyclerview->{
-                    readyGo(AdNativeListActivity::class.java)
+                    readyGo(AdNativeListActivity::class.java){
+                        it.putExtra("ad_slot_name", Datas.NATIVE)
+                    }
                 }
                 R.id.btn_load_native -> {
                     loadNativeAd { success ->

+ 4 - 3
app/src/main/java/com/convenient/android/lib/ui/sample/ad/activity/AdNativeListActivity.kt

@@ -17,16 +17,17 @@ import kotlinx.coroutines.launch
  */
 class AdNativeListActivity : BaseBindingActivity<ActivityAdNativeListBinding>(ActivityAdNativeListBinding::inflate) {
 
-    private var adapter : NativeAdSampleListAdapter = NativeAdSampleListAdapter()
+    private lateinit var adapter : NativeAdSampleListAdapter
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-
+        val adSlotName = intent.getStringExtra("ad_slot_name")?:Datas.NATIVE
+        adapter = NativeAdSampleListAdapter()
         binding.recyclerView.layoutManager = LinearLayoutManager(this)
         binding.recyclerView.adapter = adapter
 
         lifecycleScope.launch {
-            val list = Datas.getNativeADSampleLists(this@AdNativeListActivity)
+            val list = Datas.getNativeADSampleLists(this@AdNativeListActivity, adSlotName)
             adapter.setData(list.toMutableList())
         }
     }

+ 107 - 0
app/src/main/java/com/convenient/android/lib/ui/sample/ad/activity/AdNativeTemplateActivity.kt

@@ -0,0 +1,107 @@
+package com.convenient.android.lib.ui.sample.ad.activity
+
+import android.os.Bundle
+import androidx.core.view.isVisible
+import androidx.lifecycle.lifecycleScope
+import com.composition.android.lib.ad.AdLoad
+import com.composition.android.lib.ad.AdManager
+import com.composition.android.lib.ad.basic.AdResult
+import com.composition.android.lib.ad.basic.buildAdNativeViewHolder
+import com.composition.android.lib.ad.impl.NormalAdListener
+import com.composition.android.lib.ad.util.adLogE
+import com.convenient.android.common.base.viewbinding.BaseBindingActivity
+import com.convenient.android.common.extension.readyGo
+import com.convenient.android.common.extension.setViewsClick
+import com.convenient.android.common.utils.ToastUtil
+import com.convenient.android.lib.R
+import com.convenient.android.lib.databinding.ActivityAdNativeBinding
+import com.convenient.android.lib.databinding.ActivityAdNativeTemplateBinding
+import com.convenient.android.lib.databinding.ViewAdNativeBinding
+import com.convenient.android.lib.ui.sample.ad.model.Datas
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/6
+ * description: 横幅广告示例
+ */
+class AdNativeTemplateActivity : BaseBindingActivity<ActivityAdNativeTemplateBinding>(ActivityAdNativeTemplateBinding::inflate) {
+
+    private var adResult: AdResult.Success? = null
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setViewsClick({
+            when (it.id) {
+                R.id.btn_load_native_in_recyclerview->{
+                    readyGo(AdNativeListActivity::class.java){
+                        it.putExtra("ad_slot_name", Datas.NATIVE_TEMPLATE)
+                    }
+                }
+                R.id.btn_load_native -> {
+                    loadNativeAd { success ->
+                        adResult = success
+                    }
+                }
+                R.id.btn_show_native -> {
+                    lifecycleScope.launch {
+                        delay(1000)
+                        showNativeAd()
+                    }
+                }
+                R.id.btn_load_and_show -> {
+                    lifecycleScope.launch {
+                        binding.llAdContent.removeAllViews()
+                        delay(1000)
+                        loadNativeAd {
+                            adResult = it
+                            showNativeAd()
+                        }
+                    }
+                }
+            }
+
+        }, binding.btnLoadNative, binding.btnShowNative, binding.btnLoadAndShow,binding.btnLoadNativeInRecyclerview)
+    }
+
+    private fun loadNativeAd(success: (AdResult.Success) -> Unit) {
+        lifecycleScope.launch {
+            AdLoad.loadAd(this@AdNativeTemplateActivity, Datas.NATIVE_TEMPLATE)
+                .collect {
+                    if (it is AdResult.Success) {
+                        ToastUtil.showLongToast(this@AdNativeTemplateActivity, "加载原生广告成功")
+                        success.invoke(it)
+                    } else {
+                        adLogE(AdManager.TAG, it.msg)
+                    }
+                }
+        }
+    }
+
+    private fun showNativeAd() {
+        adResult?.let {
+
+            val viewHolder = buildAdNativeViewHolder {
+                this.activity= this@AdNativeTemplateActivity
+                this.adListener = object : NormalAdListener(){
+                    override fun onAdDisLike() {
+                        super.onAdDisLike()
+                        binding.llAdContent.isVisible = false
+                        binding.llAdContent.removeAllViews()
+                    }
+                }
+            }
+
+            AdLoad.getNativeAdView(this, it, viewHolder)?.let {
+                binding.llAdContent.removeAllViews()
+                binding.llAdContent.addView(it)
+                binding.llAdContent.isVisible = true
+            }
+
+        } ?: ToastUtil.showLongToast(this, "请先加载广告")
+    }
+
+
+}

+ 28 - 20
app/src/main/java/com/convenient/android/lib/ui/sample/ad/adapter/NativeAdSampleListAdapter.kt

@@ -1,14 +1,13 @@
 package com.convenient.android.lib.ui.sample.ad.adapter
 
-import android.view.View
 import android.view.ViewGroup
 import androidx.recyclerview.widget.RecyclerView
-import com.composition.android.lib.ad.AdLoad
 import com.convenient.android.common.base.viewbinding.BindingViewHolder
 import com.convenient.android.common.utils.date.DateUtils
 import com.convenient.android.common.utils.date.toDate
 import com.convenient.android.lib.R
 import com.convenient.android.lib.databinding.ViewRvAdNativeItemBinding
+import com.convenient.android.lib.databinding.ViewRvAdNativeTemplateItemBinding
 import com.convenient.android.lib.databinding.ViewRvMediaSampleItemBinding
 import com.convenient.android.lib.ui.sample.ad.model.NativeListBean
 
@@ -18,12 +17,14 @@ import com.convenient.android.lib.ui.sample.ad.model.NativeListBean
  * @date: 2022/9/8
  * description:
  */
-class NativeAdSampleListAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
+class NativeAdSampleListAdapter() : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
 
     companion object{
-        const val NORMAL_ITEM = 0
+        const val ITEM_NORMAL = 0
 
-        const val AD_ITEM = 1
+        const val ITEM_NATIVE_AD = 1
+
+        const val ITEM_NATIVE_TEMPLATE_AD = 2
     }
 
     private var lists : MutableList<NativeListBean> = mutableListOf()
@@ -39,27 +40,34 @@ class NativeAdSampleListAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>(
 
 
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
-        return if (viewType == NORMAL_ITEM){
-            BindingViewHolder(parent, ViewRvMediaSampleItemBinding::inflate)
-        }else{
-            BindingViewHolder(parent, ViewRvAdNativeItemBinding::inflate)
+        return when(viewType){
+            ITEM_NORMAL-> BindingViewHolder(parent, ViewRvMediaSampleItemBinding::inflate)
+            ITEM_NATIVE_AD->  BindingViewHolder(parent, ViewRvAdNativeItemBinding::inflate)
+            else-> BindingViewHolder(parent, ViewRvAdNativeTemplateItemBinding::inflate)
         }
     }
 
     override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
-        if(lists[position].viewType == NORMAL_ITEM){
-            val normalHolder = holder as BindingViewHolder<ViewRvMediaSampleItemBinding>
-            val item = lists[position]
-            item.media?.let {
-                normalHolder.binding.ivMediaItemIcon.setImageResource(if (item.media.isFile) R.drawable.ic_icons8_file else R.drawable.ic_icons8_folder)
-                normalHolder.binding.let {
-                    it.tvMediaItemTitle.text = item.media.name
-                    it.tvMediaItemDate.text = item.media.lastModified.toDate(DateUtils.DateFormat.DEFAULT_PATTERN.dateFormat)
+        when(lists[position].viewType){
+            ITEM_NORMAL->{
+                val normalHolder = holder as BindingViewHolder<ViewRvMediaSampleItemBinding>
+                val item = lists[position]
+                item.media?.let {
+                    normalHolder.binding.ivMediaItemIcon.setImageResource(if (item.media.isFile) R.drawable.ic_icons8_file else R.drawable.ic_icons8_folder)
+                    normalHolder.binding.let {
+                        it.tvMediaItemTitle.text = item.media.name
+                        it.tvMediaItemDate.text = item.media.lastModified.toDate(DateUtils.DateFormat.DEFAULT_PATTERN.dateFormat)
+                    }
                 }
             }
-        }else{
-            (holder as BindingViewHolder<ViewRvAdNativeItemBinding>)
-                .binding.nativeAdView.populateNativeAd(lists[position].success!!)
+            ITEM_NATIVE_AD->{
+                (holder as BindingViewHolder<ViewRvAdNativeItemBinding>)
+                    .binding.nativeAdView.populateNativeAd(lists[position].success!!)
+            }
+            else->{
+                (holder as BindingViewHolder<ViewRvAdNativeTemplateItemBinding>)
+                    .binding.nativeAdView.populateNativeAd(lists[position].success!!)
+            }
         }
     }
 

+ 21 - 8
app/src/main/java/com/convenient/android/lib/ui/sample/ad/model/Datas.kt

@@ -2,6 +2,7 @@ package com.convenient.android.lib.ui.sample.ad.model
 
 import android.content.Context
 import com.composition.android.ad.csj.impl.CSJBannerAdSize
+import com.composition.android.ad.gromore.load.impl.GMBannerAdSize
 import com.composition.android.lib.ad.AdLoad
 import com.composition.android.lib.ad.basic.AdResult
 import com.composition.android.lib.ad.basic.AdType
@@ -35,6 +36,7 @@ object Datas {
 
     val BANNER = "banner"
     val NATIVE = "native"
+    val NATIVE_TEMPLATE = "NativeTemplate"
     val INTERSTITIAL = "interstitial"
     val REWARDED_VIDEO = "rewarded_video"
     val REWARDED_INTERSTITIAL = "rewarded_interstitial"
@@ -52,31 +54,41 @@ object Datas {
         )
 
 
-    val CSJAdUnitList : List<AdUnitBean> =
+    val CSJAdUnitList: List<AdUnitBean> =
         listOf(
             AdUnitBean(BANNER, Advertisers.CSJ.name, AdType.BANNER.name, "949726232", adSize = CSJBannerAdSize(600F, 90F)),
-            AdUnitBean(NATIVE, Advertisers.CSJ.name, AdType.NATIVE.name, "949726254"),
+            AdUnitBean(NATIVE_TEMPLATE, Advertisers.CSJ.name, AdType.NATIVE_TEMPLATE.name, "949726254"),
             AdUnitBean(INTERSTITIAL, Advertisers.CSJ.name, AdType.INTERSTITIAL.name, "949726267"),
             AdUnitBean(REWARDED_VIDEO, Advertisers.CSJ.name, AdType.REWARDED_VIDEO.name, "949726565"),
             AdUnitBean(APP_OPEN, Advertisers.CSJ.name, AdType.APP_OPEN.name, "887922330", requestAdConfig = AdUnitLoadConfig(adLoadRetryCount = 1, adLoadTimeOut = 5000))
         )
 
+    val GroMoreAdUnitList: List<AdUnitBean> =
+        listOf(
+            AdUnitBean(BANNER, Advertisers.GroMore.name, AdType.BANNER.name, "102138574", adSize = GMBannerAdSize(600 to 90 /*GroMore的横幅广告为一张图片样式,这里的尺寸最好与GroMore代码位配置的一致*/)),
+            AdUnitBean(INTERSTITIAL, Advertisers.GroMore.name, AdType.INTERSTITIAL.name, "102138039"),
+            AdUnitBean(APP_OPEN, Advertisers.GroMore.name, AdType.APP_OPEN.name, "102137355"),
+            AdUnitBean(REWARDED_VIDEO, Advertisers.GroMore.name, AdType.REWARDED_VIDEO.name, "102137844"),
+            AdUnitBean(NATIVE_TEMPLATE, Advertisers.GroMore.name, AdType.NATIVE_TEMPLATE.name, "102140510")
+
+        )
+
 
-    suspend fun getNativeADSampleLists(context: Context): List<NativeListBean> {
+    suspend fun getNativeADSampleLists(context: Context, adSlotName: String): List<NativeListBean> {
 
         val list = mutableListOf<NativeListBean>()
 
-        var files = (0..100).map {
+        var files = (0..20).map {
             MediaBean(name = "测试:${it}", lastModified = System.currentTimeMillis(), isFile = true, extension = "png", parentPath = "", mediaPath = "")
         }.map {
-            NativeListBean(viewType = NativeAdSampleListAdapter.NORMAL_ITEM, media = it)
+            NativeListBean(viewType = NativeAdSampleListAdapter.ITEM_NORMAL, media = it)
         }
         list.addAll(files)
 
 
         val adList = mutableListOf<AdResult.Success>()
-        for (i in 0..4) {
-            val adResult = AdLoad.loadAd(context, NATIVE).firstOrNull()
+        for (i in 0..3) {
+            val adResult = AdLoad.loadAd(context, adSlotName).firstOrNull()
             if (adResult is AdResult.Success) {
                 adList.add(adResult)
             }
@@ -85,7 +97,8 @@ object Datas {
         for (success in adList) {
             val rand = Random(System.nanoTime())
             val randomNum = (0..list.size).random(rand)
-            list.add(randomNum, NativeListBean(viewType = NativeAdSampleListAdapter.AD_ITEM, success = success))
+            val viewType = if (success.adBean.getAdType() == AdType.NATIVE) NativeAdSampleListAdapter.ITEM_NATIVE_AD else NativeAdSampleListAdapter.ITEM_NATIVE_TEMPLATE_AD
+            list.add(randomNum, NativeListBean(viewType = viewType, success = success))
         }
 
         return list

+ 4 - 4
app/src/main/java/com/convenient/android/lib/ui/sample/ad/page/AdHomePage.kt

@@ -17,11 +17,8 @@ import androidx.compose.ui.unit.dp
 import androidx.navigation.NavHostController
 import com.composition.android.lib.ad.basic.Advertisers
 import com.convenient.android.common.extension.readyGo
-import com.convenient.android.lib.ui.sample.ad.activity.AdAppOpenActivity
+import com.convenient.android.lib.ui.sample.ad.activity.*
 import com.convenient.android.lib.ui.sample.ad.model.Datas
-import com.convenient.android.lib.ui.sample.ad.activity.AdBannerActivity
-import com.convenient.android.lib.ui.sample.ad.activity.AdFullScreenAdActivity
-import com.convenient.android.lib.ui.sample.ad.activity.AdNativeActivity
 import com.convenient.android.lib.ui.sample.ad.viewmodel.AdConfigViewModel
 
 /**
@@ -81,6 +78,9 @@ fun AdHomePage(viewModel: AdConfigViewModel, navHostController: NavHostControlle
             Item(modifier = modifier, title = "原生广告") {
                 context.readyGo(AdNativeActivity::class.java)
             }
+            Item(modifier = modifier, title = "原生模板广告") {
+                context.readyGo(AdNativeTemplateActivity::class.java)
+            }
             Item(modifier = modifier, title = "插屏广告") {
                 context.readyGo(AdFullScreenAdActivity::class.java){
                     it.putExtra("ad_slot_name", Datas.INTERSTITIAL)

+ 10 - 8
app/src/main/java/com/convenient/android/lib/ui/sample/ad/viewmodel/AdConfigViewModel.kt

@@ -8,6 +8,7 @@ import com.composition.android.lib.ad.impl.UnknownAdLoader
 import com.composition.android.lib.ad.interfaces.AdLoader
 import com.composition.android.ad.admob.load.AdmobAdLoader
 import com.composition.android.ad.csj.load.CSJAdLoader
+import com.composition.android.ad.gromore.load.GroMoreAdLoader
 
 /**
  * @classname:
@@ -20,20 +21,21 @@ class AdConfigViewModel : ViewModel() {
     var advertisers = mutableStateOf(Advertisers.UNKNOWN)
 
 
-    fun changeRegisterAdvertisers(advertisers: Advertisers){
-        if (this.advertisers.value == advertisers){
+    fun changeRegisterAdvertisers(advertisers: Advertisers) {
+        if (this.advertisers.value == advertisers) {
             this.advertisers.value = Advertisers.UNKNOWN
-        }else{
+        } else {
             this.advertisers.value = advertisers
         }
         AdManager.instance.registerAdLoader(getAdLoader(this.advertisers.value))
     }
 
-    fun getAdLoader(advertisers: Advertisers) : Pair<Advertisers, AdLoader>{
-       return when(advertisers){
-            Advertisers.Admob-> Advertisers.Admob to AdmobAdLoader()
-           Advertisers.CSJ -> Advertisers.CSJ to CSJAdLoader()
-            else-> Advertisers.UNKNOWN to UnknownAdLoader()
+    fun getAdLoader(advertisers: Advertisers): Pair<Advertisers, AdLoader> {
+        return when (advertisers) {
+            Advertisers.Admob -> Advertisers.Admob to AdmobAdLoader()
+            Advertisers.CSJ -> Advertisers.CSJ to CSJAdLoader()
+            Advertisers.GroMore -> Advertisers.GroMore to GroMoreAdLoader()
+            else -> Advertisers.UNKNOWN to UnknownAdLoader()
         }
     }
 

+ 82 - 0
app/src/main/res/layout/activity_ad_native_template.xml

@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <androidx.appcompat.widget.AppCompatButton
+            android:id="@+id/btn_load_native_in_recyclerview"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="原生模板广告在RecyclerView中运用"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <androidx.appcompat.widget.AppCompatButton
+            android:id="@+id/btn_load_native"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="加载广告"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <androidx.appcompat.widget.AppCompatButton
+            android:id="@+id/btn_show_native"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="显示广告"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <androidx.appcompat.widget.AppCompatButton
+            android:id="@+id/btn_load_and_show"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="加载并显示广告"
+            app:layout_constraintEnd_toEndOf="parent"
+            app:layout_constraintStart_toStartOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <androidx.appcompat.widget.AppCompatTextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="此处为getNativeAdView, 自定义布局不用写在此界面,通过addView添加到界面中" />
+
+        <LinearLayout
+            android:id="@+id/ll_ad_content"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical" />
+
+
+        <androidx.appcompat.widget.AppCompatTextView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="16dp"
+            android:text="原生模板广告自行加载填充模式,在Xml NativeAdView中设置好配置, View中自动完成加载"
+            />
+
+        <com.composition.android.lib.ad.widget.NativeAdView
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            app:native_ad_slot_name="NativeTemplate"
+            app:ad_auto_populate="true"
+            app:native_admob_advertisers_root_view="@layout/layout_admob_native_ad_view_root"
+            app:native_gro_more_advertisers_root_view="@layout/layout_gm_native_ad_view_root"
+            >
+
+
+        </com.composition.android.lib.ad.widget.NativeAdView>
+
+    </LinearLayout>
+
+</ScrollView>

+ 1 - 1
app/src/main/res/layout/view_ad_native.xml

@@ -36,7 +36,7 @@
         <FrameLayout
             android:id="@+id/fl_ad_media_content"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
+            android:layout_height="200dp"
             app:layout_constraintEnd_toEndOf="parent"
             app:layout_constraintStart_toStartOf="parent"
             android:layout_marginTop="8dp"

+ 4 - 3
app/src/main/res/layout/view_rv_ad_native_item.xml

@@ -10,7 +10,7 @@
         android:id="@+id/native_ad_view"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:padding="8dp"
+        app:ad_auto_populate="false"
         app:ad_view_call_to_action="@id/btn_call_to_action_1"
         app:ad_view_icon="@id/iv_ad_icon_1"
         app:ad_view_media_content_group="@id/fl_ad_media_content_1"
@@ -20,9 +20,10 @@
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:ad_auto_populate="false"
         app:native_ad_slot_name="native"
-        app:native_admob_advertisers_root_view="@layout/layout_admob_native_ad_view_root">
+        app:native_admob_advertisers_root_view="@layout/layout_admob_native_ad_view_root"
+        app:native_gro_more_advertisers_root_view="@layout/layout_gm_native_ad_view_root"
+        >
 
         <androidx.constraintlayout.widget.ConstraintLayout
             android:id="@+id/cl_ad_root_1"

+ 33 - 0
app/src/main/res/layout/view_rv_ad_native_template_item.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+
+    <com.composition.android.lib.ad.widget.NativeAdView
+        android:id="@+id/native_ad_view"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:ad_auto_populate="false"
+        app:layout_constraintBottom_toBottomOf="parent"
+        app:layout_constraintEnd_toEndOf="parent"
+        app:layout_constraintStart_toStartOf="parent"
+        app:layout_constraintTop_toTopOf="parent"
+        app:native_ad_slot_name="NativeTemplate"
+        app:native_admob_advertisers_root_view="@layout/layout_admob_native_ad_view_root"
+        app:native_gro_more_advertisers_root_view="@layout/layout_gm_native_ad_view_root"
+        >
+
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/cl_ad_root_1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
+    </com.composition.android.lib.ad.widget.NativeAdView>
+
+
+</androidx.constraintlayout.widget.ConstraintLayout>

+ 26 - 0
lib_ad_core/src/main/java/com/composition/android/lib/ad/basic/AdType.kt

@@ -8,17 +8,43 @@ package com.composition.android.lib.ad.basic
  */
 enum class AdType(name : String) {
 
+    /**
+     * 开屏广告
+     */
     APP_OPEN("AppOpen"),
 
+    /**
+     * 横幅广告
+     */
     BANNER("Banner"),
 
+    /**
+     * 原生自填充广告
+     */
     NATIVE("Native"),
 
+    /**
+     * 原生模板广告,类似于横幅广告,不需要自己填充内容
+     */
+    NATIVE_TEMPLATE("NativeTemplate"),
+
+    /**
+     * 插屏广告
+     */
     INTERSTITIAL("Interstitial"),
 
+    /**
+     * 激励视频广告
+     */
     REWARDED_VIDEO("RewardedVideo"),
 
+    /**
+     * 激励插屏广告
+     */
     REWARDED_INTERSTITIAL("RewardedInterstitial"),
 
+    /**
+     * 未知
+     */
     UNKNOWN("Unknown")
 }

+ 1 - 2
lib_ad_core/src/main/java/com/composition/android/lib/ad/interfaces/AdLoader.kt

@@ -30,11 +30,10 @@ interface AdLoader {
      */
     suspend fun loadByStrategy(context: Context, adUnitBean: AdUnitBean, iAdFormatRequest: IAdFormatRequest?) : AdResult{
         if (iAdFormatRequest == null){
-            return AdResult.Fail(adUnitBean, msg = "广告类型解析出错,请检查adType")
+            return AdResult.Fail(adUnitBean, msg = "广告类型解析出错,请检查adType, 当前广告商:${adUnitBean.advertisersName} 不支持 ${adUnitBean.adType} 类型的广告加载")
         }
         return try {
             withTimeoutOrNull(adUnitBean.requestAdConfig.adLoadTimeOut){
-
                 flow<AdResult> {
                     emit(iAdFormatRequest.load(context, adUnitBean))
                 }.onEach {

+ 7 - 1
lib_ad_core/src/main/java/com/composition/android/lib/ad/widget/NativeAdView.kt

@@ -11,6 +11,7 @@ import androidx.core.view.isVisible
 import androidx.lifecycle.findViewTreeLifecycleOwner
 import androidx.lifecycle.lifecycleScope
 import com.composition.android.lib.ad.AdLoad
+import com.composition.android.lib.ad.AdManager
 import com.composition.android.lib.ad.AdUnitConfigManager
 import com.composition.android.lib.ad.R
 import com.composition.android.lib.ad.basic.AdResult
@@ -18,6 +19,7 @@ import com.composition.android.lib.ad.basic.Advertisers
 import com.composition.android.lib.ad.basic.NativeAdViewHolder
 import com.composition.android.lib.ad.basic.buildAdNativeViewHolder
 import com.composition.android.lib.ad.impl.NormalAdListener
+import com.composition.android.lib.ad.util.adLogE
 import com.convenient.android.common.extension.getActivityFromView
 import kotlinx.coroutines.flow.firstOrNull
 import kotlinx.coroutines.launch
@@ -94,12 +96,16 @@ class NativeAdView : LinearLayout {
         val typedArray: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.NativeAdView)
         //获取到配置的广告名称
         adSlotName = typedArray.getString(R.styleable.NativeAdView_native_ad_slot_name) ?: ""
-        val adUnitBean = AdUnitConfigManager.instance.getAdUnitBySlotName(adSlotNames = listOf(adSlotName)).getOrNull(0)
 
+        val adUnitBean = AdUnitConfigManager.instance.getAdUnitBySlotName(adSlotNames = listOf(adSlotName)).getOrNull(0)
+        if (adUnitBean == null){
+            adLogE(AdManager.TAG, "配置的广告位数据不存在, 当前广告位:${adSlotName}")
+        }
         when (adUnitBean?.getAdvertisers()) {
             Advertisers.Admob -> attachedAdvertisersNativeAdViewToRoot(typedArray, R.styleable.NativeAdView_native_admob_advertisers_root_view)
             Advertisers.CSJ -> adRootView = this
             Advertisers.AppLovin-> attachedAdvertisersNativeAdViewToRoot(typedArray, R.styleable.NativeAdView_native_app_lovin_advertisers_root_view)
+            Advertisers.GroMore -> attachedAdvertisersNativeAdViewToRoot(typedArray, R.styleable.NativeAdView_native_gro_more_advertisers_root_view)
             Advertisers.AppLovinMax -> attachedAdvertisersNativeAdViewToRoot(typedArray, R.styleable.NativeAdView_native_app_lovin_max_advertisers_root_view)
             Advertisers.CUSTOM -> attachedAdvertisersNativeAdViewToRoot(typedArray, R.styleable.NativeAdView_native_custom_advertisers_root_view)
             else -> {}

+ 1 - 0
lib_ad_core/src/main/res/values/attr.xml

@@ -21,6 +21,7 @@
         <attr name="native_csj_advertisers_root_view" format="reference"/>
         <attr name="native_admob_advertisers_root_view" format="reference"/>
         <attr name="native_app_lovin_advertisers_root_view" format="reference"/>
+        <attr name="native_gro_more_advertisers_root_view" format="reference"/>
         <attr name="native_app_lovin_max_advertisers_root_view" format="reference"/>
         <attr name="native_custom_advertisers_root_view" format="reference"/>
         <attr name="native_ad_slot_name" format="string"/>

+ 34 - 34
lib_ad_csj/src/main/java/com/composition/android/ad/csj/load/CSJAdLoader.kt

@@ -25,54 +25,54 @@ class CSJAdLoader : AdLoader {
 
 
     override suspend fun load(context: Context, adUnitBean: AdUnitBean): AdResult {
-        if (adUnitBean.isAvailable().not()){
+        if (adUnitBean.isAvailable().not()) {
             return AdResult.Fail(adUnitBean, msg = "AdUnitBean无效")
         }
         //获取到具体的广告格式加载类
         val adFormatRequestImpl =
-            when(adUnitBean.getAdType()){
-            AdType.REWARDED_VIDEO, AdType.REWARDED_INTERSTITIAL-> CSJRewardRequestImpl()
-            AdType.INTERSTITIAL-> CSJInterstitialRequestImpl()
-            AdType.APP_OPEN -> CSJAppOpenRequestImpl()
-            AdType.BANNER-> CSJBannerRequestImpl()
-            AdType.NATIVE-> CSJNativeRequestImpl()
-            else-> null
-        }
+            when (adUnitBean.getAdType()) {
+                AdType.REWARDED_VIDEO -> CSJRewardRequestImpl()
+                AdType.INTERSTITIAL -> CSJInterstitialRequestImpl()
+                AdType.APP_OPEN -> CSJAppOpenRequestImpl()
+                AdType.BANNER -> CSJBannerRequestImpl()
+                AdType.NATIVE_TEMPLATE -> CSJNativeTemplateRequestImpl()
+                else -> null
+            }
         return loadByStrategy(context, adUnitBean, adFormatRequestImpl)
     }
 
     override fun getBannerView(context: Context, adResult: AdResult.Success, viewHolder: BannerAdViewHolder): BasicAdView<*>? {
-       return if (adResult.adObject != null) {
-           AdManager.instance.globalListener?.invoke(adResult.adBean)
-           CSJBannerView(context, viewHolder).apply {
-               render(adResult)
-           }
-       }else{
-           null
-       }
+        return if (adResult.adObject != null) {
+            AdManager.instance.globalListener?.invoke(adResult.adBean)
+            CSJBannerView(context, viewHolder).apply {
+                render(adResult)
+            }
+        } else {
+            null
+        }
     }
 
     override fun getNativeAdView(context: Context, adResult: AdResult.Success, viewHolder: NativeAdViewHolder): View? {
-        return if (adResult.adObject != null){
+        return if (adResult.adObject != null) {
             AdManager.instance.globalListener?.invoke(adResult.adBean)
             CSJNativeAdView(context).apply {
                 setViewHolder(viewHolder)
                 render(adResult)
             }
-        }else{
+        } else {
             null
         }
     }
 
     override fun populateNativeAdView(context: Context, adResult: AdResult.Success, viewHolder: NativeAdViewHolder, adRootView: View) {
         AdManager.instance.globalListener?.invoke(adResult.adBean)
-        CSJNativeAdView.populateNativeAdView(context,adResult, viewHolder, adRootView)
+        CSJNativeAdView.populateNativeAdView(context, adResult, viewHolder, adRootView)
     }
 
     override fun showInterstitialAd(activity: Activity, success: AdResult.Success, adListener: AdListener) {
-        if (success.adObject is TTFullScreenVideoAd){
+        if (success.adObject is TTFullScreenVideoAd) {
             val ttFullScreenVideoAd = success.adObject as TTFullScreenVideoAd
-            ttFullScreenVideoAd.setFullScreenVideoAdInteractionListener(object : TTFullScreenVideoAd.FullScreenVideoAdInteractionListener{
+            ttFullScreenVideoAd.setFullScreenVideoAdInteractionListener(object : TTFullScreenVideoAd.FullScreenVideoAdInteractionListener {
                 override fun onAdShow() {
                     adListener.onAdShow(success.adBean)
                     AdManager.instance.globalListener?.invoke(success.adBean)
@@ -97,18 +97,18 @@ class CSJAdLoader : AdLoader {
 
             })
             ttFullScreenVideoAd.showFullScreenVideoAd(activity, TTAdConstant.RitScenes.CUSTOMIZE_SCENES, null)
-        }else{
+        } else {
             adListener.onAdShowFail("adObject类型错误,当前为:${success.adObject?.javaClass?.simpleName}, 应该为:TTNativeExpressAd")
         }
     }
 
     override fun showRewardedAd(activity: Activity, success: AdResult.Success, adListener: AdListener) {
 
-        if (success.adObject is TTRewardVideoAd){
+        if (success.adObject is TTRewardVideoAd) {
             val ttRewardVideoAd = success.adObject as TTRewardVideoAd
 
 
-            ttRewardVideoAd.setRewardAdInteractionListener(object : TTRewardVideoAd.RewardAdInteractionListener{
+            ttRewardVideoAd.setRewardAdInteractionListener(object : TTRewardVideoAd.RewardAdInteractionListener {
                 override fun onAdShow() {
                     adListener.onAdShow(success.adBean)
                     AdManager.instance.globalListener?.invoke(success.adBean)
@@ -138,14 +138,14 @@ class CSJAdLoader : AdLoader {
                 }
 
                 override fun onSkippedVideo() {
-                   adListener.onAdSkip()
+                    adListener.onAdSkip()
                 }
 
             })
 
             ttRewardVideoAd.showRewardVideoAd(activity)
 
-        }else{
+        } else {
             adListener.onAdShowFail("穿山甲激励广告展示失败,类型错误,当前类型为:${success.adObject?.javaClass?.simpleName}, 应为:TTRewardVideoAd")
         }
 
@@ -153,13 +153,13 @@ class CSJAdLoader : AdLoader {
     }
 
     override fun showRewardedInterstitialAd(activity: Activity, success: AdResult.Success, adListener: AdListener) {
-       showRewardedAd(activity, success, adListener)
+        adListener.onAdShowFail("穿山甲广告不支持激励插屏广告,请使用激励视频广告")
     }
 
     override fun showSplashAd(activity: Activity, splashViewGroup: ViewGroup?, success: AdResult.Success, adListener: AdListener) {
-        if (success.adObject is TTSplashAd){
+        if (success.adObject is TTSplashAd) {
             val ttSplashAd = success.adObject as TTSplashAd
-            ttSplashAd.setSplashInteractionListener(object : TTSplashAd.AdInteractionListener{
+            ttSplashAd.setSplashInteractionListener(object : TTSplashAd.AdInteractionListener {
                 override fun onAdClicked(p0: View?, p1: Int) {
                     adListener.onAdClick()
                 }
@@ -179,16 +179,16 @@ class CSJAdLoader : AdLoader {
             })
             splashViewGroup?.removeAllViews()
             splashViewGroup?.addView(ttSplashAd.splashView)
-        }else{
+        } else {
             adListener.onAdShowFail("穿山甲激励广告展示失败,类型错误,当前类型为:${success.adObject?.javaClass?.simpleName}, 应为:TTRewardVideoAd")
         }
     }
 
     override fun showFullScreenAd(activity: Activity, success: AdResult.Success, adListener: AdListener) {
-        when(success.adBean.getAdType()){
-            AdType.REWARDED_INTERSTITIAL,AdType.INTERSTITIAL-> showInterstitialAd(activity, success, adListener)
+        when (success.adBean.getAdType()) {
+            AdType.INTERSTITIAL -> showInterstitialAd(activity, success, adListener)
             AdType.REWARDED_VIDEO -> showRewardedAd(activity, success, adListener)
-            else->{
+            else -> {
                 adListener.onAdShowFail("不支持的广告类型:${success.adBean.adType}")
             }
         }

+ 2 - 3
lib_ad_csj/src/main/java/com/composition/android/ad/csj/load/request/CSJBannerRequestImpl.kt

@@ -28,9 +28,8 @@ class CSJBannerRequestImpl : IAdFormatRequest {
             val adSlot = AdSlot.Builder()
                 .setCodeId(adUnitBean.adUnitId)
                 .setAdCount(1)
-                .setImageAcceptedSize(600, 300)
-                .setExpressViewAcceptedSize(size.first, size.second)
-                .setAdLoadType(TTAdLoadType.LOAD)
+                .setExpressViewAcceptedSize(size.first /2F, size.second/2F)
+                .setAdLoadType(TTAdLoadType.PRELOAD)
                 .build()
 
             TTAdSdk.getAdManager().createAdNative(context)

+ 4 - 7
lib_ad_csj/src/main/java/com/composition/android/ad/csj/load/request/CSJNativeRequestImpl.kt

@@ -17,21 +17,18 @@ import kotlin.coroutines.resume
  * @classname:
  * @author: LiuXiaoLong
  * @date: 2022/9/13
- * description:穿山甲原生广告加载类
+ * description:穿山甲原生模板广告加载类
  */
-class CSJNativeRequestImpl : IAdFormatRequest {
+class CSJNativeTemplateRequestImpl : IAdFormatRequest {
 
     override suspend fun load(context: Context, adUnitBean: AdUnitBean): AdResult {
         return suspendCancellableCoroutine {
-            adLogE(AdManager.TAG, "穿山甲广告已不再支持原生广告格式,请使用横幅模板广告 AdType.Banner")
-            it.resume(AdResult.Fail(adUnitBean, msg = "穿山甲已不再支持原生广告格式,请改用横幅广告"))
 
- /*           val adSlot = AdSlot.Builder()
+            val adSlot = AdSlot.Builder()
                 .setCodeId(adUnitBean.adUnitId)
                 .setAdCount(1)
                 .setImageAcceptedSize(640, 320)
                 .setAdLoadType(TTAdLoadType.PRELOAD)
-                .setNativeAdType(AdSlot.TYPE_BANNER)
                 .build()
 
             TTAdSdk.getAdManager().createAdNative(context)
@@ -53,7 +50,7 @@ class CSJNativeRequestImpl : IAdFormatRequest {
                             }
                         }
                     }
-                })*/
+                })
 
         }
     }

+ 1 - 0
lib_ad_csj/src/main/java/com/composition/android/ad/csj/load/view/CSJBannerView.kt

@@ -40,6 +40,7 @@ class CSJBannerView(context: Context?,var viewHolder: BannerAdViewHolder) : Basi
             }
 
             override fun onRenderSuccess(p0: View?, p1: Float, p2: Float) {
+                adLog(AdManager.TAG, "穿山甲广告渲染成功width:${p1}, height:${p2}")
             }
         })
         viewHolder.activity?.let {

+ 13 - 16
lib_ad_csj/src/main/java/com/composition/android/ad/csj/load/view/CSJNativeAdView.kt

@@ -3,16 +3,13 @@ package com.composition.android.ad.csj.load.view
 import android.content.Context
 import android.view.View
 import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.LinearLayout
-import androidx.appcompat.widget.AppCompatImageView
-import androidx.appcompat.widget.AppCompatTextView
-import androidx.core.view.isVisible
 import com.bytedance.sdk.openadsdk.*
-import com.composition.android.ad.csj.R
+import com.composition.android.lib.ad.AdManager
 import com.composition.android.lib.ad.basic.AdResult
 import com.composition.android.lib.ad.basic.BasicAdView
 import com.composition.android.lib.ad.basic.NativeAdViewHolder
+import com.composition.android.lib.ad.util.adLogE
+import com.convenient.android.common.extension.getScreenWidth
 
 /**
  * @classname:
@@ -35,7 +32,6 @@ class CSJNativeAdView(context: Context?) : BasicAdView<View>(context) {
         }
         populateNativeAdView(context, adResult = adResult!!, viewHolder = viewHolder!!, null)
         val ttNativeExpressAd = adResult?.adObject as TTNativeExpressAd
-
         return ttNativeExpressAd.expressAdView
     }
 
@@ -43,6 +39,7 @@ class CSJNativeAdView(context: Context?) : BasicAdView<View>(context) {
     }
 
     override fun onPause() {
+
     }
 
     override fun onDestroy() {
@@ -52,11 +49,8 @@ class CSJNativeAdView(context: Context?) : BasicAdView<View>(context) {
 
     companion object {
 
-
-
         fun populateNativeAdView(context: Context, adResult: AdResult.Success, viewHolder: NativeAdViewHolder, adRootView : View?) {
             val ttNativeExpressAd = adResult.adObject as TTNativeExpressAd
-
             viewHolder.activity?.let {
                 ttNativeExpressAd.setDislikeCallback(it, object : TTAdDislike.DislikeInteractionCallback {
                     override fun onShow() {
@@ -87,19 +81,22 @@ class CSJNativeAdView(context: Context?) : BasicAdView<View>(context) {
                     viewHolder.adListener?.onAdShowFail("穿山甲原生模板广告渲染失败")
                 }
 
-                override fun onRenderSuccess(p0: View?, p1: Float, p2: Float) {
+                override fun onRenderSuccess(p0: View?, width: Float, height: Float) {
+                    adLogE(AdManager.TAG, "穿山甲原生广告渲染成功width:${width},height:${height}")
+                    (adRootView as? ViewGroup)?.let {
+                        val sWidth = context.getScreenWidth()
+                        val sHeight = (sWidth * height / width).toInt()
+                        it.removeAllViews()
+                        it.addView(ttNativeExpressAd.expressAdView, sWidth,sHeight)
+                    }
                 }
 
                 override fun onAdDismiss() {
                     viewHolder.adListener?.onAdClose()
                 }
-
             })
             ttNativeExpressAd.render()
-            (adRootView as? ViewGroup)?.let {
-                it.removeAllViews()
-                it.addView(ttNativeExpressAd.expressAdView)
-            }
+
         }
     }
 

+ 1 - 0
lib_ad_gromore/.gitignore

@@ -0,0 +1 @@
+/build

+ 64 - 0
lib_ad_gromore/build.gradle

@@ -0,0 +1,64 @@
+plugins {
+    id 'com.android.library'
+    id 'org.jetbrains.kotlin.android'
+}
+
+android {
+    compileSdk 32
+
+    defaultConfig {
+        minSdk 21
+        targetSdk 32
+
+        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+        consumerProguardFiles "consumer-rules.pro"
+    }
+
+    buildTypes {
+        release {
+            minifyEnabled false
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+        }
+    }
+    compileOptions {
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+    kotlinOptions {
+        jvmTarget = '1.8'
+    }
+}
+
+dependencies {
+
+    implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
+
+    implementation project(':lib_ad_core')
+    api "com.gromore.cn:gromore-sdk:3.6.0.2"
+    implementation "com.gromore.cn:pangle-adapter:4.7.1.2.0"
+
+    implementation 'androidx.core:core-ktx:1.8.0'
+    implementation 'androidx.appcompat:appcompat:1.5.1'
+    implementation 'com.google.android.material:material:1.6.1'
+    testImplementation 'junit:junit:4.13.2'
+    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
+
+
+    //mintegral
+    implementation("com.mbridge.msdk.support:videojs:16.1.97")
+    implementation("com.mbridge.msdk.support:mbjscommon:16.1.97")
+    implementation("com.mbridge.msdk.support:playercommon:16.1.97")
+    implementation("com.mbridge.msdk.support:reward:16.1.97")
+    implementation("com.mbridge.msdk.support:videocommon:16.1.97")
+    implementation("com.mbridge.msdk.support:chinasame:16.1.97")
+    implementation("com.mbridge.msdk.support:interstitialvideo:16.1.97")
+    implementation("com.mbridge.msdk.support:mbnative:16.1.97")
+    implementation("com.mbridge.msdk.support:nativeex:16.1.97")
+    implementation("com.mbridge.msdk.support:mbnativeadvanced:16.1.97")
+    implementation("com.mbridge.msdk.support:interstitial:16.1.97")
+    implementation("com.mbridge.msdk.support:mbbanner:16.1.97")
+    implementation("com.mbridge.msdk.support:mbsplash:16.1.97")
+    implementation("com.mbridge.msdk.support:mbbid:16.1.97")
+    implementation("com.mbridge.msdk.support:newinterstitial:16.1.97")
+}

+ 0 - 0
lib_ad_gromore/consumer-rules.pro


BIN
lib_ad_gromore/libs/open_ad_sdk.aar


+ 156 - 0
lib_ad_gromore/proguard-rules.pro

@@ -0,0 +1,156 @@
+# 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
+
+## pangle 穿山甲原有的
+-keepclassmembers class * {
+    *** getContext(...);
+    *** getActivity(...);
+    *** getResources(...);
+    *** startActivity(...);
+    *** startActivityForResult(...);
+    *** registerReceiver(...);
+    *** unregisterReceiver(...);
+    *** query(...);
+    *** getType(...);
+    *** insert(...);
+    *** delete(...);
+    *** update(...);
+    *** call(...);
+    *** setResult(...);
+    *** startService(...);
+    *** stopService(...);
+    *** bindService(...);
+    *** unbindService(...);
+    *** requestPermissions(...);
+    *** getIdentifier(...);
+   }
+
+-keep class com.bytedance.pangle.** {*;}
+-keep class com.bytedance.sdk.openadsdk.** { *; }
+-keep class com.bytedance.frameworks.** { *; }
+
+-keep class ms.bd.c.Pgl.**{*;}
+-keep class com.bytedance.mobsec.metasec.ml.**{*;}
+
+-keep class com.ss.android.**{*;}
+
+-keep class com.bytedance.embedapplog.** {*;}
+-keep class com.bytedance.embed_dr.** {*;}
+
+-keep class com.bykv.vk.** {*;}
+
+
+//聚合混淆
+-keep class bykvm*.**
+-keep class com.bytedance.msdk.adapter.**{ public *; }
+-keep class com.bytedance.msdk.api.** {
+ public *;
+}
+-keep class com.bytedance.msdk.base.TTBaseAd{*;}
+-keep class com.bytedance.msdk.adapter.TTAbsAdLoaderAdapter{
+    public *;
+    protected <fields>;
+}
+
+# baidu sdk 不接入baidu sdk可以不引入
+-ignorewarnings
+-dontwarn com.baidu.mobads.sdk.api.**
+-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.style.widget.** {*;}
+-keep class com.component.** {*;}
+-keep class com.baidu.ad.magic.flute.** {*;}
+-keep class com.baidu.mobstat.forbes.** {*;}
+
+
+# Admob 不接入admob sdk可以不引入
+-keep class com.google.android.gms.ads.MobileAds {
+ public *;
+}
+
+#sigmob  不接入sigmob sdk可以不引入
+-dontwarn android.support.v4.**
+-keep class android.support.v4.** { *; }
+-keep interface android.support.v4.** { *; }
+-keep public class * extends android.support.v4.**
+
+-keep class sun.misc.Unsafe { *; }
+-dontwarn com.sigmob.**
+-keep class com.sigmob.**.**{*;}
+
+#oaid 不同的版本混淆代码不太一致,你注意你接入的oaid版本 ,不接入oaid可以不添加
+-dontwarn com.bun.**
+-keep class com.bun.** {*;}
+-keep class a.**{*;}
+-keep class XI.CA.XI.**{*;}
+-keep class XI.K0.XI.**{*;}
+-keep class XI.XI.K0.**{*;}
+-keep class XI.vs.K0.**{*;}
+-keep class XI.xo.XI.XI.**{*;}
+-keep class com.asus.msa.SupplementaryDID.**{*;}
+-keep class com.asus.msa.sdid.**{*;}
+-keep class com.huawei.hms.ads.identifier.**{*;}
+-keep class com.samsung.android.deviceidservice.**{*;}
+-keep class com.zui.opendeviceidlibrary.**{*;}
+-keep class org.json.**{*;}
+-keep public class com.netease.nis.sdkwrapper.Utils {public <methods>;}
+
+
+#klevin 游可赢
+-keep class com.tencent.tgpa.**{*;}
+-keep class com.tencent.klevin.**{*;}
+
+
+#Mintegral 不接入Mintegral sdk,可以不引入
+-keepattributes Signature
+-keepattributes *Annotation*
+-keep class com.mbridge.** {*; }
+-keep interface com.mbridge.** {*; }
+-keep class android.support.v4.** { *; }
+-dontwarn com.mbridge.**
+-keep class **.R$* { public static final int mbridge*; }
+
+
+注意: SDK代码被混淆后会导致广告无法展现或者其它异常。
+
+注意: SDK中使用的so文件支持1种架构:armeabi-v7a 如果您应用中支持的架构超出这
+1种,请在build.gradle中使用abiFilters选择支持的架构(需要注意ADN支持的架构有几种)。如下所示:
+
+    ndk {
+            // 设置支持的 SO 库构架,注意这里要根据你的实际情况来设置
+            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64', 'armeabi'
+    }
+    packagingOptions {
+            doNotStrip "*/armeabi-v7a/*.so"
+            doNotStrip "*/x86/*.so"
+            doNotStrip "*/arm64-v8a/*.so"
+            doNotStrip "*/x86_64/*.so"
+            doNotStrip "armeabi.so"
+    }

+ 24 - 0
lib_ad_gromore/src/androidTest/java/com/composition/android/ad/gromore/ExampleInstrumentedTest.kt

@@ -0,0 +1,24 @@
+package com.composition.android.ad.gromore
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+    @Test
+    fun useAppContext() {
+        // Context of the app under test.
+        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+        assertEquals("com.composition.android.ad.gromore.test", appContext.packageName)
+    }
+}

+ 53 - 0
lib_ad_gromore/src/main/AndroidManifest.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.composition.android.ad.gromore">
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
+
+    <permission
+        android:name="${applicationId}.openadsdk.permission.TT_PANGOLIN"
+        android:protectionLevel="signature" />
+    <uses-permission android:name="${applicationId}.openadsdk.permission.TT_PANGOLIN" />
+
+    <!--可选权限-->
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.GET_TASKS"/>
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <!-- 如果有视频相关的广告且使用textureView播放,请务必添加,否则黑屏 -->
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+
+    <application
+       >
+
+        <activity
+            android:name="com.baidu.mobads.sdk.api.AppActivity"
+            android:configChanges="screenSize|keyboard|keyboardHidden|orientation"
+            android:theme="@android:style/Theme.NoTitleBar"/>
+        <!-- 声明打开显示激励视频/全屏视频的Activity-->
+        <activity
+            android:name="com.baidu.mobads.sdk.api.MobRewardVideoActivity"
+            android:configChanges="screenSize|orientation|keyboardHidden"
+            android:launchMode="singleTask"
+            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
+        <!-- 如果targetSdkVersion设置值>=24,则强烈建议添加以下provider,否则会影响app变现 -->
+        <!-- android:authorities="${packageName}.bd.provider" authorities中${packageName}部分必须替换成app自己的包名 -->
+        <!-- 原来的FileProvider在新版本中改为BdFileProvider,继承自v4的FileProvider,需要在应用内引用support-v4包 -->
+        <provider
+            android:name="com.baidu.mobads.sdk.api.BdFileProvider"
+            android:authorities="${applicationId}.bd.provider"
+            android:exported="false"
+            android:grantUriPermissions="true">
+            <meta-data
+                android:name="android.support.FILE_PROVIDER_PATHS"
+                android:resource="@xml/bd_file_paths" />
+        </provider>
+    </application>
+</manifest>

+ 218 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/GroMoreAdLoader.kt

@@ -0,0 +1,218 @@
+package com.composition.android.ad.gromore.load
+
+import android.app.Activity
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import com.bytedance.msdk.api.AdError
+import com.bytedance.msdk.api.format.TTNativeAdView
+import com.bytedance.msdk.api.reward.RewardItem
+import com.bytedance.msdk.api.v2.ad.interstitialFull.GMInterstitialFullAd
+import com.bytedance.msdk.api.v2.ad.interstitialFull.GMInterstitialFullAdListener
+import com.bytedance.msdk.api.v2.ad.reward.GMRewardAd
+import com.bytedance.msdk.api.v2.ad.reward.GMRewardedAdListener
+import com.bytedance.msdk.api.v2.ad.splash.GMSplashAd
+import com.bytedance.msdk.api.v2.ad.splash.GMSplashAdListener
+import com.composition.android.ad.gromore.load.request.*
+import com.composition.android.ad.gromore.load.view.GMBannerView
+import com.composition.android.ad.gromore.load.view.GMNativeTemplateAdView
+import com.composition.android.lib.ad.AdManager
+import com.composition.android.lib.ad.basic.*
+import com.composition.android.lib.ad.bean.AdUnitBean
+import com.composition.android.lib.ad.interfaces.AdListener
+import com.composition.android.lib.ad.interfaces.AdLoader
+import com.composition.android.lib.ad.util.adLogE
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/15
+ * description:GroMore广告加载类
+ */
+class GroMoreAdLoader : AdLoader {
+
+    override suspend fun load(context: Context, adUnitBean: AdUnitBean): AdResult {
+        val adRequest = when (adUnitBean.getAdType()) {
+            AdType.BANNER -> GMBannerRequestImpl()
+            AdType.NATIVE_TEMPLATE -> GMNativeTemplateRequestImpl()
+            AdType.INTERSTITIAL, AdType.REWARDED_INTERSTITIAL -> GMInterstitialRequestImpl()
+            AdType.REWARDED_VIDEO -> GMRewardRequestImpl()
+            AdType.APP_OPEN -> GMAppOpenRequestImpl()
+            else -> null
+        }
+        return loadByStrategy(context, adUnitBean, adRequest)
+
+    }
+
+    override fun getBannerView(context: Context, adResult: AdResult.Success, viewHolder: BannerAdViewHolder): BasicAdView<*>? {
+        return if (adResult.adObject != null) {
+            GMBannerView(context).apply {
+                setBannerViewHolder(viewHolder)
+                render(adResult)
+                AdManager.instance.globalListener?.invoke(adResult.adBean)
+            }
+        } else {
+            null
+        }
+    }
+
+    override fun getNativeAdView(context: Context, adResult: AdResult.Success, viewHolder: NativeAdViewHolder): View? {
+        return if (adResult.adObject != null) {
+            GMNativeTemplateAdView(context).apply {
+                setViewHolder(viewHolder)
+                render(adResult)
+                AdManager.instance.globalListener?.invoke(adResult.adBean)
+            }
+        } else {
+            null
+        }
+    }
+
+
+    override fun populateNativeAdView(context: Context, adResult: AdResult.Success, viewHolder: NativeAdViewHolder, adRootView: View) {
+        if (adRootView is TTNativeAdView) {
+            GMNativeTemplateAdView.populateNativeAdView(context, adResult, viewHolder, adRootView)
+        } else {
+            adLogE(AdManager.TAG, "GroMore原生模板广告填充失败, adRootView错误,当前类型为${adRootView.javaClass.simpleName},需要为${TTNativeAdView::class.java.simpleName}")
+        }
+    }
+
+    override fun showInterstitialAd(activity: Activity, success: AdResult.Success, adListener: AdListener) {
+        if (success.adObject is GMInterstitialFullAd) {
+            val mInterstitialFullAd = success.adObject as GMInterstitialFullAd
+            mInterstitialFullAd.setAdInterstitialFullListener(object : GMInterstitialFullAdListener {
+                override fun onInterstitialFullShow() {
+                    adListener.onAdShow(success.adBean)
+                    AdManager.instance.globalListener?.invoke(success.adBean)
+                }
+
+                override fun onInterstitialFullShowFail(p0: AdError) {
+                    adListener.onAdShowFail(p0.message)
+                }
+
+                override fun onInterstitialFullClick() {
+                    adListener.onAdClick()
+                }
+
+                override fun onInterstitialFullClosed() {
+                    adListener.onAdClose()
+                }
+
+                override fun onVideoComplete() {
+                }
+
+                override fun onVideoError() {
+                }
+
+                override fun onSkippedVideo() {
+                }
+
+                override fun onAdOpened() {
+                }
+
+                override fun onAdLeftApplication() {
+                }
+
+                override fun onRewardVerify(p0: RewardItem) {
+                    adListener.onAdRewarded()
+                }
+
+            })
+            mInterstitialFullAd.showAd(activity)
+
+        } else {
+            adListener.onAdShowFail("adObject类型错误或为空:${success.adObject?.javaClass?.simpleName}")
+        }
+    }
+
+    override fun showRewardedAd(activity: Activity, success: AdResult.Success, adListener: AdListener) {
+        if (success.adObject is GMRewardAd) {
+            val gmRewardAd = success.adObject as GMRewardAd
+            gmRewardAd.setRewardAdListener(object : GMRewardedAdListener {
+                override fun onRewardedAdShow() {
+                    adListener.onAdShow(success.adBean)
+                    AdManager.instance.globalListener?.invoke(success.adBean)
+                }
+
+                override fun onRewardedAdShowFail(p0: AdError) {
+                    adListener.onAdShowFail(p0.message)
+                }
+
+                override fun onRewardClick() {
+                    adListener.onAdClick()
+                }
+
+                override fun onRewardedAdClosed() {
+                    adListener.onAdClose()
+                }
+
+                override fun onVideoComplete() {
+                }
+
+                override fun onVideoError() {
+                }
+
+                override fun onRewardVerify(p0: RewardItem) {
+                    adListener.onAdRewarded()
+                }
+
+                override fun onSkippedVideo() {
+                }
+            })
+
+            if (gmRewardAd.isReady) {
+                gmRewardAd.showRewardAd(activity)
+            } else {
+                adListener.onAdShowFail("GroMore激励视频对象还未准备完成,显示失败")
+            }
+        } else {
+            adListener.onAdShowFail("adObject类型错误或为空:${success.adObject?.javaClass?.simpleName}")
+        }
+
+    }
+
+    override fun showRewardedInterstitialAd(activity: Activity, success: AdResult.Success, adListener: AdListener) {
+        adListener.onAdShowFail("GroMore不支持激励插屏广告")
+    }
+
+    override fun showSplashAd(activity: Activity, splashViewGroup: ViewGroup?, success: AdResult.Success, adListener: AdListener) {
+        if (success.adObject is GMSplashAd) {
+            val gmAppOpenAd = success.adObject as GMSplashAd
+            if (gmAppOpenAd.isReady) {
+                gmAppOpenAd.setAdSplashListener(object : GMSplashAdListener {
+                    override fun onAdClicked() {
+                        adListener.onAdClick()
+                    }
+
+                    override fun onAdShow() {
+                        adListener.onAdShow(success.adBean)
+                        AdManager.instance.globalListener?.invoke(success.adBean)
+                    }
+
+                    override fun onAdShowFail(p0: AdError) {
+                        adListener.onAdShowFail(p0.message)
+                    }
+
+                    override fun onAdSkip() {
+                        adListener.onAdSkip()
+                    }
+
+                    override fun onAdDismiss() {
+                        adListener.onAdClose()
+                    }
+                })
+                gmAppOpenAd.showAd(splashViewGroup)
+            }
+        }
+    }
+
+    override fun showFullScreenAd(activity: Activity, success: AdResult.Success, adListener: AdListener) {
+        when (success.adBean.getAdType()) {
+            AdType.INTERSTITIAL -> showInterstitialAd(activity, success, adListener)
+            AdType.REWARDED_VIDEO -> showRewardedAd(activity, success, adListener)
+            else -> {
+                adListener.onAdShowFail("无对应广告类型的广告进行展示 AdType:${success.adBean.adType}")
+            }
+        }
+    }
+}

+ 17 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/impl/GMBannerAdSize.kt

@@ -0,0 +1,17 @@
+package com.composition.android.ad.gromore.load.impl
+
+import com.bytedance.msdk.api.v2.GMAdSize
+import com.composition.android.lib.ad.interfaces.IAdSize
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/15
+ * description: GroMore Banner 广告高度
+ */
+class GMBannerAdSize(var gmAdSize : Pair<Int, Int>) : IAdSize<Pair<Int, Int>> {
+
+    override fun getAdSize(): Pair<Int, Int> {
+        return gmAdSize
+    }
+}

+ 40 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/impl/GroMoreInitialize.kt

@@ -0,0 +1,40 @@
+package com.composition.android.ad.gromore.load.impl
+
+import android.content.Context
+import android.os.Build
+import com.bytedance.msdk.api.v2.*
+import com.composition.android.lib.ad.interfaces.Initialize
+import com.convenient.android.common.config.MyPdfBaseModule
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/15
+ * description:GroMore SDK初始化
+ */
+class GroMoreInitialize(var appId : String) : Initialize {
+
+
+    override fun init(context: Context) {
+
+        GMMediationAdSdk.initialize(context, GMAdConfig.Builder()
+            .setAppId(appId)
+            .setAppName(context.packageName)
+            .setDebug(MyPdfBaseModule.isDebug)
+            .setOpenAdnTest(false)
+            .setPrivacyConfig(object : GMPrivacyConfig(){
+                override fun isCanUsePhoneState(): Boolean {
+                    return true
+                }
+
+                override fun getMacAddress(): String {
+                    return ""
+                }
+
+                override fun getAgeGroup(): GMAdConstant.ADULT_STATE {
+                    return GMAdConstant.ADULT_STATE.AGE_ADULT
+                }
+            })
+            .build())
+    }
+}

+ 63 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/request/GMAppOpenRequestImpl.kt

@@ -0,0 +1,63 @@
+package com.composition.android.ad.gromore.load.request
+
+import android.app.Activity
+import android.content.Context
+import com.bytedance.msdk.api.AdError
+import com.bytedance.msdk.api.v2.ad.splash.GMSplashAd
+import com.bytedance.msdk.api.v2.ad.splash.GMSplashAdLoadCallback
+import com.bytedance.msdk.api.v2.slot.GMAdSlotSplash
+import com.composition.android.ad.gromore.load.util.GMSettingConfig
+import com.composition.android.ad.gromore.load.util.printAdFailInfo
+import com.composition.android.ad.gromore.load.util.printAdInfo
+import com.composition.android.lib.ad.basic.AdResult
+import com.composition.android.lib.ad.bean.AdUnitBean
+import com.composition.android.lib.ad.interfaces.IAdFormatRequest
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlin.coroutines.resume
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/16
+ * description:GroMore开屏广告加载类
+ */
+class GMAppOpenRequestImpl : IAdFormatRequest{
+    override suspend fun load(context: Context, adUnitBean: AdUnitBean): AdResult {
+        return suspendCancellableCoroutine {
+            if (context is Activity){
+                GMSettingConfig.loadAdConfig {
+                    val mTTSplashAd = GMSplashAd(context, adUnitBean.adUnitId)
+                    mTTSplashAd.loadAd(GMAdSlotSplash.Builder()
+                        .build(),object : GMSplashAdLoadCallback{
+                        override fun onSplashAdLoadFail(p0: AdError) {
+                            printAdFailInfo(p0.code, p0.message)
+                            if (it.isActive) {
+                                it.resume(AdResult.Fail(adUnitBean, msg = "GroMore开屏广告加载失败:${p0.message}"))
+                            }
+                        }
+
+                        override fun onSplashAdLoadSuccess() {
+                            printAdInfo(adUnitBean)
+                            if (it.isActive){
+                                it.resume(AdResult.Success(adBean = adUnitBean, adObject = mTTSplashAd, msg = "GroMore开屏广告加载成功"))
+                            }
+                        }
+
+                        override fun onAdLoadTimeout() {
+                            printAdFailInfo(0, "GroMore开屏广告加载超时")
+                            if (it.isActive){
+                                it.resume(AdResult.Fail(adUnitBean, msg = "GroMore开屏广告加载超时"))
+                            }
+
+                        }
+                    })
+                }
+
+            }else{
+                if (it.isActive) {
+                    it.resume(AdResult.Fail(adUnitBean, msg = "GroMore开屏广告需要context为Activity"))
+                }
+            }
+        }
+    }
+}

+ 67 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/request/GMBannerRequestImpl.kt

@@ -0,0 +1,67 @@
+package com.composition.android.ad.gromore.load.request
+
+import android.app.Activity
+import android.content.Context
+import com.bytedance.msdk.api.AdError
+import com.bytedance.msdk.api.v2.GMAdSize
+import com.bytedance.msdk.api.v2.ad.banner.GMBannerAd
+import com.bytedance.msdk.api.v2.ad.banner.GMBannerAdLoadCallback
+import com.bytedance.msdk.api.v2.slot.GMAdSlotBanner
+import com.composition.android.ad.gromore.load.impl.GMBannerAdSize
+import com.composition.android.ad.gromore.load.util.GMSettingConfig
+import com.composition.android.ad.gromore.load.util.printAdFailInfo
+import com.composition.android.ad.gromore.load.util.printAdInfo
+import com.composition.android.lib.ad.AdManager
+import com.composition.android.lib.ad.basic.AdResult
+import com.composition.android.lib.ad.bean.AdUnitBean
+import com.composition.android.lib.ad.interfaces.IAdFormatRequest
+import com.composition.android.lib.ad.util.adLogE
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlin.coroutines.resume
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/15
+ * description: GroMore Banner广告加载类
+ */
+class GMBannerRequestImpl : IAdFormatRequest {
+
+    override suspend fun load(context: Context, adUnitBean: AdUnitBean): AdResult {
+        return suspendCancellableCoroutine {
+
+            GMSettingConfig.loadAdConfig {
+
+                if (context is Activity) {
+                    val mTTBannerViewAd = GMBannerAd(context, adUnitBean.adUnitId)
+                    val size = if (adUnitBean.adSize is GMBannerAdSize) (adUnitBean.adSize as GMBannerAdSize).gmAdSize else 600 to 90
+                    val slotBanner = GMAdSlotBanner.Builder()
+                        .setBannerSize(GMAdSize.BANNER_CUSTOME)
+                        .setAllowShowCloseBtn(true)
+                        .setImageAdSize(size.first, size.second)
+                        .setMuted(true)
+                        .build()
+                    mTTBannerViewAd.loadAd(slotBanner, object : GMBannerAdLoadCallback {
+                        override fun onAdFailedToLoad(p0: AdError) {
+                            printAdFailInfo(p0.code, p0.message)
+                            if (it.isActive) {
+                                it.resume(AdResult.Fail(adUnitBean, msg = p0.message))
+                            }
+                        }
+
+                        override fun onAdLoaded() {
+                            printAdInfo(adUnitBean)
+                            if (it.isActive) {
+                                it.resume(AdResult.Success(adBean = adUnitBean, adObject = mTTBannerViewAd, msg = "GroMore Banner广告加载成功"))
+                            }
+                        }
+                    })
+
+                } else {
+                    adLogE(AdManager.TAG, "GroMore广告加载context需要为Activity")
+                    it.resume(AdResult.Fail(adUnitBean, msg = "GroMore广告加载context需要为Activity"))
+                }
+            }
+        }
+    }
+}

+ 64 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/request/GMInterstitialRequestImpl.kt

@@ -0,0 +1,64 @@
+package com.composition.android.ad.gromore.load.request
+
+import android.app.Activity
+import android.content.Context
+import com.bytedance.msdk.api.AdError
+import com.bytedance.msdk.api.v2.ad.interstitialFull.GMInterstitialFullAd
+import com.bytedance.msdk.api.v2.ad.interstitialFull.GMInterstitialFullAdLoadCallback
+import com.bytedance.msdk.api.v2.slot.GMAdOptionUtil
+import com.bytedance.msdk.api.v2.slot.GMAdSlotInterstitialFull
+import com.composition.android.ad.gromore.load.util.GMSettingConfig
+import com.composition.android.ad.gromore.load.util.printAdFailInfo
+import com.composition.android.ad.gromore.load.util.printAdInfo
+import com.composition.android.lib.ad.basic.AdResult
+import com.composition.android.lib.ad.bean.AdUnitBean
+import com.composition.android.lib.ad.interfaces.IAdFormatRequest
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlin.coroutines.resume
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/16
+ * description:GroMore 插屏广告加载类
+ */
+class GMInterstitialRequestImpl : IAdFormatRequest {
+    override suspend fun load(context: Context, adUnitBean: AdUnitBean): AdResult {
+        return suspendCancellableCoroutine {
+            GMSettingConfig.loadAdConfig {
+                    if (context is Activity){
+                        val mInterstitialFullAd = GMInterstitialFullAd(context, adUnitBean.adUnitId)
+                        val adSlot = GMAdSlotInterstitialFull.Builder()
+                            .setGMAdSlotBaiduOption(GMAdOptionUtil.getGMAdSlotBaiduOption().build())
+                            .setGMAdSlotGDTOption(GMAdOptionUtil.getGMAdSlotGDTOption().build())
+                            .build()
+
+                        mInterstitialFullAd.loadAd(adSlot, object : GMInterstitialFullAdLoadCallback{
+                            override fun onInterstitialFullLoadFail(p0: AdError) {
+                                printAdFailInfo(p0.code, p0.message)
+                                if (it.isActive){
+                                    it.resume(AdResult.Fail(adUnitBean, msg = "GroMore插屏广告加载失败:${p0.message}"))
+                                }
+                            }
+
+                            override fun onInterstitialFullAdLoad() {
+                                //这里为广告加载成功,但还没缓存好
+                            }
+
+                            override fun onInterstitialFullCached() {
+                                printAdInfo(adUnitBean)
+                                //这里为广告已经缓存好了,保证流畅播放,再次返回成功
+                                if (it.isActive){
+                                    it.resume(AdResult.Success(adBean = adUnitBean, adObject = mInterstitialFullAd, msg = "GroMore 插屏广告加载成功"))
+                                }
+                            }
+                        })
+
+                    }else{
+                        it.resume(AdResult.Fail(adUnitBean, msg = "GroMore加载插屏广告context 类型需要为activity"))
+                    }
+
+            }
+        }
+    }
+}

+ 67 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/request/GMNativeTemplateRequestImpl.kt

@@ -0,0 +1,67 @@
+package com.composition.android.ad.gromore.load.request
+
+import android.app.Activity
+import android.content.Context
+import com.bytedance.msdk.api.AdError
+import com.bytedance.msdk.api.v2.ad.nativeAd.GMNativeAd
+import com.bytedance.msdk.api.v2.ad.nativeAd.GMNativeAdLoadCallback
+import com.bytedance.msdk.api.v2.ad.nativeAd.GMUnifiedNativeAd
+import com.bytedance.msdk.api.v2.slot.GMAdOptionUtil
+import com.bytedance.msdk.api.v2.slot.GMAdSlotNative
+import com.bytedance.sdk.openadsdk.AdSlot
+import com.composition.android.ad.gromore.load.util.GMSettingConfig
+import com.composition.android.lib.ad.basic.AdResult
+import com.composition.android.lib.ad.bean.AdUnitBean
+import com.composition.android.lib.ad.interfaces.IAdFormatRequest
+import com.convenient.android.common.extension.getScreenWidthDp
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlin.coroutines.resume
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/16
+ * description: GroMore原生模板广告加载类
+ */
+class GMNativeTemplateRequestImpl() : IAdFormatRequest {
+
+    override suspend fun load(context: Context, adUnitBean: AdUnitBean): AdResult {
+
+        return suspendCancellableCoroutine {
+            if (context is Activity){
+                GMSettingConfig.loadAdConfig {
+
+                    val gmNativeAd = GMUnifiedNativeAd(context, adUnitBean.adUnitId)
+                    gmNativeAd.loadAd(GMAdSlotNative.Builder()
+                        .setAdCount(1)
+                        .setGMAdSlotBaiduOption(GMAdOptionUtil.getGMAdSlotBaiduOption().build())
+                        .setGMAdSlotGDTOption(GMAdOptionUtil.getGMAdSlotGDTOption().build())
+                        .setAdStyleType(AdSlot.TYPE_FEED)
+                        .setImageAdSize(context.getScreenWidthDp().toInt(), 340)
+                        .build(),
+                        object  : GMNativeAdLoadCallback{
+                            override fun onAdLoaded(p0: MutableList<GMNativeAd>) {
+                                if (it.isActive) {
+                                    if (p0.isNullOrEmpty().not()){
+                                        it.resume(AdResult.Success(adBean = adUnitBean, adObject = p0.get(0), msg = "GroMore原生模板广告加载成功"))
+                                    }else{
+                                        it.resume(AdResult.Fail(adUnitBean, msg = "GroMore 原生模板广告"))
+                                    }
+                                }
+                            }
+                            override fun onAdLoadedFail(p0: AdError) {
+                            }
+                        }
+                    )
+                }
+
+            }else{
+                if (it.isActive) {
+                    it.resume(AdResult.Fail(adUnitBean, msg = "GroMore 原生广告加载需要context为Activity类型"))
+                }
+            }
+
+        }
+
+    }
+}

+ 63 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/request/GMRewardRequestImpl.kt

@@ -0,0 +1,63 @@
+package com.composition.android.ad.gromore.load.request
+
+import android.app.Activity
+import android.content.Context
+import com.bytedance.msdk.api.AdError
+import com.bytedance.msdk.api.v2.GMAdConstant
+import com.bytedance.msdk.api.v2.ad.reward.GMRewardAd
+import com.bytedance.msdk.api.v2.ad.reward.GMRewardedAdLoadCallback
+import com.bytedance.msdk.api.v2.slot.GMAdSlotRewardVideo
+import com.composition.android.ad.gromore.load.util.GMSettingConfig
+import com.composition.android.ad.gromore.load.util.printAdFailInfo
+import com.composition.android.lib.ad.basic.AdResult
+import com.composition.android.lib.ad.bean.AdUnitBean
+import com.composition.android.lib.ad.interfaces.IAdFormatRequest
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlin.coroutines.resume
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/16
+ * description: GroMore 激励视频广告加载类
+ */
+class GMRewardRequestImpl : IAdFormatRequest {
+    override suspend fun load(context: Context, adUnitBean: AdUnitBean): AdResult {
+
+        return suspendCancellableCoroutine {
+            if (context is Activity){
+                GMSettingConfig.loadAdConfig {
+                    val gmRewardAd = GMRewardAd(context, adUnitBean.adUnitId)
+                    gmRewardAd.loadAd(GMAdSlotRewardVideo.Builder()
+                        .setRewardAmount(1)
+                        .setMuted(true)
+                        .setOrientation(GMAdConstant.VERTICAL)
+                        .build(), object : GMRewardedAdLoadCallback{
+                        override fun onRewardVideoLoadFail(p0: AdError) {
+                           printAdFailInfo(p0.code, p0.message)
+                            if (it.isActive){
+                                it.resume(AdResult.Fail(adUnitBean, msg = "GroMore激励视频广告加载失败:${p0.message}"))
+                            }
+                        }
+
+                        override fun onRewardVideoAdLoad() {
+                        }
+
+                        override fun onRewardVideoCached() {
+                            if (it.isActive){
+                                it.resume(AdResult.Success(adBean = adUnitBean, adObject = gmRewardAd, msg = "GroMore激励视频广告加载成功"))
+                            }
+                        }
+
+                    })
+                }
+            }else{
+                printAdFailInfo(0, "GroMore加载激励视频广告需要context为Activity")
+                if (it.isActive){
+                    it.resume(AdResult.Fail(adUnitBean, msg = "GroMore加载激励视频广告需要context为Activity"))
+                }
+            }
+
+        }
+    }
+}

+ 51 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/util/GMAdExpan.kt

@@ -0,0 +1,51 @@
+package com.composition.android.ad.gromore.load.util
+
+import com.composition.android.lib.ad.AdManager
+import com.composition.android.lib.ad.bean.AdUnitBean
+import com.composition.android.lib.ad.util.adLog
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/13
+ * description:
+ */
+
+internal fun printAdFailInfo(code : Int, msg : String?){
+    adLog(
+        AdManager.TAG,
+        "-------------------------------------------------------------------"
+    )
+
+    adLog(AdManager.TAG, "广告加载失败")
+    adLog(AdManager.TAG, "Code:${code}")
+    adLog(AdManager.TAG, "错误信息:${msg}")
+
+    adLog(
+        AdManager.TAG,
+        "-------------------------------------------------------------------"
+    )
+}
+
+
+internal fun printAdInfo(adBean: AdUnitBean){
+
+    adLog(
+        AdManager.TAG,
+        "-------------------------------------------------------------------"
+    )
+
+    adLog(AdManager.TAG, "广告加载成功")
+    adLog(AdManager.TAG, "广告商:${adBean.advertisersName}")
+    adLog(AdManager.TAG, "广告位:${adBean.adSlotName}")
+    adLog(AdManager.TAG, "广告ID:${adBean.adUnitId}")
+    adLog(AdManager.TAG, "广告类型:${adBean.adType}")
+
+    adLog(
+        AdManager.TAG,
+        "-------------------------------------------------------------------"
+    )
+}
+
+
+

+ 28 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/util/GMSettingConfig.kt

@@ -0,0 +1,28 @@
+package com.composition.android.ad.gromore.load.util
+
+import com.bytedance.msdk.api.v2.GMMediationAdSdk
+import com.bytedance.msdk.api.v2.GMSettingConfigCallback
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlin.coroutines.resume
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/15
+ * description:
+ */
+object GMSettingConfig {
+
+
+    fun loadAdConfig(callBack: () -> Unit) {
+        if (GMMediationAdSdk.configLoadSuccess()) {
+            callBack.invoke()
+        } else {
+            GMMediationAdSdk.registerConfigCallback {
+                callBack.invoke()
+            }
+        }
+    }
+
+
+}

+ 74 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/view/GMBannerView.kt

@@ -0,0 +1,74 @@
+package com.composition.android.ad.gromore.load.view
+
+import android.content.Context
+import android.graphics.Color
+import android.view.View
+import androidx.core.content.ContextCompat
+import com.bytedance.msdk.api.AdError
+import com.bytedance.msdk.api.v2.ad.banner.GMBannerAd
+import com.bytedance.msdk.api.v2.ad.banner.GMBannerAdListener
+import com.composition.android.lib.ad.AdManager
+import com.composition.android.lib.ad.basic.BannerAdViewHolder
+import com.composition.android.lib.ad.basic.BasicAdView
+import com.composition.android.lib.ad.util.adLogE
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/15
+ * description: GroMore Banner广告View
+ */
+class GMBannerView(context: Context?) : BasicAdView<View>(context) {
+
+    private var viewHolder : BannerAdViewHolder? = null
+
+    fun setBannerViewHolder(viewHolder: BannerAdViewHolder){
+        this.viewHolder = viewHolder
+    }
+
+    override fun adContentView(): View? {
+        val gmBannerAd = getGmBannerAd()
+        gmBannerAd?.setAdBannerListener(object : GMBannerAdListener{
+            override fun onAdOpened() {
+            }
+
+            override fun onAdLeftApplication() {
+
+            }
+
+            override fun onAdClosed() {
+                viewHolder?.adListener?.onAdClose()
+            }
+
+            override fun onAdClicked() {
+                viewHolder?.adListener?.onAdClick()
+            }
+
+            override fun onAdShow() {
+                adResult?.adBean?.let { viewHolder?.adListener?.onAdShow(it) }
+            }
+
+            override fun onAdShowFail(p0: AdError) {
+                viewHolder?.adListener?.onAdShowFail(p0.message)
+            }
+        })
+        return gmBannerAd?.bannerView
+    }
+
+    private fun getGmBannerAd() : GMBannerAd?{
+        return adResult?.adObject as? GMBannerAd
+    }
+
+    override fun onResume() {
+        getGmBannerAd()?.onResume()
+    }
+
+    override fun onPause() {
+        getGmBannerAd()?.onPause()
+    }
+
+    override fun onDestroy() {
+        getGmBannerAd()?.destroy()
+        adResult?.adObject = null
+    }
+}

+ 98 - 0
lib_ad_gromore/src/main/java/com/composition/android/ad/gromore/load/view/GMNativeTemplateAdView.kt

@@ -0,0 +1,98 @@
+package com.composition.android.ad.gromore.load.view
+
+import android.content.Context
+import android.view.LayoutInflater
+import android.view.View
+import com.bytedance.msdk.api.format.TTNativeAdView
+import com.bytedance.msdk.api.v2.GMDislikeCallback
+import com.bytedance.msdk.api.v2.ad.nativeAd.GMNativeAd
+import com.bytedance.msdk.api.v2.ad.nativeAd.GMNativeAdListener
+import com.bytedance.sdk.openadsdk.TTNativeExpressAd
+import com.composition.android.ad.gromore.R
+import com.composition.android.lib.ad.basic.AdResult
+import com.composition.android.lib.ad.basic.BasicAdView
+import com.composition.android.lib.ad.basic.NativeAdViewHolder
+
+/**
+ * @classname:
+ * @author: LiuXiaoLong
+ * @date: 2022/9/19
+ * description: GroMore原生模板广告View
+ */
+class GMNativeTemplateAdView(context: Context?) : BasicAdView<View>(context) {
+
+
+    private var viewHolder: NativeAdViewHolder? = null
+
+    fun setViewHolder(viewHolder: NativeAdViewHolder) {
+        this.viewHolder = viewHolder
+    }
+
+    private fun getGmNativeAd() : GMNativeAd?{
+        return adResult?.adObject as? GMNativeAd
+    }
+
+    override fun adContentView(): View? {
+        if (adResult == null || viewHolder == null) {
+            return null
+        }
+
+        return populateNativeAdView(context, adResult!!, viewHolder!!)
+    }
+
+    override fun onResume() {
+        getGmNativeAd()?.resume()
+    }
+
+    override fun onPause() {
+        getGmNativeAd()?.onPause()
+    }
+
+    override fun onDestroy() {
+        getGmNativeAd()?.destroy()
+        adResult?.adObject = null
+    }
+
+    companion object {
+        fun populateNativeAdView(context: Context, success: AdResult.Success, nativeAdViewHolder: NativeAdViewHolder) : View{
+            val ttNativeAdView = LayoutInflater.from(context).inflate(R.layout.layout_gm_native_ad_view_root, null) as TTNativeAdView
+            populateNativeAdView(context, success, nativeAdViewHolder, ttNativeAdView)
+            return ttNativeAdView
+        }
+
+
+        fun populateNativeAdView(context: Context, success: AdResult.Success, nativeAdViewHolder: NativeAdViewHolder, ttNativeAdView: TTNativeAdView) {
+
+            val gmNativeAd = success.adObject as GMNativeAd
+            if (gmNativeAd.hasDislike() && nativeAdViewHolder.activity != null) {
+                gmNativeAd.setDislikeCallback(nativeAdViewHolder.activity, object : GMDislikeCallback {
+                    override fun onSelected(p0: Int, p1: String?) {
+                        nativeAdViewHolder.adListener?.onAdDisLike()
+                    }
+
+                    override fun onCancel() {
+                    }
+
+                    override fun onRefuse() {
+                    }
+
+                    override fun onShow() {
+                    }
+
+                })
+            }
+            gmNativeAd.setNativeAdListener(object : GMNativeAdListener {
+                override fun onAdClick() {
+                    nativeAdViewHolder.adListener?.onAdClick()
+                }
+
+                override fun onAdShow() {
+                    nativeAdViewHolder.adListener?.onAdShow(adUnitBean = success.adBean)
+                }
+            })
+            gmNativeAd.render()
+            ttNativeAdView.removeAllViews()
+            ttNativeAdView.addView(gmNativeAd.expressView)
+        }
+    }
+}

+ 8 - 0
lib_ad_gromore/src/main/res/layout/layout_gm_native_ad_view_root.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.bytedance.msdk.api.format.TTNativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+
+
+</com.bytedance.msdk.api.format.TTNativeAdView>

+ 17 - 0
lib_ad_gromore/src/test/java/com/composition/android/ad/gromore/ExampleUnitTest.kt

@@ -0,0 +1,17 @@
+package com.composition.android.ad.gromore
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+    @Test
+    fun addition_isCorrect() {
+        assertEquals(4, 2 + 2)
+    }
+}

+ 1 - 0
settings.gradle

@@ -32,3 +32,4 @@ include ':lib_common'
 include ':lib_ad_core'
 include ':lib_ad_admob'
 include ':lib_ad_csj'
+include ':lib_ad_gromore'