添加参数上传,添加admob广告封装。

This commit is contained in:
ocean 2025-11-28 12:12:16 +08:00
parent 135ec734db
commit e714a1ef63
13 changed files with 341 additions and 3 deletions

View File

@ -84,6 +84,7 @@ android {
} }
dependencies { dependencies {
implementation(files("libs/UpLoadLibrary_11_24_18_30-release.aar"))
implementation(libs.androidx.fragment.ktx) implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.appcompat) implementation(libs.androidx.appcompat)
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
@ -112,4 +113,11 @@ dependencies {
implementation(platform("com.google.firebase:firebase-bom:34.6.0")) implementation(platform("com.google.firebase:firebase-bom:34.6.0"))
implementation("com.google.firebase:firebase-crashlytics-ndk") implementation("com.google.firebase:firebase-crashlytics-ndk")
implementation("com.google.firebase:firebase-analytics") implementation("com.google.firebase:firebase-analytics")
// google ads
implementation("com.google.android.gms:play-services-ads:24.7.0")
implementation ("com.google.android.gms:play-services-ads-identifier:18.0.1")
// okhttp
implementation ("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
} }

Binary file not shown.

View File

@ -35,10 +35,14 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:largeHeap="true" android:largeHeap="true"
android:networkSecurityConfig="@xml/net"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.PDFReaderPro"> android:theme="@style/Theme.PDFReaderPro">
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713" />
<meta-data <meta-data
android:name="android.max_aspect" android:name="android.max_aspect"
android:value="2.4" /> android:value="2.4" />

View File

@ -6,7 +6,10 @@ import androidx.annotation.StringRes
import com.all.pdfreader.pdf.reader.room.repository.PdfRepository import com.all.pdfreader.pdf.reader.room.repository.PdfRepository
import com.all.pdfreader.pdf.reader.util.AnalyticsUtils import com.all.pdfreader.pdf.reader.util.AnalyticsUtils
import com.all.pdfreader.pdf.reader.util.FileChangeObserver import com.all.pdfreader.pdf.reader.util.FileChangeObserver
import com.google.android.gms.ads.MobileAds
import com.google.android.gms.ads.RequestConfiguration
import com.tom_roush.pdfbox.android.PDFBoxResourceLoader import com.tom_roush.pdfbox.android.PDFBoxResourceLoader
import com.up.uploadlibrary.UpLoadManager
class PRApp : Application() { class PRApp : Application() {
@ -39,10 +42,20 @@ class PRApp : Application() {
PdfRepository.initialize(this) PdfRepository.initialize(this)
// 初始化pdfbox // 初始化pdfbox
PDFBoxResourceLoader.init(this) PDFBoxResourceLoader.init(this)
// 上传
UpLoadManager.init(context = this, tag = "PRApp_upload_task") { _, _ -> }
// 广告初始化
MobileAds.initialize(this)
}
private fun initMobileAds(){
val testDeviceIds = listOf("TEST_DEVICE_ID")
val configuration = RequestConfiguration.Builder().setTestDeviceIds(testDeviceIds).build()
MobileAds.setRequestConfiguration(configuration)
} }
// 在权限授权后调用 // 在权限授权后调用
fun startFileChangeObserving() { fun startFileChangeObserving() {
fileChangeObserver.startObserving() // fileChangeObserver.startObserving()
} }
} }

View File

@ -0,0 +1,68 @@
package com.all.pdfreader.pdf.reader.ad
import android.app.Activity
import android.util.Log
import com.all.pdfreader.pdf.reader.util.AnalyticsUtils
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.interstitial.InterstitialAd
import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback
class AdInstLoad(
private val activity: Activity,
private val placement: AdsInsUtil.AdPlacement,
private val adLoadListener: LoadListener?
) {
init {
loadAd()
}
private fun loadAd() {
//多处调用load也不会重复、不影响缓存广告、展示安全
val cachedAd = InstAdCacheManager.instance.getAdCache(placement)
if (cachedAd != null) {
Log.d("ocean","广告存在缓存,跳过加载,返回成功")
//缓存广告有效,跳过加载,返回成功
adLoadListener?.loaded(cachedAd)
return
}
val adUnitId = AdsInsUtil.adUnitIdMap[placement] ?: run {
val errorMsg = "No AdUnitId for $placement"
Log.d("ocean","没找到对应的广告ID->$placement")
adLoadListener?.loadFailed(errorMsg)
AnalyticsUtils.logAdEvent(
placement,
AnalyticsUtils.AdEvent.LOAD_FAIL,
null,
errorMsg
)
return
}
AnalyticsUtils.logAdEvent(placement, AnalyticsUtils.AdEvent.REQ)
InterstitialAd.load(
activity,
adUnitId,
AdRequest.Builder().build(),
object : InterstitialAdLoadCallback() {
override fun onAdLoaded(ad: InterstitialAd) {
InstAdCacheManager.instance.setAdCache(placement, ad)
AnalyticsUtils.logAdEvent(placement, AnalyticsUtils.AdEvent.LOADED)
adLoadListener?.loaded(ad)
}
override fun onAdFailedToLoad(adError: LoadAdError) {
AnalyticsUtils.logAdEvent(
placement,
AnalyticsUtils.AdEvent.LOAD_FAIL,
adError.code,
adError.message
)
adLoadListener?.loadFailed(adError.toString())
}
},
)
}
}

View File

@ -0,0 +1,68 @@
package com.all.pdfreader.pdf.reader.ad
import android.app.Activity
import com.all.pdfreader.pdf.reader.ad.AdsInsUtil.AdPlacement
import com.all.pdfreader.pdf.reader.util.AnalyticsUtils
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.FullScreenContentCallback
class AdInstShower(
private val activity: Activity,
private val placement: AdPlacement,
private val showListener: ShowListener?
) {
init {
showAd()
}
private fun showAd() {
val interstitialAd = InstAdCacheManager.instance.getAdCache(placement)
?: run {
val errorMsg = "InterstitialAd cache is null for place = $placement"
AnalyticsUtils.logAdEvent(
placement,
AnalyticsUtils.AdEvent.SHOW_FAIL,
null,
errorMsg
)
showListener?.onAdShowFailed(errorMsg)
return
}
interstitialAd.fullScreenContentCallback = object : FullScreenContentCallback() {
override fun onAdShowedFullScreenContent() {
AnalyticsUtils.logAdEvent(placement, AnalyticsUtils.AdEvent.SHOW_SUC)
showListener?.onAdShown()
}
override fun onAdDismissedFullScreenContent() {
// 用户关闭广告
InstAdCacheManager.instance.remove(placement)
showListener?.onAdClosed()
}
override fun onAdFailedToShowFullScreenContent(adError: AdError) {
AnalyticsUtils.logAdEvent(
placement,
AnalyticsUtils.AdEvent.SHOW_FAIL,
adError.code,
adError.message
)
InstAdCacheManager.instance.remove(placement)
showListener?.onAdShowFailed(adError.toString())
}
override fun onAdClicked() {
showListener?.onAdClicked()
}
override fun onAdImpression() {
// 曝光回调
}
}
interstitialAd.show(activity)
}
}

View File

@ -0,0 +1,82 @@
package com.all.pdfreader.pdf.reader.ad
import android.app.Activity
object AdsInsUtil {
/** 广告位定义(可扩展) */
enum class AdPlacement(val tag: String) {
SPL_AND_INTO_HOME(Placement.SPL_AND_INTO_HOME), INT_AND_TOPDF(Placement.INT_AND_TOPDF), INT_AND_PDFTOHOME(
Placement.INT_AND_PDFTOHOME
),
INT_AND_MERGE(Placement.INT_AND_MERGE), INT_AND_SPLIT(Placement.INT_AND_SPLIT), NATIVE_AND_EXIT(
Placement.NATIVE_AND_EXIT
),
BAN_AND_HOMEPAGE(Placement.BAN_AND_HOMEPAGE)
}
object Placement {
/**
* 启动页插页
*/
const val SPL_AND_INTO_HOME = "spl_and_into_home"
/**
* 在首页/最近页/喜欢页-点击文件进入PDF内容页过程中弹出缓存的插屏广告
*/
const val INT_AND_TOPDF = "int_and_topdf"
/**
* PDF内容页点击返回到首页/最近页/喜欢页过程中弹出缓存的插屏广告
*/
const val INT_AND_PDFTOHOME = "int_and_pdftohome"
/**
* 首页/最近/喜欢-PDF内容页-更多-合并文件在点击ok后出现插屏广告插屏广告结束后到合并成功页面
*/
const val INT_AND_MERGE = "int_and_merge"
/**
* 首页/最近/喜欢-PDF内容页-更多-拆分文件(点击ok后出现插屏广告插屏广告结束后到拆分成功页面)
*/
const val INT_AND_SPLIT = "int_and_split"
/**
* 退出提示对话框原生
*/
const val NATIVE_AND_EXIT = "native_and_exit"
/**
* 首页横幅
*/
const val BAN_AND_HOMEPAGE = "ban_and_homepage"
}
// 广告位对应的广告ID
val adUnitIdMap: Map<AdPlacement, String> = mapOf(
AdPlacement.SPL_AND_INTO_HOME to "ca-app-pub-5717753826607607/5211991318",
AdPlacement.INT_AND_TOPDF to "ca-app-pub-5717753826607607/5308904672",
AdPlacement.INT_AND_PDFTOHOME to "ca-app-pub-5717753826607607/7085128570",
AdPlacement.INT_AND_MERGE to "ca-app-pub-5717753826607607/8928693282",
AdPlacement.INT_AND_SPLIT to "ca-app-pub-5717753826607607/2338415962",
AdPlacement.NATIVE_AND_EXIT to "ca-app-pub-5717753826607607/7276700267",
AdPlacement.BAN_AND_HOMEPAGE to "ca-app-pub-5717753826607607/5939567861"
)
fun loadAd(
act: Activity, adPlacement: AdPlacement
): AdInstLoad {
return AdInstLoad(act, adPlacement, null)
}
fun loadAd(
act: Activity, adPlacement: AdPlacement, loadListener: LoadListener?
): AdInstLoad {
return AdInstLoad(act, adPlacement, loadListener)
}
fun showAd(
act: Activity, adPlacement: AdPlacement, listener: ShowListener?
): AdInstShower {
return AdInstShower(act, adPlacement, listener)
}
}

View File

@ -0,0 +1,39 @@
package com.all.pdfreader.pdf.reader.ad
import com.google.android.gms.ads.interstitial.InterstitialAd
class InstAdCacheManager {
private val mAdCacheDict: MutableMap<AdsInsUtil.AdPlacement, CachedAd> = mutableMapOf()
companion object {
val instance: InstAdCacheManager by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
InstAdCacheManager()
}
}
fun setAdCache(place: AdsInsUtil.AdPlacement, adCache: InterstitialAd) {
mAdCacheDict[place] = CachedAd(adCache)
}
fun getAdCache(place: AdsInsUtil.AdPlacement): InterstitialAd? {
val cached = mAdCacheDict[place]
return if (cached != null && cached.isValid()) cached.ad
else {
mAdCacheDict.remove(place) // 过期广告清理
null
}
}
fun remove(place: AdsInsUtil.AdPlacement) {
mAdCacheDict.remove(place)
}
data class CachedAd(
val ad: InterstitialAd,
val loadedAt: Long = System.currentTimeMillis()
) {
// 广告有效期, 1 小时
fun isValid(): Boolean = System.currentTimeMillis() - loadedAt < 3600_000
}
}

View File

@ -0,0 +1,8 @@
package com.all.pdfreader.pdf.reader.ad
import com.google.android.gms.ads.interstitial.InterstitialAd
interface LoadListener {
fun loadFailed(string: String) {}
fun loaded(ad: InterstitialAd) {}
}

View File

@ -0,0 +1,8 @@
package com.all.pdfreader.pdf.reader.ad
interface ShowListener {
fun onAdShown() {}
fun onAdShowFailed(string: String) {}
fun onAdClosed() {}
fun onAdClicked() {}
}

View File

@ -2,6 +2,7 @@ package com.all.pdfreader.pdf.reader.util
import android.os.Bundle import android.os.Bundle
import com.all.pdfreader.pdf.reader.BuildConfig import com.all.pdfreader.pdf.reader.BuildConfig
import com.all.pdfreader.pdf.reader.ad.AdsInsUtil
import com.google.firebase.Firebase import com.google.firebase.Firebase
import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.analytics import com.google.firebase.analytics.analytics
@ -97,8 +98,35 @@ object AnalyticsUtils {
const val KEEP_SCREEN_CLOSE = "keep_screen_close" // 点击关闭keep_screen_close const val KEEP_SCREEN_CLOSE = "keep_screen_close" // 点击关闭keep_screen_close
} }
/** param 常量 */ /** param 常量(可扩展) */
object Param { object Param {
const val PLACE = "place"
const val ERROR_CODE = "error_code"
const val ERROR_MSG = "error_msg"
} }
/** 广告事件类型 */
enum class AdEvent(val suffix: String) {
REQ("req_header"),
LOADED("loaded_header"),
LOAD_FAIL("load_fail_header"),
SHOW_SUC("show_suc_header"),
SHOW_FAIL("show_fail_header"),
}
/** 统一广告打点 */
fun logAdEvent(
placement: AdsInsUtil.AdPlacement,
event: AdEvent,
errorCode: Int? = null,
errorMsg: String? = null
) {
val eventName = "${placement.tag}_${event.suffix}"
logEvent(eventName) {
put(Param.PLACE, placement.tag)
errorCode?.let { put(Param.ERROR_CODE, it) }
errorMsg?.let { put(Param.ERROR_MSG, it) }
}
}
} }

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:tools="http://schemas.android.com/tools">
<domain-config cleartextTrafficPermitted="true">
<domain tools:ignore="NetworkSecurityConfig">mobile-server.lux-ad.com</domain>
</domain-config>
</network-security-config>

View File

@ -1,3 +1,5 @@
import org.gradle.kotlin.dsl.flatDir
pluginManagement { pluginManagement {
repositories { repositories {
google { google {
@ -7,6 +9,7 @@ pluginManagement {
includeGroupByRegex("androidx.*") includeGroupByRegex("androidx.*")
} }
} }
google()
mavenCentral() mavenCentral()
gradlePluginPortal() gradlePluginPortal()
} }
@ -17,6 +20,9 @@ dependencyResolutionManagement {
google() google()
mavenCentral() mavenCentral()
maven("https://jitpack.io") maven("https://jitpack.io")
flatDir {
dirs("libs")
}
} }
} }