Commit a8524ab6 authored by wanglei's avatar wanglei

...

parent 259dc618
Pipeline #1365 canceled with stages
# swiftcleanerphonehelper # swiftcleanerphonehelper
## 1.FCM (firebase 推送服务)
plugins { plugins {
id("com.android.application") id("com.android.application")
id("com.google.gms.google-services") id("com.google.gms.google-services")
alias(libs.plugins.kotlin.android)
id("com.google.firebase.crashlytics")
} }
android { android {
namespace = "com.swiftcleaner.chovey" namespace = "com.swiftcleaner.chovey"
compileSdk = 33 compileSdk = 34
defaultConfig { defaultConfig {
applicationId = "com.clean_swift" applicationId = "com.clean_swift"
minSdk = 28 minSdk = 28
targetSdk = 33 targetSdk = 34
versionCode = 1 versionCode = 1
versionName = "1.0" versionName = "1.0"
...@@ -43,10 +44,14 @@ android { ...@@ -43,10 +44,14 @@ android {
} }
buildFeatures { buildFeatures {
viewBinding = true viewBinding = true
buildConfig = true
} }
dependenciesInfo { dependenciesInfo {
includeInApk = true includeInApk = true
} }
kotlinOptions {
jvmTarget = "1.8"
}
} }
...@@ -55,6 +60,7 @@ dependencies { ...@@ -55,6 +60,7 @@ dependencies {
implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.8.0") implementation("com.google.android.material:material:1.8.0")
implementation("androidx.constraintlayout:constraintlayout:2.1.4") implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation(libs.core.ktx)
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
...@@ -64,6 +70,37 @@ dependencies { ...@@ -64,6 +70,37 @@ dependencies {
api("com.geyifeng.immersionbar:immersionbar:3.2.2") api("com.geyifeng.immersionbar:immersionbar:3.2.2")
api("com.airbnb.android:lottie:5.2.0") api("com.airbnb.android:lottie:5.2.0")
implementation ("com.google.firebase:firebase-messaging:23.2.1") implementation("com.google.firebase:firebase-messaging:23.2.1")
//solar 归因
implementation("com.reyun.solar.engine.oversea:solar-engine-core:1.2.8.3")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
//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.firebase:firebase-messaging-directboot")
//facebook
implementation("com.facebook.android:facebook-android-sdk:[8,9)")
} }
\ No newline at end of file
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
<uses-permission android:name="android.permission.READ_NOTIFICATIONS" /> <uses-permission android:name="android.permission.READ_NOTIFICATIONS" />
<queries> <queries>
<intent> <intent>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
...@@ -19,6 +20,7 @@ ...@@ -19,6 +20,7 @@
</queries> </queries>
<application <application
android:name="com.tool.zxdemo.ZxApplication"
android:allowBackup="true" android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
...@@ -37,15 +39,15 @@ ...@@ -37,15 +39,15 @@
<action android:name="com.google.firebase.MESSAGING_EVENT" /> <action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter> </intent-filter>
</service> </service>
<!-- <receiver--> <!-- <receiver-->
<!-- android:name="自定义 Receiver"--> <!-- android:name="自定义 Receiver"-->
<!-- android:enabled="true"--> <!-- android:enabled="true"-->
<!-- android:exported="false" >--> <!-- android:exported="false" >-->
<!-- <intent-filter>--> <!-- <intent-filter>-->
<!-- <action android:name="cn.jpush.android.intent.RECEIVER_MESSAGE" />--> <!-- <action android:name="cn.jpush.android.intent.RECEIVER_MESSAGE" />-->
<!-- <category android:name="com.clean_swift" />--> <!-- <category android:name="com.clean_swift" />-->
<!-- </intent-filter>--> <!-- </intent-filter>-->
<!-- </receiver>--> <!-- </receiver>-->
<activity <activity
android:name=".view.activity.SimilarPhotosActivity" android:name=".view.activity.SimilarPhotosActivity"
android:exported="false" /> android:exported="false" />
...@@ -104,6 +106,18 @@ ...@@ -104,6 +106,18 @@
<meta-data <meta-data
android:name="android.max_aspect" android:name="android.max_aspect"
android:value="2.4" /> android:value="2.4" />
<!-- 广告的appId每次打包正式需要改 -->
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713" />
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id" />
</application> </application>
</manifest> </manifest>
\ No newline at end of file
//package com.tool.zxdemo
//
//import android.Manifest
//import android.content.Intent
//import android.os.Build
//import android.os.Bundle
//import android.widget.Toast
//import androidx.activity.result.contract.ActivityResultContracts
//import androidx.appcompat.app.AppCompatActivity
//import androidx.core.view.isVisible
//import com.applovin.sdk.AppLovinSdk
//import com.reyun.solar.engine.SolarEngineConfig
//import com.reyun.solar.engine.SolarEngineManager
//import com.tool.zxdemo.admob.com.zxdemo.admob.AdmobHelper
//import com.tool.zxdemo.databinding.ActivityMainBinding
//import com.tool.zxdemo.http.com.zxdemo.http.ZxHttp
//import com.tool.zxdemo.service.PermanentNotifyService
//import com.tool.zxdemo.service.PermanentNotifyService.Companion.startOmgNotification
//import com.tool.zxdemo.utils.com.zxdemo.utils.GlobalTimer
//import com.tool.zxdemo.utils.com.zxdemo.utils.SpUtils
//import java.util.Random
//
//class MainActivity : AppCompatActivity() {
//
// private val binding by lazy {
// ActivityMainBinding.inflate(layoutInflater)
// }
//
// override fun onCreate(savedInstanceState: Bundle?) {
// super.onCreate(savedInstanceState)
// setContentView(binding.root)
// SolarEngineManager.getInstance().preInit(this, "f3ea1ff055365453")//(归因)同意隐私之前进行预加载
// var config = SolarEngineConfig.Builder().build()//同意之后再进行初始化
// SolarEngineManager.getInstance()
// .initialize(this, "APP_KEY", config)
// if (Build.VERSION.SDK_INT >= 33) {
// registerForActivityResult(ActivityResultContracts.RequestPermission()) {}.launch(
// Manifest.permission.POST_NOTIFICATIONS
// )
// }
// startOmgNotification()
//
// val random = Random()
// val randomNumber = random.nextInt(5)
// var sTimer = com.zxdemo.utils.SpUtils.getInstance().getBoolean("sTimer", false)
// binding.sTimer.isChecked = sTimer
//// if (sTimer) {
//// com.zxdemo.utils.GlobalTimer.getInstance()
//// .scheduleTask(3 * 1000L, 5 * 1000L)
//// }
//
// var sNotify = com.zxdemo.utils.SpUtils.getInstance().getBoolean("sNotify", false)
// binding.sNotify.isChecked = sNotify
// binding.sAd.isChecked = com.zxdemo.admob.AdmobHelper.useAdmob
// binding.sAd.setOnCheckedChangeListener { buttonView, isChecked ->
// com.zxdemo.admob.AdmobHelper.useAdmob = isChecked
// com.zxdemo.admob.AdmobHelper.init(this, {}, {})
// if (isChecked) {
// binding.buttonAppApplovin.isVisible = false
// } else {
// binding.buttonAppApplovin.apply {
// setOnClickListener {
// AppLovinSdk.getInstance(context).showMediationDebugger()
// }
// }.isVisible = true
// }
// }
// binding.sTimer.setOnCheckedChangeListener { buttonView, isChecked ->
// if (isChecked) {
// com.zxdemo.utils.GlobalTimer
// .scheduleTask(3 * 1000L, 20 * 1000L)
// } else {
// com.zxdemo.utils.GlobalTimer.stopTaskTimer()
// }
// com.zxdemo.utils.SpUtils.getInstance().putBoolean("sTimer", isChecked)
// }
// binding.sNotify.setOnCheckedChangeListener { buttonView, isChecked ->
// if (isChecked) {
// startOmgNotification()
// } else {
// val serviceIntent = Intent(this, PermanentNotifyService::class.java)
// stopService(serviceIntent)
// }
// com.zxdemo.utils.SpUtils.getInstance().putBoolean("sNotify", isChecked)
// }
//
// binding.buttonAppOpen.setOnClickListener {
// if (com.zxdemo.admob.AdmobHelper.isLoadingAppOpenAd) {
// Toast.makeText(this, "请求开屏广告中请稍后", Toast.LENGTH_SHORT).show()
// return@setOnClickListener
// }
// com.zxdemo.admob.AdmobHelper.showAppOpenAd(this, failed = {
// Toast.makeText(this, "显示开屏广告失败", Toast.LENGTH_SHORT).show()
// })
// }
// binding.buttonInterstitial.setOnClickListener {
// if (com.zxdemo.admob.AdmobHelper.isLoadingInterstitialAd) {
// Toast.makeText(this, "请求插屏广告中请稍后", Toast.LENGTH_SHORT).show()
// return@setOnClickListener
// }
// com.zxdemo.admob.AdmobHelper.showInterstitialAd(this, failed = {
// Toast.makeText(this, "显示插屏广告失败", Toast.LENGTH_SHORT).show()
// })
// }
// binding.buttonBanner.setOnClickListener {
// Toast.makeText(this, "请求Banner广告中请稍后...", Toast.LENGTH_SHORT).show()
// binding.buttonBanner.isClickable = false
// com.zxdemo.admob.AdmobHelper.showBannerAd(
// this,
// binding.frameBanner,
// completed = {
// binding.buttonBanner.isClickable = true
// println()
// },
// failed = {
// binding.buttonBanner.isClickable = true
// Toast.makeText(this, "显示Banner广告失败", Toast.LENGTH_SHORT).show()
// }
// )
// }
// binding.buttonNative.setOnClickListener {
// Toast.makeText(this, "请求原生广告中请稍后...", Toast.LENGTH_SHORT).show()
// binding.buttonNative.isClickable = false
// com.zxdemo.admob.AdmobHelper.showNativeAd(
// this,
// { nativeAd ->
// binding.buttonNative.isClickable = true
// binding.adNative.setNativeAd(nativeAd)
// },
// { nativeAdLoader, nativeMaxAd ->
// binding.buttonNative.isClickable = true
// binding.adNative.setNativeAd(nativeAdLoader, nativeMaxAd)
// },
// {
// binding.buttonNative.isClickable = true
// Toast.makeText(this, "显示原生广告失败", Toast.LENGTH_SHORT).show()
// }
// )
// }
// com.zxdemo.http.ZxHttp.getHttpConfig { }
// com.zxdemo.http.ZxHttp.getBlacklist { com.zxdemo.admob.AdmobHelper.blacklist = it }
// com.zxdemo.admob.AdmobHelper.init(this, {}, {})
// if (!com.zxdemo.admob.AdmobHelper.useAdmob) {
// binding.buttonAppApplovin.apply {
// setOnClickListener {
// AppLovinSdk.getInstance(context).showMediationDebugger()
// }
// }.isVisible = true
// }
// }
//}
\ No newline at end of file
package com.tool.zxdemo
import android.app.Activity
import android.app.Application
import android.app.KeyguardManager
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.os.Bundle
import android.os.PowerManager
import androidx.annotation.RequiresApi
import com.reyun.solar.engine.SolarEngineConfig
import com.reyun.solar.engine.SolarEngineManager
import com.zxdemo.receiver.AppInstallReceiver
import com.zxdemo.receiver.BatteryStatusReceiver
import com.zxdemo.receiver.UnlockReceiver
import com.zxdemo.utils.ActivityCollector
import com.zxdemo.utils.DeviceUtils
import com.zxdemo.utils.FcmUtils
import com.zxdemo.utils.InstallRefeerUtils
import com.zxdemo.utils.SpUtils
import java.time.LocalTime
class ZxApplication : Application() {
companion object {
lateinit var context: Context
var APP_STATE = 0
val packname = "com.testsdktestestababa.aa.com"
var isDeviceLocked: Boolean = false
var isAppInForeground: Boolean = false
var isScreenOn: Boolean = false
var GID = ""
val APP_KEY = "f3ea1ff055365453"
val noLoadingActivities = listOf(
"full", // 过滤全屏广告
"adActivity",
"AppLovinFullscreenActivity",
// 返回前台时不跳转启动页的 activity
)
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate() {
super.onCreate()
DeviceUtils.getGoogleAdvertiserId()
context = applicationContext
sendBroadCast()
registerActivityLifecycleCallbacks()
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
isScreenOn = powerManager.isInteractive
InstallRefeerUtils.init()
}
@RequiresApi(Build.VERSION_CODES.O)
fun sendBroadCast() {
//注册广播
AppInstallReceiver.registerReceiver(context)
UnlockReceiver().initBroadcast(context)
val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
if (context != null) {
context.registerReceiver(BatteryStatusReceiver(), filter)
}
var minute = SpUtils.getInstance().getInt("MINUTE", -1)
if (minute < 0) {
minute = LocalTime.now().minute
} else {
SpUtils.getInstance().putInt("MINUTE", minute)
}
FcmUtils().initFirebase(context)
FcmUtils().subscribeToTopic("${packname}_push_$minute")
var config = SolarEngineConfig.Builder().build()
SolarEngineManager.getInstance()
.initialize(context, APP_KEY, config)
}
private var lastTimePause = 0L
private var lastTimeResume = 0L
private fun isHotLaunch(): Boolean {
if ((lastTimeResume - lastTimePause) > 5000) {
return true
}
return false
}
private fun registerActivityLifecycleCallbacks() {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
private var count = 0
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
}
override fun onActivityStarted(activity: Activity) {
count++
lastTimeResume = System.currentTimeMillis()
if (count == 1 && isHotLaunch()) {
val topActivity = ActivityCollector.getTopActivity()
if (topActivity == null) {
// 跳转启动页
return
}
var flag = noLoadingActivities.all {
!topActivity.localClassName.contains(
it,
true
)
}
if (flag) {
// 跳转启动页
}
lastTimeResume = 0
}
}
override fun onActivityResumed(activity: Activity) {
APP_STATE = 1
isAppInForeground = true
}
override fun onActivityPaused(activity: Activity) {
APP_STATE = 2
lastTimePause = System.currentTimeMillis()
isAppInForeground = false
}
override fun onActivityStopped(activity: Activity) {
count--
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
}
override fun onActivityDestroyed(activity: Activity) {
}
})
val keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
isDeviceLocked = keyguardManager.isKeyguardLocked
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
package com.zxdemo.http
import android.util.Log
import com.swiftcleaner.chovey.BuildConfig
import com.tool.zxdemo.ZxApplication
import com.zxdemo.utils.AESUtils
import com.zxdemo.utils.DeviceUtils
import com.zxdemo.utils.HttpUtils
import com.zxdemo.utils.SpUtils
import okhttp3.Call
import okhttp3.Callback
import okhttp3.Response
import org.json.JSONObject
import java.io.IOException
object ZxHttp {
private const val REPORT_DOMAIN = "https://rp.fluxbettingtips.xyz"
private const val INTERFACE_DOMAIN = "https://api.fluxbettingtips.xyz"
fun getHttpConfig(requestBack: () -> Unit) {
var referrer = ""
var referrerSp = SpUtils.getInstance().getString("referrer", "")
if (referrerSp.isNotEmpty()) {
// referrer = Base64.getEncoder().encodeToString(referrer.toByteArray())
referrer = android.util.Base64.encodeToString(referrer.toByteArray(), android.util.Base64.DEFAULT)
}
val urlstr = StringBuffer()
urlstr.append("$INTERFACE_DOMAIN/ccspk?pkg=${ZxApplication.packname}")
urlstr.append("&referrer=$referrer")
urlstr.append("&vn=${BuildConfig.VERSION_NAME}")
urlstr.append("&vc=${BuildConfig.VERSION_CODE}")
urlstr.append("&device=${ZxApplication.GID}")
urlstr.append("&aid=${DeviceUtils.getUID()}")
urlstr.append("&mode=2")
// var url="https://api.swiftdevinc.xyz/ccspk?pkg=${ZxApplication.packname}&referrer=$referrer"
// var url = "https://feedapihk.zhangxinhulian.com/ccspk?pkg=${ZxApplication.packname}&mode=2"
HttpUtils.get(
urlstr.toString(),
object :
Callback {
override fun onFailure(call: Call, e: IOException) {
// 请求失败时的处理逻辑
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
requestBack.invoke()
// 请求成功时的处理逻辑
try {
val responseString = response.body?.string()
if (responseString != null && responseString.contains("result")) {
var jsonObject = JSONObject(responseString)
var status = jsonObject.getInt("status")
if (status == 200) {
var result = jsonObject.getJSONObject("result")
var data = result.getString("data")
var decrypt = AESUtils.decrypt(data.toString())
Log.d("TAG", "onResponse:decrypt--- $decrypt")
SpUtils.getInstance().saveJsonObjectToSp(decrypt)
}
}
} catch (e: IOException) {
e.printStackTrace()
} finally {
// 确保响应体被关闭
response.body?.close()
}
}
})
}
fun getBlacklist(requestBack: (Int) -> Unit) {
var jsonParms = DeviceUtils.getConfigParms()
// val url = "https://api.swiftdevinc.xyz?pkg=${ZxApplication.packname}"
val url = "$INTERFACE_DOMAIN/jsoncl?pkg=${ZxApplication.packname}"
var json = JSONObject()
json.put("bp", jsonParms)
HttpUtils.postJson(url, json.toString(), object : Callback {
override fun onFailure(call: Call, e: IOException) {
// 请求失败时的处理逻辑
requestBack.invoke(1)
e.printStackTrace()
}
override fun onResponse(call: Call, response: Response) {
// 请求成功时的处理逻辑
try {
val responseString = response.body?.string()
Log.d("TAG", "onResponse: $responseString")
if (responseString != null && responseString.contains("data")) {
var data =
JSONObject(responseString).getJSONObject("result").getString("data")
if (data == "true") {
//黑名单中,不展示任何推送
requestBack.invoke(0)
} else {
requestBack.invoke(1)
Log.d("TAG", "onResponse: 展示推送")
}
} else {
requestBack.invoke(1)
}
} catch (e: IOException) {
e.printStackTrace()
requestBack.invoke(1)
} finally {
// 确保响应体被关闭
response.body?.close()
}
}
})
}
fun getHttpReportInterface(action: String, value: String, ext: JSONObject?) {
var bp = DeviceUtils.getConfigParms()
// val url = "https://rp.swiftdevinc.xyz/jsonsp?pkg=${ZxApplication.packname}"
val url = "$REPORT_DOMAIN/jsonsp?pkg=${ZxApplication.packname}"
var json = JSONObject()
json.put("bp", bp)
var jData = JSONObject()
jData.put("action", action)
if (value.isNotEmpty()) {
jData.put("value", value)
}
jData.put("ext", ext)
json.put("data", jData)
Log.d("TAG", "getHttpReportInterface: $json")
var result = AESUtils.encrypt(json.toString())
HttpUtils.postJson(url, result, object : Callback {
override fun onFailure(call: Call, e: IOException) {
// 请求失败时的处理逻辑
e.printStackTrace()
Log.d("TAG", "onFailure:上报失败 ${e.printStackTrace()}")
}
override fun onResponse(call: Call, response: Response) {
Log.d("TAG", "onResponse:上报成功 ${response.body} --$json")
// 请求成功时的处理逻辑
try {
val responseString = response.body?.string()
if (responseString != null && responseString.contains("result")) {
println("Response -getHttpReportInterface-: $responseString")
var jsonObject = JSONObject(responseString)
var result = jsonObject.getJSONObject("result")
var data = result.getString("data")
var decrypt = AESUtils.decrypt(data.toString())
println("Response --: $decrypt")
}
} catch (e: IOException) {
e.printStackTrace()
} finally {
// 确保响应体被关闭
response.body?.close()
}
}
})
}
}
\ No newline at end of file
package com.tool.zxdemo.notity
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.media.AudioAttributes
import android.os.Build
import android.os.Handler
import android.os.HandlerThread
import android.util.Log
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import com.swiftcleaner.chovey.R
import com.swiftcleaner.chovey.view.MainActivity
import com.tool.zxdemo.ZxApplication
import com.tool.zxdemo.ZxApplication.Companion.isAppInForeground
import com.tool.zxdemo.ZxApplication.Companion.isDeviceLocked
import com.tool.zxdemo.ZxApplication.Companion.isScreenOn
import com.zxdemo.http.ZxHttp
import com.zxdemo.utils.SpUtils
import java.util.Random
object NotificationUtils {
val ID_CLEAN_JUNK = 0
val ID_APP_MANAGER = 1
val ID_WHATSAPP = 2
val ID_LARGE_FILE = 3
val ID_SCREENTSHOT = 4
val ID_BATTERY_LOW = 5
private val NOTIFICATION_IDS = intArrayOf(
ID_CLEAN_JUNK,
ID_APP_MANAGER,
ID_WHATSAPP,
ID_LARGE_FILE,
ID_SCREENTSHOT,
ID_BATTERY_LOW,
)
private var handlerThread: HandlerThread? = null
private var handler: Handler? = null
private const val CHANNEL_ID = "notification_id" // 通知渠道ID
private const val CHANNEL_NAME = "fcm_channel" // 通知渠道名称
private const val NOTIFICATION_SHOW = -1
private const val NOTICE_CURRENT = "notice_current"
fun createNotificationChannel(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH
)
channel.setShowBadge(false)
channel.setSound(null, AudioAttributes.Builder().build())
channel.enableVibration(false)
val manager = ContextCompat.getSystemService(context, NotificationManager::class.java)
manager?.createNotificationChannel(channel)
}
}
fun sendNotification(
context: Context,
intent: Intent,
bigRemoteViews: RemoteViews?,
smallRemoteViews: RemoteViews?,
title: String,
action:String,
value: String,
isStay: Boolean? = false
) {
var notificationCount = SpUtils.getInstance().getInt("notificationCount", 45)
val currentNum =
SpUtils.getInstance().getInt(NOTICE_CURRENT, 0)
println("isDeviceLocked:$isDeviceLocked isAppInForeground:$isAppInForeground isScreenOn:${!isScreenOn} $value")
if (isDeviceLocked || isAppInForeground || !isScreenOn || (notificationCount != 0 && currentNum >= notificationCount)) {
return
}
createNotificationChannel(context)
val notificationManager = ContextCompat.getSystemService(
ZxApplication.context,
NotificationManager::class.java
) as NotificationManager
val pendingIntent = PendingIntent.getActivity(
context, // context
0, // request code
intent, // intent
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // flags
)
val builder = NotificationCompat.Builder(context, CHANNEL_ID)
.setLargeIcon(
BitmapFactory.decodeResource(
context.resources,
R.mipmap.ic_launcher
)
)
.setSmallIcon(R.mipmap.ic_launcher_round)
.setVibrate(longArrayOf(0)) // 禁止震动
.setSound(null) // 禁止声音
.setContentTitle(title)
// .setContentText(context.resources.getString(R.string.app_name))
.setContentIntent(pendingIntent)
// .setDeleteIntent(deletePendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setAutoCancel(true)
var small = bigRemoteViews
//Android 12以下需要适配小RemoteViews
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
small = smallRemoteViews
}
builder.setContent(small)
builder.setCustomHeadsUpContentView(small)
builder.setCustomContentView(small)
builder.setCustomBigContentView(bigRemoteViews)
var actionId = intent.getIntExtra("actionId", 0)
if (actionId < 10) incrementNotification()
//存入推送的时间
if (isStay == false) {
ZxHttp.getHttpReportInterface(action, value, null)
}
notificationManager.notify(actionId, builder.build())
}
fun sendNotification(context: Context, action: String, value: String) {
var actionId = nextNotificationId
val bigRemoteViews = RemoteViews(context.packageName, R.layout.notice_expand)
val smallRemoteViews = RemoteViews(context.packageName, R.layout.notice_fold)
when (actionId) {
ID_CLEAN_JUNK -> {
}
ID_APP_MANAGER -> {
}
ID_WHATSAPP -> {
}
ID_LARGE_FILE -> {
}
ID_SCREENTSHOT -> {
}
ID_BATTERY_LOW -> {
}
else -> {
return
}
}
val flag = PendingIntent.FLAG_IMMUTABLE
val btnRequestCode = Random().nextInt(1000)
var intent = Intent(context, MainActivity::class.java)
intent.putExtra("actionId", actionId)
val btnPendingIntent = PendingIntent.getActivity(context, btnRequestCode, intent, flag)
// bigRemoteViews.setOnClickPendingIntent(R.id.btn_notice, btnPendingIntent)
// smallRemoteViews.setOnClickPendingIntent(R.id.notice_btn, btnPendingIntent)
val open = SpUtils.getInstance().getInt("NotificationStayStatus", 0)
if (open == 1) {
val num = SpUtils.getInstance().getInt("NotificationStayCount", 5)
val delay = SpUtils.getInstance().getInt("NotificationStayDelay", 4000).toLong()
handlerThread = HandlerThread("NotificationHandlerThread")
handlerThread!!.start()
// 创建 Handler
handler = Handler(handlerThread!!.getLooper())
for (i in 1..num) {
val time = i * delay
handler?.postDelayed(Runnable {
if (ZxApplication.APP_STATE == 1) {
if (handler != null) {
handler?.removeCallbacksAndMessages(null)
}
return@Runnable
}
if (ZxApplication.APP_STATE != 1) {
sendNotification(
context,
intent,
bigRemoteViews,
smallRemoteViews,
"titletitle",
action,
value, isStay = true
)
if (i == 1) {
Log.d("TAG", "sendNotification:isStay == true $value $actionId ")
ZxHttp.getHttpReportInterface(action, "$actionId", null)
}
}
}, time)
}
}else{
sendNotification(
context,
intent,
bigRemoteViews,
smallRemoteViews,
"titletitle",
action,
value, isStay = false
)
}
}
private var currentNotificationIdIndex = -1
val nextNotificationId: Int
get() {
// 将当前通知 ID 索引加 1
currentNotificationIdIndex++
// 如果当前通知 ID 索引超出列表范围,则将其重置为 0
if (currentNotificationIdIndex >= NOTIFICATION_IDS.size) {
currentNotificationIdIndex = 0
}
// 返回下一个通知 ID
return NOTIFICATION_IDS[currentNotificationIdIndex]
}
private fun incrementNotification() {
var s = SpUtils.getInstance().getInt(NOTICE_CURRENT, 0)
s++
SpUtils.getInstance().putInt(NOTICE_CURRENT, s)
}
fun checkNotificationPermission(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
NotificationManagerCompat.from(context).areNotificationsEnabled()
} else {
true
}
}
}
package com.zxdemo.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.tool.zxdemo.notity.NotificationUtils
import com.zxdemo.utils.SpUtils
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
class AppInstallReceiver : BroadcastReceiver() {
companion object {
fun registerReceiver(context: Context) {
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED)//卸载
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED)//安装
intentFilter.addDataScheme("package")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.registerReceiver(
AppInstallReceiver(),
intentFilter,
Context.RECEIVER_EXPORTED
)
} else {
context.registerReceiver(AppInstallReceiver(), intentFilter)
}
}
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context, intent: Intent) {
//获取当前时间和上一次推送的时间
var current = LocalDateTime.now()
val intervalTime = 1L //间隔时间(分钟)
val lastTime =
SpUtils.getInstance().getString("NOTICE_APP_TIME", "")
var parsedDateTime: LocalDateTime = current
if (lastTime != "") {
parsedDateTime =
LocalDateTime.parse(lastTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
}
// 计算两个时间点之间的差异
val minutesBetween = ChronoUnit.MINUTES.between(parsedDateTime, current)
if (minutesBetween >= intervalTime || minutesBetween.toInt() == 0) {
intent.action?.let {
Log.d("TAG", "onReceive:安装卸载推送 ${intent.action}")
NotificationUtils.sendNotification(context, "showNotification", "receive_app")
SpUtils.getInstance().putString(
"NOTICE_APP_TIME",
current.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
)
}
}
}
}
package com.zxdemo.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.BatteryManager
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.tool.zxdemo.notity.NotificationUtils
import com.zxdemo.utils.SpUtils
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
class BatteryStatusReceiver() : BroadcastReceiver() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context?, batteryIntent: Intent?) {
val level = batteryIntent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1) ?: -1
val scale = batteryIntent?.getIntExtra(BatteryManager.EXTRA_SCALE, -1) ?: -1
val state = batteryIntent?.getIntExtra(BatteryManager.EXTRA_STATUS, -1) ?: -1
val now =
batteryIntent?.getIntExtra(BatteryManager.BATTERY_PROPERTY_CURRENT_NOW.toString(), -1)
?: -1
val health = batteryIntent?.getIntExtra(BatteryManager.EXTRA_HEALTH, -1) ?: -1
val voltage = batteryIntent?.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1) ?: -1
val temperature = batteryIntent?.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1) ?: -1
val technology = batteryIntent?.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY) ?: "Unknown"
val batteryPct = level * 100 / scale.toFloat()
val intervalTime = SpUtils.getInstance().getInt("batteryNotificationInterval", 5)
var current = LocalDateTime.now()
var lastTime =
SpUtils.getInstance().getString("NOTICE_BATTERY_TIME", "")
var parsedDateTime = current
if (lastTime != "") {
parsedDateTime =
LocalDateTime.parse(lastTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
}
var batteryNotificationStatus = SpUtils.getInstance().getInt("batteryNotificationStatus", 0)
val minutesBetween = ChronoUnit.MINUTES.between(parsedDateTime, current)
// Log.d("TAG", "onReceive:电池 $minutesBetween $intervalTime")
if ((batteryNotificationStatus == 1 && (minutesBetween > intervalTime && minutesBetween.toInt() == 0)) && (state == BatteryManager.BATTERY_STATUS_CHARGING || (level < 20 && level > 10))) {
Log.d("TAG", "onReceive: 电池推送")
if (context != null) {
NotificationUtils.sendNotification(
context,
"showNotification",
"receive_battery"
)
SpUtils.getInstance().putString(
"NOTICE_BATTERY_TIME",
current.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
)
}
}
}
}
\ No newline at end of file
package com.zxdemo.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
class FcmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d("TAG", "onReceive:$intent ")
}
}
\ No newline at end of file
package com.zxdemo.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.tool.zxdemo.ZxApplication
import com.tool.zxdemo.notity.NotificationUtils
import com.zxdemo.utils.SpUtils
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
class UnlockReceiver : BroadcastReceiver() {
companion object {
var mIsScreenOn = true
var isLock = false
}
fun initBroadcast(context: Context) {
Log.d("onReceive", "initBroadcast")
val filter = IntentFilter()
filter.addAction(Intent.ACTION_SCREEN_OFF)
filter.addAction(Intent.ACTION_SCREEN_ON)
filter.addAction(Intent.ACTION_USER_PRESENT)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.registerReceiver(this, filter, Context.RECEIVER_EXPORTED)
} else {
context.registerReceiver(this, filter)
}
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
when (action) {
Intent.ACTION_SCREEN_ON -> {
mIsScreenOn = true
}
Intent.ACTION_SCREEN_OFF -> {
mIsScreenOn = false
isLock = true
}
Intent.ACTION_USER_PRESENT -> {
isLock = false
// 执行解锁后的操作,比如启动服务、发送通知等
var lockNotificationInterval =
SpUtils.getInstance().getInt("lockNotificationInterval")
val lastTime =
SpUtils.getInstance()
.getString("NOTICE_UNLOCK_TIME", "")
var current = LocalDateTime.now()
var parsedDateTime: LocalDateTime = current
if (lastTime != "") {
parsedDateTime = LocalDateTime.parse(
lastTime,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")
)
}
val minutesBetween = ChronoUnit.MINUTES.between(parsedDateTime, current)
Log.d("TAG", "onReceive:: $minutesBetween")
var lockNotificationStatus =
SpUtils.getInstance().getInt("lockNotificationStatus", 0)
var lockNotificationCount =
SpUtils.getInstance().getInt("lockNotificationCount", 45)
var count = SpUtils.getInstance().getInt("NOTICE_UNLOCK_COUNT", 0)
//获取当前时间和上一次推送的时间
if (lockNotificationStatus == 1 && mIsScreenOn && !isLock && (minutesBetween.toInt() == 0 || minutesBetween > lockNotificationInterval)) {
if (lockNotificationCount == 0 || count < lockNotificationCount) {
Log.d("TAG", "onReceive: 解锁推送")
NotificationUtils.sendNotification(
ZxApplication.context,
"showNotification",
"receive_unlock"
)
SpUtils.getInstance().putString(
"NOTICE_UNLOCK_COUNT",
current.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
)
}
}
}
else -> {
}
}
}
}
\ No newline at end of file
package com.zxdemo.service
import android.util.Log
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.tool.zxdemo.ZxApplication
import com.tool.zxdemo.notity.NotificationUtils
import com.zxdemo.http.ZxHttp
class FcmService : FirebaseMessagingService() {
override fun onMessageReceived(message: RemoteMessage) {
Log.d("TAG", "onMessageReceived: ${message.data}")
ZxHttp.getHttpReportInterface("FCM_Received", "", null)
NotificationUtils.sendNotification(ZxApplication.context, "showNotification", "FCM")
}
}
\ No newline at end of file
package com.tool.zxdemo.service
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import android.graphics.BitmapFactory
import android.os.Build
import android.os.IBinder
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import com.swiftcleaner.chovey.R
import com.swiftcleaner.chovey.view.MainActivity
class PermanentNotifyService : Service() {
companion object {
var isRunning = false
fun Context.startOmgNotification() {
val intent = Intent(this, PermanentNotifyService::class.java)
// if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) {
// return
// }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
}
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (!isRunning) {
val notification = createPermanentNotification(applicationContext)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(16, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC)
} else {
startForeground(16, notification)
}
isRunning = true
}
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onDestroy() {
isRunning = false
super.onDestroy()
// 取消监听
}
private fun createPermanentNotification(context: Context): Notification {
val isOngoing = true //是否持续(为不消失的常驻通知)
val channelName = "Foreground Service Channel"
val channelId = "Service_Id"
val category = Notification.CATEGORY_SERVICE
val contentView = RemoteViews(context.packageName, R.layout.notice_fold)
val expendView = RemoteViews(context.packageName, R.layout.notice_fold)
val cleanIntent = PendingIntent.getActivity(
context, // context
0, // request code
Intent("CleanJunkActivity", null, context, MainActivity::class.java), // intent
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // flags
)
// contentView.setOnClickPendingIntent(R.id.tv_clean, cleanIntent)
// expendView.setOnClickPendingIntent(R.id.tv_clean, cleanIntent)
val appIntent = PendingIntent.getActivity(
context, // context
0, // request code
Intent("AppManagerActivity", null, context, MainActivity::class.java), // intent
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // flags
)
// contentView.setOnClickPendingIntent(R.id.tv_app, appIntent)
// expendView.setOnClickPendingIntent(R.id.tv_app, appIntent)
val whatsIntent = PendingIntent.getActivity(
context, // context
0, // request code
Intent("CleanerActivity", null, context, MainActivity::class.java), // intent
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // flags
)
// contentView.setOnClickPendingIntent(R.id.tv_whatsapp, whatsIntent)
// expendView.setOnClickPendingIntent(R.id.tv_whatsapp, whatsIntent)
val largeIntent = PendingIntent.getActivity(
context, // context
0, // request code
Intent(
"LargeFileCleanActivity",
null,
context,
MainActivity::class.java
), // intent
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE // flags
)
// contentView.setOnClickPendingIntent(R.id.tv_large, largeIntent)
// expendView.setOnClickPendingIntent(R.id.tv_large, largeIntent)
val nfIntent = Intent(context, MainActivity::class.java)
val pendingIntent =
PendingIntent.getActivity(context, 0, nfIntent, PendingIntent.FLAG_IMMUTABLE)
val builder = NotificationCompat.Builder(context, channelId)
// builder.setSmallIcon(R.drawable.lig) //设置状态栏内的小图标
// builder.setLargeIcon(BitmapFactory.decodeResource(context.resources, R.drawable.icon_apk))
builder.setContentTitle(context.resources.getString(R.string.app_name))
builder.setContentIntent(pendingIntent) //设置PendingIntent
builder.setVisibility(NotificationCompat.VISIBILITY_PRIVATE) //设置通知公开可见
builder.setAutoCancel(false)
builder.priority = NotificationCompat.PRIORITY_MAX //优先级为:重要通知
builder.setWhen(System.currentTimeMillis())
builder.setCustomContentView(contentView)
builder.setCustomBigContentView(expendView)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel =
NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_LOW)
channel.lockscreenVisibility = 1
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
builder.setChannelId(channelId)
}
return builder.build()
}
}
\ No newline at end of file
package com.zxdemo.utils
import android.util.Base64
import java.security.SecureRandom
import javax.crypto.Cipher
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
object AESUtils {
private const val aesKey = "mj7lm6bfcez79lr8"
private val cipher by lazy {
Cipher.getInstance("AES/GCM/NoPadding")
}
fun encrypt(content: String): String {
try {
val iv = ByteArray(12).apply {
SecureRandom().nextBytes(this)
}
val contentBytes = content.toByteArray(Charsets.UTF_8)
val params = GCMParameterSpec(128, iv)
cipher.init(
Cipher.ENCRYPT_MODE,
secretKey, params
)
val encryptData = cipher.doFinal(contentBytes)
if (encryptData.size != contentBytes.size + 16) {
throw IllegalStateException("Encryption failed")
}
val message = ByteArray(12 + contentBytes.size + 16)
System.arraycopy(iv, 0, message, 0, 12)
System.arraycopy(encryptData, 0, message, 12, encryptData.size)
return String(Base64.encode(message, Base64.NO_WRAP), Charsets.UTF_8)
} catch (_: Exception) {
}
return content
}
@Synchronized
fun decrypt(content: String): String {
try {
val con = content.replace(" ".toRegex(), "+")
val contentByte = Base64.decode(con, Base64.NO_WRAP)
require(contentByte.size >= 12 + 16)
val params = GCMParameterSpec(128, contentByte, 0, 12)
cipher.init(
Cipher.DECRYPT_MODE,
secretKey, params
)
val decryptData = cipher.doFinal(contentByte, 12, contentByte.size - 12)
return String(decryptData, Charsets.UTF_8)
} catch (_: Exception) {
}
return content
}
private val secretKey by lazy {
SecretKeySpec(aesKey.toByteArray(), "AES")
}
}
\ No newline at end of file
package com.zxdemo.utils
import android.app.Activity
import java.util.Stack
object ActivityCollector {
private val activityStack = Stack<Activity>()
/**
* 添加Activity到堆栈
*/
fun add(activity: Activity) {
activityStack.add(activity)
}
/**
* 移除Activity从堆栈
*/
fun remove(activity: Activity) {
activityStack.remove(activity)
}
/**
* 结束指定的Activity
*/
fun finish(activity: Activity?) {
if (activity != null) {
activityStack.remove(activity)
activity.finish()
}
}
/**
* 结束所有Activity
*/
fun finishAll() {
for (activity in activityStack) {
activity?.finish()
}
activityStack.clear()
}
/**
* 检查Activity是否存在于堆栈中
*/
fun isActivityInStack(cls: Class<*>?): Boolean {
var isExist = false
if (cls != null) {
for (activity in activityStack) {
if (cls == activity.javaClass) {
isExist = true
break
}
}
}
return isExist
}
fun getAll(): List<Activity> {
return activityStack
}
fun getTopActivity(): Activity? {
return if (activityStack.isEmpty()) {
null
} else {
activityStack.peek()
}
}
}
\ No newline at end of file
package com.zxdemo.utils
import android.os.Build
import android.provider.Settings
import android.util.Log
import android.webkit.WebSettings
import com.google.android.gms.ads.identifier.AdvertisingIdClient
import com.tool.zxdemo.ZxApplication
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.json.JSONObject
import java.util.UUID
object DeviceUtils {
fun getScreenHeight(): Int {
return ZxApplication.context.resources.displayMetrics.heightPixels
}
fun getScreenWidth(): Int {
return ZxApplication.context.resources.displayMetrics.widthPixels
}
fun getDeviceModel(): String {
return Build.MODEL
}
fun getManufacturer(): String {
return Build.MANUFACTURER
}
fun getAndroidVersion(): String {
return Build.VERSION.RELEASE
}
fun getAppVersion(): String {
return try {
val packageInfo = ZxApplication.context.packageManager.getPackageInfo(
ZxApplication.context.packageName,
0
)
packageInfo.versionName
} catch (e: Exception) {
"Unknown"
}
}
fun getAndroidID(): String {
return Settings.Secure.getString(
ZxApplication.context.contentResolver,
Settings.Secure.ANDROID_ID
)
}
fun getGoogleAdvertiserId() {
GlobalScope.launch(Dispatchers.IO) {
try {
ZxApplication.GID =
AdvertisingIdClient.getAdvertisingIdInfo(ZxApplication.context).id ?: ""
} catch (e: Exception) {
Log.d("TAG", "getGoogleAdvertiserId: ${e.printStackTrace()}")
}
}
}
fun getUID(): String {
return UUID.randomUUID().toString() + System.currentTimeMillis()
}
fun getUserAgent(): String {
return WebSettings.getDefaultUserAgent(ZxApplication.context)
}
fun getAndroidVersionCode(): Int {
return Build.VERSION.SDK_INT
}
fun getConfigParms(): JSONObject {
var packname = "com.a.xxxxxx.m.storage.zxcv"
var jsonObject = JSONObject()
jsonObject.put("${packname}_1", getScreenHeight())//高度
jsonObject.put("${packname}_2", getScreenWidth())//宽度
jsonObject.put("${packname}_3", getDeviceModel())//手机型号
jsonObject.put("${packname}_4", getManufacturer())//手机厂商
jsonObject.put("${packname}_5", getAndroidVersion())//android系统版本号
jsonObject.put("${packname}_8", getAppVersion())//APP版本号,如:1.1.2
jsonObject.put("${packname}_9", getAndroidID())//Android id
jsonObject.put("${packname}_10", ZxApplication.GID)//Google advertiser id
jsonObject.put("${packname}_11", getUserAgent())//User agent
jsonObject.put("${packname}_12", getUID())//用户id
jsonObject.put("${packname}_13", "android")//platform 默认android
jsonObject.put("${packname}_14", getAndroidVersionCode())//android版本,如:13
// jsonObject.put("${packname}_23","en")//语言
// jsonObject.put("${packname}_24", BuildConfig.BUILD_TYPE)//环境
return jsonObject
}
}
\ No newline at end of file
package com.zxdemo.utils
import android.content.Context
import android.util.Log
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.FirebaseApp
import com.google.firebase.messaging.FirebaseMessaging
import com.zxdemo.http.ZxHttp
class FcmUtils {
fun initFirebase(context: Context?) {
FirebaseApp.initializeApp(context!!)
}
fun subscribeToTopic(topic: String) {
Log.d("TAG", "subscribeToTopic: $topic")
FirebaseMessaging.getInstance().subscribeToTopic(topic).addOnCompleteListener {
Log.d("TAG", "subscribeToTopic:isSuccessful ${it.isSuccessful}")
if (it.isSuccessful) {
ZxHttp.getHttpReportInterface("FCM_Topic$topic", "", null)
Log.d("FCMUtil", "suc")
} else {
Log.d("FCMUtil", "fail")
}
}
}
fun unsubscribeFromTopic(topic: String) {
FirebaseMessaging.getInstance().unsubscribeFromTopic(topic)
.addOnCompleteListener(OnCompleteListener<Void?> { task ->
if (task.isSuccessful) {
} else {
}
})
}
}
\ No newline at end of file
package com.zxdemo.utils
import android.util.Log
import com.tool.zxdemo.ZxApplication
import com.tool.zxdemo.ZxApplication.Companion.isAppInForeground
import com.tool.zxdemo.ZxApplication.Companion.isDeviceLocked
import com.tool.zxdemo.ZxApplication.Companion.isScreenOn
import com.tool.zxdemo.notity.NotificationUtils
import java.util.Timer
import java.util.TimerTask
object GlobalTimer {
private var instance: GlobalTimer? = null
private var taskTimer: Timer? = null
private var isTimerActive = false
// 单例模式获取实例
fun getInstance(): GlobalTimer {
if (instance == null) {
instance = GlobalTimer
}
return instance!!
}
// 调度任务
fun scheduleTask(delay: Long, period: Long) {
synchronized(GlobalTimer::class) {
ensureTimerIsStopped() // 确保定时器未运行
taskTimer = Timer() // 创建新的 Timer 实例
val task = object : TimerTask() {
override fun run() {
Log.d("glc", "Scheduled task is running")
Log.d("glc", "${!isDeviceLocked} ${!isAppInForeground} $isScreenOn")
// 确保设备处于交互状态,未锁定,且应用未暂停
NotificationUtils.sendNotification(ZxApplication.context,"showNotification","timer")
}
}
taskTimer!!.schedule(task, delay, period) // 调度任务
isTimerActive = true // 设置定时器状态为活跃
}
}
// 确保定时器停止
private fun ensureTimerIsStopped() {
if (isTimerActive) {
if (taskTimer != null) {
taskTimer!!.cancel()
taskTimer!!.purge() // 清除所有取消的任务
}
isTimerActive = false // 重置定时器状态
}
}
// 停止任务定时器
fun stopTaskTimer() {
synchronized(GlobalTimer::class) {
ensureTimerIsStopped() // 停止定时器
}
}
// 检查任务定时器是否活跃
fun isTaskTimerActive(): Boolean {
return isTimerActive
}
}
package com.zxdemo.utils
import okhttp3.Callback
import okhttp3.FormBody
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
object HttpUtils {
private val client = OkHttpClient()
// GET 请求
fun get(url: String, callback: Callback) {
val request = Request.Builder().url(url).build()
client.newCall(request).enqueue(callback)
}
// POST 请求,传入 JSON 字符串
fun postJson(url: String, json: String, callback: Callback) {
val mediaType = "application/json; charset=utf-8".toMediaTypeOrNull()
val body: RequestBody = RequestBody.create(mediaType, json)
val request = Request.Builder().url(url).post(body).build()
client.newCall(request).enqueue(callback)
}
// POST 请求,传入表单数据
fun postForm(url: String, params: Map<String, String>, callback: Callback) {
val formBody = FormBody.Builder().apply {
params.forEach { (key, value) ->
add(key, value)
}
}.build()
val request = Request.Builder().url(url).post(formBody).build()
client.newCall(request).enqueue(callback)
}
}
\ No newline at end of file
package com.zxdemo.utils
import android.text.TextUtils
import android.util.Log
import com.android.installreferrer.api.InstallReferrerClient
import com.android.installreferrer.api.InstallReferrerStateListener
import com.tool.zxdemo.ZxApplication
import com.zxdemo.http.ZxHttp
import org.json.JSONObject
object InstallRefeerUtils {
fun init() {
if (TextUtils.isEmpty(SpUtils.getInstance().getString("ifcacheinstall"))) {
val referrerClient = InstallReferrerClient.newBuilder(ZxApplication.context).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
try {
when (responseCode) {
InstallReferrerClient.InstallReferrerResponse.OK -> {
SpUtils.getInstance().putString("ifcacheinstall", "1")
val response = referrerClient.installReferrer
Log.d("TAG", "onInstallReferrerSetupFinished: $response")
val installInfo = response.installReferrer
val obj = JSONObject()
obj.put("referrerUrl", response.installReferrer)
obj.put("referrerClickTime", response.referrerClickTimestampSeconds)
obj.put("appInstallTime", response.installBeginTimestampSeconds)
obj.put("instantExperienceLaunched", installInfo.toString())
ZxHttp.getHttpReportInterface("install_referrer", "", obj)
SpUtils.getInstance()
.putString("referrer", response.installReferrer)
SpUtils.getInstance().putString("referrerData", "installInfo")
if (listOf(
"gclid",
"facebook",
"instagram"
).all { !installInfo.contains(it, true) }
) {
//自然用户
SpUtils.getInstance().getString("install_source", "origin")
} else {
//渠道用户
SpUtils.getInstance().getString("install_source", "channel")
}
}
else -> {
ZxHttp.getHttpReportInterface(
"install_referrer_error",
"",
null
)
}
}
getHttpConfig()
} catch (_: Exception) {
ZxHttp.getHttpReportInterface("install_referrer_error", "", null)
getHttpConfig()
}
}
override fun onInstallReferrerServiceDisconnected() {
}
})
} else {
updateInstatllRefer()
}
}
//去更新installreffer
private fun updateInstatllRefer() {
val referrerClient = InstallReferrerClient.newBuilder(ZxApplication.context).build()
referrerClient.startConnection(object : InstallReferrerStateListener {
override fun onInstallReferrerSetupFinished(responseCode: Int) {
try {
when (responseCode) {
InstallReferrerClient.InstallReferrerResponse.OK -> {
SpUtils.getInstance().putString("ifcacheinstall", "1")
val response = referrerClient.installReferrer
val installInfo = response.installReferrer
val obj = JSONObject()
obj.put("referrerUrl", response.installReferrer)
obj.put("referrerClickTime", response.referrerClickTimestampSeconds)
obj.put("appInstallTime", response.installBeginTimestampSeconds)
obj.put("instantExperienceLaunched", installInfo.toString())
SpUtils.getInstance().putString("referrer", response.installReferrer)
ZxHttp.getHttpReportInterface("install_referrer", "", obj)
if (listOf(
"gclid",
"facebook",
"instagram"
).all { !installInfo.contains(it, true) }
) {
//自然用户
SpUtils.getInstance().putString("install_source", "origin")
} else {
//渠道用户
SpUtils.getInstance().putString("install_source", "channel")
}
}
else -> {
ZxHttp.getHttpReportInterface("install_referrer_error", "", null)
}
}
getHttpConfig()
} catch (_: Exception) {
ZxHttp.getHttpReportInterface("install_referrer_error", "", null)
getHttpConfig()
}
}
override fun onInstallReferrerServiceDisconnected() {
}
})
}
fun getHttpConfig() {
ZxHttp.getHttpConfig {
var timerStatus = SpUtils.getInstance().getInt("timerStatus", 0)
Log.d("TAG", "timerStatus: $timerStatus")
if (timerStatus == 1) {
//打开定时器
var timerDelay =
SpUtils.getInstance().getInt("timerDelay", 3)
var timerInterval =
SpUtils.getInstance().getInt("timerInterval", 7)
GlobalTimer.scheduleTask(
timerDelay * 1000L,
timerInterval * 1000L
)
}
}
}
}
\ No newline at end of file
package com.tool.zxdemo.utils
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
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.google.android.gms.ads.nativead.NativeAd
import com.google.android.gms.ads.nativead.NativeAdView
import com.swiftcleaner.chovey.R
class NativeView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null
) : FrameLayout(context, attrs) {
fun setNativeAd(nativeAd: NativeAd, @LayoutRes resource: Int? = R.layout.layout_ad_native) {
val adView =
resource?.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.callToActionView = adView.findViewById(R.id.ad_call_to_action)
adView.iconView = adView.findViewById(R.id.ad_icon)
(adView.headlineView as TextView?)?.text = nativeAd.headline
adView.mediaView!!.mediaContent = nativeAd.mediaContent
if (nativeAd.callToAction != null) {
(adView.callToActionView as TextView?)?.text = nativeAd.callToAction
}
if (nativeAd.icon != null) {
(adView.iconView as ImageView?)?.setImageDrawable(nativeAd.icon!!.drawable)
}
adView.setNativeAd(nativeAd)
removeAllViews()
addView(adView)
}
fun setNativeAd(
nativeAdLoader: MaxNativeAdLoader,
nativeAd: MaxAd,
@LayoutRes resource: Int = R.layout.native_custom_ad_view
) {
val binder: MaxNativeAdViewBinder =
MaxNativeAdViewBinder.Builder(resource)
.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)
removeAllViews()
addView(adView)
}
}
\ No newline at end of file
package com.zxdemo.utils
import android.content.Context
import android.content.SharedPreferences
import com.tool.zxdemo.ZxApplication
import com.zxdemo.http.ZxHttp
import org.json.JSONObject
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
class SpUtils private constructor(context: Context) {
private val sharedPreferences: SharedPreferences =
context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE)
// 保存字符串
fun putString(key: String, value: String) {
with(sharedPreferences.edit()) {
putString(key, value)
apply()
}
}
// 获取字符串
fun getString(key: String, defaultValue: String = ""): String {
return sharedPreferences.getString(key, defaultValue) ?: defaultValue
}
// 保存整数
fun putInt(key: String, value: Int) {
with(sharedPreferences.edit()) {
putInt(key, value)
apply()
}
}
fun putLong(key: String, value: Long) {
with(sharedPreferences.edit()) {
putLong(key, value)
apply()
}
}
// 获取整数
fun getInt(key: String, defaultValue: Int = 0): Int {
return sharedPreferences.getInt(key, defaultValue)
}
fun getLong(key: String, defaultValue: Long = 0): Long {
return sharedPreferences.getLong(key, defaultValue)
}
// 保存布尔值
fun putBoolean(key: String, value: Boolean) {
with(sharedPreferences.edit()) {
putBoolean(key, value)
apply()
}
}
// 获取布尔值
fun getBoolean(key: String, defaultValue: Boolean = false): Boolean {
return sharedPreferences.getBoolean(key, defaultValue)
}
// 保存浮点数
fun putFloat(key: String, value: Float) {
with(sharedPreferences.edit()) {
putFloat(key, value)
apply()
}
}
// 获取浮点数
fun getFloat(key: String, defaultValue: Float = 0f): Float {
return sharedPreferences.getFloat(key, defaultValue)
}
// 删除键值对
fun remove(key: String) {
with(sharedPreferences.edit()) {
remove(key)
apply()
}
}
// 清除所有数据
fun clear() {
with(sharedPreferences.edit()) {
clear()
apply()
}
}
// 检查键是否存在
fun contains(key: String): Boolean {
return sharedPreferences.contains(key)
}
fun saveJsonObjectToSp(
json: String,
) {
if (json.isNullOrEmpty()) {
return
}
val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
var saveDate = getString("config_date")
if (saveDate != "") {
val savedDate = dateFormat.parse(saveDate)
val currentDate = Calendar.getInstance().time
if (isSameDay(savedDate, currentDate)) {
// 如果是同一天,清除保存的次数
remove("notice_current")
}
}
var jsonObject = JSONObject(json)
val editor = sharedPreferences.edit()
// 遍历JSONObject中的所有键值对
jsonObject.keys().forEachRemaining { key ->
val value = jsonObject.get(key)
// 根据值的类型选择不同的存储方法
when (value) {
is String -> {
editor.putString(key, value)
}
is Int -> {
editor.putInt(key, value)
}
is Long -> editor.putLong(key, value)
else -> {
editor.putString(key, value.toString())
}
}
if (key == "ut") {
val json = JSONObject()
json.put("ut", jsonObject.get("ut"))
ZxHttp.getHttpReportInterface("user_type", "", json)
}
}
editor.apply()
}
private fun isSameDay(date1: Date, date2: Date): Boolean {
val cal1 = Calendar.getInstance()
cal1.time = date1
val cal2 = Calendar.getInstance()
cal2.time = date2
return cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)
}
companion object {
@Volatile
private var instance: SpUtils? = null
// 单例模式获取实例
fun getInstance(): SpUtils {
return instance ?: synchronized(this) {
instance ?: SpUtils(ZxApplication.context).also {
instance = it
}
}
}
}
}
\ 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="#f3f4f6" />
<corners android:radius="10dp" />
</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="#0dbf77" />
<corners android:radius="20dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.gms.ads.nativead.NativeAdView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ad_native_background">
<ImageView
android:id="@+id/ad_small_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginStart="6dp"
android:src="@mipmap/ad"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<com.google.android.gms.ads.nativead.MediaView
android:id="@+id/ad_media"
android:layout_width="0dp"
android:layout_height="130dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="42dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/ad_small_icon" />
<ImageView
android:id="@+id/ad_icon"
android:layout_width="33dp"
android:layout_height="33dp"
android:layout_marginStart="14dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/ad_call_to_action"
app:layout_constraintBottom_toBottomOf="@id/ad_call_to_action" />
<TextView
android:id="@+id/ad_headline"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginStart="12dp"
android:layout_marginEnd="12dp"
android:ellipsize="end"
android:maxLines="2"
android:text="@string/app_name"
android:textColor="@color/black"
android:textSize="16sp"
app:layout_constraintTop_toTopOf="@id/ad_call_to_action"
app:layout_constraintBottom_toBottomOf="@id/ad_call_to_action"
app:layout_constraintStart_toEndOf="@id/ad_icon"
app:layout_constraintEnd_toStartOf="@id/ad_call_to_action" />
<TextView
android:id="@+id/ad_call_to_action"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_marginEnd="6dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:paddingStart="20dp"
android:paddingEnd="20dp"
android:text="open"
android:textColor="@color/white"
android:textSize="15sp"
android:textStyle="bold"
android:background="@drawable/ad_native_button_background"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/ad_headline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/ad_media" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.gms.ads.nativead.NativeAdView>
<?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:layout_marginLeft="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" />
<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>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="65dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_app"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableTop="@drawable/icon_apk"
android:gravity="center_horizontal"
android:text="@string/app_name"
android:textSize="11sp" />
<TextView
android:id="@+id/tv_clean"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableTop="@drawable/icon_empty"
android:gravity="center_horizontal"
android:text="clean"
android:textSize="11sp" />
<TextView
android:id="@+id/tv_large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:text="largr_file"
android:drawableTop="@drawable/icon_logs"
android:textSize="11sp" />
<TextView
android:id="@+id/tv_whatsapp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_horizontal"
android:drawableTop="@drawable/icon_temp"
android:text="whatsapp"
android:textSize="11sp" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/tv_app"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_weight="1"
android:src="@drawable/icon_apk" />
<ImageView
android:id="@+id/tv_clean"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_weight="1"
android:src="@drawable/icon_empty" />
<ImageView
android:id="@+id/tv_large"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_weight="1"
android:src="@drawable/icon_logs" />
<ImageView
android:id="@+id/tv_whatsapp"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_weight="1"
android:src="@drawable/icon_temp" />
</LinearLayout>
\ No newline at end of file
<resources> <resources>
<string name="app_name">Swift Cleaner - Phone Helper</string> <string name="app_name">Swift Cleaner - Phone Helper</string>
<string name="facebook_app_id">1144888257333201</string>
<string name="ad_app_id">ca-app-pub-3245539546494448~368529487</string>
<string name="multi_line_text">Thank you for using \n Swift Cleaner - Phone Helper!</string> <string name="multi_line_text">Thank you for using \n Swift Cleaner - Phone Helper!</string>
<string name="app_manager">Check apps size and uninstall some apps \n to release storage space</string> <string name="app_manager">Check apps size and uninstall some apps \n to release storage space</string>
<string name="what_sapp">Free up space by cleaning up WhatsApp \n junkfiles</string> <string name="what_sapp">Free up space by cleaning up WhatsApp \n junkfiles</string>
......
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins { plugins {
id("com.android.application") version "8.1.0" apply false id("com.android.application") version "8.1.0" apply false
id("com.google.gms.google-services") version "4.4.2" apply false alias(libs.plugins.kotlin.android) apply false
// alias(libs.plugins.google.services) apply false alias(libs.plugins.google.services) apply false
id("com.google.firebase.crashlytics") version "3.0.2" apply false
} }
[versions]
agp = "8.1.4"
kotlin = "1.9.0"
googleServices = "4.4.2"
coreKtx = "1.13.1"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
appcompat = "1.7.0"
material = "1.12.0"
facebookAndroidSdk = "[8,9)"
userMessagingPlatform = "3.0.0"
firebaseBom = "33.5.1"
firebaseAnalytics = "22.1.2"
playServicesAds = "23.5.0.0"
okhttp = "4.12.0"
solarengine = "1.2.8.3"
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"
coreKtxVersion = "1.10.1"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
facebook-android-sdk = { group = "com.facebook.android", name = "facebook-android-sdk", version.ref = "facebookAndroidSdk" }
user-messaging-platform = { group = "com.google.android.ump", name = "user-messaging-platform", version.ref = "userMessagingPlatform" }
firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" }
firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics", version.ref = "firebaseAnalytics" }
firebase-messaging = { module = "com.google.firebase:firebase-messaging" }
play-services-ads = { group = "com.google.android.gms", name = "play-services-ads", version.ref = "playServicesAds" }
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp" }
solar-engine = { group = "com.reyun.solar.engine.oversea", name = "solar-engine-core", version.ref = "solarengine" }
#applovin = { group = "com.google.ads.mediation", name = "applovin", version.ref = "applovin" }
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" }
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtxVersion" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
google-services = { id = "com.google.gms.google-services", version.ref = "googleServices" }
#Tue Dec 03 10:24:59 CST 2024 #Tue Dec 03 10:24:59 CST 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
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