diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 69073b2..d429e3d 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -6,7 +6,15 @@ plugins {
alias(libs.plugins.kotlin.android)
id("com.google.devtools.ksp")
id("kotlin-parcelize")
+ id("applovin-quality-service")
+ id("com.google.gms.google-services")
+ id("com.google.firebase.crashlytics")
}
+
+applovin{
+ apiKey = "HdbZLNGSr7OhD4EivCuW_2IFaTzgsdvK7EC53RUzaKNc7HACu4BOIyurAlWPlOgPP1TAcNL4RMpAeP5LeqU0U7"
+}
+
val timestamp: String = SimpleDateFormat("MM_dd_HH_mm").format(Date())
android {
namespace = "com.wallpaper.lumawallpaper"
@@ -16,8 +24,8 @@ android {
applicationId = "com.wallpaper.lumawallpaper"
minSdk = 23
targetSdk = 35
- versionCode = 1
- versionName = "1.0.0"
+ versionCode = 2
+ versionName = "1.0.1"
setProperty(
"archivesBaseName",
"Luma Wallpaper_V" + versionName + "(${versionCode})_$timestamp"
@@ -66,9 +74,48 @@ dependencies {
implementation("androidx.room:room-ktx:2.7.1")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.9.0")
-
- implementation ("com.squareup.okhttp3:okhttp:4.12.0")
-
+
implementation ("androidx.activity:activity-ktx:1.10.1")
implementation ("androidx.lifecycle:lifecycle-runtime-ktx:2.9.0")
+
+ //获取gaid
+ implementation("com.google.android.gms:play-services-ads-identifier:18.0.1")
+ implementation("com.google.android.gms:play-services-appset:16.0.1")
+ //开启协程
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2")
+
+
+ implementation ("com.squareup.okhttp3:okhttp:4.12.0")
+ implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
+
+
+ // Import the BoM for the Firebase platform
+ implementation(platform("com.google.firebase:firebase-bom:33.7.0"))
+
+ // Add the dependencies for the Crashlytics and Analytics libraries
+ // When using the BoM, you don't specify versions in Firebase library dependencies
+ implementation("com.google.firebase:firebase-crashlytics")
+ implementation("com.google.firebase:firebase-analytics")
+ implementation("com.google.firebase:firebase-config")
+
+ //--------------------------MAX(Liftoff Monetize(vungle)、Mintegral、Pangle、Unity Ads)
+ implementation("com.applovin:applovin-sdk:+")
+ implementation("com.applovin.mediation:bigoads-adapter:+")
+ implementation("com.applovin.mediation:chartboost-adapter:+")
+ implementation("com.google.android.gms:play-services-base:16.1.0")
+ implementation("com.applovin.mediation:fyber-adapter:+")
+ //Google Ad Manager
+ // implementation("com.applovin.mediation:google-ad-manager-adapter:+")
+
+ //Google Bidding and Google AdMob
+ //implementation("com.applovin.mediation:google-adapter:+")
+ implementation("com.applovin.mediation:inmobi-adapter:+")
+ implementation("com.squareup.picasso:picasso:2.71828")
+ implementation("androidx.recyclerview:recyclerview:1.1.0")
+ implementation("com.applovin.mediation:ironsource-adapter:+")
+ implementation("com.applovin.mediation:vungle-adapter:+")
+ implementation("com.applovin.mediation:facebook-adapter:+")
+ implementation("com.applovin.mediation:moloco-adapter:+")
+ implementation("com.applovin.mediation:bytedance-adapter:+")
+ implementation("com.applovin.mediation:unityads-adapter:+")
}
\ No newline at end of file
diff --git a/app/google-services.json b/app/google-services.json
new file mode 100644
index 0000000..988ec5f
--- /dev/null
+++ b/app/google-services.json
@@ -0,0 +1,29 @@
+{
+ "project_info": {
+ "project_number": "172035119331",
+ "project_id": "luma-wallpaper",
+ "storage_bucket": "luma-wallpaper.firebasestorage.app"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:172035119331:android:ef92444a6efd9074708dd6",
+ "android_client_info": {
+ "package_name": "com.wallpaper.lumawallpaper"
+ }
+ },
+ "oauth_client": [],
+ "api_key": [
+ {
+ "current_key": "AIzaSyAJBYy9PBz7Pqu4bOhcOijiLEiVcZZAhrg"
+ }
+ ],
+ "services": {
+ "appinvite_service": {
+ "other_platform_oauth_client": []
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index de3c96a..0716515 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,8 @@
+
+
adList = new ArrayList<>();
+
+ public static MaxInterstitialAd getAd(List list) {
+ Collections.shuffle(list);
+ for (MaxInterstitialAd ad : list) {
+ if (ad.isReady()) {
+ return ad;
+ }
+ }
+ return null;
+ }
+
+ public static List onLoadAd() {
+ if (adList.isEmpty()) {
+ MaxInterstitialAd AdT = new MaxInterstitialAd(two_Ad, App.getContext());
+ MaxInterstitialAd AdOne = new MaxInterstitialAd(one_AD, App.getContext());
+ MaxInterstitialAd AdThree = new MaxInterstitialAd(three_ad, App.getContext());
+ adList.add(AdOne);
+ adList.add(AdT);
+ adList.add(AdThree);
+ }
+
+ for (MaxInterstitialAd ad : adList) {
+ if (!ad.isReady()) {
+ setMyListener(ad, new MaxListener() {
+ @Override
+ public void onFail(MaxAd ad) {
+
+ }
+
+ @Override
+ public void onShowSuccess(MaxAd ad) {
+
+ }
+
+ @Override
+ public void onHidden() {
+
+ }
+ });
+ ad.loadAd();
+ }
+
+ }
+
+ return adList;
+ }
+
+ public static void setMyListener(MaxInterstitialAd ad, MaxListener maxListener) {
+ ad.setListener(new MaxAdListener() {
+ @Override
+ public void onAdLoaded(@NonNull MaxAd maxAd) {
+ Log.d(App.TAG, "-------onAdLoaded-----maxAd=" + maxAd.getAdUnitId());
+ }
+
+ @Override
+ public void onAdDisplayed(@NonNull MaxAd maxAd) {
+ Log.d(App.TAG, "-------onAdDisplayed-----maxAd=" + maxAd.getAdUnitId());
+ maxListener.onShowSuccess(maxAd);
+ }
+
+ @Override
+ public void onAdHidden(@NonNull MaxAd maxAd) {
+ Log.d(App.TAG, "-------onAdHidden-----maxAd=" + maxAd.getAdUnitId());
+ maxListener.onHidden();
+ setMyListener(ad, new MaxListener() {
+ @Override
+ public void onFail(MaxAd ad) {
+
+ }
+
+ @Override
+ public void onShowSuccess(MaxAd ad) {
+
+ }
+
+ @Override
+ public void onHidden() {
+
+ }
+ });
+ ad.loadAd();
+ }
+
+ @Override
+ public void onAdClicked(@NonNull MaxAd maxAd) {
+
+ }
+
+ @Override
+ public void onAdLoadFailed(@NonNull String s, @NonNull MaxError maxError) {
+ Log.d(App.TAG, "-------onAdLoadFailed-----s=" + s+"----maxError="+maxError.getMessage());
+ }
+
+ @Override
+ public void onAdDisplayFailed(@NonNull MaxAd maxAd, @NonNull MaxError maxError) {
+ maxListener.onFail(maxAd);
+ }
+ });
+
+ }
+
+ public static void ShowAd(Activity activity, onAdStatusListener listener) {
+ MaxInterstitialAd ad = MaxManager.getAd(adList);
+ if (ad == null) {
+ listener.onAdStatus(type_no_cache);
+ } else {
+ listener.onAdStatus(type_has_cache);
+ MaxManager.setMyListener(ad, new MaxListener() {
+ @Override
+ public void onFail(MaxAd ad) {
+ listener.onAdStatus(type_show_fail);
+ }
+
+ @Override
+ public void onShowSuccess(MaxAd ad) {
+ listener.onAdStatus(type_show_success);
+ }
+
+ @Override
+ public void onHidden() {
+ listener.onAdStatus(type_show_close);
+ }
+ });
+ ad.showAd(activity);
+ }
+ }
+
+
+ public static void startShowMaxAd(Activity activity, onAdAfterAction listener) {
+ MaxManager.ShowAd(activity, new onAdStatusListener() {
+ @Override
+ public void onAdStatus(int type) {
+ if (type == MaxManager.type_show_close || type == MaxManager.type_show_fail || type == MaxManager.type_no_cache) {
+ if (listener != null)
+ listener.onAction();
+ }
+ }
+ });
+ }
+
+}
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/max/WelComManager.kt b/app/src/main/java/com/wallpaper/lumawallpaper/max/WelComManager.kt
new file mode 100644
index 0000000..d7a4858
--- /dev/null
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/max/WelComManager.kt
@@ -0,0 +1,44 @@
+package com.wallpaper.lumawallpaper.max
+
+import android.app.Activity
+import android.os.CountDownTimer
+import android.util.Log
+import com.wallpaper.lumawallpaper.App
+
+object WelComManager {
+
+ private lateinit var timer: CountDownTimer
+ private var need_Show = true
+
+ @JvmStatic
+ fun initTimer(activity: Activity, countTime: Long, countAction: (Long) -> Unit, goMainAction: () -> Unit): CountDownTimer {
+ need_Show = true
+ timer = object : CountDownTimer(countTime, 100) {
+ override fun onTick(millisUntilFinished: Long) {
+ countAction.invoke(millisUntilFinished)
+ if (need_Show) {
+ MaxManager.ShowAd(activity) {
+ Log.d(App.TAG, "--onTick----------it=$it")
+ if (it == MaxManager.type_has_cache) {
+ need_Show = false
+ }
+ if (it == MaxManager.type_show_close || it == MaxManager.type_show_fail) {
+ Log.d(App.TAG, "--onTick---------enter")
+ goMainAction.invoke()
+ }
+ }
+ }
+ }
+
+ override fun onFinish() {
+ if (need_Show) {
+ MaxManager.ShowAd(activity) {
+ goMainAction.invoke()
+ }
+ }
+ }
+ }
+ return timer
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/max/onAdAfterAction.java b/app/src/main/java/com/wallpaper/lumawallpaper/max/onAdAfterAction.java
new file mode 100644
index 0000000..8468ce6
--- /dev/null
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/max/onAdAfterAction.java
@@ -0,0 +1,6 @@
+package com.wallpaper.lumawallpaper.max;
+
+public interface onAdAfterAction {
+
+ void onAction();
+}
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/max/onAdStatusListener.java b/app/src/main/java/com/wallpaper/lumawallpaper/max/onAdStatusListener.java
new file mode 100644
index 0000000..2d07da6
--- /dev/null
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/max/onAdStatusListener.java
@@ -0,0 +1,6 @@
+package com.wallpaper.lumawallpaper.max;
+
+public interface onAdStatusListener {
+
+ void onAdStatus(int type);
+}
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/CategoryActivity.kt b/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/CategoryActivity.kt
index 37f4b47..0127eed 100644
--- a/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/CategoryActivity.kt
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/CategoryActivity.kt
@@ -10,6 +10,7 @@ import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.wallpaper.lumawallpaper.R
import com.wallpaper.lumawallpaper.databinding.ActivityCategoryBinding
+import com.wallpaper.lumawallpaper.max.MaxManager
import com.wallpaper.lumawallpaper.ui.adapter.LumaAdapter
import com.wallpaper.lumawallpaper.ui.viewmodel.LumaViewModel
import com.wallpaper.lumawallpaper.utils.ItemDecoration
@@ -31,6 +32,10 @@ class CategoryActivity : AppCompatActivity() {
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
+
+ MaxManager.onLoadAd()
+ MaxManager.startShowMaxAd(this@CategoryActivity) { }
+
initData()
initEvent()
}
@@ -85,7 +90,9 @@ class CategoryActivity : AppCompatActivity() {
private fun initEvent() {
binding.back.setOnClickListener {
- finish()
+ MaxManager.startShowMaxAd(this@CategoryActivity) {
+ finish()
+ }
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/LumaActivity.kt b/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/LumaActivity.kt
index 42a7935..e9302d2 100644
--- a/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/LumaActivity.kt
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/LumaActivity.kt
@@ -22,8 +22,10 @@ import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.wallpaper.lumawallpaper.R
-import com.wallpaper.lumawallpaper.databinding.ActivityLumaBinding
import com.wallpaper.lumawallpaper.database.LumaEntity
+import com.wallpaper.lumawallpaper.databinding.ActivityLumaBinding
+import com.wallpaper.lumawallpaper.max.MaxManager
+import com.wallpaper.lumawallpaper.max.onAdAfterAction
import com.wallpaper.lumawallpaper.ui.viewmodel.LumaViewModel
import com.wallpaper.lumawallpaper.utils.WallpaperUtil
import kotlinx.coroutines.Dispatchers
@@ -47,6 +49,10 @@ class LumaActivity : AppCompatActivity() {
enableEdgeToEdge()
lumaBinding = ActivityLumaBinding.inflate(layoutInflater)
setContentView(lumaBinding.root)
+
+ MaxManager.onLoadAd()
+ MaxManager.startShowMaxAd(this@LumaActivity) { }
+
configureWindowInsets()
initializeComponents()
registerEventListeners()
@@ -78,15 +84,25 @@ class LumaActivity : AppCompatActivity() {
@RequiresApi(Build.VERSION_CODES.N)
private fun registerEventListeners() {
showProgress()
- lumaBinding.back.setOnClickListener { finishActivity() }
+ lumaBinding.back.setOnClickListener {
+ MaxManager.startShowMaxAd(this@LumaActivity) {
+ finishActivity()
+ }
+ }
lumaBinding.like.setOnClickListener {
toggleFavoriteStatus()
refreshFavoriteIcon()
}
- lumaBinding.set.setOnClickListener { showWallpaperDialog() }
+ lumaBinding.set.setOnClickListener {
+ MaxManager.startShowMaxAd(this@LumaActivity) {
+ showWallpaperDialog()
+ }
+ }
lumaBinding.downPicture.setOnClickListener {
- showProgress()
- utilHelper.downloadWallpaper(this, originalImageUrl)
+ MaxManager.startShowMaxAd(this@LumaActivity) {
+ showProgress()
+ utilHelper.downloadWallpaper(this, originalImageUrl)
+ }
}
loadImageContent()
monitorFavoriteChanges()
@@ -111,7 +127,10 @@ class LumaActivity : AppCompatActivity() {
val bottomDialog = BottomSheetDialog(this)
val dialogView = LayoutInflater.from(this).inflate(R.layout.set_dialog, null)
dialogView.findViewById(R.id.both).setOnClickListener {
- configureWallpaper(loadedBitmap, WallpaperManager.FLAG_SYSTEM or WallpaperManager.FLAG_LOCK)
+ configureWallpaper(
+ loadedBitmap,
+ WallpaperManager.FLAG_SYSTEM or WallpaperManager.FLAG_LOCK
+ )
bottomDialog.dismiss()
}
dialogView.findViewById(R.id.lock).setOnClickListener {
@@ -134,12 +153,17 @@ class LumaActivity : AppCompatActivity() {
setWallpaperImage(bitmap, flags)
withContext(Dispatchers.Main) {
hideProgress()
- Toast.makeText(this@LumaActivity, "Wallpaper applied", Toast.LENGTH_SHORT).show()
+ Toast.makeText(this@LumaActivity, "Wallpaper applied", Toast.LENGTH_SHORT)
+ .show()
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
hideProgress()
- Toast.makeText(this@LumaActivity, "Failed to apply wallpaper", Toast.LENGTH_SHORT).show()
+ Toast.makeText(
+ this@LumaActivity,
+ "Failed to apply wallpaper",
+ Toast.LENGTH_SHORT
+ ).show()
}
}
}
@@ -165,9 +189,11 @@ class LumaActivity : AppCompatActivity() {
loadedBitmap = resource
hideProgress()
}
+
override fun onLoadCleared(placeholder: Drawable?) {
lumaBinding.imageView.setImageDrawable(placeholder)
}
+
override fun onLoadFailed(errorDrawable: Drawable?) {
lumaBinding.imageView.setImageDrawable(errorDrawable)
hideProgress()
@@ -177,7 +203,8 @@ class LumaActivity : AppCompatActivity() {
private fun monitorFavoriteChanges() {
lifecycleScope.launch {
- viewModel.getFavoriteStatus(imageSourceUrl, imageTitle).collect { refreshFavoriteIcon() }
+ viewModel.getFavoriteStatus(imageSourceUrl, imageTitle)
+ .collect { refreshFavoriteIcon() }
}
}
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/MainActivity.kt b/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/MainActivity.kt
index b3abe5c..112ecf8 100644
--- a/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/MainActivity.kt
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/MainActivity.kt
@@ -15,7 +15,10 @@ import com.google.android.material.tabs.TabLayoutMediator
import com.wallpaper.lumawallpaper.R
import com.wallpaper.lumawallpaper.databinding.ActivityMainBinding
import com.wallpaper.lumawallpaper.databinding.MainTabBinding
+import com.wallpaper.lumawallpaper.max.MaxManager
import com.wallpaper.lumawallpaper.ui.adapter.MainAdapter
+import com.wallpaper.lumawallpaper.upload.Http
+import com.wallpaper.lumawallpaper.upload.SaveUtils
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
@@ -32,8 +35,12 @@ class MainActivity : AppCompatActivity() {
insets
}
+ MaxManager.onLoadAd()
+
initData()
initEvent()
+
+ upload()
}
private fun initData() {
@@ -109,4 +116,12 @@ class MainActivity : AppCompatActivity() {
}
return if (isSelected) R.drawable.home else R.drawable.un_home
}
+
+ private fun upload() {
+ val post = SaveUtils.isPost
+ if (!post) {
+ Http.makeGetRequest(this@MainActivity)
+ SaveUtils.isPost = true
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/SplashActivity.kt b/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/SplashActivity.kt
index 8e9af0f..2f9c578 100644
--- a/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/SplashActivity.kt
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/ui/activity/SplashActivity.kt
@@ -14,6 +14,8 @@ import com.bumptech.glide.load.resource.bitmap.CenterCrop
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.wallpaper.lumawallpaper.R
import com.wallpaper.lumawallpaper.databinding.ActivitySplashBinding
+import com.wallpaper.lumawallpaper.max.MaxManager
+import com.wallpaper.lumawallpaper.max.WelComManager
@SuppressLint("CustomSplashScreen")
class SplashActivity : AppCompatActivity() {
@@ -21,7 +23,7 @@ class SplashActivity : AppCompatActivity() {
private lateinit var countDownTimer: CountDownTimer
companion object {
- private const val TOTAL_TIME: Long = 1000
+ private const val TOTAL_TIME: Long = 11000
}
override fun onCreate(savedInstanceState: Bundle?) {
@@ -38,21 +40,24 @@ class SplashActivity : AppCompatActivity() {
insets
}
+ MaxManager.onLoadAd()
+
Glide.with(this)
.load(R.mipmap.placeholder)
.transform(CenterCrop(), RoundedCorners(32))
.into(binding.image)
- countDownTimer = object : CountDownTimer(TOTAL_TIME, 50) {
- override fun onTick(millisUntilFinished: Long) {
- val percentage = (100 - millisUntilFinished.toFloat() / TOTAL_TIME * 100).toInt()
+ countDownTimer = WelComManager.initTimer(
+ this,
+ TOTAL_TIME,
+ { millisUntilFinished ->
+ val percentage = (100 - (millisUntilFinished.toFloat() / TOTAL_TIME * 100)).toInt()
binding.progressBar.progress = percentage
- }
-
- override fun onFinish() {
+ },
+ {
startMain()
}
- }.start()
+ )
countDownTimer.start()
}
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/upload/AESUtils.kt b/app/src/main/java/com/wallpaper/lumawallpaper/upload/AESUtils.kt
new file mode 100644
index 0000000..7823ae5
--- /dev/null
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/upload/AESUtils.kt
@@ -0,0 +1,105 @@
+package com.wallpaper.lumawallpaper.upload
+
+import android.app.Activity
+import android.util.Base64
+import java.security.SecureRandom
+import javax.crypto.Cipher
+import javax.crypto.KeyGenerator
+import javax.crypto.SecretKey
+import javax.crypto.spec.IvParameterSpec
+import javax.crypto.spec.SecretKeySpec
+
+
+object AESUtils {
+// private const val AES_MODE = "AES/CBC/PKCS5Padding"
+ private const val AES_MODE = "AES"
+ private const val AES_ALGORITHM = "AES"
+ private const val AES_KEY_SIZE = 256 // 支持 128/192/256
+
+ /**
+ * 生成 AES 密钥
+ */
+ fun generateAESKey(): String {
+ val keyGenerator = KeyGenerator.getInstance(AES_ALGORITHM)
+ keyGenerator.init(AES_KEY_SIZE, SecureRandom())
+ val secretKey: SecretKey = keyGenerator.generateKey()
+ return Base64.encodeToString(secretKey.encoded, Base64.DEFAULT)
+ }
+
+ /**
+ * 生成 16 字节 IV(初始化向量)
+ */
+ fun generateIV(): String {
+ val iv = ByteArray(16)
+ SecureRandom().nextBytes(iv)
+ return Base64.encodeToString(iv, Base64.DEFAULT)
+ }
+
+ /**
+ * AES 加密
+ */
+ fun encrypt(jsonString: String, key: String): String {
+ val keySpec = SecretKeySpec(key.toByteArray(Charsets.UTF_8), AES_ALGORITHM)
+ val ivSpec = IvParameterSpec(key.toByteArray(Charsets.UTF_8))
+
+ val cipher = Cipher.getInstance(AES_MODE)
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec)
+
+ val encryptedBytes = cipher.doFinal(jsonString.toByteArray(Charsets.UTF_8))
+ return Base64.encodeToString(encryptedBytes, Base64.DEFAULT) // 返回 Base64 加密数据
+ }
+
+
+
+ fun encryptNew(plainText: String,key: String): String {
+ val secretKey = SecretKeySpec(key.toByteArray(), AES_MODE)
+ val cipher = Cipher.getInstance(AES_MODE)
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey)
+ val encryptedBytes = cipher.doFinal(plainText.toByteArray())
+ return Base64.encodeToString(encryptedBytes, Base64.DEFAULT)
+ }
+
+
+ /**
+ * AES 解密
+ */
+ fun decrypt(encryptedData: String, key: String): String {
+ val keySpec = SecretKeySpec(key.toByteArray(Charsets.UTF_8), AES_ALGORITHM)
+ val ivSpec = IvParameterSpec(key.toByteArray(Charsets.UTF_8))
+
+ val cipher = Cipher.getInstance(AES_MODE)
+ cipher.init(Cipher.DECRYPT_MODE, keySpec)
+
+ val decryptedBytes = cipher.doFinal(Base64.decode(encryptedData, Base64.DEFAULT))
+ return String(decryptedBytes, Charsets.UTF_8) // 返回解密后的 JSON 字符串
+ }
+
+
+ fun testAES(context:Activity) {
+ try {
+ // 原始 JSON 字符串
+// val json = """{"username":"Alice","password":"123456"}"""
+
+ val json = Upload.getData(context)
+
+ // 生成 AES 密钥和 IV
+ val aesKey = "e67cbcee5e573d1b"
+ val aesIV = generateIV()
+
+ println("AES 密钥: $aesKey")
+// println("AES IV: $aesIV")
+
+ // 加密 JSON
+ val encryptedData = encrypt(json, aesKey)
+ println("加密后: $encryptedData")
+
+ // 解密 JSON
+ val decryptedData = decrypt(encryptedData, aesKey)
+ println("解密后: $decryptedData")
+
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/upload/Http.kt b/app/src/main/java/com/wallpaper/lumawallpaper/upload/Http.kt
new file mode 100644
index 0000000..6b57a49
--- /dev/null
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/upload/Http.kt
@@ -0,0 +1,72 @@
+package com.wallpaper.lumawallpaper.upload
+
+import android.app.Activity
+import android.util.Log
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.MediaType.Companion.toMediaType
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.RequestBody
+import okhttp3.RequestBody.Companion.toRequestBody
+import okhttp3.Response
+import okhttp3.logging.HttpLoggingInterceptor
+import org.json.JSONObject
+import java.io.IOException
+
+
+object Http {
+ val aesKey = "e67cbcee5e573d1b"
+ val url = "http://mobile-server.lux-ad.com:58077/api/mobile/save"
+
+
+ fun makeGetRequest(context: Activity) {
+ val logging = HttpLoggingInterceptor()
+ logging.setLevel(HttpLoggingInterceptor.Level.BODY)
+
+
+
+ GlobalScope.launch(Dispatchers.IO) {
+ val data = Upload.getData(context)
+
+ withContext(Dispatchers.Main){
+ val encryptJson = AESUtils.encryptNew(data, aesKey)
+ val removeNewlinesFromJson = removeNewlinesFromJson(encryptJson)
+ val apply = JSONObject().apply {
+ put("encrypted", removeNewlinesFromJson)
+ }
+ val client: OkHttpClient = OkHttpClient.Builder()
+ .addInterceptor(logging)
+ .build()
+// val client = OkHttpClient()
+ val requestBody: RequestBody =
+ apply.toString().toRequestBody("application/json; charset=utf-8".toMediaType())
+
+ val request: Request = Request.Builder()
+ .url(url)
+ .post(requestBody)
+ .build()
+ client.newCall(request).enqueue(object : Callback {
+ override fun onFailure(call: Call, e: IOException) {
+ Log.e("==================", "onFailure e=${e.message}")
+ }
+
+ override fun onResponse(call: Call, response: Response) {
+ Log.e("==================", "response=${response.code} ${response.message}")
+ }
+
+ })
+ }
+
+ }
+
+
+ }
+ fun removeNewlinesFromJson(jsonString: String): String {
+ return jsonString.replace("\n", "").replace("\r", "")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/upload/SaveUtils.kt b/app/src/main/java/com/wallpaper/lumawallpaper/upload/SaveUtils.kt
new file mode 100644
index 0000000..5f1d5ee
--- /dev/null
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/upload/SaveUtils.kt
@@ -0,0 +1,47 @@
+package com.wallpaper.lumawallpaper.upload
+
+import android.content.Context
+import android.content.SharedPreferences
+import com.wallpaper.lumawallpaper.App
+
+
+object SaveUtils {
+
+
+ val IS_POST = App.getContext().packageName+"is_post"
+ private var shared: SharedPreferences? = null
+
+ var isPost: Boolean
+ get() = queryBoolean(
+ IS_POST,
+ false
+ )
+ set(value) {
+ saveBoolean(IS_POST, value)
+ }
+
+
+
+ private fun getShared(): SharedPreferences {
+ if (shared == null) {
+ shared = App.getContext().getSharedPreferences("Wallpaper", Context.MODE_PRIVATE)
+ }
+ return shared!!
+
+ }
+
+
+ fun saveBoolean(key: String, value: Boolean) {
+ getShared().edit()
+ .putBoolean(key, value).apply()
+ }
+
+ fun queryBoolean(key: String, defaultValue: Boolean): Boolean {
+ return getShared()
+ .getBoolean(key, defaultValue)
+ }
+
+
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/wallpaper/lumawallpaper/upload/Upload.kt b/app/src/main/java/com/wallpaper/lumawallpaper/upload/Upload.kt
new file mode 100644
index 0000000..741e74d
--- /dev/null
+++ b/app/src/main/java/com/wallpaper/lumawallpaper/upload/Upload.kt
@@ -0,0 +1,353 @@
+package com.wallpaper.lumawallpaper.upload
+
+import android.annotation.SuppressLint
+import android.app.Activity
+import android.content.Context
+import android.content.pm.PackageInfo
+import android.content.pm.PackageManager
+import android.location.Location
+import android.net.wifi.WifiInfo
+import android.net.wifi.WifiManager
+import android.os.BatteryManager
+import android.os.Build
+import android.os.SystemClock
+import android.provider.Settings
+import android.telephony.TelephonyManager
+import android.text.format.Formatter
+import android.util.Log
+import android.webkit.WebView
+import com.google.android.gms.ads.identifier.AdvertisingIdClient
+import org.json.JSONObject
+import java.io.File
+import java.text.SimpleDateFormat
+import java.util.Date
+import java.util.Locale
+import java.util.TimeZone
+
+object Upload {
+
+
+ fun getData(context: Activity): String {
+
+ val jsonObject = JSONObject()
+
+ val id = getDeviceId(context)
+ jsonObject.put("gaid", id)
+
+ getWebViewPackageInfo(context)?.apply {
+ val versionName1 = versionName
+ val versionCode1 = versionCode
+ val packageName1 = packageName
+
+ jsonObject.put("webVersionName", versionName)
+ jsonObject.put("webVersionCode", versionCode)
+ jsonObject.put("webPackageName", packageName)
+// Log.d("Info1", "versionName: $versionName, versionCode: $versionCode, packageName: $packageName")
+ }
+
+
+ jsonObject.put("brand", Build.BRAND)
+ jsonObject.put("manufacturer", Build.MANUFACTURER)
+ jsonObject.put("model", Build.MODEL)
+ jsonObject.put("product", Build.PRODUCT)
+ jsonObject.put("device", Build.DEVICE)
+ jsonObject.put("board", Build.BOARD)
+ jsonObject.put("hardware", Build.HARDWARE)
+ jsonObject.put("fingerPrint", Build.FINGERPRINT)
+ jsonObject.put("buildId", Build.ID)
+ jsonObject.put("display", Build.DISPLAY)
+ jsonObject.put("type", Build.TYPE)
+ jsonObject.put("user", Build.USER)
+ jsonObject.put("host", Build.HOST)
+ jsonObject.put("tags", Build.TAGS)
+ jsonObject.put("serial", Build.SERIAL)
+ jsonObject.put("bootloader", Build.BOOTLOADER)
+ jsonObject.put("sdkInt", Build.VERSION.SDK_INT)
+ jsonObject.put("androidVersion", Build.VERSION.RELEASE)
+ jsonObject.put("baseOs", Build.VERSION.BASE_OS)
+ jsonObject.put("incremental", Build.VERSION.INCREMENTAL)
+ jsonObject.put("codename", Build.VERSION.CODENAME)
+
+
+ val androidID = getAndroidID(context)
+ jsonObject.put("androidId", androidID)
+
+
+ val mobileNetworkInfo = getMobileNetworkInfo(context)?.let {
+ //SIM卡的运营商名称
+ it.networkOperatorName
+ //SIM卡的运营商代码
+ it.simOperator
+ //国家代码
+ it.simCountryIso
+ //SIM 卡状态
+ it.simState
+ jsonObject.put("simOperator", it.simOperator)
+ jsonObject.put("simOperatorName", it.networkOperatorName)
+ jsonObject.put("simCountry", it.simCountryIso)
+ jsonObject.put("simState", it.simState)
+
+// if (ActivityCompat.checkSelfPermission(
+// context,
+// Manifest.permission.READ_PHONE_STATE
+// ) != PackageManager.PERMISSION_GRANTED
+// ) {
+// //没有权限
+// Log.e("==================", "无法获取phone权限")
+// return@let
+// } else {
+// //网络类型
+// val networkType = getNet(it.networkType)
+// jsonObject.put("networkType",networkType)
+// }
+
+
+ }
+ getWifiInfo(context).let { wifiInfo ->
+ val ssid = wifiInfo.ssid // WiFi 名称
+ val bssid = wifiInfo.bssid // 路由器 MAC 地址
+ val ip = wifiInfo.ipAddress
+ val ipAddress: String = Formatter.formatIpAddress(ip) // IP 地址
+// Log.d("WiFi Info", "SSID: $ssid, BSSID: $bssid, IP: $ipAddress")
+
+ jsonObject.put("wifiSSID", ssid)
+ jsonObject.put("wifiBSSID", bssid)
+
+ }
+
+// getLastLocation(context){location->
+// location?.let {
+// val latitude: Double = location.latitude
+// val longitude: Double = location.longitude
+// val accuracy = location.accuracy // 获取精度(米)
+// jsonObject.put("longitude",longitude)
+// jsonObject.put("latitude",latitude)
+//// jsonObject.put("randomOffset",latitude)
+// Log.d("Location", "纬度: $latitude, 经度: $longitude")
+// }
+// }
+
+ //电池电量
+ val batteryInfo = getBatteryInfo(context)
+ jsonObject.put("batteryLevel", batteryInfo)
+
+ //处理器核心数
+ val coreCount = Runtime.getRuntime().availableProcessors()
+ jsonObject.put("availableProcessors", coreCount)
+
+ //系统启动时长
+// val convertTimestampToDate =
+// convertTimestampToDate(System.currentTimeMillis() - SystemClock.elapsedRealtime())
+// val systemUptime = getSystemUptime()
+ jsonObject.put("systemStarTime", SystemClock.elapsedRealtime())
+
+ //应用程序 APK 文件的最后修改时间
+ val installTime = getInstallTime(context)
+ jsonObject.put("apkLastModified", installTime)
+
+ //安装来源
+ val installSource = getInstallSourceNew(context)
+ jsonObject.put("installerPkg", installSource)
+
+
+ Log.d("===================================", jsonObject.toString())
+ return jsonObject.toString()
+
+ }
+
+
+ fun getInstallSource(context: Context): String? {
+ val packageManager = context.packageManager
+ val installer = packageManager.getInstallerPackageName(context.packageName)
+ return installer ?: "未知"
+ }
+
+ fun getInstallSourceNew(context: Context): String? {
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // API 30+
+ try {
+ val packageManager = context.packageManager
+ val installSourceInfo = packageManager.getInstallSourceInfo(context.packageName)
+ installSourceInfo.installingPackageName // 安装来源
+ } catch (e: PackageManager.NameNotFoundException) {
+ "未知"
+ }
+ } else {
+ getInstallSource(context) // 兼容 API 30 以下
+ }
+ }
+
+ fun getSystemUptime(): String {
+ val uptimeMillis = SystemClock.elapsedRealtime() // 设备启动后的毫秒数
+ val uptimeSeconds = uptimeMillis / 1000
+ val hours = uptimeSeconds / 3600
+ val minutes = uptimeSeconds % 3600 / 60
+ val seconds = uptimeSeconds % 60
+ val uptimeFormatted = "$hours 小时 $minutes 分钟 $seconds 秒"
+ Log.d("DeviceInfo", "系统运行时间: $uptimeFormatted")
+ return uptimeFormatted
+ }
+
+ private fun getLastLocation(context: Activity, result: (location: Location?) -> Unit) {
+// val fusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
+//
+// if (ActivityCompat.checkSelfPermission(
+// context,
+// Manifest.permission.ACCESS_FINE_LOCATION
+// ) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
+// context,
+// Manifest.permission.ACCESS_COARSE_LOCATION
+// ) != PackageManager.PERMISSION_GRANTED
+// ) {
+// Log.e("==================", "无法获取位置权限")
+// return
+// }
+// fusedLocationClient.lastLocation
+// .addOnSuccessListener(context, object : OnSuccessListener {
+// override fun onSuccess(location: Location?) {
+// result.invoke(location)
+// if (location != null) {
+// } else {
+//
+// Log.e("Location", "无法获取位置")
+// }
+// }
+// })
+ }
+
+ fun getInstallTime(context: Context): String {
+ val lastModified = File(context.applicationInfo.sourceDir).lastModified()
+ return convertTimestampToDate(lastModified)
+ }
+
+// fun getInstallSource(context: Context): String? {
+// return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
+// context.packageManager.getInstallSourceInfo(context.applicationInfo.packageName).installingPackageName
+// } else {
+// context.packageManager.getInstallerPackageName(context.applicationInfo.packageName)
+// }
+//
+// }
+
+ fun getBatteryInfo(context: Context): Int {
+ val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
+ val batteryLevel =
+ batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY) // 获取电池电量(0-100%)
+ val isCharging = batteryManager.isCharging // 是否在充电
+
+ return batteryLevel
+ }
+
+ /**
+ * ACCESS_FINE_LOCATION
+ *
+ * ACCESS_WIFI_STATE
+ */
+ fun getWifiInfo(context: Context): WifiInfo {
+ val wifiManager = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
+ return wifiManager.connectionInfo
+
+ }
+
+
+ /**
+ * READ_PHONE_STATE
+ */
+ fun getMobileNetworkInfo(context: Context): TelephonyManager? {
+ val telephonyManager =
+ context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
+ val operatorName = telephonyManager.networkOperatorName // 运营商名称
+
+
+ return telephonyManager
+
+
+// Log.d("Mobile Network", "Operator: $operatorName, Type: $networkType")
+ }
+
+ fun getNet(networkType: Int): String {
+ return when (networkType) {
+ TelephonyManager.NETWORK_TYPE_LTE -> "4G"
+
+ TelephonyManager.NETWORK_TYPE_NR -> "5G(Android 11+)"
+
+ TelephonyManager.NETWORK_TYPE_HSPA -> "3G"
+
+ TelephonyManager.NETWORK_TYPE_GPRS -> "2G"
+ else -> ""
+ }
+ }
+
+ fun getWebViewPackageInfo(context: Activity): PackageInfo? {
+ val packageManager: PackageManager = context.packageManager
+
+ // 如果系统支持直接获取 WebView 包信息 (Android 7.0 及以上)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ return WebView.getCurrentWebViewPackage()
+ }
+ // 如果不支持,尝试通过常见的 WebView 包名来获取信息
+ val webviewPackageNames = listOf(
+ "com.google.android.webview",
+ "com.android.webview",
+ "com.android.chrome"
+ )
+ for (packageName in webviewPackageNames) {
+ try {
+ val packageInfo = packageManager.getPackageInfo(packageName, 0)
+ if (packageInfo != null) {
+ return packageInfo
+ }
+ } catch (e: PackageManager.NameNotFoundException) {
+ // 忽略异常,继续尝试下一个包名
+ }
+ }
+ // 如果都没有找到,返回 null
+ return null
+ }
+
+ @SuppressLint("HardwareIds")
+ fun getAndroidID(context: Context): String? {
+ return Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
+ }
+
+
+ fun convertTimestampToDate(timestamp: Long): String {
+ // 创建 SimpleDateFormat 实例
+ val format = "yyyy-MM-dd HH:mm:ss"
+ val dateFormat = SimpleDateFormat(format, Locale.getDefault())
+ dateFormat.timeZone = TimeZone.getTimeZone("GMT") // 设置时区为 UTC,或者根据需要选择其他时区
+
+ // 将时间戳转换为 Date 对象
+ val date = Date(timestamp)
+
+ // 格式化 Date 对象为指定格式的字符串
+ return dateFormat.format(date)
+ }
+
+
+ fun getDeviceId(context: Context): String? =
+ try {
+ // 优先尝试获取 GAID
+ val adInfo = AdvertisingIdClient.getAdvertisingIdInfo(context)
+ if (!adInfo.isLimitAdTrackingEnabled && !adInfo.id.isNullOrEmpty()) {
+ Log.d("DeviceIdHelper", "Using GAID: ${adInfo.id}")
+ adInfo.id
+ } else {
+ Log.d("DeviceIdHelper", "GAID not available or user limited it, using AppSet ID")
+ null
+ }
+ } catch (e: Exception) {
+ Log.e("DeviceIdHelper", "GAID fetch failed: ${e.message}")
+ null
+ }
+
+ // ✅ 回退获取 App Set ID(Android 12+ 替代方案)
+// return@withContext try {
+// val appSetInfo: AppSetIdInfo = AppSet.getClient(context).appSetIdInfo.await()
+// Log.d("DeviceIdHelper", "Using App Set ID: ${appSetInfo.id}")
+// appSetInfo.id
+// } catch (e: Exception) {
+// Log.e("DeviceIdHelper", "App Set ID fetch failed: ${e.message}")
+// null
+// }
+
+}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index c3fa0b8..9ba800e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -3,5 +3,14 @@ plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
+ id("com.google.gms.google-services") version "4.4.2" apply false
+ id ("com.google.firebase.crashlytics") version "3.0.3" apply false
+
id("com.google.devtools.ksp") version "2.0.21-1.0.27" apply false
+}
+
+buildscript {
+ dependencies {
+ classpath("com.applovin.quality:AppLovinQualityServiceGradlePlugin:+")
+ }
}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 20e2a01..97a23a8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,7 +6,7 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 273ed5d..4bbd4ce 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -9,6 +9,8 @@ pluginManagement {
}
mavenCentral()
gradlePluginPortal()
+
+ maven { url = uri("https://artifacts.applovin.com/android") }
}
}
dependencyResolutionManagement {
@@ -16,6 +18,10 @@ dependencyResolutionManagement {
repositories {
google()
mavenCentral()
+
+ maven { url = uri("https://cboost.jfrog.io/artifactory/chartboost-ads/") }
+ maven { url = uri("https://android-sdk.is.com") }
+ maven { url = uri("https://artifact.bytedance.com/repository/pangle") }
}
}