This commit is contained in:
Administrator 2025-07-04 16:38:32 +08:00
parent 890539cbc0
commit 1e7ceae4ed
24 changed files with 1174 additions and 338 deletions

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -9,6 +9,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BIND_VPN_SERVICE" <uses-permission android:name="android.permission.BIND_VPN_SERVICE"
tools:ignore="ProtectedPermissions" /> tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"
android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VPN_SERVICE" /> <uses-permission android:name="android.permission.VPN_SERVICE" />
@ -41,6 +43,7 @@
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
@ -117,8 +120,6 @@
android:name="android.accessibilityservice" android:name="android.accessibilityservice"
android:resource="@xml/accessibility_service_config" /> android:resource="@xml/accessibility_service_config" />
</service> </service>
<receiver android:name="com.android.grape.receiver.ScriptReceiver" />
</application> </application>
</manifest> </manifest>

View File

@ -13,18 +13,24 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.lifecycle.lifecycleScope
import com.android.grape.databinding.ActivityMainBinding import com.android.grape.databinding.ActivityMainBinding
import com.android.grape.job.MonitorService import com.android.grape.job.MonitorService
import com.android.grape.receiver.ScriptReceiver import com.android.grape.receiver.ScriptReceiver
import com.android.grape.util.ClashUtil import com.android.grape.util.ClashUtil
import com.android.grape.util.HttpUtil
import com.android.grape.util.NotificationPermissionHandler
import com.android.grape.util.StoragePermissionHelper import com.android.grape.util.StoragePermissionHelper
import com.blankj.utilcode.util.LogUtils import com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private val viewModel by viewModels<MainViewModel>() private val viewModel by viewModels<MainViewModel>()
private lateinit var viewBinding: ActivityMainBinding private lateinit var viewBinding: ActivityMainBinding
private var intentFilter: IntentFilter? = null private var intentFilter: IntentFilter? = null
private var scriptReceiver: ScriptReceiver? = null private var scriptReceiver: ScriptReceiver? = null
private lateinit var permissionHandler: NotificationPermissionHandler
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
@ -39,15 +45,14 @@ class MainActivity : AppCompatActivity() {
registerReceiver() registerReceiver()
viewBinding.start.setOnClickListener { viewBinding.start.setOnClickListener {
try { try {
ClashUtil.startProxy(this) // 在主线程中调用 ClashUtil.startProxy(this)
ClashUtil.switchProxyGroup("GLOBAL", "us", "http://127.0.0.1:6170") ClashUtil.switchProxyGroup(
} catch (e: Exception) { "GLOBAL",
LogUtils.log( ClashUtil.getRandomLocale(),
Log.ERROR, "http://127.0.0.1:6170"
"MainActivity",
"startProxyVpn: Failed to start VPN",
e
) )
} catch (e: Exception) {
LogUtils.e("startProxyVpn: Failed to start VPN", e)
Toast.makeText( Toast.makeText(
this, this,
"Failed to start VPN: " + (if (e.message != null) e.message else "Unknown error"), "Failed to start VPN: " + (if (e.message != null) e.message else "Unknown error"),
@ -77,7 +82,11 @@ class MainActivity : AppCompatActivity() {
} }
private fun checkPermission() { private fun checkPermission() {
viewModel.checkAccessibilityService() permissionHandler = NotificationPermissionHandler(this) { result ->
handlePermissionResult(result)
}
checkNotificationPermission()
StoragePermissionHelper.requestFullStoragePermission( StoragePermissionHelper.requestFullStoragePermission(
activity = this, activity = this,
onGranted = { performFileOperation() }, onGranted = { performFileOperation() },
@ -85,10 +94,56 @@ class MainActivity : AppCompatActivity() {
) )
} }
private fun checkNotificationPermission() {
when (val result = NotificationPermissionHandler.checkPermissionState(this)) {
NotificationPermissionHandler.PermissionResult.GRANTED,
NotificationPermissionHandler.PermissionResult.NOT_NEEDED -> {
showNotification()
}
NotificationPermissionHandler.PermissionResult.DENIED,
NotificationPermissionHandler.PermissionResult.NEEDS_SETTINGS -> {
// 请求权限
permissionHandler.requestNotificationPermission()
}
}
}
/**
* 处理权限结果回调
*/
private fun handlePermissionResult(result: NotificationPermissionHandler.PermissionResult) {
when (result) {
NotificationPermissionHandler.PermissionResult.GRANTED -> {
// 权限已授予,显示通知
showNotification()
Toast.makeText(this, "通知权限已开启", Toast.LENGTH_SHORT).show()
}
NotificationPermissionHandler.PermissionResult.DENIED -> {
// 权限被拒绝
Toast.makeText(this, "通知权限被拒绝", Toast.LENGTH_SHORT).show()
}
NotificationPermissionHandler.PermissionResult.NEEDS_SETTINGS -> {
Toast.makeText(this, "通知权限被拒绝", Toast.LENGTH_SHORT).show()
}
NotificationPermissionHandler.PermissionResult.NOT_NEEDED -> {
// 不需要特殊权限(旧设备)
showNotification()
}
}
}
private fun showNotification() {
viewModel.checkAccessibilityService()
}
private fun performFileOperation() { private fun performFileOperation() {
// 执行文件读写操作 // 执行文件读写操作
// Toast.makeText(this, "文件访问权限已授予", Toast.LENGTH_SHORT).show() // Toast.makeText(this, "文件访问权限已授予", Toast.LENGTH_SHORT).show()
MonitorService.onEvent(this) // MonitorService.onEvent(this)
} }
private fun showPermissionDeniedDialog() { private fun showPermissionDeniedDialog() {

View File

@ -0,0 +1,8 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class As(
var nameValuePairs: NameValuePairs = NameValuePairs()
)

View File

@ -0,0 +1,11 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class DdlInfo(
var fromfg: Int = 0,
var net0: Int = 0,
var rfrwait: Int = 0,
var status: String = ""
)

View File

@ -0,0 +1,113 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class Device(
var advertiserId: String = "",
@SerializedName("af_preinstalled")
var afPreinstalled: Boolean = false,
var androidId: String = "",
var arch: String = "",
@SerializedName("as")
var asX: As = As(),
var battery: Int = 0,
var battery1: Int = 0,
var batteryLevel: Int = 0,
var batteryType: Int = 0,
var bn: String = "",
var brand: String = "",
var btch: String = "",
@SerializedName("build_display_id")
var buildDisplayId: String = "",
var carrier: String = "",
@SerializedName("click_ts")
var clickTs: Int = 0,
var clk: String = "",
var country: String = "",
@SerializedName("cpu_abi")
var cpuAbi: String = "",
@SerializedName("cpu_abi2")
var cpuAbi2: String = "",
var ddlInfo: DdlInfo = DdlInfo(),
var debug: Boolean = false,
var device: String = "",
var deviceCity: String = "",
var deviceType: String = "",
var dim: Dim = Dim(),
var dimId: Int = 0,
var dimReset: Int = 0,
var dimType: Int = 0,
var disk: String = "",
var diskRate: Double = 0.0,
var expand: Expand = Expand(),
var fetchAdIdLatency: Int = 0,
@SerializedName("from_fg")
var fromFg: Int = 0,
@SerializedName("google_custom")
var googleCustom: GoogleCustom = GoogleCustom(),
var hook: String = "",
@SerializedName("init_to_fg")
var initToFg: Int = 0,
var install: String = "",
@SerializedName("install_begin_ts")
var installBeginTs: Int = 0,
@SerializedName("installer_package")
var installerPackage: String = "",
var instant: Boolean = false,
var ip: String = "",
var ivc: Boolean = false,
var lang: String = "",
@SerializedName("lang_code")
var langCode: String = "",
@SerializedName("last_boot_time")
var lastBootTime: Long = 0,
var lastBootTimeOff: Int = 0,
var latency: Int = 0,
var locale: Locale = Locale(),
var manufactor: String = "",
var mcc: Int = 0,
var mnc: Int = 0,
var model: String = "",
@SerializedName("native_dir")
var nativeDir: Boolean = false,
var network: String = "",
var noRcLatency: Boolean = false,
@SerializedName("open_referrer")
var openReferrer: String = "",
@SerializedName("open_referrerReset")
var openReferrerReset: Int = 0,
var opener: String = "",
var `operator`: String = "",
var platformextension: String = "",
var pr: Pr = Pr(),
var product: String = "",
var rawDevice: String = "",
var rawProduct: String = "",
@SerializedName("rc.delay")
var rcDelay: Int = 0,
@SerializedName("rc.latency")
var rcLatency: Int = 0,
var referrer: String = "",
@SerializedName("sc_o")
var scO: String = "",
var sdk: String = "",
var sdkVer: String = "",
var sensor: List<Sensor> = listOf(),
var sensorReset: Int = 0,
@SerializedName("sensor_size")
var sensorSize: Int = 0,
@SerializedName("sig_n")
var sigN: String = "",
@SerializedName("sys_ua")
var sysUa: String = "",
var timepassedsincelastlaunch: Int = 0,
var tzDisplayName: String = "",
var tzOffTime: Int = 0,
@SerializedName("val")
var valX: String = "",
var vendingVersionCode: String = "",
var vendingVersionName: String = "",
@SerializedName("web_ua")
var webUa: String = ""
)

View File

@ -0,0 +1,16 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class Dim(
@SerializedName("d_dpi")
var dDpi: String = "",
var size: String = "",
@SerializedName("x_px")
var xPx: String = "",
var xdp: String = "",
@SerializedName("y_px")
var yPx: String = "",
var ydp: String = ""
)

View File

@ -0,0 +1,87 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class Expand(
@SerializedName("ABI")
var aBI: String = "",
@SerializedName("API")
var aPI: String = "",
var amGetConfig: String = "",
@SerializedName("AndroidID")
var androidID: String = "",
@SerializedName("AndroidVer")
var androidVer: String = "",
@SerializedName("BSSID")
var bSSID: String = "",
var baseband: String = "",
var batteryLevel: Int = 0,
var board: String = "",
var bootLoader: String = "",
var brand: String = "",
var country: String = "",
@SerializedName("CountryCode")
var countryCode: String = "",
var cpuinfobuf: String = "",
var cpuinfostr: String = "",
@SerializedName("DPI")
var dPI: Int = 0,
var dataStatfs: Long = 0,
var device: String = "",
var display: String = "",
var displayLang: String = "",
var downloadCacheStatfs: Long = 0,
var fingerprint: String = "",
var firstInstallTime: Int = 0,
var gaid: String = "",
var glExtensions: String = "",
var glRenderer: String = "",
var glVendor: String = "",
var glVersion: String = "",
var height: Int = 0,
@SerializedName("ID")
var iD: String = "",
var incremental: String = "",
var lang: String = "",
var lastUpdateTime: Int = 0,
var latitude: Double = 0.0,
var localip: String = "",
var longtitude: Double = 0.0,
var lyMAC: String = "",
@SerializedName("Manufacture")
var manufacture: String = "",
var model: String = "",
var network: String = "",
var phoneBootTime: Int = 0,
var phoneUsedTime: Int = 0,
var pmfea: String = "",
var pmlib: String = "",
var procStat: String = "",
var procVersion: String = "",
var ratioVersion: String = "",
var referrerClickTime: Long = 0,
var referrerFromGP: String = "",
var regionid: String = "",
var roBoardPlatform: String = "",
var roBootimageBuildFingerprint: String = "",
var roBuildDateUtc: Int = 0,
var roBuildDescription: String = "",
var roHardware: String = "",
var roProductCpuAbilist: String = "",
var roProductName: String = "",
var rootStatfs: Int = 0,
var screenBrightness: Int = 0,
var sdStatfs: Long = 0,
var sdcardCreateTime: Int = 0,
var soRomRam: String = "",
var timerawoff: Int = 0,
var tmdisplayname: String = "",
var uname: String = "",
var width: Int = 0,
@SerializedName("WifiMAC")
var wifiMAC: String = "",
@SerializedName("WifiName")
var wifiName: String = "",
var wvua: String = ""
)

View File

@ -0,0 +1,14 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class GoogleCustom(
@SerializedName("click_server_ts")
var clickServerTs: Int = 0,
@SerializedName("install_begin_server_ts")
var installBeginServerTs: Int = 0,
@SerializedName("install_version")
var installVersion: String = "",
var instant: Boolean = false
)

View File

@ -0,0 +1,10 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class Locale(
var country: String = "",
var displayLang: String = "",
var lang: String = ""
)

View File

@ -0,0 +1,11 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class NameValuePairs(
var cav: Int = 0,
@SerializedName("null")
var nullX: Int = 0,
var other: Int = 0
)

View File

@ -0,0 +1,22 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class NameValuePairsX(
var ac: String = "",
var ah: String = "",
var ai: String = "",
var ak: String = "",
var al: String = "",
var am: String = "",
var an: String = "",
var ap: String = "",
var aq: String = "",
var ar: String = "",
@SerializedName("as")
var asX: String = "",
var at: String = "",
var au: String = "",
var av: String = ""
)

View File

@ -0,0 +1,8 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class Pr(
var nameValuePairs: NameValuePairsX = NameValuePairsX()
)

View File

@ -0,0 +1,12 @@
package com.android.grape.data
import com.google.gson.annotations.SerializedName
data class Sensor(
var sN: String = "",
var sT: Int = 0,
var sV: String = "",
var sVE: List<Double> = listOf(),
var sVS: List<Double> = listOf()
)

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.util.Log import android.util.Log
import androidx.core.app.JobIntentService import androidx.core.app.JobIntentService
import com.android.grape.util.ChangeDeviceInfoUtil
import com.android.grape.util.MockTools import com.android.grape.util.MockTools
import com.android.grape.util.ServiceUtils import com.android.grape.util.ServiceUtils
import com.android.grape.util.Util import com.android.grape.util.Util
@ -28,13 +29,15 @@ class OpenAppService : JobIntentService() {
Util.doScript(this, Util.AUTO_JSPACKAGENAME) //autojs Util.doScript(this, Util.AUTO_JSPACKAGENAME) //autojs
} }
try { try {
if (Util.isNeedRestored) { //todo fix 改机流程
Log.d("IOSTQ:", "执行留存任务") // if (Util.isNeedRestored) {
Util.setRrInfo(this) // Log.d("IOSTQ:", "执行留存任务")
} else { // Util.setRrInfo(this)
Log.d("IOSTQ:", "执行新装任务") // } else {
Util.setInfo(this) // Log.d("IOSTQ:", "执行新装任务")
} // Util.setInfo(this)
// }
ChangeDeviceInfoUtil.changeDeviceInfo()
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
} }

View File

@ -3,329 +3,150 @@ package com.android.grape.util
import android.content.ContentResolver import android.content.ContentResolver
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import com.android.grape.data.AfInfo import com.android.grape.MainApplication
import com.android.grape.data.BigoInfo import com.android.grape.data.Device
import com.android.grape.data.DeviceInfo import com.android.grape.util.Util.paramsJson
import com.blankj.utilcode.util.LogUtils import com.blankj.utilcode.util.LogUtils
import org.json.JSONObject import org.json.JSONObject
import java.lang.reflect.InvocationTargetException import java.lang.reflect.InvocationTargetException
object ChangeDeviceInfoUtil { object ChangeDeviceInfoUtil {
fun changeDeviceInfo( fun changeDeviceInfo(
current_pkg_name: String,
context: Context?,
bigoDeviceObject: JSONObject?,
afDeviceObject: JSONObject?
) { ) {
var bigoDeviceObject = bigoDeviceObject
var afDeviceObject = afDeviceObject
try { try {
val bigoDevice: BigoInfo val deviceObject = paramsJson?.getJSONObject("device")
if (bigoDeviceObject != null) { if (deviceObject == null) {
// BIGO LogUtils.d("ERROR", "ChangeDeviceInfoUtil", "device is null")
val cpuClockSpeed = bigoDeviceObject.optString("cpu_clock_speed") return
val gaid = bigoDeviceObject.optString("gaid")
val userAgent = bigoDeviceObject.optString("User-Agent")
val osLang = bigoDeviceObject.optString("os_lang")
val osVer = bigoDeviceObject.optString("os_ver")
val tz = bigoDeviceObject.optString("tz")
val systemCountry = bigoDeviceObject.optString("system_country")
val simCountry = bigoDeviceObject.optString("sim_country")
val romFreeIn = bigoDeviceObject.optLong("rom_free_in")
val resolution = bigoDeviceObject.optString("resolution")
val vendor = bigoDeviceObject.optString("vendor")
val batteryScale = bigoDeviceObject.optInt("bat_scale")
// String model = deviceObject.optString("model");
val net = bigoDeviceObject.optString("net")
val dpi = bigoDeviceObject.optLong("dpi")
val romFreeExt = bigoDeviceObject.optLong("rom_free_ext")
val dpiF = bigoDeviceObject.optString("dpi_f")
val cpuCoreNum = bigoDeviceObject.optLong("cpu_core_num")
bigoDevice = BigoInfo()
bigoDevice.cpuClockSpeed = cpuClockSpeed
bigoDevice.gaid = gaid
bigoDevice.userAgent = userAgent
bigoDevice.osLang = osLang
bigoDevice.osVer = osVer
bigoDevice.tz = tz
bigoDevice.systemCountry = systemCountry
bigoDevice.simCountry = simCountry
bigoDevice.romFreeIn = romFreeIn
bigoDevice.resolution = resolution
bigoDevice.vendor = vendor
bigoDevice.batteryScale = batteryScale
bigoDevice.net = net
bigoDevice.dpi = dpi
bigoDevice.romFreeExt = romFreeExt
bigoDevice.dpiF = dpiF
bigoDevice.cpuCoreNum = cpuCoreNum
// TaskUtil.setBigoDevice(bigoDevice)
try {
callVCloudSettings_put(
"$current_pkg_name.system_country",
systemCountry,
context
)
callVCloudSettings_put("$current_pkg_name.sim_country", simCountry, context)
callVCloudSettings_put(
"$current_pkg_name.rom_free_in",
romFreeIn.toString(),
context
)
callVCloudSettings_put("$current_pkg_name.resolution", resolution, context)
callVCloudSettings_put("$current_pkg_name.vendor", vendor, context)
callVCloudSettings_put(
"$current_pkg_name.battery_scale",
batteryScale.toString(),
context
)
callVCloudSettings_put("$current_pkg_name.os_lang", osLang, context)
// callVCloudSettings_put(current_pkg_name + ".model", model, context);
callVCloudSettings_put("$current_pkg_name.net", net, context)
callVCloudSettings_put("$current_pkg_name.dpi", dpi.toString(), context)
callVCloudSettings_put(
"$current_pkg_name.rom_free_ext",
romFreeExt.toString(),
context
)
callVCloudSettings_put("$current_pkg_name.dpi_f", dpiF, context)
callVCloudSettings_put(
"$current_pkg_name.cpu_core_num",
cpuCoreNum.toString(),
context
)
callVCloudSettings_put(
"$current_pkg_name.cpu_clock_speed",
cpuClockSpeed,
context
)
callVCloudSettings_put(current_pkg_name + "_gaid", gaid, context)
// **User-Agent**
callVCloudSettings_put(current_pkg_name + "_user_agent", userAgent, context)
// **os_lang**系统语言
callVCloudSettings_put(current_pkg_name + "_os_lang", osLang, context)
// **os_ver**
callVCloudSettings_put(current_pkg_name + "_os_ver", osVer, context)
// **tz** (时区)
callVCloudSettings_put(current_pkg_name + "_tz", tz, context)
} catch (e: Throwable) {
LogUtils.e(
Log.ERROR,
"ChangeDeviceInfoUtil",
"Error occurred while changing device info",
e
)
throw RuntimeException("Error occurred in changeDeviceInfo", e)
}
bigoDeviceObject = null
} }
val context = MainApplication.instance
val device = GsonUtils.fromJsonObject(deviceObject.toString(), Device::class.java)
val currentPkgName = MainApplication.instance.packageName
vcloudsettingsPut(
"$currentPkgName.system_country",
device.country,
context
)
vcloudsettingsPut("$currentPkgName.sim_country", device.country, context)
// callVCloudSettings_put(
// "$currentPkgName.rom_free_in",
// romFreeIn.toString(),
// context
// )
vcloudsettingsPut(
"$currentPkgName.resolution",
"${device.expand.width}x${device.expand.height}}",
context
)
vcloudsettingsPut("$currentPkgName.vendor", device.expand.glVendor, context)
// callVCloudSettings_put("$currentPkgName.battery_scale", batteryScale.toString(), context)
vcloudsettingsPut("$currentPkgName.os_lang", device.lang, context)
vcloudsettingsPut("$currentPkgName.model", device.model, context);
vcloudsettingsPut("$currentPkgName.net", device.network, context)
vcloudsettingsPut("$currentPkgName.dpi", device.expand.dPI.toString(), context)
// callVCloudSettings_put(
// "$currentPkgName.rom_free_ext",
// romFreeExt.toString(),
// context
// )
// callVCloudSettings_put("$currentPkgName.dpi_f", dpiF, context)
// callVCloudSettings_put("$currentPkgName.cpu_core_num", cpuCoreNum.toString(), context)
// callVCloudSettings_put("$currentPkgName.cpu_clock_speed", cpuClockSpeed, context)
vcloudsettingsPut(currentPkgName + "_gaid", device.expand.gaid, context)
// **User-Agent**
// callVCloudSettings_put(currentPkgName + "_user_agent", userAgent, context)
// **os_lang**系统语言
vcloudsettingsPut(currentPkgName + "_os_lang", device.lang, context)
// **os_ver**
vcloudsettingsPut(currentPkgName + "_os_ver", device.sdkVer, context)
// **tz** (时区)
vcloudsettingsPut(currentPkgName + "_tz", device.tzOffTime.toString(), context)
val deviceInfo: DeviceInfo vcloudsettingsPut("$currentPkgName.advertiserId", device.advertiserId, context)
val afDevice: AfInfo vcloudsettingsPut("$currentPkgName.brand", device.brand, context)
if (afDeviceObject != null) { vcloudsettingsPut("$currentPkgName.android_id", device.androidId, context)
val advertiserId = afDeviceObject.optString(".advertiserId") vcloudsettingsPut("$currentPkgName.lang", device.lang, context)
val model = afDeviceObject.optString(".model") vcloudsettingsPut("$currentPkgName.country", device.country, context)
val brand = afDeviceObject.optString(".brand") vcloudsettingsPut(
val androidId = afDeviceObject.optString(".android_id") "$currentPkgName.batteryLevel",
val xPixels = afDeviceObject.optInt(".deviceData.dim.x_px") device.batteryLevel.toString(), context
val yPixels = afDeviceObject.optInt(".deviceData.dim.y_px") )
val densityDpi = afDeviceObject.optInt(".deviceData.dim.d_dpi") // callVCloudSettings_put(
val country = afDeviceObject.optString(".country") // currentPkgName + "_screen.optMetrics.stack",
val batteryLevel = afDeviceObject.optString(".batteryLevel") // stackInfo,
val stackInfo = Thread.currentThread().stackTrace[2].toString() // context
val product = afDeviceObject.optString(".product") // )
val network = afDeviceObject.optString(".network") vcloudsettingsPut("$currentPkgName.product", device.product, context)
val langCode = afDeviceObject.optString(".lang_code") vcloudsettingsPut("$currentPkgName.network", device.network, context)
val cpuAbi = afDeviceObject.optString(".deviceData.cpu_abi") vcloudsettingsPut("$currentPkgName.cpu_abi", device.cpuAbi, context)
val yDp = afDeviceObject.optLong(".deviceData.dim.ydp") vcloudsettingsPut("$currentPkgName.lang_code", device.langCode, context)
// **广告标识符 (advertiserId)** 及 **启用状态**
val isAdIdEnabled = true // 默认启用广告 ID
vcloudsettingsPut(
"$currentPkgName.advertiserIdEnabled",
isAdIdEnabled.toString(),
context
)
afDevice = AfInfo() val displayMetrics = JSONObject()
afDevice.advertiserId = advertiserId
afDevice.model = model
afDevice.brand = brand
afDevice.androidId = androidId
afDevice.xPixels = xPixels
afDevice.yPixels = yPixels
afDevice.densityDpi = densityDpi
afDevice.country = country
afDevice.batteryLevel = batteryLevel
afDevice.stackInfo = stackInfo
afDevice.product = product
afDevice.network = network
afDevice.langCode = langCode
afDevice.cpuAbi = cpuAbi
afDevice.yDp = yDp
// TaskUtil.setAfDevice(afDevice)
val lang = afDeviceObject.optString(".lang") displayMetrics.put("widthPixels", device.expand.width)
val ro_product_brand = afDeviceObject.optString("ro.product.brand", "")
val ro_product_model = afDeviceObject.optString("ro.product.model", "")
val ro_product_manufacturer =
afDeviceObject.optString("ro.product.manufacturer", "")
val ro_product_device = afDeviceObject.optString("ro.product.device", "")
val ro_product_name = afDeviceObject.optString("ro.product.name", "")
val ro_build_version_incremental =
afDeviceObject.optString("ro.build.version.incremental", "")
val ro_build_fingerprint = afDeviceObject.optString("ro.build.fingerprint", "")
val ro_odm_build_fingerprint =
afDeviceObject.optString("ro.odm.build.fingerprint", "")
val ro_product_build_fingerprint =
afDeviceObject.optString("ro.product.build.fingerprint", "")
val ro_system_build_fingerprint =
afDeviceObject.optString("ro.system.build.fingerprint", "")
val ro_system_ext_build_fingerprint =
afDeviceObject.optString("ro.system_ext.build.fingerprint", "")
val ro_vendor_build_fingerprint =
afDeviceObject.optString("ro.vendor.build.fingerprint", "")
val ro_build_platform = afDeviceObject.optString("ro.board.platform", "")
val persist_sys_cloud_drm_id =
afDeviceObject.optString("persist.sys.cloud.drm.id", "")
val persist_sys_cloud_battery_capacity =
afDeviceObject.optInt("persist.sys.cloud.battery.capacity", -1)
val persist_sys_cloud_gpu_gl_vendor =
afDeviceObject.optString("persist.sys.cloud.gpu.gl_vendor", "")
val persist_sys_cloud_gpu_gl_renderer =
afDeviceObject.optString("persist.sys.cloud.gpu.gl_renderer", "")
val persist_sys_cloud_gpu_gl_version =
afDeviceObject.optString("persist.sys.cloud.gpu.gl_version", "")
val persist_sys_cloud_gpu_egl_vendor =
afDeviceObject.optString("persist.sys.cloud.gpu.egl_vendor", "")
val persist_sys_cloud_gpu_egl_version =
afDeviceObject.optString("persist.sys.cloud.gpu.egl_version", "")
val global_android_id = afDeviceObject.optString(".android_id", "")
val anticheck_pkgs = afDeviceObject.optString(".anticheck_pkgs", "")
val pm_list_features = afDeviceObject.optString(".pm_list_features", "")
val pm_list_libraries = afDeviceObject.optString(".pm_list_libraries", "")
val system_http_agent = afDeviceObject.optString("system.http.agent", "")
val webkit_http_agent = afDeviceObject.optString("webkit.http.agent", "")
val com_fk_tools_pkgInfo = afDeviceObject.optString(".pkg_info", "")
val appsflyerKey = afDeviceObject.optString(".appsflyerKey", "")
val appUserId = afDeviceObject.optString(".appUserId", "")
val disk = afDeviceObject.optString(".disk", "")
val operator = afDeviceObject.optString(".operator", "")
val cell_mcc = afDeviceObject.optString(".cell.mcc", "")
val cell_mnc = afDeviceObject.optString(".cell.mnc", "")
val date1 = afDeviceObject.optString(".date1", "")
val date2 = afDeviceObject.optString(".date2", "")
val bootId = afDeviceObject.optString("BootId", "")
deviceInfo = DeviceInfo() displayMetrics.put("heightPixels", device.expand.height)
deviceInfo.lang = lang displayMetrics.put("densityDpi", device.expand.dPI)
deviceInfo.roProductBrand = ro_product_brand displayMetrics.put("yDp", device.dim.ydp)
deviceInfo.roProductModel = ro_product_model vcloudsettingsPut(
deviceInfo.roProductManufacturer = ro_product_manufacturer "screen.device.displayMetrics",
deviceInfo.roProductDevice = ro_product_device displayMetrics.toString(),
deviceInfo.roProductName = ro_product_name context
deviceInfo.roBuildVersionIncremental = ro_build_version_incremental )
deviceInfo.roBuildFingerprint = ro_build_fingerprint
deviceInfo.roOdmBuildFingerprint = ro_odm_build_fingerprint
deviceInfo.roProductBuildFingerprint = ro_product_build_fingerprint
deviceInfo.roSystemBuildFingerprint = ro_system_build_fingerprint
deviceInfo.roSystemExtBuildFingerprint = ro_system_ext_build_fingerprint
deviceInfo.roVendorBuildFingerprint = ro_vendor_build_fingerprint
deviceInfo.roBuildPlatform = ro_build_platform
deviceInfo.persistSysCloudDrmId = persist_sys_cloud_drm_id
deviceInfo.persistSysCloudBatteryCapacity = persist_sys_cloud_battery_capacity
deviceInfo.persistSysCloudGpuGlVendor = persist_sys_cloud_gpu_gl_vendor
deviceInfo.persistSysCloudGpuGlRenderer = persist_sys_cloud_gpu_gl_renderer
deviceInfo.persistSysCloudGpuGlVersion = persist_sys_cloud_gpu_gl_version
deviceInfo.persistSysCloudGpuEglVendor = persist_sys_cloud_gpu_egl_vendor
deviceInfo.persistSysCloudGpuEglVersion = persist_sys_cloud_gpu_egl_version
// TaskUtil.setDeviceInfo(deviceInfo)
try {
callVCloudSettings_put("$current_pkg_name.advertiserId", advertiserId, context)
callVCloudSettings_put("$current_pkg_name.model", model, context)
callVCloudSettings_put("$current_pkg_name.brand", brand, context)
callVCloudSettings_put("$current_pkg_name.android_id", androidId, context)
callVCloudSettings_put("$current_pkg_name.lang", lang, context)
callVCloudSettings_put("$current_pkg_name.country", country, context)
callVCloudSettings_put("$current_pkg_name.batteryLevel", batteryLevel, context)
callVCloudSettings_put(
current_pkg_name + "_screen.optMetrics.stack",
stackInfo,
context
)
callVCloudSettings_put("$current_pkg_name.product", product, context)
callVCloudSettings_put("$current_pkg_name.network", network, context)
callVCloudSettings_put("$current_pkg_name.cpu_abi", cpuAbi, context)
callVCloudSettings_put("$current_pkg_name.lang_code", langCode, context)
// **广告标识符 (advertiserId)** 及 **启用状态**
val isAdIdEnabled = true // 默认启用广告 ID
callVCloudSettings_put(
"$current_pkg_name.advertiserIdEnabled",
isAdIdEnabled.toString(),
context
)
val displayMetrics = JSONObject() if (!ShellUtils.hasRootAccess()) {
LogUtils.d(
displayMetrics.put("widthPixels", xPixels) "ERROR",
"ChangeDeviceInfoUtil",
displayMetrics.put("heightPixels", yPixels) "Root access is required to execute system property changes"
displayMetrics.put("densityDpi", densityDpi) )
displayMetrics.put("yDp", yDp)
callVCloudSettings_put(
"screen.device.displayMetrics",
displayMetrics.toString(),
context
)
if (!ShellUtils.hasRootAccess()) {
LogUtils.d(
"ERROR",
"ChangeDeviceInfoUtil",
"Root access is required to execute system property changes"
)
}
// 设置机型, 直接设置属性
ShellUtils.execRootCmd("setprop ro.product.brand $ro_product_brand")
ShellUtils.execRootCmd("setprop ro.product.model $ro_product_model")
ShellUtils.execRootCmd("setprop ro.product.manufacturer $ro_product_manufacturer")
ShellUtils.execRootCmd("setprop ro.product.device $ro_product_device")
ShellUtils.execRootCmd("setprop ro.product.name $ro_product_name")
ShellUtils.execRootCmd("setprop ro.build.version.incremental $ro_build_version_incremental")
ShellUtils.execRootCmd("setprop ro.build.fingerprint $ro_build_fingerprint")
ShellUtils.execRootCmd("setprop ro.odm.build.fingerprint $ro_odm_build_fingerprint")
ShellUtils.execRootCmd("setprop ro.product.build.fingerprint $ro_product_build_fingerprint")
ShellUtils.execRootCmd("setprop ro.system.build.fingerprint $ro_system_build_fingerprint")
ShellUtils.execRootCmd("setprop ro.system_ext.build.fingerprint $ro_system_ext_build_fingerprint")
ShellUtils.execRootCmd("setprop ro.vendor.build.fingerprint $ro_vendor_build_fingerprint")
ShellUtils.execRootCmd("setprop ro.board.platform $ro_build_platform")
// Native.setBootId(bootId);
// 修改drm id
ShellUtils.execRootCmd("setprop persist.sys.cloud.drm.id $persist_sys_cloud_drm_id")
// 电量模拟需要大于1000
ShellUtils.execRootCmd("setprop persist.sys.cloud.battery.capacity $persist_sys_cloud_battery_capacity")
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_vendor $persist_sys_cloud_gpu_gl_vendor")
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_renderer $persist_sys_cloud_gpu_gl_renderer")
// 这个值不能随便改 必须是 OpenGL ES %d.%d 这个格式
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_version $persist_sys_cloud_gpu_gl_version")
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_vendor $persist_sys_cloud_gpu_egl_vendor")
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_version $persist_sys_cloud_gpu_egl_version")
} catch (e: Throwable) {
LogUtils.e(
Log.ERROR,
"ChangeDeviceInfoUtil",
"Error occurred in changeDeviceInfo",
e
)
throw RuntimeException("Error occurred in changeDeviceInfo", e)
}
afDeviceObject = null
} }
} catch (e: Exception) { // 设置机型, 直接设置属性
e.printStackTrace() ShellUtils.execRootCmd("setprop ro.product.brand ${device.brand}")
ShellUtils.execRootCmd("setprop ro.product.model ${device.model}")
ShellUtils.execRootCmd("setprop ro.product.manufacturer ${device.manufactor}")
ShellUtils.execRootCmd("setprop ro.product.device ${device.device}")
ShellUtils.execRootCmd("setprop ro.product.name ${device.expand.roProductName}")
ShellUtils.execRootCmd("setprop ro.build.version.incremental ${device.expand.incremental}")
ShellUtils.execRootCmd("setprop ro.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
ShellUtils.execRootCmd("setprop ro.odm.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
ShellUtils.execRootCmd("setprop ro.product.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
ShellUtils.execRootCmd("setprop ro.system.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
ShellUtils.execRootCmd("setprop ro.system_ext.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
ShellUtils.execRootCmd("setprop ro.vendor.build.fingerprint ${device.expand.roBootimageBuildFingerprint}")
ShellUtils.execRootCmd("setprop ro.board.platform ${device.expand.roBoardPlatform}")
// 修改drm id
// ShellUtils.execRootCmd("setprop persist.sys.cloud.drm.id $persist_sys_cloud_drm_id")
// 电量模拟需要大于1000
ShellUtils.execRootCmd("setprop persist.sys.cloud.battery.capacity ${device.battery}")
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_vendor ${device.expand.glVendor}")
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_renderer ${device.expand.glRenderer}")
// 这个值不能随便改 必须是 OpenGL ES %d.%d 这个格式
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_version ${device.expand.glVersion}")
// ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_vendor $persist_sys_cloud_gpu_egl_vendor")
// ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_version $persist_sys_cloud_gpu_egl_version")
} catch (e: Throwable) {
LogUtils.e(
Log.ERROR,
"ChangeDeviceInfoUtil",
"Error occurred while changing device info",
e
)
throw RuntimeException("Error occurred in changeDeviceInfo", e)
} }
} }
private fun callVCloudSettings_put(key: String?, value: String?, context: Context?) { private fun vcloudsettingsPut(key: String?, value: String?, context: Context) {
if (context == null) { if (key.isNullOrEmpty()) {
LogUtils.e(Log.ERROR, "ChangeDeviceInfoUtil", "Context cannot be null", null)
throw IllegalArgumentException("Context cannot be null")
}
if (key == null || key.isEmpty()) {
LogUtils.e(Log.ERROR, "ChangeDeviceInfoUtil", "Key cannot be null or empty", null) LogUtils.e(Log.ERROR, "ChangeDeviceInfoUtil", "Key cannot be null or empty", null)
throw IllegalArgumentException("Key cannot be null or empty") throw IllegalArgumentException("Key cannot be null or empty")
} }
@ -350,15 +171,11 @@ object ChangeDeviceInfoUtil {
Log.d("Debug", "putString executed successfully.") Log.d("Debug", "putString executed successfully.")
} catch (e: ClassNotFoundException) { } catch (e: ClassNotFoundException) {
LogUtils.e( LogUtils.e(
Log.WARN,
"ChangeDeviceInfoUtil",
"Class not found: android.provider.VCloudSettings\$Global. This may not be supported on this device.", "Class not found: android.provider.VCloudSettings\$Global. This may not be supported on this device.",
e e
) )
} catch (e: NoSuchMethodException) { } catch (e: NoSuchMethodException) {
LogUtils.e( LogUtils.e(
Log.WARN,
"ChangeDeviceInfoUtil",
"Method not found: android.provider.VCloudSettings\$Global.putString. This may not be supported on this", "Method not found: android.provider.VCloudSettings\$Global.putString. This may not be supported on this",
e e
) )
@ -366,23 +183,17 @@ object ChangeDeviceInfoUtil {
val cause = e.targetException val cause = e.targetException
if (cause is SecurityException) { if (cause is SecurityException) {
LogUtils.e( LogUtils.e(
Log.ERROR,
"ChangeDeviceInfoUtil",
"Error occurred in changeDeviceInfo", "Error occurred in changeDeviceInfo",
cause cause
) )
} else { } else {
LogUtils.e( LogUtils.e(
Log.ERROR,
"ChangeDeviceInfoUtil",
"Error occurred in changeDeviceInfo", "Error occurred in changeDeviceInfo",
cause cause
) )
} }
} catch (e: Exception) { } catch (e: Exception) {
LogUtils.e( LogUtils.e(
Log.ERROR,
"ChangeDeviceInfoUtil",
"Unexpected error during putString invocation", "Unexpected error during putString invocation",
e e
) )

View File

@ -77,9 +77,19 @@ object ClashUtil {
} }
fun unregisterReceiver(context: Context) { fun unregisterReceiver(context: Context) {
context.unregisterReceiver(clashStatusReceiver) try {
context.unregisterReceiver(clashStatusReceiver)
} catch (e: Exception) {
e.printStackTrace()
}
} }
fun getRandomLocale(): String {
val locales = listOf("ru", "us")
return locales.random()
}
fun switchProxyGroup(groupName: String?, proxyName: String?, controllerUrl: String) { fun switchProxyGroup(groupName: String?, proxyName: String?, controllerUrl: String) {
if (groupName == null || groupName.trim { it <= ' ' } if (groupName == null || groupName.trim { it <= ' ' }
.isEmpty() || proxyName == null || proxyName.trim { it <= ' ' }.isEmpty()) { .isEmpty() || proxyName == null || proxyName.trim { it <= ' ' }.isEmpty()) {

View File

@ -0,0 +1,72 @@
package com.android.grape.util
import android.os.Build
import androidx.annotation.RequiresApi
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonDeserializer
import com.google.gson.JsonObject
import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type
import java.util.*
object GsonUtils {
// 可配置的Gson实例
private val gson: Gson by lazy {
GsonBuilder()
// .setDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
.create()
}
// 自定义Gson实例
private val customGson = mutableMapOf<String, Gson>()
/**
* 通用转换函数
* @param json JsonObject
* @param clazz 目标类型
*/
fun <T> fromJsonObject(json: String, clazz: Class<T>): T {
return gson.fromJson(json, clazz)
}
/**
* 通用转换函数带泛型
* @param json JsonObject
* @param typeToken 类型Token
*/
fun <T> fromJsonObject(json: JsonObject, typeToken: TypeToken<T>): T {
return gson.fromJson(json, typeToken.type)
}
/**
* 使用自定义适配器转换
* @param json JsonObject
* @param clazz 目标类型
* @param adapters 适配器列表
*/
@RequiresApi(Build.VERSION_CODES.P)
fun <T> fromJsonObject(
json: JsonObject,
clazz: Class<T>,
vararg adapters: Pair<Type, Any>
): T {
val gsonKey = clazz.name + adapters.joinToString { it.first.typeName }
val customGsonInstance = customGson[gsonKey] ?: buildCustomGson(adapters).also {
customGson[gsonKey] = it
}
return customGsonInstance.fromJson(json, clazz)
}
private fun buildCustomGson(adapters: Array<out Pair<Type, Any>>): Gson {
val builder = GsonBuilder()
adapters.forEach { (type, adapter) ->
when (adapter) {
is JsonDeserializer<*> -> builder.registerTypeAdapter(type, adapter)
else -> throw IllegalArgumentException("Unsupported adapter type")
}
}
return builder.create()
}
}

View File

@ -0,0 +1,49 @@
package com.android.grape.util;
import android.content.Context;
import android.provider.Settings;
import android.util.Log;
import com.blankj.utilcode.util.LogUtils;
import org.json.JSONObject;
import java.nio.charset.StandardCharsets;
public class HttpUtil {
public static void execReloginTask(Context context) {
String url = "http://39.103.73.250/tt/ddj/preRequest!requestRelogin.do";
String ANDROID_ID = Settings.System.getString(context.getContentResolver(), Settings.System.ANDROID_ID);
String params = "platform=Android&tag=" + "119" + "&uuid=" + ANDROID_ID;
System.out.println("IOSTQ:execReloginTask->url:" + url + "?" + params);
try {
String result = new MyPost().PostData(context, " ".getBytes(StandardCharsets.UTF_8), url + "?" + params);
LogUtils.e("request result : " + result);
} catch (Exception e) {
Log.i("TAG", "execTask error:" + e.getMessage());
}
}
public static void execInstallTask(Context context) {
String url = "http://39.103.73.250/tt/ddj/preRequest!requestInstall.do";
String ANDROID_ID = Settings.System.getString(context.getContentResolver(), Settings.System.ANDROID_ID);
String params = "platform=Android&tag=" + "119" + "&uuid=" + ANDROID_ID;
LogUtils.e("IOSTQ:request result : " + url + "?" + params);
try {
String result = new MyPost().PostData(context, " ".getBytes("utf-8"), url + "?" + params);
LogUtils.e("request result : " + result);
} catch (Exception e) {
e.printStackTrace();
LogUtils.i("TAG", "execTask error:" + e.getMessage());
}
}
}

View File

@ -0,0 +1,168 @@
package com.android.grape.util;
import android.content.Context;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
public class MyPost {
private static final String TAG = "MyPost";
// private static final String TAG = TT.dd("4B7HyaIsVcs=");
private static okhttp3.OkHttpClient oklient = new okhttp3.OkHttpClient();
public String PostData(Context context, byte[] byt, String url_) {
byte[] bytes = postDataBytes(context, byt, url_);
if (bytes != null && bytes.length > 0) {
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return null;
}
public String PostDataCommon(Context context, byte[] byt, String url_) {
byte[] bytes = postDataBytes(context, byt, url_);
if (bytes != null && bytes.length >= 0) {
if (bytes.length == 0) {
return "";
} else {
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
return null;
}
public String httpGet(String url) throws Exception {
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
//默认值我GET
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
System.out.println("\nSending 'GET' request to URL : " + url);
System.out.println("Response Code : " + responseCode);
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer response = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
//打印结果
System.out.println(response.toString());
return response.toString();
}
public byte[] postDataBytes(Context context, byte[] byt, String url_) {
String result = null;
HttpURLConnection httpUrlConnection = null;
InputStream inStrm = null;
ByteArrayOutputStream baos = null;
BufferedInputStream bis = null;
try {
httpUrlConnection = NetWorkUtils.getHttpURLConnection(context, url_);
httpUrlConnection.setAllowUserInteraction(true);
httpUrlConnection.setDoOutput(true);
httpUrlConnection.setDoInput(true);
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setRequestProperty("Connection", "close");//add 20200428
httpUrlConnection.setRequestProperty("Content-type", "application/x-java-serialized-object");
// httpUrlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
httpUrlConnection.setRequestMethod("POST");
httpUrlConnection.setConnectTimeout(20000);
OutputStream outStrm = null;
outStrm = httpUrlConnection.getOutputStream();
outStrm.write(byt);
outStrm.flush();
outStrm.close();
inStrm = httpUrlConnection.getInputStream();
baos = new ByteArrayOutputStream();
bis = new BufferedInputStream(inStrm);
byte[] buf = new byte[1024];
int readSize = -1;
while ((readSize = bis.read(buf)) != -1) {
baos.write(buf, 0, readSize);
}
byte[] data = baos.toByteArray();
return data;
} catch (Exception e) {
e.printStackTrace();
result = null;
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inStrm != null) {
try {
inStrm.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (httpUrlConnection != null) {
httpUrlConnection.disconnect();
httpUrlConnection = null;
}
System.gc();
}
return null;
}
}

View File

@ -0,0 +1,27 @@
package com.android.grape.util;
import android.content.Context;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
public class NetWorkUtils {
public static HttpURLConnection getHttpURLConnection(Context context,
String _url) throws IOException {
return getHttpURLConnection(context, _url, false);
}
private static int dynamicPort0 = 20380;
public static HttpURLConnection getHttpURLConnection(Context context, String _url, boolean isProxy) throws IOException {
URL url = new URL(_url);
HttpURLConnection httpUrlConnection = null;
httpUrlConnection = (HttpURLConnection)url.openConnection();
return httpUrlConnection;
}
}

View File

@ -0,0 +1,309 @@
package com.android.grape.util
import android.Manifest
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
/**
* 通知权限管理工具
*
* 使用示例
*
* class MainActivity : AppCompatActivity() {
* private lateinit var permissionHandler: NotificationPermissionHandler
*
* override fun onCreate(savedInstanceState: Bundle?) {
* super.onCreate(savedInstanceState)
*
* // 初始化权限处理器
* permissionHandler = NotificationPermissionHandler(this, ::onPermissionResult)
*
* // 检查通知权限
* if (permissionHandler.shouldRequestNotificationPermission()) {
* permissionHandler.requestNotificationPermission()
* }
* }
*
* override fun onResume() {
* super.onResume()
* // 处理从设置返回的情况
* permissionHandler.handleReturnFromSettings()
* }
*
* // 权限回调处理
* private fun onPermissionResult(result: PermissionResult) {
* when(result) {
* PermissionResult.GRANTED -> showNotification()
* PermissionResult.DENIED -> showRationale()
* PermissionResult.NEEDS_SETTINGS -> showSettingsGuide()
* PermissionResult.NOT_NEEDED -> showNotification()
* }
* }
* }
*/
class NotificationPermissionHandler(
private val context: Context,
private val callback: (PermissionResult) -> Unit
) {
// Android 13+ 通知权限请求启动器
private var permissionLauncher: ActivityResultLauncher<String>? = null
// 请求状态跟踪
private var permissionRequestPending = false
private var lastPermissionState = false
// 用于跟踪从设置页面返回的状态
private var returnFromSettings = false
init {
registerPermissionLauncherIfNeeded()
}
/**
* 检查是否需要请求通知权限
*/
fun shouldRequestNotificationPermission(): Boolean {
return !areNotificationsEnabled()
}
/**
* 检查通知权限是否已授予
*/
fun areNotificationsEnabled(): Boolean {
return when {
// Android 13+ (TIRAMISU) 需要运行时权限
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
ContextCompat.checkSelfPermission(
context,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
}
// Android 8.0+ (Oreo) 检查通知设置
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
NotificationManagerCompat.from(context).areNotificationsEnabled()
}
// Android 7.1 及以下不需要特别权限
else -> true
}
}
/**
* 请求通知权限
*/
fun requestNotificationPermission() {
// 保存当前权限状态,用于比较设置后是否发生变化
lastPermissionState = areNotificationsEnabled()
when {
// Android 13+ - 使用运行时权限请求
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
requestPermissionApi33()
}
// Android 8.0-12 - 跳转到应用通知设置
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
openNotificationSettings()
permissionRequestPending = true
}
// Android 7.1 及以下 - 默认启用
else -> {
callback(PermissionResult.NOT_NEEDED)
}
}
}
/**
* 处理从设置页面返回的情况
* 应在Activity的onResume中调用
*/
fun handleReturnFromSettings() {
if (returnFromSettings) {
returnFromSettings = false
checkSettingsChanged()
}
}
/**
* 打开应用的通知设置页面
*/
fun openNotificationSettings() {
val intent = when {
// Android 8.0及以上
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
Intent().apply {
action = Settings.ACTION_APP_NOTIFICATION_SETTINGS
putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
// 处理特定设备需要额外设置的情况
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
putExtra(Settings.EXTRA_CHANNEL_ID, context.applicationInfo.uid)
}
}
}
// Android 7.1及以下
else -> {
Intent().apply {
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
addCategory(Intent.CATEGORY_DEFAULT)
data = Uri.parse("package:${context.packageName}")
}
}
}
if (context is AppCompatActivity) {
returnFromSettings = true
context.startActivity(intent)
}
}
/**
* 显示权限解释对话框
*/
fun showPermissionRationaleDialog() {
if (context !is AppCompatActivity) return
val activity = context as AppCompatActivity
AlertDialog.Builder(activity)
.setTitle("需要通知权限")
.setMessage("我们需要通知权限来向你发送重要信息、更新提醒等内容。请允许通知权限以使用完整功能。")
.setPositiveButton("确定") { _, _ ->
requestNotificationPermission()
}
.setNegativeButton("取消", null)
.show()
}
// 私有方法 --------------------------------------------
/**
* Android 13+ 权限请求处理
*/
@RequiresApi(33)
private fun requestPermissionApi33() {
if (permissionLauncher == null) {
throw IllegalStateException("Permission launcher not registered. Call registerPermissionLauncherIfNeeded() first.")
}
val activity = context as? AppCompatActivity ?: return
when {
// 已经拥有权限
areNotificationsEnabled() -> {
callback(PermissionResult.GRANTED)
}
// 需要显示权限解释
ActivityCompat.shouldShowRequestPermissionRationale(
activity,
Manifest.permission.POST_NOTIFICATIONS
) -> {
showPermissionRationaleDialog()
}
// 请求权限
else -> {
permissionRequestPending = true
permissionLauncher?.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
}
/**
* 注册权限启动器仅Android 13+需要
*/
private fun registerPermissionLauncherIfNeeded() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
if (context !is AppCompatActivity) return
val activity = context as AppCompatActivity
permissionLauncher = activity.registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
callback(PermissionResult.GRANTED)
} else {
// 如果用户勾选了"不再询问"
if (!ActivityCompat.shouldShowRequestPermissionRationale(
activity,
Manifest.permission.POST_NOTIFICATIONS
)) {
callback(PermissionResult.NEEDS_SETTINGS)
} else {
callback(PermissionResult.DENIED)
}
}
permissionRequestPending = false
}
}
/**
* 检查设置页面返回后的权限变化
*/
private fun checkSettingsChanged() {
if (!permissionRequestPending) return
permissionRequestPending = false
val currentState = areNotificationsEnabled()
when {
currentState -> callback(PermissionResult.GRANTED)
currentState != lastPermissionState -> callback(PermissionResult.DENIED)
// 状态未改变
else -> Unit // 无操作
}
}
/**
* 权限请求结果枚举
*/
enum class PermissionResult {
GRANTED, // 权限已授予
DENIED, // 权限被拒绝
NEEDS_SETTINGS, // 需要跳转到设置
NOT_NEEDED // 不需要权限Android 7.1及以下)
}
companion object {
/**
* 快速检查当前设备的通知权限状态
*/
@JvmStatic
fun checkPermissionState(context: Context): PermissionResult {
return when {
// Android 13+ 需要运行时权限
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
if (ContextCompat.checkSelfPermission(
context,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED) {
PermissionResult.GRANTED
} else {
PermissionResult.DENIED
}
}
// Android 8.0+ 检查通知设置
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
if (NotificationManagerCompat.from(context).areNotificationsEnabled()) {
PermissionResult.GRANTED
} else {
PermissionResult.NEEDS_SETTINGS
}
}
// Android 7.1 及以下默认启用通知
else -> PermissionResult.NOT_NEEDED
}
}
}
}

View File

@ -696,7 +696,7 @@ object Util {
val valid = false val valid = false
println("IOSTQ:execReloginTask->url:$url?$params") println("IOSTQ:execReloginTask->url:$url?$params")
try { try {
val result: String? = MyPost.postData(" ".toByteArray(charset("utf-8")), val result: String? = MyPost.postData(" ".toByteArray(charset = Charsets.UTF_8),
"$url?$params" "$url?$params"
) )
@ -748,7 +748,7 @@ object Util {
// boolean valid = false; // boolean valid = false;
printStr("IOSTQ:request result : $url?$params") printStr("IOSTQ:request result : $url?$params")
try { try {
val result: String? = MyPost.postData(" ".toByteArray(charset("utf-8")), val result: String? = MyPost.postData(" ".toByteArray(charset = Charsets.UTF_8),
"$url?$params" "$url?$params"
) )
@ -2394,7 +2394,7 @@ object Util {
// Log.i(TAG, "setFinish"); // Log.i(TAG, "setFinish");
MonitorService.setRunning(false) MonitorService.setRunning(false)
killRecordProcess(context, "com.tunnelworkshop.postern") // killRecordProcess(context, "com.tunnelworkshop.postern")
killRecordProcess(context, AUTO_JSPACKAGENAME) killRecordProcess(context, AUTO_JSPACKAGENAME)
Handler(Looper.getMainLooper()).postDelayed(Runnable { Handler(Looper.getMainLooper()).postDelayed(Runnable {
MonitorService.onEvent( MonitorService.onEvent(

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">127.0.0.1</domain>
</domain-config>
</network-security-config>