Commit e8ade6bb authored by wanglei's avatar wanglei

...广告

parent fe134c80
...@@ -77,7 +77,6 @@ dependencies { ...@@ -77,7 +77,6 @@ dependencies {
androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
//网络请求 //网络请求
implementation("com.google.code.gson:gson:2.11.0") implementation("com.google.code.gson:gson:2.11.0")
...@@ -89,6 +88,8 @@ dependencies { ...@@ -89,6 +88,8 @@ dependencies {
api(libs.immersionbar.ktx) api(libs.immersionbar.ktx)
//facebook
implementation("com.facebook.android:facebook-android-sdk:[8,9)")
//solar 归因 //solar 归因
implementation("com.reyun.solar.engine.oversea:solar-engine-core:1.2.8.3") implementation("com.reyun.solar.engine.oversea:solar-engine-core:1.2.8.3")
...@@ -113,5 +114,31 @@ dependencies { ...@@ -113,5 +114,31 @@ dependencies {
// implementation("com.google.zxing:android-integration:$zxing") // implementation("com.google.zxing:android-integration:$zxing")
// implementation("com.google.zxing:zxing-android-embedded:$zxing") // implementation("com.google.zxing:zxing-android-embedded:$zxing")
//广告
//admob渠道
implementation(libs.vungle)
implementation(libs.facebook)
implementation(libs.mintegral)
implementation(libs.pangle)
//applovin sdk
implementation(libs.applovin)
//applovin渠道
implementation(libs.applovin.google)
implementation(libs.applovin.admob)
implementation(libs.applovin.facebook) //meta
implementation(libs.applovin.mintegral)//mintegral
implementation(libs.applovin.pangle) //pangle
implementation(libs.applovin.vungle) //vungle
//firebase
implementation(platform("com.google.firebase:firebase-bom:32.3.1"))
implementation("com.google.firebase:firebase-messaging")
implementation("com.google.firebase:firebase-analytics-ktx")
implementation("com.google.firebase:firebase-crashlytics")
implementation("com.google.firebase:firebase-config")
//冲突版本确定版本
implementation("com.google.guava:guava:29.0-android")
} }
...@@ -6,12 +6,15 @@ import android.content.Context ...@@ -6,12 +6,15 @@ import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
import com.base.scanqr.ads.AdsMgr
import com.base.scanqr.bean.ConstObject.appLanguageCountrySp import com.base.scanqr.bean.ConstObject.appLanguageCountrySp
import com.base.scanqr.bean.ConstObject.appLanguageSp import com.base.scanqr.bean.ConstObject.appLanguageSp
import com.base.scanqr.helper.AppConfig import com.base.scanqr.fcm.FCMManager
import com.base.scanqr.utils.ActivityManagerUtils import com.base.scanqr.utils.ActivityManagerUtils
import com.base.scanqr.utils.AppPreferences import com.base.scanqr.utils.AppPreferences
import com.base.scanqr.utils.LogEx import com.base.scanqr.utils.LogEx
import com.facebook.FacebookSdk
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.hjq.language.MultiLanguages import com.hjq.language.MultiLanguages
import com.hjq.language.OnLanguageListener import com.hjq.language.OnLanguageListener
import java.util.Locale import java.util.Locale
...@@ -20,7 +23,7 @@ import java.util.UUID ...@@ -20,7 +23,7 @@ import java.util.UUID
class MyApplication : Application() { class MyApplication : Application() {
private val TAG = "MyApplication" private val TAG = "MyApplication"
var uuid = "" private var uuid = ""
companion object { companion object {
...@@ -28,6 +31,15 @@ class MyApplication : Application() { ...@@ -28,6 +31,15 @@ class MyApplication : Application() {
@JvmField @JvmField
var PAUSED_VALUE = 0 var PAUSED_VALUE = 0
val noLoadingActivities = listOf(
"full", // 过滤全屏广告
"adActivity",
"AdActivity",
"AppLovinFullscreenActivity",
// SplashActivity::class.java.simpleName,
// 返回前台时不跳转启动页的 activity
)
} }
...@@ -35,11 +47,11 @@ class MyApplication : Application() { ...@@ -35,11 +47,11 @@ class MyApplication : Application() {
super.onCreate() super.onCreate()
appContext = this appContext = this
initUUid() initUUid()
initGid()
initApp() initApp()
// 初始化语种切换框架 // 初始化语种切换框架
MultiLanguages.init(this) MultiLanguages.init(this)
// 设置语种变化监听器 // 设置语种变化监听器
MultiLanguages.setOnLanguageListener(object : OnLanguageListener { MultiLanguages.setOnLanguageListener(object : OnLanguageListener {
override fun onAppLocaleChange(oldLocale: Locale, newLocale: Locale) { override fun onAppLocaleChange(oldLocale: Locale, newLocale: Locale) {
...@@ -71,16 +83,24 @@ class MyApplication : Application() { ...@@ -71,16 +83,24 @@ class MyApplication : Application() {
LogEx.logDebug(TAG, "uuid=${AppPreferences.getInstance().getString("uuid", "")}") LogEx.logDebug(TAG, "uuid=${AppPreferences.getInstance().getString("uuid", "")}")
} }
private fun initGid() {
Thread {
val info: AdvertisingIdClient.Info = AdvertisingIdClient.getAdvertisingIdInfo(applicationContext)
val advertisingId = info.id
AppPreferences.getInstance().put("gid", advertisingId)
}.start()
}
private fun initApp() { private fun initApp() {
//初始化广告相关业务 //初始化广告相关业务
// AdsMgr.init(appContext) AdsMgr.init(appContext)
// FacebookSdk.sdkInitialize(applicationContext) FacebookSdk.sdkInitialize(applicationContext)
// val token = AppPreferences.getInstance().getString("token", "") val token = AppPreferences.getInstance().getString("token", "")
// val topic = AppConfig.packageName + "_push" val topic = GlobalConfig.PACKAGE_NAME + "_push"
// LogEx.logDebug(TAG, "topic=${topic} token=$token") LogEx.logDebug(TAG, "topic=${topic} token=$token")
// FCMManager.initFirebase(this) FCMManager.initFirebase(this)
// FCMManager.subscribeToTopic(topic) FCMManager.subscribeToTopic(topic)
// initConfig() // initConfig()
// //
...@@ -131,7 +151,7 @@ class MyApplication : Application() { ...@@ -131,7 +151,7 @@ class MyApplication : Application() {
val flag = if (topActivity == null) { val flag = if (topActivity == null) {
true true
} else { } else {
AppConfig.noLoadingActivities.all { !topActivity.localClassName.contains(it, true) } noLoadingActivities.all { !topActivity.localClassName.contains(it, true) }
} }
LogEx.logDebug(TAG, "flag=$flag" + " activity:" + activity.localClassName) LogEx.logDebug(TAG, "flag=$flag" + " activity:" + activity.localClassName)
...@@ -199,8 +219,8 @@ class MyApplication : Application() { ...@@ -199,8 +219,8 @@ class MyApplication : Application() {
// ConfigBean.configBean = configBean // ConfigBean.configBean = configBean
// //
// //广告 // //广告
// AdsMgr.adsConfigBean = configBean.adConfigBean // com.base.scanqr.ads.AdsMgr.adsConfigBean = configBean.adConfigBean
// com.base.localweatherwhite.utils.LogEx.logDebug("initConfig", "AdsMgr.adsConfigBean=${configBean.adConfigBean.functionInShowAd}") // com.base.localweatherwhite.utils.LogEx.logDebug("initConfig", "com.base.scanqr.ads.AdsMgr.adsConfigBean=${configBean.adConfigBean.functionInShowAd}")
// //
// //通知 // //通知
// PopupConstObject.popupConfigBean = configBean.popupConfigBean // PopupConstObject.popupConfigBean = configBean.popupConfigBean
......
package com.base.scanqr.ads
import android.animation.ObjectAnimator
import android.animation.ValueAnimator.INFINITE
import android.app.AlertDialog
import android.content.Context
import android.view.LayoutInflater
import android.view.animation.LinearInterpolator
import com.base.scanqr.databinding.DialogAdPreparingBinding
import com.base.scanqr.utils.DensityUtils
import com.base.scanqr.utils.LogEx
object AdDialog {
private val TAG = "AdDialog"
fun Context.showAdPreparingDialog(where: Int = 0): AlertDialog {
LogEx.logDebug(TAG, "where=$where")
val binding = DialogAdPreparingBinding.inflate(LayoutInflater.from(this))
val dialog = AlertDialog.Builder(this).create()
dialog.setView(binding.root)
dialog.setCancelable(false)
dialog.setCanceledOnTouchOutside(false)
dialog.show()
val params = dialog.window?.attributes
params?.width = DensityUtils.dip2px(200f)
params?.height = DensityUtils.dip2px(146f)
dialog.window?.attributes = params
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
// 创建一个旋转动画
val rotateAnimator = ObjectAnimator.ofFloat(binding.iv, "rotation", 0f, -360f)
rotateAnimator.setDuration(1000) // 设置动画持续时间为1000毫秒
rotateAnimator.repeatCount = INFINITE
rotateAnimator.interpolator = LinearInterpolator() // 设置插值器为线性插值
rotateAnimator.start()
return dialog
}
}
\ No newline at end of file
package com.base.scanqr.ads
import com.base.scanqr.MyApplication
import com.base.scanqr.helper.EventUtils
import com.base.scanqr.utils.LogEx
import org.json.JSONObject
import java.util.UUID
val taichiPref by lazy {
MyApplication.appContext.getSharedPreferences("TaichiTroasCache", 0)
}
val taichiSharedPreferencesEditor by lazy {
taichiPref.edit()
}
abstract class AdEvent {
abstract val TAG: String
var adUnit: String = ""
var from: String = ""
val reqId = UUID.randomUUID().toString()
fun adPrepareShow() {
val obj1 = JSONObject()
obj1.put("ad_unit", adUnit)
obj1.put("req_id", reqId)
obj1.put("from", from)
EventUtils.event("ad_prepare_show", ext = obj1)
LogEx.logDebug(TAG, "ad_prepare_show $obj1")
}
fun adPulStart() {
val obj = JSONObject()
obj.put("req_id", reqId)
obj.put("ad_unit", adUnit)
obj.put("ad_type", adUnit)
obj.put("from", from)
EventUtils.event("ad_pull_start", ext = obj)
LogEx.logDebug(TAG, "ad_pull_start $obj")
}
fun adShowError(reason: Any) {
val obj = JSONObject()
obj.put("ad_unit", adUnit)
obj.put("req_id", reqId)
obj.put("from", from)
obj.put("reason", reason.toString())
EventUtils.event("ad_show_error", ext = obj)
LogEx.logDebug(TAG, "ad_show_error $obj")
}
fun adLimited(value: String) {
val obj = JSONObject()
obj.put("ad_unit", adUnit)
obj.put("req_id", reqId)
obj.put("from", from)
EventUtils.event("ad_limit", value, obj)
LogEx.logDebug(TAG, "ad_limit $obj")
}
}
\ No newline at end of file
package com.base.scanqr.ads
import android.app.Activity
import android.content.Context
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import com.applovin.sdk.AppLovinMediationProvider
import com.applovin.sdk.AppLovinSdk
import com.applovin.sdk.AppLovinSdkInitializationConfiguration
import com.base.appzxhy.bean.config.ConfigBean.Companion.configBean
import com.base.scanqr.BuildConfig
import com.base.scanqr.GlobalConfig
import com.base.scanqr.ads.admob.AdBannerMgr
import com.base.scanqr.ads.admob.AdInsertMgr
import com.base.scanqr.ads.admob.AdNativeMgr
import com.base.scanqr.ads.admob.AdOpenMgr
import com.base.scanqr.ads.admob.AdmobEvent
import com.base.scanqr.ads.applovin.AdMaxEvent
import com.base.scanqr.ads.applovin.MaxInsertMgr
import com.base.scanqr.ads.applovin.MaxNativeMgr
import com.base.scanqr.ads.applovin.MaxOpenMgr
import com.base.scanqr.bean.config.AdConfigBean
import com.base.scanqr.helper.EventUtils
import com.base.scanqr.utils.AppPreferences
import com.base.scanqr.utils.LogEx
import com.base.scanqr.utils.ToastUtils.toast
import com.google.android.gms.ads.MobileAds
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.google.android.gms.ads.initialization.AdapterStatus
import java.util.Collections
import java.util.concurrent.Executors
/**
* 广告管理类
*/
object AdsMgr {
private val adOpenMgr by lazy {
AdOpenMgr()
}
private val adInsertMgr by lazy {
AdInsertMgr()
}
private val adNativeMgr by lazy {
AdNativeMgr()
}
private val adBannerMgr by lazy {
AdBannerMgr()
}
private val maxOpenMgr by lazy {
MaxOpenMgr()
}
private val maxInsertMgr by lazy {
MaxInsertMgr()
}
private val maxNativeMgr by lazy {
MaxNativeMgr()
}
/**
* 是否初始化
*/
var isAdmobInit = false
private set
/**
* 是否初始化
*/
var isMaxInit = false
private set
/**
* 广告配置项目
*/
var adsConfigBean: AdConfigBean = AdConfigBean()
/**
* Init 初始化
*
* @param context 这里最好是appContext,因为是耗时操作,等它初始化完毕马上加载开屏和插屏广告
*/
fun init(context: Context) {
if (configBean.isInBlackList) {
EventUtils.event("isInBlackList", configBean.isInBlackList.toString())
return
}
initAdmob(context)
initMax(context)
}
private fun initAdmob(context: Context) {
MobileAds.initialize(context) {
val readyAdapter = it.adapterStatusMap.entries.find { entry ->
entry.value.initializationState == AdapterStatus.State.READY
}
isAdmobInit = readyAdapter != null
EventUtils.event("AdmobInit", "AdmobInit")
// context.toast("admob init")
if (adsConfigBean.adSwitch) {
admobInitCallBack?.invoke()
admobInitCallBack = null
adOpenMgr.loadAd(context, false, AdmobEvent("openAd", context::class.java.simpleName))
adInsertMgr.loadAd(context, false, AdmobEvent("interAd", context::class.java.simpleName))
}
}
}
private fun initMax(context: Context) = kotlin.runCatching {
val executor = Executors.newSingleThreadExecutor()
executor.execute {
val currentGaid = AdvertisingIdClient.getAdvertisingIdInfo(context).id
AppPreferences.getInstance().getString("gid", currentGaid)
val build = AppLovinSdkInitializationConfiguration
.builder(GlobalConfig.KEY_MAX, context)
build.setMediationProvider(AppLovinMediationProvider.MAX)
if (BuildConfig.DEBUG) {
build.testDeviceAdvertisingIds = Collections.singletonList(currentGaid)
}
val initConfig = build.build()
runCatching {
AppLovinSdk.getInstance(context).initialize(initConfig) {
isMaxInit = true
// maxOpenMgr.loadAd(context)
if (!adsConfigBean.adSwitch) {
maxInsertMgr.loadAd(context, false, AdMaxEvent("interAd", context::class.java.simpleName))
context.toast("max init")
maxInitCallBack?.invoke()
maxInitCallBack = null
}
}
}
}
}
private var admobInitCallBack: (() -> Unit)? = null
private var maxInitCallBack: (() -> Unit)? = null
/**
* 展示开屏广告
*
* @param activity 当前页面
* @param showCallBack 展示回调
*/
fun showOpen(
activity: Activity,
isUnLimit: Boolean = false,
showCallBack: AdsShowCallBack? = null,
) {
if (configBean.isInBlackList) {
EventUtils.event("isInBlackList", "isInBlackList=${configBean.isInBlackList}")
return
}
val from = activity::class.java.simpleName
if (adsConfigBean.adSwitch) {
if (isAdmobInit) {
adOpenMgr.show(activity, isUnLimit, AdmobEvent("openAd", from), showCallBack)
} else {
admobInitCallBack = {
}
adOpenMgr.show(activity, isUnLimit, AdmobEvent("openAd", from), showCallBack)
}
} else {
if (isMaxInit) {
maxOpenMgr.show(activity, isUnLimit, AdMaxEvent("openAd", from), showCallBack)
} else {
maxInitCallBack = {
maxOpenMgr.show(activity, isUnLimit, AdMaxEvent("openAd", from), showCallBack)
}
}
}
}
/**
* 展示插屏广告
*
* @param activity 当前页面
* @param showCallBack 展示回调
* @param isUnLimit 是否不受限制 默认false 代表受到限制
*/
fun showInsert(
activity: Activity,
isUnLimit: Boolean = false,
showCallBack: AdsShowCallBack? = null,
) {
if (configBean.isInBlackList) {
EventUtils.event("isInBlackList", configBean.isInBlackList.toString())
return
}
LogEx.logDebug("showAd", "adSwitch=${adsConfigBean.adSwitch}")
val from = activity::class.java.simpleName
if (adsConfigBean.adSwitch) {
adInsertMgr.show(activity, isUnLimit, AdmobEvent("interAd", from), showCallBack)
} else {
maxInsertMgr.show(activity, isUnLimit, AdMaxEvent("interAd", from), showCallBack)
}
}
/**
* 展示原生广告
*
* @param nativeView 需要展示广告的布局容器
* @param layout 原生广告布局 ,这里传入的layout要和com.example.mydemo.strategy.ads.admob.NativeView里的id一致
*/
fun showNative(
nativeView: NativeParentView,
@LayoutRes layout: Int,
nativeCallBack: ((Any?) -> Unit)? = null
) {
if (configBean.isInBlackList) {
EventUtils.event("isInBlackList", configBean.isInBlackList.toString())
return
}
if (!isAdmobInit) return
if (adsConfigBean.adSwitch) {
adNativeMgr.show(AdmobEvent("nativeAd", "nativeAd"), nativeView, layout, nativeCallBack)
} else {
maxNativeMgr.show(AdMaxEvent("nativeAd", "nativeAd"), nativeView, layout, nativeCallBack)
}
}
fun isNativeShow() = (isAdmobInit && !configBean.isInBlackList) && LimitUtils.isAdShow(AdsType.NATIVE, null)
/**
* 展示banner广告
*
* @param parent 展示广告的父布局容器
*/
fun showBanner(parent: ViewGroup, collapsible: Boolean = true, adClose: (() -> Unit)? = null) {
if (configBean.isInBlackList) {
EventUtils.event("isInBlackList", configBean.isInBlackList.toString())
return
}
if (adsConfigBean.adSwitch) {
adBannerMgr.show(parent, collapsible, adClose)
}
}
}
\ No newline at end of file
package com.base.scanqr.ads
abstract class AdsShowCallBack {
open fun show() {}
abstract fun close(where: Int = 0)
abstract fun failed(where: Int = 0)
abstract fun googleFailed(where: Int = 0)
}
\ No newline at end of file
package com.base.scanqr.ads
/**
* 广告类型
* 0=开屏广告、1=插屏广告、2=原生广告、3=Banner横幅广告
*/
@JvmInline
value class AdsType private constructor(val value: Int) {
companion object {
val OPEN = AdsType(0)
val INSERT = AdsType(1)
val NATIVE = AdsType(2)
val BANNER = AdsType(3)
fun from(adsType: Int): AdsType {
return when (adsType) {
OPEN.value -> OPEN
INSERT.value -> INSERT
NATIVE.value -> NATIVE
else -> BANNER
}
}
}
}
\ No newline at end of file
package com.base.scanqr.ads
import android.app.Activity
import android.app.Dialog
import android.content.Context
import java.lang.ref.WeakReference
class adState<T>() {
var adDialog: Dialog? = null
/**
* 当前缓存的广告
*/
var currentAd: T? = null
/**
* 是否正在缓存加载广告
*/
var loadingAd: Boolean = false
/**
* 是否正在显示广告
*/
var showingAd: Boolean = false
/**
* 用于保存引用现有页面,在此页面显示广告(因为要等待广告加载完毕)
*/
var activityRef: WeakReference<Activity>? = null
/**
* 上一次的缓存成功时间
*/
var lastLoadTime: Long = 0
/**
* 上次展示时间
*/
var lastShowTime: Long = 0
fun onAdDisplayed() {
showingAd = true
adDialog?.dismiss()
adDialog = null
lastShowTime = System.currentTimeMillis()
currentAd = null
activityRef = null
}
fun onAdHidden() {
// 广告关闭,清空缓存数据,重新加载
showingAd = false
}
fun onAdDisplayFailed() {
adDialog?.dismiss()
adDialog = null
showingAd = false
currentAd = null
activityRef = null
}
fun onAdLoaded(ad: T?) {
//这里可能提前设置,所有可以不设置,max回调的类型可能不同
if (ad != null) {
currentAd = ad
}
loadingAd = false
lastLoadTime = System.currentTimeMillis()
}
fun onAdLoadFailed() {
adDialog?.dismiss()
adDialog = null
loadingAd = false
}
}
/**
* 特定广告管理基类
* @param T 缓存广告的类
*/
abstract class BaseAdMgr<T> {
/**
* 广告展示回调
*/
protected var showCallBack: AdsShowCallBack? = null
/**
* 当前缓存的广告
*/
protected var currentAd: T? = null
/**
* 是否正在缓存加载广告
*/
protected var loadingAd: Boolean = false
/**
* 是否正在显示广告
*/
protected var showingAd: Boolean = false
/**
* 用于保存引用现有页面,在此页面显示广告(因为要等待广告加载完毕)
*/
protected var activityRef: WeakReference<Activity>? = null
/**
* 上一次的缓存成功时间
*/
protected var lastLoadTime: Long = 0
/**
* 预加载广告
*
* @param context 加载所用的上下文,一般使用appContext
*/
abstract fun loadAd(context: Context, isUnLimit: Boolean = true, adEvent: AdEvent)
/**
* 广告显示
*
* @param activity 当前页面
*/
abstract fun show(activity: Activity, isUnLimit: Boolean = true, adEvent: AdEvent, showCallBack: AdsShowCallBack? = null)
/**
* 预加载的缓存超时判断
*
* @return true:没有超时 false:超时需要重新加载
*/
abstract fun adAvailable(): Boolean
}
\ No newline at end of file
package com.base.scanqr.ads
import com.base.scanqr.utils.AppPreferences
import com.base.scanqr.utils.KotlinExt.toFormatTime4
/**
* 控制广告计数与判断显示条件
*
*/
object LimitUtils {
const val NUM_DISPLAY = "local_numDisplayLimit"
const val NUM_REQUEST = "local_numRequestLimit"
const val NUM_CLICK = "local_numClickLimit"
const val SAVE_DATE = "local_SAVE_DATE"
/**
* 保存的时间,用来判断是否是当天,不是当天要重置计数次数
*/
private var saveDate
get() = AppPreferences.getInstance()
.getString(SAVE_DATE, System.currentTimeMillis().toFormatTime4())
set(value) = AppPreferences.getInstance().put(SAVE_DATE, value)
/**
* 广告请求是否到达限制
*/
private inline val isRequestLimited: Boolean
get() {
val maxCount = AdsMgr.adsConfigBean.numRequestLimit
return maxCount > -1 && AppPreferences.getInstance()
.getInt(NUM_REQUEST, 0) >= maxCount
}
/**
* 广告展示是否到达限制
*/
private inline val isDisplayLimited: Boolean
get() {
val maxCount = AdsMgr.adsConfigBean.numDisplayLimit
return maxCount > -1 && AppPreferences.getInstance()
.getInt(NUM_DISPLAY, 0) >= maxCount
}
/**
* 广告点击是否到达限制
*/
private inline val isClickLimited: Boolean
get() {
val maxCount = AdsMgr.adsConfigBean.numClickLimit
return maxCount > -1 && AppPreferences.getInstance()
.getInt(NUM_CLICK, 0) >= maxCount
}
private fun getAdEventMsg(adsType: AdsType): String {
return when (adsType) {
AdsType.OPEN -> "Open"
AdsType.INSERT -> "Inter"
AdsType.NATIVE -> "Native"
else -> "Banner"
}
}
/**
* 是否显示广告
*
* @return true or false
*/
fun isAdShow(adsType: AdsType, adEvent: AdEvent?): Boolean {
val currentDate = System.currentTimeMillis().toFormatTime4()
if (saveDate != currentDate) {
//如果已经不是今天了,就重置个数
saveDate = currentDate
AppPreferences.getInstance().put(NUM_DISPLAY, 0)
AppPreferences.getInstance().put(NUM_REQUEST, 0)
AppPreferences.getInstance().put(NUM_CLICK, 0)
}
if (isDisplayLimited) {
val value = "current${getAdEventMsg(adsType)} " +
"show=${AppPreferences.getInstance().getInt(NUM_DISPLAY, 0)} " +
"${getAdEventMsg(adsType).lowercase()}_" + "max_show=${AdsMgr.adsConfigBean.numDisplayLimit}"
adEvent?.adLimited(value)
}
if (isClickLimited) {
val value =
"current${getAdEventMsg(adsType)}Click=${AppPreferences.getInstance().getInt(NUM_CLICK, 0)} "
"${getAdEventMsg(adsType).lowercase()}_max_click=${AdsMgr.adsConfigBean.numClickLimit}"
adEvent?.adLimited(value)
}
if (isRequestLimited) {
val value = "current${getAdEventMsg(adsType)}Request=${AppPreferences.getInstance().getInt(NUM_REQUEST, 0)} " +
"${getAdEventMsg(adsType).lowercase()}_max_request=${AdsMgr.adsConfigBean.numRequestLimit}"
adEvent?.adLimited(value)
}
return !(isDisplayLimited || isClickLimited || isRequestLimited)
}
private fun addNum(key: String) {
val currentDate = System.currentTimeMillis().toFormatTime4()
if (saveDate != currentDate) {
//如果已经不是今天了,就重置个数
saveDate = currentDate
AppPreferences.getInstance().put(key, 1)
return
}
AppPreferences.getInstance()
.put(key, (AppPreferences.getInstance().getInt(key, 0) + 1))
}
fun addDisplayNum() {
addNum(NUM_DISPLAY)
}
fun addRequestNum() {
addNum(NUM_REQUEST)
}
fun addClickNum() {
addNum(NUM_CLICK)
}
/**
* 开屏和插页广告的显示间隔限制
*
* @param lastTime 上一次显示的时间
*/
fun isIntervalLimited(lastTime: Long, adEvent: AdEvent): Boolean {
val flag = ((System.currentTimeMillis() - lastTime) / 1000).toInt() < (AdsMgr.adsConfigBean.timeInterval)
if (flag) {
adEvent.adShowError("ad in timeInterval")
}
return flag
}
}
\ No newline at end of file
package com.base.scanqr.ads
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.LayoutRes
import com.applovin.mediation.MaxAd
import com.applovin.mediation.nativeAds.MaxNativeAdLoader
import com.applovin.mediation.nativeAds.MaxNativeAdView
import com.applovin.mediation.nativeAds.MaxNativeAdViewBinder
import com.base.scanqr.R
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdView
@SuppressLint("ViewConstructor")
class NativeParentView(context: Context, attrs: AttributeSet? = null) :
FrameLayout(context, attrs) {
fun setNativeAd(
nativeAd: NativeAd,
@LayoutRes resource: Int? = null
) {
val layout = resource ?: R.layout.layout_admob_native_custom
val adView =
layout.let { LayoutInflater.from(context).inflate(it, null) } as NativeAdView
adView.mediaView = adView.findViewById(R.id.ad_media)
adView.headlineView = adView.findViewById(R.id.ad_headline)
adView.bodyView = adView.findViewById(R.id.ad_body)
adView.callToActionView = adView.findViewById(R.id.ad_call_to_action)
adView.iconView = adView.findViewById(R.id.ad_app_icon)
(adView.headlineView as TextView?)?.text = nativeAd.headline
adView.mediaView?.mediaContent = nativeAd.mediaContent
if (nativeAd.body == null) {
adView.bodyView?.visibility = View.INVISIBLE
} else {
adView.bodyView?.visibility = View.VISIBLE
(adView.bodyView as TextView?)?.text = nativeAd.body
}
if (nativeAd.callToAction == null) {
adView.callToActionView?.visibility = View.INVISIBLE
} else {
adView.callToActionView?.visibility = View.VISIBLE
(adView.callToActionView as Button?)?.text = nativeAd.callToAction
}
if (nativeAd.icon == null) {
adView.iconView?.visibility = View.GONE
} else {
(adView.iconView as ImageView?)?.setImageDrawable(
nativeAd.icon?.drawable
)
adView.iconView?.visibility = View.VISIBLE
}
adView.setNativeAd(nativeAd)
setBackgroundResource(0)
removeAllViews()
addView(adView)
}
fun setNativeAd(
nativeAdLoader: MaxNativeAdLoader,
nativeAd: MaxAd,
@LayoutRes resource: Int? = null
) {
val layout = resource ?: R.layout.layout_max_native_custom
val binder: MaxNativeAdViewBinder =
MaxNativeAdViewBinder.Builder(layout)
.setTitleTextViewId(R.id.title_text_view)
.setBodyTextViewId(R.id.body_text_view)
.setAdvertiserTextViewId(R.id.advertiser_text_view)
.setIconImageViewId(R.id.icon_image_view)
.setMediaContentViewGroupId(R.id.media_view_container)
.setOptionsContentViewGroupId(R.id.options_view)
.setStarRatingContentViewGroupId(R.id.star_rating_view)
.setCallToActionButtonId(R.id.cta_button)
.build()
val adView = MaxNativeAdView(binder, context)
nativeAdLoader.render(adView, nativeAd)
setBackgroundResource(0)
removeAllViews()
addView(adView)
}
}
package com.base.scanqr.ads.admob
import android.os.Bundle
import android.view.ViewGroup
import android.view.ViewTreeObserver
import com.base.scanqr.GlobalConfig
import com.base.scanqr.ads.AdsMgr
import com.base.scanqr.ads.AdsType
import com.base.scanqr.ads.LimitUtils
import com.google.ads.mediation.admob.AdMobAdapter
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.AdSize
import com.google.android.gms.ads.AdView
import com.google.android.gms.ads.LoadAdError
import java.util.UUID
/**
*banner广告加载显示管理类
*/
class AdBannerMgr {
private var adView: AdView? = null
private var listener: ViewTreeObserver.OnGlobalLayoutListener? = null
fun show(parent: ViewGroup, collapsible: Boolean, adClose: (() -> Unit)? = null) {
if (!AdsMgr.adsConfigBean.adSwitch) {
return
}
val admobEvent = AdmobEvent("banner", "banner")
if (!LimitUtils.isAdShow(AdsType.BANNER, admobEvent)) {
adView = null
return
}
parent.removeAllViews()
adView?.destroy()
adView = null
adView = AdView(parent.context)
parent.addView(adView)
adView?.onPaidEventListener = AdmobEvent.EventOnPaidEventListener(adView)
listener = ViewTreeObserver.OnGlobalLayoutListener {
val screenPixelDensity = parent.context.resources.displayMetrics.density
val adWidth = (parent.width / screenPixelDensity).toInt()
val adSize =
AdSize.getCurrentOrientationAnchoredAdaptiveBannerAdSize(parent.context, adWidth)
adView?.adUnitId = GlobalConfig.ID_ADMOB_BANNER
adView?.setAdSize(adSize)
loadAd(admobEvent, collapsible, adClose)
parent.viewTreeObserver.removeOnGlobalLayoutListener(listener)
}
parent.viewTreeObserver.addOnGlobalLayoutListener(listener)
}
fun loadAd(admobEvent: AdmobEvent, collapsible: Boolean, adClose: (() -> Unit)?) {
val build = AdRequest.Builder()
if (collapsible) {
val extras = Bundle()
extras.putString("collapsible", "bottom")
extras.putString("collapsible_request_id", UUID.randomUUID().toString())
build.addNetworkExtrasBundle(AdMobAdapter::class.java, extras)
}
val adRequest = build.build()
adView?.adListener =
object : AdListener() {
override fun onAdFailedToLoad(loadAdError: LoadAdError) {
super.onAdFailedToLoad(loadAdError)
admobEvent.pullAd(loadAdError.responseInfo, loadAdError)
}
override fun onAdLoaded() {
admobEvent.pullAd(adView?.responseInfo)
}
override fun onAdOpened() {
}
override fun onAdClosed() {
super.onAdClosed()
adClose?.invoke()
}
}
adView?.loadAd(adRequest)
}
}
\ No newline at end of file
package com.base.scanqr.ads.admob
import android.app.Activity
import android.content.Context
import com.base.scanqr.GlobalConfig
import com.base.scanqr.ads.AdDialog.showAdPreparingDialog
import com.base.scanqr.ads.AdEvent
import com.base.scanqr.ads.AdsShowCallBack
import com.base.scanqr.ads.AdsType
import com.base.scanqr.ads.LimitUtils
import com.base.scanqr.ads.adState
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.FullScreenContentCallback
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.interstitial.InterstitialAd
import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
import java.lang.ref.WeakReference
/**
*插屏广告加载显示管理类
*/
class AdInsertMgr {
private var adState = adState<InterstitialAd>()
private var showCallBack: AdsShowCallBack? = null
fun show(activity: Activity, isUnLimit: Boolean, adEvent: AdEvent, showCallBack: AdsShowCallBack?) {
if (activity.isFinishing || activity.isDestroyed) {
showCallBack?.failed(0)
return
}
if (adState.showingAd) {
showCallBack?.failed(1)
return
}
if (showCallBack != null) {
this.showCallBack = showCallBack
adState.activityRef = WeakReference(activity)
if (adState.adDialog == null) {
adState.adDialog = activity.showAdPreparingDialog(1)
}
adEvent.adPrepareShow()
}
if (!adState.loadingAd) {
if (!isUnLimit) {
if (!LimitUtils.isAdShow(AdsType.INSERT, adEvent)) {
showCallBack?.failed(2)
return
}
if (LimitUtils.isIntervalLimited(adState.lastShowTime, adEvent)) {
showCallBack?.failed(3)
return
}
}
if (adState.currentAd == null) {
loadAd(activity, isUnLimit, adEvent)
return
}
if (!adAvailable()) {
loadAd(activity, isUnLimit, adEvent)
return
}
showReadyAd(adEvent, activity)
}
}
private fun showReadyAd(adEvent: AdEvent, activity: Activity) {
adState.currentAd?.run {
fullScreenContentCallback = object : FullScreenContentCallback() {
override fun onAdShowedFullScreenContent() {
super.onAdShowedFullScreenContent()
adState.onAdDisplayed()
showCallBack?.show()
(adEvent as AdmobEvent).showAd(responseInfo, activity)
LimitUtils.addDisplayNum()
}
override fun onAdFailedToShowFullScreenContent(adError: AdError) {
super.onAdFailedToShowFullScreenContent(adError)
adState.onAdDisplayFailed()
showCallBack?.googleFailed()
showCallBack = null
adEvent.adShowError(adError)
}
override fun onAdDismissedFullScreenContent() {
super.onAdDismissedFullScreenContent()
adState.onAdHidden()
showCallBack?.close()
showCallBack = null
loadAd(activity.applicationContext, false, AdmobEvent("interAd", "preload"))
}
override fun onAdClicked() {
super.onAdClicked()
(adEvent as AdmobEvent).clickAd(responseInfo)
//计数
LimitUtils.addClickNum()
}
}
show(activity)
}
}
fun loadAd(context: Context, isUnLimit: Boolean, adEvent: AdEvent) {
if (!isUnLimit) {
if (!LimitUtils.isAdShow(AdsType.INSERT, adEvent)) {
this.showCallBack?.close(4)
this.showCallBack = null
return
}
}
if (!adState.loadingAd) {
adState.loadingAd = true
adEvent.adPulStart()
InterstitialAd.load(context, GlobalConfig.ID_ADMOB_INTER, AdRequest.Builder().build(),
object : InterstitialAdLoadCallback() {
override fun onAdLoaded(ad: InterstitialAd) {
adState.onAdLoaded(ad)
val ac = adState.activityRef?.get()
if (ac != null) {
show(ac, isUnLimit, adEvent, null)
}
(adEvent as AdmobEvent).pullAd(ad.responseInfo)
LimitUtils.addRequestNum()
ad.onPaidEventListener = AdmobEvent.EventOnPaidEventListener(ad)
}
override fun onAdFailedToLoad(loadAdError: LoadAdError) {
adState.onAdLoadFailed()
(adEvent as AdmobEvent).pullAd(loadAdError.responseInfo, loadAdError)
showCallBack?.googleFailed()
showCallBack = null
}
}
)
}
}
private fun adAvailable() = ((System.currentTimeMillis() - adState.lastLoadTime) / 1000 / 60).toInt() < 30
}
\ No newline at end of file
package com.base.scanqr.ads.admob
import com.base.scanqr.GlobalConfig
import com.base.scanqr.ads.AdsType
import com.base.scanqr.ads.LimitUtils
import com.base.scanqr.ads.NativeParentView
import com.google.android.gms.ads.AdListener
import com.google.android.gms.ads.AdLoader
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdOptions
import java.util.concurrent.ConcurrentLinkedDeque
/**
*原生广告加载显示管理类
*/
class AdNativeMgr {
/**
* 上一次的缓存成功时间
*/
protected var lastTime: Long = 0
/**
* 原生广告缓存队列
*/
private val cacheItems = ConcurrentLinkedDeque<NativeAd>()
private fun loadAd(
admobEvent: AdmobEvent,
parent: NativeParentView,
layout: Int
) {
admobEvent.adPulStart()
if (!LimitUtils.isAdShow(AdsType.NATIVE, admobEvent)) return
var currentNativeAd: NativeAd? = null
val adLoader = AdLoader.Builder(
parent.context,
GlobalConfig.ID_ADMOB_NATIVE
).forNativeAd { nativeAd ->
currentNativeAd = nativeAd
cacheItems.offer(nativeAd)
lastTime = System.currentTimeMillis()
nativeAd.setOnPaidEventListener(AdmobEvent.EventOnPaidEventListener(nativeAd))
admobEvent.pullAd(nativeAd.responseInfo)
show(admobEvent, parent, layout)
}.withAdListener(object : AdListener() {
override fun onAdFailedToLoad(error: LoadAdError) {
admobEvent.pullAd(error.responseInfo, error)
}
override fun onAdClicked() {
super.onAdClicked()
admobEvent.clickAd(currentNativeAd?.responseInfo)
}
override fun onAdClosed() {
super.onAdClosed()
}
}).withNativeAdOptions(
NativeAdOptions.Builder()
.build()
).build()
adLoader.loadAds(AdRequest.Builder().build(), 1)
}
fun show(
admobEvent: AdmobEvent,
parent: NativeParentView,
layout: Int,
nativeCallBack: ((Any?) -> Unit)? = null
) {
admobEvent.adPrepareShow()
if (!LimitUtils.isAdShow(AdsType.NATIVE, admobEvent)) {
cacheItems.clear()
return
}
val nativeAd = cacheItems.peek()
if (nativeAd == null || !adAvailable()) {
//缓存过期了就清空
cacheItems.clear()
loadAd(admobEvent, parent, layout)
return
}
nativeCallBack?.invoke(nativeAd)
parent.setNativeAd(nativeAd, layout)
admobEvent.showAd(nativeAd.responseInfo)
}
private fun adAvailable(): Boolean {
return ((System.currentTimeMillis() - lastTime) / 1000 / 60).toInt() < 30
}
}
\ No newline at end of file
package com.base.scanqr.ads.admob
import android.app.Activity
import android.content.Context
import com.base.scanqr.GlobalConfig
import com.base.scanqr.ads.AdEvent
import com.base.scanqr.ads.AdsShowCallBack
import com.base.scanqr.ads.AdsType
import com.base.scanqr.ads.LimitUtils
import com.base.scanqr.ads.adState
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.FullScreenContentCallback
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.appopen.AppOpenAd
import java.lang.ref.WeakReference
/**
* 开屏广告加载显示管理类
*/
class AdOpenMgr {
private val adState = adState<AppOpenAd>()
private var showCallBack: AdsShowCallBack? = null
fun show(activity: Activity, isUnLimit: Boolean, adEvent: AdEvent, showCallBack: AdsShowCallBack?) {
if (activity.isFinishing || activity.isDestroyed) {
return
}
if (adState.showingAd) {
showCallBack?.failed()
adEvent.adShowError("showingAd")
return
}
if (showCallBack != null) {
this.showCallBack = showCallBack
adState.activityRef = WeakReference(activity)
adEvent.adPrepareShow()
}
if (!adState.loadingAd) {
if (!isUnLimit) {
if (!LimitUtils.isAdShow(AdsType.OPEN, adEvent)) {
showCallBack?.failed()
return
}
if (LimitUtils.isIntervalLimited(adState.lastShowTime, adEvent)) {
showCallBack?.failed()
return
}
}
if (!adAvailable() || adState.currentAd == null) {
loadAd(activity, isUnLimit, adEvent)
return
}
showReadyAd(adEvent, activity)
}
}
private fun showReadyAd(adEvent: AdEvent, activity: Activity) {
adState.currentAd?.run {
fullScreenContentCallback = object : FullScreenContentCallback() {
override fun onAdShowedFullScreenContent() {
showCallBack?.show()
(adEvent as AdmobEvent).showAd(this@run.responseInfo, activity)
adState.onAdDisplayed()
//计数
LimitUtils.addDisplayNum()
}
override fun onAdFailedToShowFullScreenContent(adError: AdError) {
super.onAdFailedToShowFullScreenContent(adError)
showCallBack?.googleFailed()
showCallBack = null
adState.onAdDisplayed()
(adEvent as AdmobEvent).adShowError(adError)
}
override fun onAdDismissedFullScreenContent() {
super.onAdDismissedFullScreenContent()
showCallBack?.close()
showCallBack = null
adState.onAdHidden()
loadAd(activity.applicationContext, false, AdmobEvent("openAd", "preload"))
}
override fun onAdClicked() {
(adEvent as AdmobEvent).clickAd(this@run.responseInfo)
//计数
LimitUtils.addClickNum()
}
}
show(activity)
}
}
fun loadAd(context: Context, isUnLimit: Boolean, adEvent: AdEvent) {
if (!isUnLimit) {
if (!LimitUtils.isAdShow(AdsType.OPEN, adEvent)) {
this.showCallBack?.close()
this.showCallBack = null
return
}
}
if (!adState.loadingAd) {
adState.loadingAd = true
adEvent.adPulStart()
AppOpenAd.load(
context,
GlobalConfig.ID_ADMOB_OPEN,
AdRequest.Builder().build(),
object : AppOpenAd.AppOpenAdLoadCallback() {
override fun onAdLoaded(appOpenAd: AppOpenAd) {
adState.onAdLoaded(appOpenAd)
val ac = adState.activityRef?.get()
if (ac != null) {
show(ac, isUnLimit, adEvent, null)
}
(adEvent as AdmobEvent).pullAd(appOpenAd.responseInfo)
appOpenAd.onPaidEventListener = AdmobEvent.EventOnPaidEventListener(appOpenAd)
LimitUtils.addRequestNum()
}
override fun onAdFailedToLoad(loadAdError: LoadAdError) {
showCallBack?.googleFailed()
showCallBack = null
adState.onAdLoadFailed()
(adEvent as AdmobEvent).pullAd(loadAdError.responseInfo, loadAdError)
}
}
)
}
}
private fun adAvailable() = ((System.currentTimeMillis() - adState.lastLoadTime) / 1000 / 60).toInt() < 30
}
\ No newline at end of file
This diff is collapsed.
package com.base.scanqr.ads.applovin
import android.os.Bundle
import com.applovin.mediation.MaxAd
import com.applovin.mediation.MaxAdRevenueListener
import com.applovin.mediation.MaxError
import com.applovin.sdk.AppLovinSdk
import com.base.scanqr.MyApplication
import com.base.scanqr.ads.AdEvent
import com.base.scanqr.ads.taichiPref
import com.base.scanqr.ads.taichiSharedPreferencesEditor
import com.base.scanqr.helper.EventUtils
import com.base.scanqr.utils.LogEx.logDebug
import com.facebook.appevents.AppEventsConstants
import com.facebook.appevents.AppEventsLogger
import com.google.firebase.analytics.FirebaseAnalytics
import org.json.JSONObject
class AdMaxEvent : AdEvent {
override val TAG: String = "AdMaxEvent"
constructor(adUnit: String, from: String) : super() {
this.adUnit = adUnit
this.from = from
}
fun pullAd(
ad: MaxAd?,
error: MaxError? = null
) {
val obj = JSONObject()
obj.put("UnitId", ad?.adUnitId)
obj.put("ad_unit", adUnit)
obj.put(
"creativeId",
ad?.creativeId
)
obj.put("req_id", reqId)
obj.put("from", from)
obj.put("status", if (ad == null) "0" else "1")
obj.put("networkname", ad?.networkName)
obj.put("placement", ad?.placement)
obj.put("networkplacement", ad?.networkPlacement)
obj.put("latency", ad?.requestLatencyMillis)
obj.put("valueMicros", ad?.revenue)
if (error == null) {
obj.put("status", "1")
} else {
obj.put("errMsg", error)
obj.put("status", "2")
}
EventUtils.event("ad_pull", ext = obj)
logDebug(TAG, "ad_pull $obj")
}
fun clickAd(ad: MaxAd?) {
val obj = JSONObject()
obj.put("UnitId", ad?.adUnitId)
obj.put("ad_unit", adUnit)
obj.put(
"creativeId",
ad?.creativeId
)
obj.put("networkname", ad?.networkName)
obj.put("placement", ad?.placement)
obj.put("networkplacement", ad?.networkPlacement)
obj.put("latency", ad?.requestLatencyMillis)
obj.put("valueMicros", ad?.revenue)
if (!adUnit.equals("nativeAd")) {
EventUtils.event("ad_click", ext = obj)
} else {
EventUtils.event("ad_click", ext = obj)
}
}
fun showAd(ad: MaxAd?, activity: String?) {
val obj = JSONObject()
obj.put("UnitId", ad?.adUnitId)
obj.put("ad_unit", adUnit)
obj.put(
"creativeId",
ad?.creativeId
)
obj.put("networkname", ad?.networkName)
obj.put("placement", ad?.placement)
obj.put("networkplacement", ad?.networkPlacement)
obj.put("latency", ad?.requestLatencyMillis)
obj.put("valueMicros", ad?.revenue)
obj.put("from", activity)
obj.put("mediation", "applovin")
if (adUnit != "nativeAd") {
EventUtils.event("ad_show", ext = obj)
} else {
EventUtils.event("ad_show", ext = obj)
}
}
class EventOnPaidEventListener : MaxAdRevenueListener {
override fun onAdRevenuePaid(ad: MaxAd) {
val params = Bundle()
val currentImpressionRevenue: Double = ad.revenue // In USD
val mFirebaseAnalytics = FirebaseAnalytics.getInstance(MyApplication.appContext)
params.putString(FirebaseAnalytics.Param.AD_PLATFORM, "appLovin")
params.putString(FirebaseAnalytics.Param.AD_SOURCE, ad.networkName)
params.putString(FirebaseAnalytics.Param.AD_FORMAT, ad.format.getDisplayName())
params.putString(FirebaseAnalytics.Param.AD_UNIT_NAME, ad.adUnitId)
params.putDouble(FirebaseAnalytics.Param.VALUE, currentImpressionRevenue)
params.putString(FirebaseAnalytics.Param.CURRENCY, "USD")
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.AD_IMPRESSION, params)
mFirebaseAnalytics.logEvent("Ad_Impression_Revenue", params)
val previousTaichiTroasCache = taichiPref.getFloat("TaichiTroasCache", 0f)
val currentTaichiTroasCache = previousTaichiTroasCache + currentImpressionRevenue
if (currentTaichiTroasCache >= 0.01) {
val roasbundle = Bundle()
roasbundle.putDouble(FirebaseAnalytics.Param.VALUE, currentTaichiTroasCache)
roasbundle.putString(FirebaseAnalytics.Param.CURRENCY, "USD")///(Required)tROAS事件必须
mFirebaseAnalytics.logEvent("Total_Ads_Revenue_001", roasbundle) // 给Taichi用
taichiSharedPreferencesEditor.putFloat("TaichiTroasCache", 0f)//重新清零,开始计算
val logger = AppEventsLogger.newLogger(MyApplication.appContext)
val parameters = Bundle()
parameters.putString(AppEventsConstants.EVENT_PARAM_CURRENCY, "USD")
logger.logEvent("ad_value", currentTaichiTroasCache, parameters)
} else {
taichiSharedPreferencesEditor.putFloat(
"TaichiTroasCache",
currentTaichiTroasCache.toFloat()
)
taichiSharedPreferencesEditor.commit()
}
val obj = JSONObject()
val revenue = ad.revenue
val countryCode =
AppLovinSdk.getInstance(MyApplication.appContext).configuration.countryCode
val networkName = ad.networkName
val adUnitId = ad.adUnitId
val adFormat = ad.format
val placement = ad.placement
val networkPlacement = ad.networkPlacement
obj.put("valueMicros", revenue)
obj.put("currencyCode", countryCode)
obj.put("adUnitId", adUnitId)
obj.put("networkName", networkName)
obj.put("adFormat", adFormat)
obj.put("placement", placement)
obj.put("networkPlacement", networkPlacement)
EventUtils.event("ad_price", ext = obj)
}
}
}
\ No newline at end of file
package com.base.scanqr.ads.applovin
import android.app.Activity
import android.content.Context
import com.applovin.mediation.MaxAd
import com.applovin.mediation.MaxAdListener
import com.applovin.mediation.MaxError
import com.applovin.mediation.ads.MaxInterstitialAd
import com.base.scanqr.GlobalConfig
import com.base.scanqr.ads.AdDialog.showAdPreparingDialog
import com.base.scanqr.ads.AdEvent
import com.base.scanqr.ads.AdsShowCallBack
import com.base.scanqr.ads.AdsType
import com.base.scanqr.ads.LimitUtils
import com.base.scanqr.ads.adState
import java.lang.ref.WeakReference
/**
*插屏广告加载显示管理类
*/
class MaxInsertMgr {
private var adState = adState<MaxInterstitialAd>()
private var showCallBack: AdsShowCallBack? = null
fun show(
activity: Activity,
isUnLimit: Boolean,
adEvent: AdEvent,
showCallBack: AdsShowCallBack?
) {
if (activity.isFinishing || activity.isDestroyed) {
showCallBack?.failed(1)
return
}
if (adState.showingAd) {
showCallBack?.failed(2)
return
}
if (showCallBack != null) {
adState.activityRef = WeakReference(activity)
this.showCallBack = showCallBack
if (adState.adDialog == null) {
adState.adDialog = activity.showAdPreparingDialog(2)
}
adEvent.adPrepareShow()
}
if (!adState.loadingAd) {
if (!isUnLimit) {
if (!LimitUtils.isAdShow(AdsType.INSERT, adEvent)) {
showCallBack?.failed(3)
return
}
if (LimitUtils.isIntervalLimited(adState.lastShowTime, adEvent)) {
showCallBack?.failed(4)
return
}
}
if (!adAvailable() || adState.currentAd == null) {
loadAd(activity, isUnLimit, adEvent)
return
}
if (adState.currentAd?.isReady == false) {
loadAd(activity, isUnLimit, adEvent)
return
}
showReadyAd(adEvent)
}
}
private fun showReadyAd(adEvent: AdEvent) {
adState.currentAd?.run {
setListener(object : MaxAdListener {
override fun onAdLoaded(p0: MaxAd) = Unit
override fun onAdLoadFailed(p0: String, p1: MaxError) = Unit
override fun onAdDisplayed(ad: MaxAd) {
adState.onAdDisplayed()
showCallBack?.show()
(adEvent as AdMaxEvent).showAd(ad, activity::class.simpleName)
//计数
LimitUtils.addDisplayNum()
}
override fun onAdDisplayFailed(ad: MaxAd, error: MaxError) {
adState.onAdDisplayFailed()
showCallBack?.googleFailed()
showCallBack = null
(adEvent as AdMaxEvent).adShowError(error)
}
override fun onAdHidden(p0: MaxAd) {
adState.onAdHidden()
showCallBack?.close()
loadAd(activity.applicationContext, false, AdMaxEvent("interAd", "preload"))
}
override fun onAdClicked(ad: MaxAd) {
(adEvent as AdMaxEvent).clickAd(ad)
//计数
LimitUtils.addClickNum()
}
})
setRevenueListener(AdMaxEvent.EventOnPaidEventListener())
showAd(activity)
}
}
fun loadAd(
context: Context,
isUnLimit: Boolean,
adEvent: AdEvent,
) {
if (!isUnLimit) {
if (!LimitUtils.isAdShow(AdsType.INSERT, adEvent)) {
this.showCallBack?.close(4)
this.showCallBack = null
return
}
}
if (!adState.loadingAd) {
adState.loadingAd = true
adEvent.adPulStart()
adState.currentAd = MaxInterstitialAd(GlobalConfig.ID_MAX_INTER, context)
adState.currentAd?.setListener(object : MaxAdListener {
override fun onAdDisplayed(p0: MaxAd) = Unit
override fun onAdHidden(p0: MaxAd) = Unit
override fun onAdClicked(p0: MaxAd) = Unit
override fun onAdDisplayFailed(p0: MaxAd, p1: MaxError) = Unit
override fun onAdLoaded(ad: MaxAd) {
adState.onAdLoaded(null)
val ac = adState.activityRef?.get()
if (ac != null) {
show(ac, isUnLimit, adEvent, null)
}
(adEvent as AdMaxEvent).pullAd(ad)
LimitUtils.addRequestNum()
}
override fun onAdLoadFailed(ad: String, error: MaxError) {
adState.onAdLoadFailed()
(adEvent as AdMaxEvent).pullAd(null, error)
showCallBack?.googleFailed(5)
showCallBack = null
}
})
adState.currentAd?.loadAd()
}
}
private fun adAvailable() = ((System.currentTimeMillis() - adState.lastLoadTime) / 1000 / 60).toInt() < 30
}
\ No newline at end of file
package com.base.scanqr.ads.applovin
import androidx.annotation.LayoutRes
import com.applovin.mediation.MaxAd
import com.applovin.mediation.MaxError
import com.applovin.mediation.nativeAds.MaxNativeAdListener
import com.applovin.mediation.nativeAds.MaxNativeAdLoader
import com.applovin.mediation.nativeAds.MaxNativeAdView
import com.base.scanqr.GlobalConfig
import com.base.scanqr.ads.AdsType
import com.base.scanqr.ads.LimitUtils
import com.base.scanqr.ads.NativeParentView
import com.base.scanqr.helper.EventUtils
import org.json.JSONObject
import java.util.UUID
/**
*原生广告加载显示管理类
*/
class MaxNativeMgr {
/**
* 上一次的缓存成功时间
*/
protected var lastTime: Long = 0
/**
* 原生广告
*/
private var currentAd: MaxAd? = null
private var currentLoader: MaxNativeAdLoader? = null
private fun loadAd(
adMaxEvent: AdMaxEvent,
parent: NativeParentView,
@LayoutRes layout: Int
) {
if (!LimitUtils.isAdShow(AdsType.NATIVE, adMaxEvent)) return
val reqId = UUID.randomUUID().toString()
val obj = JSONObject()
obj.put("req_id", reqId)
obj.put("ad_type", "nativeAd")
val nativeAdLoader = MaxNativeAdLoader(GlobalConfig.ID_MAX_NATIVE, parent.context)
nativeAdLoader.setNativeAdListener(object : MaxNativeAdListener() {
override fun onNativeAdLoaded(nativeAdView: MaxNativeAdView?, ad: MaxAd) {
currentLoader = nativeAdLoader
currentAd = ad
lastTime = System.currentTimeMillis()
adMaxEvent.pullAd(ad)
nativeAdLoader.setRevenueListener(AdMaxEvent.EventOnPaidEventListener())
show(adMaxEvent, parent, layout)
}
override fun onNativeAdLoadFailed(adUnitId: String, error: MaxError) {
adMaxEvent.pullAd(null, error)
}
override fun onNativeAdClicked(ad: MaxAd) {
}
})
nativeAdLoader.loadAd()
}
fun show(
adMaxEvent: AdMaxEvent,
parent: NativeParentView,
@LayoutRes layout: Int,
nativeCallBack: ((Any?) -> Unit)? = null
) {
if (!LimitUtils.isAdShow(AdsType.NATIVE, adMaxEvent)) {
currentLoader = null
currentAd = null
return
}
val nativeAd = currentAd
val nativeLoader = currentLoader
if ((nativeAd == null || nativeLoader == null).also {
if (it) {
val obj2 = JSONObject()
obj2.put("reason", "no_ad")
obj2.put("ad_unit", "nativeAd")
EventUtils.event("ad_show_error", ext = obj2)
}
} || (!adAvailable()).also {
if (it) {
val obj2 = JSONObject()
obj2.put("ad_unit", "nativeAd")
EventUtils.event("ad_expire", ext = obj2)
}
}) {
//缓存过期了就清空
currentLoader = null
currentAd = null
loadAd(AdMaxEvent("nativeAd", "preload"), parent, layout)
return
}
val obj = JSONObject()
obj.put("ad_unit", "nativeAd")
EventUtils.event("ad_prepare_show", ext = obj)
parent.setNativeAd(nativeLoader!!, nativeAd!!, layout)
nativeCallBack?.invoke(nativeAd)
}
private fun adAvailable(): Boolean {
return ((System.currentTimeMillis() - lastTime) / 1000 / 60).toInt() < 30
}
}
\ No newline at end of file
package com.base.scanqr.ads.applovin
import android.app.Activity
import android.content.Context
import com.applovin.mediation.MaxAd
import com.applovin.mediation.MaxAdListener
import com.applovin.mediation.MaxError
import com.applovin.mediation.ads.MaxAppOpenAd
import com.base.scanqr.GlobalConfig
import com.base.scanqr.ads.AdEvent
import com.base.scanqr.ads.AdsShowCallBack
import com.base.scanqr.ads.AdsType
import com.base.scanqr.ads.LimitUtils
import com.base.scanqr.ads.adState
import java.lang.ref.WeakReference
/**
* 开屏广告加载显示管理类
*/
class MaxOpenMgr {
private val adState = adState<MaxAppOpenAd>()
private var showCallBack: AdsShowCallBack? = null
fun show(activity: Activity, isUnLimit: Boolean, adEvent: AdEvent, showCallBack: AdsShowCallBack?) {
if (activity.isFinishing || activity.isDestroyed) {
return
}
if (adState.showingAd) {
showCallBack?.failed()
adEvent.adShowError("showingAd")
return
}
if (showCallBack != null) {
this.showCallBack = showCallBack
adState.activityRef = WeakReference(activity)
adEvent.adPrepareShow()
}
if (!adState.loadingAd) {
if (!isUnLimit) {
if (!LimitUtils.isAdShow(AdsType.OPEN, adEvent)) {
showCallBack?.failed()
return
}
if (LimitUtils.isIntervalLimited(adState.lastShowTime, adEvent)) {
showCallBack?.failed()
return
}
}
if (!adAvailable() || adState.currentAd == null) {
loadAd(activity, isUnLimit, adEvent)
return
}
if (adState.currentAd?.isReady != true) {
loadAd(activity, isUnLimit, adEvent)
return
}
showReadyAd(activity, adEvent)
}
}
private fun showReadyAd(activity: Activity, adEvent: AdEvent) {
adState.currentAd?.run {
setListener(object : MaxAdListener {
override fun onAdLoaded(p0: MaxAd) {
}
override fun onAdDisplayed(ad: MaxAd) {
adState.onAdDisplayed()
showCallBack?.show()
LimitUtils.addDisplayNum()
(adEvent as AdMaxEvent).showAd(ad, activity::class.simpleName)
}
override fun onAdHidden(p0: MaxAd) {
adState.onAdHidden()
showCallBack?.close()
showCallBack = null
loadAd(activity.applicationContext, false, AdMaxEvent("openAd", "preload"))
}
override fun onAdClicked(ad: MaxAd) {
(adEvent as AdMaxEvent).clickAd(ad)
//计数
LimitUtils.addClickNum()
}
override fun onAdLoadFailed(p0: String, p1: MaxError) {
}
override fun onAdDisplayFailed(p0: MaxAd, error: MaxError) {
adState.onAdDisplayFailed()
showCallBack?.googleFailed()
showCallBack = null
adEvent.adShowError(error)
}
})
showAd()
}
}
fun loadAd(context: Context, isUnLimit: Boolean, adEvent: AdEvent) {
if (!isUnLimit) {
if (!LimitUtils.isAdShow(AdsType.OPEN, adEvent)) {
this.showCallBack?.close()
this.showCallBack = null
return
}
}
if (!adState.loadingAd) {
adState.loadingAd = true
adEvent.adPulStart()
adState.currentAd = MaxAppOpenAd(GlobalConfig.ID_MAX_OPEN, context)
adState.currentAd?.setListener(object : MaxAdListener {
override fun onAdLoaded(ad: MaxAd) {
adState.onAdLoaded(null)
val ac = adState.activityRef?.get()
if (ac != null) {
show(ac, isUnLimit, adEvent, null)
}
(adEvent as AdMaxEvent).pullAd(ad)
LimitUtils.addRequestNum()
}
override fun onAdDisplayed(p0: MaxAd) {
}
override fun onAdHidden(p0: MaxAd) {
}
override fun onAdClicked(p0: MaxAd) {
}
override fun onAdLoadFailed(p0: String, error: MaxError) {
adState.onAdLoadFailed()
showCallBack?.googleFailed()
showCallBack = null
(adEvent as AdMaxEvent).pullAd(null, error)
}
override fun onAdDisplayFailed(p0: MaxAd, p1: MaxError) {
}
})
adState.currentAd?.loadAd()
}
}
fun adAvailable() = ((System.currentTimeMillis() - adState.lastLoadTime) / 1000 / 60).toInt() < 30
}
\ No newline at end of file
...@@ -4,6 +4,15 @@ import com.base.scanqr.utils.AppPreferences ...@@ -4,6 +4,15 @@ import com.base.scanqr.utils.AppPreferences
import java.util.Locale import java.util.Locale
object ConstObject { object ConstObject {
var mainStartTimes = 0
get() {
return AppPreferences.getInstance().getInt("mainStartTimes", field)
}
set(value) {
field = value
AppPreferences.getInstance().put("mainStartTimes", value, true)
}
var ifAgreePrivacy = true var ifAgreePrivacy = true
get() { get() {
......
package com.base.scanqr.bean.config
class AdConfigBean(
var adSwitch: Boolean = true,//true 走admob,false走max
var numDisplayLimit: Int = -1,
var numRequestLimit: Int = -1,
var numClickLimit: Int = -1,
var timeInterval: Int = 1,
var openAdLoading: Int = 15,
var functionBackShowAd: Boolean = true,
var functionInShowAd: Boolean = true,
)
\ No newline at end of file
package com.base.appzxhy.bean.config
import com.base.scanqr.bean.config.AdConfigBean
import com.base.scanqr.bean.config.PopupConfigBean
/**
* 后台配置
*/
data class ConfigBean(
var isInBlackList: Boolean = false,
val ut: Int = 0,
val adConfigBean: AdConfigBean = AdConfigBean(),
val popupConfigBean: PopupConfigBean = PopupConfigBean(),
) {
companion object {
var configBean: ConfigBean = ConfigBean()
}
}
\ No newline at end of file
package com.base.scanqr.bean.config
class PopupConfigBean(
var popupStatus: Boolean = true,
var popupCount: Int = 24,
var popupStart: Int = 0,
var popupEnd: Int = 24,
var popupInterval: Int = 1,
var popupTimerInterval: Int = 1,
var popupFcmInterval: Int = 1,
var popupHoverStatus: Boolean = true,
var popupHoverCount: Int = 5,
var popupHoverDelay: Int = 5000,
//定时器
var timerS: Boolean = true,
var timerDelay: Int = 1,
var timerInterval: Int = 1,
//解锁
var screenS: Boolean = true,
var popupScreenCount: Int = 20,
var popupScreenInterval: Int = 1,
//电量
var batteryS: Boolean = true,
var popupBatteryValue: Int = 20,
var popupBatteryInterval: Int = 1,
//安装卸载
var packageS: Boolean = true,
var popupPackageCount: Int = 20,
var popupPackageInterval: Int = 1
)
\ No newline at end of file
package com.base.scanqr.fcm
import android.content.Context
import android.util.Log
import com.base.scanqr.helper.EventUtils.event
import com.base.scanqr.utils.AppPreferences
import com.base.scanqr.utils.LogEx
import com.google.android.gms.tasks.OnCompleteListener
import com.google.android.gms.tasks.Task
import com.google.firebase.FirebaseApp
import com.google.firebase.messaging.FirebaseMessaging
import org.json.JSONObject
object FCMManager {
fun initFirebase(context: Context?) {
FirebaseApp.initializeApp(context!!)
LogEx.logDebug("initFirebase", "initFirebase")
getToken()
}
fun subscribeToTopic(topic: String) {
Log.e("FCMUtil", "subscribeToTopic")
FirebaseMessaging.getInstance().subscribeToTopic(topic)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
getToken()
Log.e("FCMUtil", "isSuccessful")
event("FCM_Topic_$topic", null, null)
} else {
event("FCM_Error", "subscribeToTopic task.isSuccessful=${task.isSuccessful} ", null)
}
}
}
fun unsubscribeFromTopic(topic: String?) {
FirebaseMessaging.getInstance().unsubscribeFromTopic(topic!!)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
} else {
}
}
}
/**
* 有vpn有google商店才能获取
*/
private fun getToken() {
FirebaseMessaging.getInstance().token
.addOnCompleteListener(object : OnCompleteListener<String> {
override fun onComplete(task: Task<String>) {
LogEx.logDebug("FCM", "onComplete ${task.isSuccessful}")
if (!task.isSuccessful) {
Log.e("FCM", "Fetching FCM registration token failed", task.exception)
return
}
// Get new FCM registration token
val token: String = task.result
LogEx.logDebug("FCM", "token=$token")
val json = JSONObject()
json.put("token", token)
event("fcm_message_received", ext = json)
AppPreferences.getInstance().put("token", token)
// Handle new token
LogEx.logDebug("FCM", "FCM Registration Token: $token")
}
})
}
}
package com.base.scanqr.helper
object AppConfig {
const val privacyPolicy: String = ""
const val termService: String = ""
// 正式包名
const val packageName = "com.loactation.alibabab.ccccaa"
// 域名
const val eventUrl = "https://rp.gamexzonerk.xyz"
const val apiUrl = "https://api.gamexzonerk.xyz"
val noLoadingActivities = listOf(
"full", // 过滤全屏广告
"adActivity",
"AdActivity",
"AppLovinFullscreenActivity",
// SplashActivity::class.java.simpleName,
// 返回前台时不跳转启动页的 activity
)
}
\ No newline at end of file
...@@ -2,6 +2,7 @@ package com.base.scanqr.helper ...@@ -2,6 +2,7 @@ package com.base.scanqr.helper
import android.os.Build import android.os.Build
import com.base.scanqr.BuildConfig import com.base.scanqr.BuildConfig
import com.base.scanqr.GlobalConfig
import com.base.scanqr.helper.ReportUtils.doPost import com.base.scanqr.helper.ReportUtils.doPost
import com.base.scanqr.utils.AppPreferences import com.base.scanqr.utils.AppPreferences
import com.base.scanqr.utils.LogEx import com.base.scanqr.utils.LogEx
...@@ -34,7 +35,7 @@ object EventUtils { ...@@ -34,7 +35,7 @@ object EventUtils {
Thread { Thread {
var paramJson: String? = "" var paramJson: String? = ""
try { try {
val pkg = AppConfig.packageName val pkg = GlobalConfig.PACKAGE_NAME
val s = JSONObject() val s = JSONObject()
.put("action", key) .put("action", key)
.put("value", value) .put("value", value)
...@@ -72,9 +73,9 @@ object EventUtils { ...@@ -72,9 +73,9 @@ object EventUtils {
} }
private val url by lazy { private val url by lazy {
val pkg = AppConfig.packageName val pkg = GlobalConfig.PACKAGE_NAME
val url = StringBuilder( val url = StringBuilder(
"${AppConfig.eventUrl}/${ "${GlobalConfig.URL_EVENT}/${
pkg.filter { it.isLowerCase() }.substring(4, 9) pkg.filter { it.isLowerCase() }.substring(4, 9)
}sp" }sp"
) )
......
...@@ -11,7 +11,6 @@ import androidx.camera.lifecycle.ProcessCameraProvider ...@@ -11,7 +11,6 @@ import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import com.base.scanqr.utils.LogEx
import java.util.concurrent.ExecutorService import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors import java.util.concurrent.Executors
import kotlin.math.abs import kotlin.math.abs
......
...@@ -12,10 +12,13 @@ import com.base.scanqr.bean.HomeTabUIBean ...@@ -12,10 +12,13 @@ import com.base.scanqr.bean.HomeTabUIBean
import com.base.scanqr.databinding.ActivityMainBinding import com.base.scanqr.databinding.ActivityMainBinding
import com.base.scanqr.databinding.ItemHomeTabBinding import com.base.scanqr.databinding.ItemHomeTabBinding
import com.base.scanqr.qr.CameraUtils import com.base.scanqr.qr.CameraUtils
import com.base.scanqr.ui.widget.NotificationDialog.showNotificationTurnOn
import com.base.scanqr.utils.LogEx import com.base.scanqr.utils.LogEx
import com.base.scanqr.utils.PermissionUtils.areNotificationsEnabled
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.gyf.immersionbar.ktx.immersionBar import com.gyf.immersionbar.ktx.immersionBar
import java.util.concurrent.atomic.AtomicBoolean
class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::inflate) { class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::inflate) {
...@@ -32,9 +35,20 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl ...@@ -32,9 +35,20 @@ class MainActivity : BaseActivity<ActivityMainBinding>(ActivityMainBinding::infl
) )
} }
private var bannerShowed = AtomicBoolean(false)
override fun onResumeOneShoot() { override fun onResumeOneShoot() {
super.onResumeOneShoot() super.onResumeOneShoot()
changeLanguage() val flag = changeLanguage()
if (flag) return
if (!bannerShowed.get()) {
bannerShowed.set(true)
} else {
if (!areNotificationsEnabled()) {
showNotificationTurnOn(launcher)
}
}
} }
override fun initView() { override fun initView() {
......
package com.base.scanqr.ui.widget
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.content.Context
import android.content.Intent
import android.os.Build
import android.provider.Settings
import android.view.Gravity
import android.view.LayoutInflater
import com.base.scanqr.R
import com.base.scanqr.databinding.DialogNotificationTurnOnBinding
import com.base.scanqr.utils.ActivityLauncher
object NotificationDialog {
@SuppressLint("SetTextI18n")
fun Context.showNotificationTurnOn(launcher: ActivityLauncher) {
val dialog = AlertDialog.Builder(this).create()
val binding = DialogNotificationTurnOnBinding.inflate(LayoutInflater.from(this))
dialog.setView(binding.root)
dialog.setCanceledOnTouchOutside(true)
dialog.show()
val params = dialog.window?.attributes
// params?.width = resources.getDimensionPixelOffset(R.dimen.dp_320)
// params?.height = LinearLayout.LayoutParams.WRAP_CONTENT
params?.gravity = Gravity.BOTTOM
// params?.y = 50
dialog.window?.attributes = params
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
val appName = resources.getString(R.string.app_name)
binding.tvTip.text = "Never miss important $appName notification reminders"
binding.ivClose.setOnClickListener {
dialog.dismiss()
}
binding.tvTurnOn.setOnClickListener {
dialog.dismiss()
val intent = Intent()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
intent.putExtra(Settings.EXTRA_APP_PACKAGE, this.packageName)
} else {
intent.action = "android.settings.APP_NOTIFICATION_SETTINGS"
intent.putExtra("app_package", this.packageName)
}
launcher.launch(intent)
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#6379E6" />
<corners android:radius="35dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#ff8a00" />
<corners android:radius="10dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView 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="180dp"
android:layout_height="136dp"
android:layout_margin="5dp"
app:cardCornerRadius="25dp"
app:cardElevation="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="23dp"
android:src="@mipmap/jiazai_ad"
tools:ignore="ContentDescription" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="18dp"
android:layout_marginBottom="22dp"
android:includeFontPadding="false"
android:text="@string/preparing_advertisement"
android:textColor="@color/black"
android:textSize="13sp"
tools:ignore="HardcodedText" />
</LinearLayout>
</androidx.cardview.widget.CardView>
\ No newline at end of file
<?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">
<ImageView
android:layout_width="match_parent"
android:layout_height="342dp"
android:background="@mipmap/img_tongzhi_pop_bj"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/iv_close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="25dp"
android:src="@mipmap/icon_close"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:ignore="ContentDescription" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="8dp"
android:text="@string/turn_on_notification"
android:textColor="#1A1A1A"
android:textSize="22sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginHorizontal="40dp"
android:layout_marginBottom="20dp"
android:gravity="center"
android:textColor="#666666"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_turn_on"
android:layout_width="259dp"
android:layout_height="48dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="40dp"
android:background="@drawable/bg_6379e6_35"
android:gravity="center"
android:text="@string/turn_on"
android:textColor="@color/white"
android:textSize="20sp" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<com.google.android.gms.ads.nativead.NativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="#f2f2f2"
android:baselineAligned="false">
<com.google.android.gms.ads.nativead.MediaView
android:id="@+id/ad_media"
android:layout_width="91dp"
android:layout_height="91dp"
android:layout_gravity="center_vertical"
android:layout_marginStart="5dp" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginHorizontal="8dp"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/ad_headline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/black"
android:textSize="14sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="#FF923E"
android:padding="2dp"
android:text="Ad"
android:textColor="@color/white"
android:textSize="12sp"
tools:ignore="HardcodedText,TextContrastCheck,TextContrastCheck" />
<TextView
android:id="@+id/ad_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="10dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="@color/black"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="5dp">
<ImageView
android:id="@+id/ad_app_icon"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_gravity="center_vertical"
tools:ignore="ContentDescription" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/ad_call_to_action"
android:layout_width="match_parent"
android:layout_height="26dp"
android:layout_gravity="center_vertical"
android:layout_marginHorizontal="12dp"
android:background="@drawable/bg_ff8a00_10"
android:gravity="center"
android:textColor="@color/white"
android:textSize="15sp"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck,VisualLintButtonSize" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
\ No newline at end of file
<?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"
android:maxHeight="300dp"
android:padding="8dp">
<ImageView
android:id="@+id/icon_image_view"
android:layout_width="50dp"
android:layout_height="50dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:background="@android:color/holo_green_dark"
android:padding="2dp"
android:text="Ad"
android:textAppearance="@style/TextAppearance.AppCompat.Body2"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="@+id/title_text_view"
app:layout_constraintStart_toEndOf="@+id/icon_image_view"
app:layout_constraintTop_toTopOf="@+id/title_text_view"
tools:ignore="RtlHardcoded,TextContrastCheck" />
<FrameLayout
android:id="@+id/options_view"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginBottom="8dp"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@+id/advertiser_text_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toEndOf="@+id/title_text_view"
app:layout_constraintTop_toTopOf="@+id/icon_image_view" />
<TextView
android:id="@+id/title_text_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Title"
app:layout_constraintStart_toEndOf="@+id/text_view"
app:layout_constraintTop_toTopOf="parent"
tools:text="Title" />
<TextView
android:id="@+id/advertiser_text_view"
android:layout_width="wrap_content"
android:layout_height="8dp"
android:layout_marginStart="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintBottom_toBottomOf="@+id/icon_image_view"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toEndOf="@+id/icon_image_view"
app:layout_constraintTop_toBottomOf="@+id/title_text_view"
app:layout_constraintVertical_bias="1.0"
tools:text="Advertiser"
tools:textSize="12sp" />
<FrameLayout
android:id="@+id/star_rating_view"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginTop="4dp"
app:layout_constraintBottom_toTopOf="@id/advertiser_text_view"
app:layout_constraintStart_toStartOf="@id/text_view"
app:layout_constraintTop_toBottomOf="@id/text_view" />
<TextView
android:id="@+id/body_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/icon_image_view"
tools:text="Body" />
<FrameLayout
android:id="@+id/media_view_container"
android:layout_width="0dp"
android:layout_height="150dp"
android:layout_marginTop="4dp"
android:maxHeight="150dp"
app:layout_constraintDimensionRatio="W,16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/body_text_view" />
<Button
android:id="@+id/cta_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:backgroundTint="@color/applovin_sdk_brand_color"
android:textColor="@android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/media_view_container"
tools:layout_editor_absoluteX="8dp"
tools:text="Install" />
</androidx.constraintlayout.widget.ConstraintLayout>
...@@ -64,4 +64,8 @@ ...@@ -64,4 +64,8 @@
<string name="no_qrcode">NO QRCode</string> <string name="no_qrcode">NO QRCode</string>
<string name="choose_language">Choose language</string> <string name="choose_language">Choose language</string>
<string name="web_address">Web address</string> <string name="web_address">Web address</string>
<string name="turn_on_notification">Turn on notification</string>
<string name="turn_on">Turn on</string>
<string name="preparing_advertisement">Preparing advertisement</string>
</resources> </resources>
\ No newline at end of file
...@@ -13,6 +13,13 @@ immersionbar = "3.2.2" ...@@ -13,6 +13,13 @@ immersionbar = "3.2.2"
navigationFragmentKtx = "2.6.0" navigationFragmentKtx = "2.6.0"
navigationUiKtx = "2.6.0" navigationUiKtx = "2.6.0"
playServicesAds = "23.5.0.0"
applovin = "13.0.1"
vungle = "7.4.2.0"
facebook = "6.18.0.0"
mintegral = "16.8.61.0"
pangle = "6.3.0.4.0"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
...@@ -29,6 +36,21 @@ androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navi ...@@ -29,6 +36,21 @@ androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navi
androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" } androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigationUiKtx" }
vungle = { group = "com.google.ads.mediation", name = "vungle", version.ref = "vungle" }
facebook = { group = "com.google.ads.mediation", name = "facebook", version.ref = "facebook" }
mintegral = { group = "com.google.ads.mediation", name = "mintegral", version.ref = "mintegral" }
pangle = { group = "com.google.ads.mediation", name = "pangle", version.ref = "pangle" }
applovin = { group = "com.applovin", name = "applovin-sdk", version.ref = "applovin" }
applovin_google = { group = "com.applovin.mediation", name = "google-ad-manager-adapter", version.ref = "playServicesAds" }
applovin_admob = { group = "com.applovin.mediation", name = "google-adapter", version.ref = "playServicesAds" }
applovin_vungle = { group = "com.applovin.mediation", name = "vungle-adapter", version.ref = "vungle" }
applovin_facebook = { group = "com.applovin.mediation", name = "facebook-adapter", version.ref = "facebook" }
applovin_mintegral = { group = "com.applovin.mediation", name = "mintegral-adapter", version.ref = "mintegral" }
applovin_pangle = { group = "com.applovin.mediation", name = "bytedance-adapter", version.ref = "pangle" }
[plugins] [plugins]
android-application = { id = "com.android.application", version.ref = "agp" } android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment