diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 9efde7e..85dfe1d 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -84,6 +84,7 @@ android {
}
dependencies {
+ implementation(files("libs/UpLoadLibrary_11_24_18_30-release.aar"))
implementation(libs.androidx.fragment.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.androidx.core.ktx)
@@ -112,4 +113,11 @@ dependencies {
implementation(platform("com.google.firebase:firebase-bom:34.6.0"))
implementation("com.google.firebase:firebase-crashlytics-ndk")
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")
+
}
\ No newline at end of file
diff --git a/app/libs/UpLoadLibrary_11_24_18_30-release.aar b/app/libs/UpLoadLibrary_11_24_18_30-release.aar
new file mode 100644
index 0000000..01829d2
Binary files /dev/null and b/app/libs/UpLoadLibrary_11_24_18_30-release.aar differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 49d074d..c7d19bc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -35,10 +35,14 @@
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
+ android:networkSecurityConfig="@xml/net"
android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.PDFReaderPro">
+
diff --git a/app/src/main/java/com/all/pdfreader/pdf/reader/PRApp.kt b/app/src/main/java/com/all/pdfreader/pdf/reader/PRApp.kt
index 182ba34..36c7d0e 100644
--- a/app/src/main/java/com/all/pdfreader/pdf/reader/PRApp.kt
+++ b/app/src/main/java/com/all/pdfreader/pdf/reader/PRApp.kt
@@ -6,7 +6,10 @@ import androidx.annotation.StringRes
import com.all.pdfreader.pdf.reader.room.repository.PdfRepository
import com.all.pdfreader.pdf.reader.util.AnalyticsUtils
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.up.uploadlibrary.UpLoadManager
class PRApp : Application() {
@@ -39,10 +42,20 @@ class PRApp : Application() {
PdfRepository.initialize(this)
// 初始化pdfbox
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() {
- fileChangeObserver.startObserving()
+// fileChangeObserver.startObserving()
}
}
diff --git a/app/src/main/java/com/all/pdfreader/pdf/reader/ad/AdInstLoad.kt b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/AdInstLoad.kt
new file mode 100644
index 0000000..e06bb73
--- /dev/null
+++ b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/AdInstLoad.kt
@@ -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())
+ }
+ },
+ )
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/all/pdfreader/pdf/reader/ad/AdInstShower.kt b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/AdInstShower.kt
new file mode 100644
index 0000000..7262911
--- /dev/null
+++ b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/AdInstShower.kt
@@ -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)
+ }
+}
diff --git a/app/src/main/java/com/all/pdfreader/pdf/reader/ad/AdsInsUtil.kt b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/AdsInsUtil.kt
new file mode 100644
index 0000000..774ad9c
--- /dev/null
+++ b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/AdsInsUtil.kt
@@ -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 = 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)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/all/pdfreader/pdf/reader/ad/InstAdCacheManager.kt b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/InstAdCacheManager.kt
new file mode 100644
index 0000000..915dcbb
--- /dev/null
+++ b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/InstAdCacheManager.kt
@@ -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 = 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
+ }
+}
diff --git a/app/src/main/java/com/all/pdfreader/pdf/reader/ad/LoadListener.kt b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/LoadListener.kt
new file mode 100644
index 0000000..d9dfbea
--- /dev/null
+++ b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/LoadListener.kt
@@ -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) {}
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/all/pdfreader/pdf/reader/ad/ShowListener.kt b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/ShowListener.kt
new file mode 100644
index 0000000..c92084d
--- /dev/null
+++ b/app/src/main/java/com/all/pdfreader/pdf/reader/ad/ShowListener.kt
@@ -0,0 +1,8 @@
+package com.all.pdfreader.pdf.reader.ad
+
+interface ShowListener {
+ fun onAdShown() {}
+ fun onAdShowFailed(string: String) {}
+ fun onAdClosed() {}
+ fun onAdClicked() {}
+}
diff --git a/app/src/main/java/com/all/pdfreader/pdf/reader/util/AnalyticsUtils.kt b/app/src/main/java/com/all/pdfreader/pdf/reader/util/AnalyticsUtils.kt
index cafd4fa..3d38039 100644
--- a/app/src/main/java/com/all/pdfreader/pdf/reader/util/AnalyticsUtils.kt
+++ b/app/src/main/java/com/all/pdfreader/pdf/reader/util/AnalyticsUtils.kt
@@ -2,6 +2,7 @@ package com.all.pdfreader.pdf.reader.util
import android.os.Bundle
import com.all.pdfreader.pdf.reader.BuildConfig
+import com.all.pdfreader.pdf.reader.ad.AdsInsUtil
import com.google.firebase.Firebase
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.analytics.analytics
@@ -97,8 +98,35 @@ object AnalyticsUtils {
const val KEEP_SCREEN_CLOSE = "keep_screen_close" // 点击关闭(keep_screen_close)
}
- /** param 常量 */
+ /** 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) }
+ }
+ }
+
}
diff --git a/app/src/main/res/xml/net.xml b/app/src/main/res/xml/net.xml
new file mode 100644
index 0000000..69cc842
--- /dev/null
+++ b/app/src/main/res/xml/net.xml
@@ -0,0 +1,6 @@
+
+
+
+ mobile-server.lux-ad.com
+
+
diff --git a/settings.gradle.kts b/settings.gradle.kts
index aa906bb..20120ae 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,3 +1,5 @@
+import org.gradle.kotlin.dsl.flatDir
+
pluginManagement {
repositories {
google {
@@ -7,6 +9,7 @@ pluginManagement {
includeGroupByRegex("androidx.*")
}
}
+ google()
mavenCentral()
gradlePluginPortal()
}
@@ -17,6 +20,9 @@ dependencyResolutionManagement {
google()
mavenCentral()
maven("https://jitpack.io")
+ flatDir {
+ dirs("libs")
+ }
}
}