This commit is contained in:
Administrator 2025-07-08 22:16:46 +08:00
parent b504984268
commit fc62906c0e
18 changed files with 403 additions and 230 deletions

View File

@ -4,6 +4,14 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-07-07T06:37:35.266033300Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="Default" identifier="serial=8.217.74.194:8924;connection=1af33e42" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>

View File

@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">

View File

@ -9,8 +9,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.BIND_VPN_SERVICE"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"
android:maxSdkVersion="32"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VPN_SERVICE" />

View File

@ -3,6 +3,7 @@ package com.android.grape
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
@ -11,11 +12,11 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.android.grape.databinding.ActivityMainBinding
import com.android.grape.job.MonitorService
import com.android.grape.util.ClashUtil
import com.android.grape.util.NotificationPermissionHandler
import com.android.grape.util.ScriptUtil
import com.android.grape.util.StoragePermissionHelper
import com.blankj.utilcode.util.LogUtils
class MainActivity : AppCompatActivity() {
private val viewModel by viewModels<MainViewModel>()
@ -34,21 +35,22 @@ class MainActivity : AppCompatActivity() {
checkPermission()
ScriptUtil.registerScriptResultReceiver()
viewBinding.start.setOnClickListener {
try {
ClashUtil.startProxy(this)
ClashUtil.switchProxyGroup(
"GLOBAL",
ClashUtil.getRandomLocale(),
"http://127.0.0.1:6170"
)
} catch (e: Exception) {
LogUtils.e("startProxyVpn: Failed to start VPN", e)
Toast.makeText(
this,
"Failed to start VPN: " + (if (e.message != null) e.message else "Unknown error"),
Toast.LENGTH_SHORT
).show()
}
MonitorService.onEvent(MainApplication.instance)
// try {
// ClashUtil.startProxy(this)
// ClashUtil.switchProxyGroup(
// "GLOBAL",
// ClashUtil.getRandomLocale(),
// "http://127.0.0.1:6170"
// )
// } catch (e: Exception) {
// LogUtils.e("startProxyVpn: Failed to start VPN", e)
// Toast.makeText(
// this,
// "Failed to start VPN: " + (if (e.message != null) e.message else "Unknown error"),
// Toast.LENGTH_SHORT
// ).show()
// }
}
viewBinding.stop.setOnClickListener {
ClashUtil.stopProxy(this)
@ -63,6 +65,7 @@ class MainActivity : AppCompatActivity() {
}
private fun checkPermission() {
Log.d("TAG", "checkPermission: ")
permissionHandler = NotificationPermissionHandler(this) { result ->
handlePermissionResult(result)
}

View File

@ -3,6 +3,7 @@ package com.android.grape
import androidx.lifecycle.ViewModel
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkManager
import com.android.grape.job.MonitorService
import com.android.grape.service.MyAccessibilityService
import com.android.grape.work.CheckAccessibilityWorker
import java.util.concurrent.TimeUnit
@ -21,6 +22,5 @@ class MainViewModel:ViewModel() {
.build()
WorkManager.getInstance(MainApplication.instance).enqueue(workRequest)
}
}
}

View File

@ -23,7 +23,8 @@ class DownloadAppJobService : JobIntentService() {
if (succ) {
errTime = 0L
StartVpnServerJobService.onEvent(this)
InstallService.onEvent(this)
// StartVpnServerJobService.onEvent(this)
// StartVpnPortJobService.onEvent(this)
} else {
Util.isClickRet = false

View File

@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.core.app.JobIntentService
import com.android.grape.net.ChangeCallBack
import com.android.grape.util.ChangeDeviceInfoUtil
import com.android.grape.util.MockTools
import com.android.grape.util.ServiceUtils
@ -23,9 +24,9 @@ class OpenAppService : JobIntentService() {
ServiceUtils.setEnableApp("com.android.chrome", true)
ServiceUtils.setEnableApp("com.UCMobile", true)
if (Util.isCanAuto && Util.canAutoLc.isNotEmpty()) {
MockTools.exec("pm grant org.autojs.autojs android.permission.READ_EXTERNAL_STORAGE") //sdcard权限
MockTools.exec("pm grant org.autojs.autojs android.permission.SYSTEM_ALERT_WINDOW") //悬浮窗权限
MockTools.exec("settings put secure enabled_accessibility_services org.autojs.autojs/com.stardust.autojs.core.accessibility.AccessibilityService")
MockTools.exec("pm grant ${Util.AUTO_JSPACKAGENAME} android.permission.READ_EXTERNAL_STORAGE") //sdcard权限
MockTools.exec("pm grant ${Util.AUTO_JSPACKAGENAME} android.permission.SYSTEM_ALERT_WINDOW") //悬浮窗权限
MockTools.exec("settings put secure enabled_accessibility_services ${Util.AUTO_JSPACKAGENAME}/${Util.AUTO_JSPACKAGENAME}.core.accessibility.AccessibilityService")
Util.doScript(this, Util.AUTO_JSPACKAGENAME) //autojs
}
try {
@ -37,13 +38,21 @@ class OpenAppService : JobIntentService() {
// Log.d("IOSTQ:", "执行新装任务")
// Util.setInfo(this)
// }
ChangeDeviceInfoUtil.changeDeviceInfo()
// ChangeDeviceInfoUtil.changeDeviceInfo()
ChangeDeviceInfoUtil.changeDevice(callBack = object : ChangeCallBack {
override fun changeSuccess() {
Util.openRecordApp(this@OpenAppService)
}
override fun changeFailed() {
Util.setFinish(this@OpenAppService)
}
})
} catch (e: IOException) {
e.printStackTrace()
}
// Util.hookOpenApp(this);
Util.openRecordApp(this)
}
companion object {

View File

@ -0,0 +1,6 @@
package com.android.grape.net
interface ChangeCallBack {
fun changeSuccess()
fun changeFailed()
}

View File

@ -2,22 +2,28 @@ package com.android.grape.net
import android.util.Log
import com.blankj.utilcode.util.LogUtils
import com.google.gson.Gson
import okhttp3.*
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.logging.HttpLoggingInterceptor
import okhttp3.logging.HttpLoggingInterceptor.Level
import okhttp3.logging.HttpLoggingInterceptor.Logger
import java.io.IOException
import java.util.concurrent.TimeUnit
object HttpUtils {
const val HOST: String = "https://openapi-hk.armcloud.net"
// OkHttp客户端配置
private val client: OkHttpClient by lazy {
OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(15, TimeUnit.SECONDS)
.writeTimeout(15, TimeUnit.SECONDS)
.addInterceptor(LoggingInterceptor()) // 添加日志拦截器
.addInterceptor(HttpLoggingInterceptor().apply {
level = Level.BODY
})
.build()
}
@ -30,47 +36,6 @@ object HttpUtils {
fun onFailure(error: String, code: Int?)
}
// 日志拦截器
private class LoggingInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
val url = request.url.toString()
val method = request.method
// 记录请求信息
LogUtils.d("HTTP_REQUEST", "URL: $url")
LogUtils.d("HTTP_REQUEST", "Method: $method")
if ("POST" == method) {
request.body?.let { body ->
if (body is FormBody) {
val formBody = StringBuilder()
for (i in 0 until body.size) {
formBody.append("${body.name(i)}:${body.value(i)}; ")
}
Log.d("HTTP_REQUEST", "Form Data: $formBody")
} else if (body is MultipartBody) {
Log.d("HTTP_REQUEST", "Multipart Form Data")
} else {
Log.d("HTTP_REQUEST", "Body: ${body.contentType()}")
}
}
}
val response = chain.proceed(request)
val responseBody = response.peekBody(Long.MAX_VALUE)
val responseString = responseBody.string()
// 记录响应信息
LogUtils.d("HTTP_RESPONSE", "Code: ${response.code}")
LogUtils.d("HTTP_RESPONSE", "Response: $responseString")
return response.newBuilder()
.body(responseBody)
.build()
}
}
/**
* GET 请求异步
*
@ -82,10 +47,9 @@ object HttpUtils {
fun getAsync(
url: String,
params: Map<String, String>? = null,
headers: Map<String, String>? = null,
callback: HttpCallback
) {
val request = buildGetRequest(url, params, headers)
val request = buildGetRequest(url, params)
executeRequestAsync(request, callback)
}
@ -99,31 +63,10 @@ object HttpUtils {
*/
fun postAsync(
url: String,
body: String,
headers: Map<String, String>? = null,
body: String? = null,
callback: HttpCallback
) {
val requestBody = body.toRequestBody(JSON_MEDIA_TYPE)
val request = buildPostRequest(url, requestBody, headers)
executeRequestAsync(request, callback)
}
/**
* POST Form Data 请求异步
*
* @param url 请求URL
* @param formData 表单数据
* @param headers 请求头可选
* @param callback 回调接口
*/
fun postFormAsync(
url: String,
formData: Map<String, String>,
headers: Map<String, String>? = null,
callback: HttpCallback
) {
val formBody = buildFormBody(formData)
val request = buildPostRequest(url, formBody, headers)
val request = buildPostRequest(url, body)
executeRequestAsync(request, callback)
}
@ -138,9 +81,8 @@ object HttpUtils {
fun getSync(
url: String,
params: Map<String, String>? = null,
headers: Map<String, String>? = null
): Pair<String?, Int> {
val request = buildGetRequest(url, params, headers)
val request = buildGetRequest(url, params)
return executeRequestSync(request)
}
@ -154,11 +96,9 @@ object HttpUtils {
*/
fun postSync(
url: String,
body: String,
headers: Map<String, String>? = null
body: String? = null
): Pair<String?, Int> {
val requestBody = body.toRequestBody(JSON_MEDIA_TYPE)
val request = buildPostRequest(url, requestBody, headers)
val request = buildPostRequest(url, body)
return executeRequestSync(request)
}
@ -172,46 +112,72 @@ object HttpUtils {
// 内部方法 --------------------------------
private fun buildGetRequest(
url: String,
path: String ,
params: Map<String, String>?,
headers: Map<String, String>?
): Request {
val url = "$HOST$path"
val httpUrlBuilder = url.toHttpUrlOrNull()?.newBuilder()
?: throw IllegalArgumentException("Invalid URL: $url")
// 添加查询参数
var param = ""
params?.forEach { (key, value) ->
httpUrlBuilder.addQueryParameter(key, value)
param += "&${key}=${value}"
}
if (param.isNotEmpty()){
param = param.substring(1)
}
val requestBuilder = Request.Builder().url(httpUrlBuilder.build())
// 添加请求头
addHeaders(requestBuilder, headers)
val authver = "2.0"
val timestamp = System.currentTimeMillis()
val sign =
ArmCloudSignatureV2.calculateSignature(timestamp.toString(), path, param)
addHeaders(
requestBuilder,
mapOf(
"authver" to authver,
"x-ak" to ArmCloudSignatureV2.SECRET_KEY,
"x-timestamp" to timestamp.toString(),
"x-sign" to sign
)
)
return requestBuilder.build()
}
private fun buildPostRequest(
url: String,
body: RequestBody,
headers: Map<String, String>?
path: String,
body: String? = null
): Request {
val url = "$HOST$path"
val bodyString = body?:""
val requestBuilder = Request.Builder()
.url(url)
.post(body)
// 添加请求头
addHeaders(requestBuilder, headers)
.post(bodyString.toRequestBody(JSON_MEDIA_TYPE))
val authver = "2.0"
val timestamp = System.currentTimeMillis()
val sign =
ArmCloudSignatureV2.calculateSignature(timestamp.toString(), path, body)
addHeaders(
requestBuilder,
mapOf(
"authver" to authver,
"x-ak" to ArmCloudSignatureV2.SECRET_KEY,
"x-timestamp" to timestamp.toString(),
"x-sign" to sign
)
)
return requestBuilder.build()
}
private fun addHeaders(
builder: Request.Builder,
headers: Map<String, String>?
headers: Map<String, String>
) {
headers?.forEach { (key, value) ->
headers.forEach { (key, value) ->
builder.addHeader(key, value)
}
}
@ -252,13 +218,13 @@ object HttpUtils {
private fun executeRequestSync(request: Request): Pair<String?, Int> {
return try {
val response = client.newCall(request).execute()
val responseBody = response.body?.string()
val responseBody = response.peekBody(Long.MAX_VALUE).string()
val code = response.code
if (response.isSuccessful && responseBody != null) {
Log.d("TAG", "executeRequestSync: $responseBody")
if (response.isSuccessful && responseBody.isNotEmpty()) {
Pair(responseBody, code)
} else {
Pair(null, code)
Pair(null, -1)
}
} catch (e: IOException) {
Pair(null, -1) // 网络错误状态码

View File

@ -140,7 +140,7 @@ object MyGet {
httpUrlConnection = url.openConnection() as HttpURLConnection
httpUrlConnection.allowUserInteraction = true
httpUrlConnection!!.doOutput = false
httpUrlConnection.doOutput = false
httpUrlConnection.doInput = true
httpUrlConnection.useCaches = false
httpUrlConnection.instanceFollowRedirects = false

View File

@ -1,5 +0,0 @@
package com.android.grape.net
class NetworkHelper {
}

View File

@ -5,14 +5,168 @@ import android.content.Context
import android.util.Log
import com.android.grape.MainApplication
import com.android.grape.data.Device
import com.android.grape.net.Api
import com.android.grape.net.ChangeCallBack
import com.android.grape.util.Util.paramsJson
import com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.lang.reflect.InvocationTargetException
object ChangeDeviceInfoUtil {
val scope = CoroutineScope(Dispatchers.IO)
fun changeDevice(callBack: ChangeCallBack){
try {
val deviceObject = paramsJson?.getJSONObject("device")
if (deviceObject == null) {
LogUtils.d("ERROR", "ChangeDeviceInfoUtil", "device is null")
return
}
val device = GsonUtils.fromJsonObject(deviceObject.toString(), Device::class.java)
val padCode = ShellUtils.execRootCmdAndGetResult("getprop ro.boot.pad_code")
Log.d("TAG", "changeDevice: $padCode")
val jsonString = JSONObject().apply {
put("padCodes", JSONArray().apply {
put(padCode)
})
put("modemPropertiesList", JSONArray().apply {
put(JSONObject().apply {
put("propertiesName", "MCCMNC")
put("propertiesValue", "${device.mcc},${device.mnc}")
})
})
put("systemPropertiesList", JSONArray().apply {
put(JSONObject().apply {
put("propertiesName", "ro.product.manufacturer")
put("propertiesValue", device.manufactor)
})
put(JSONObject().apply {
put("propertiesName", "ro.product.brand")
put("propertiesValue", device.brand)
})
put(JSONObject().apply {
put("propertiesName", "ro.product.model")
put("propertiesValue", device.model)
})
// put(JSONObject().apply {
// put("propertiesName", "ro.build.id")
// put("propertiesValue", device.buildDisplayId)
// })
put(JSONObject().apply {
put("propertiesName", "ro.build.display.id")
put("propertiesValue", device.buildDisplayId)
})
put(JSONObject().apply {
put("propertiesName", "ro.product.name")
put("propertiesValue", device.product)
})
put(JSONObject().apply {
put("propertiesName", "ro.product.device")
put("propertiesValue", device.device)
})
put(JSONObject().apply {
put("propertiesName", "ro.product.board")
put("propertiesValue", device.expand.board)
})
// put(JSONObject().apply {
// put("propertiesName", "ro.build.tags")
// put("propertiesValue", device.expand)
// })
put(JSONObject().apply {
put("propertiesName", "ro.build.fingerprint")
put("propertiesValue", device.expand.fingerprint)
})
put(JSONObject().apply {
put("propertiesName", "ro.build.date.utc")
put("propertiesValue", device.expand.roBuildDateUtc)
})
put(JSONObject().apply {
put("propertiesName", "ro.build.user")
put("propertiesValue", device.expand.uname)
})
// put(JSONObject().apply {
// put("propertiesName", "ro.build.host")
// put("propertiesValue", device.expand.)
// })
put(JSONObject().apply {
put("propertiesName", "ro.build.description")
put("propertiesValue", device.expand.roBuildDescription)
})
put(JSONObject().apply {
put("propertiesName", "ro.build.version.incremental")
put("propertiesValue", device.expand.incremental)
})
// put(JSONObject().apply {
// put("propertiesName", "ro.build.version.codename")
// put("propertiesValue", device.cod)
// })
})
put("settingPropertiesList", JSONArray().apply {
put(JSONObject().apply {
put("propertiesName", "ssaid/${Util.recordPackageName}")
put("propertiesValue", device.androidId)
})
put(JSONObject().apply {
put("propertiesName", "bt/mac")
put("propertiesValue", device.expand.lyMAC)
})
put(JSONObject().apply {
put("propertiesName", "language")
put("propertiesValue", device.locale.lang)
})
put(JSONObject().apply {
put("propertiesName", "timezone")
put("propertiesValue", device.tzDisplayName)
})
// put(JSONObject().apply {
// put("propertiesName", "systemvolume")
// put("propertiesValue", device.expand.)
// })
})
put("oaidPropertiesList", JSONArray().apply {
put(JSONObject().apply {
put("propertiesName", "AAID")
put("propertiesValue", device.advertiserId)
})
})
}.toString()
val response = Api.updatePad(jsonString)
val dataList = response.data
if (response.isSuccess() && dataList!= null && dataList.isNotEmpty()){
val padTask = dataList[0]
scope.launch {
Log.d("TAG", "changeDevice: $padTask")
var loop = true
while (loop) {
delay(5000)
val result = Api.padTaskDetail(padTask.taskId)
if (result == 3) {
Log.d("ChangeDeviceInfoUtil", "changeDeviceInfo changeDeviceInfo success")
loop = false
callBack.changeSuccess()
} else if (result == -1) {
Log.d("ChangeDeviceInfoUtil", "changeDeviceInfo changeDeviceInfo fail")
loop = false
callBack.changeFailed()
}
}
}
}
} catch (e: JSONException) {
e.printStackTrace()
}
}
fun changeDeviceInfo() {
try {
MockTools.exec("pm grant com.android.grape android.permission.INTERACT_ACROSS_USERS")
MockTools.exec("pm grant com.android.grape android.permission.WRITE_SECURE_SETTINGS")
MockTools.exec("pm setenforce 0")
val deviceObject = paramsJson?.getJSONObject("device")
if (deviceObject == null) {
LogUtils.d("ERROR", "ChangeDeviceInfoUtil", "device is null")
@ -51,7 +205,7 @@ object ChangeDeviceInfoUtil {
// **os_ver**
vcloudsettingsPut(currentPkgName + "_os_ver", device.sdkVer, context)
// **tz** (时区)
vcloudsettingsPut(currentPkgName + "_tz", device.tzOffTime.toString(), context)
vcloudsettingsPut(currentPkgName + "_tz", TimeZoneUtils.formatTimeZoneOffset(device.tzOffTime), context)
vcloudsettingsPut("$currentPkgName.advertiserId", device.advertiserId, context)
vcloudsettingsPut("$currentPkgName.brand", device.brand, context)
@ -121,6 +275,9 @@ object ChangeDeviceInfoUtil {
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}")
ShellUtils.execRootCmd("setprop persist.sys.timezone ${TimeZoneUtils.formatTimeZoneOffset(device.tzOffTime)}")
ShellUtils.execRootCmd("setprop persist.sys.country ${device.country}")
ShellUtils.execRootCmd("setprop persist.sys.language ${device.expand.displayLang}")
// 这个值不能随便改 必须是 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")

View File

@ -12,25 +12,26 @@ object MockTools {
fun exec(cmd: String): String {
var retString = ""
try {
//创建socket
val myCmd = "SU|$cmd"
val mSocket = Socket()
val inetSocketAddress = InetSocketAddress("127.0.0.1", 12345)
mSocket.connect(inetSocketAddress)
val bufferedWriter = BufferedWriter(OutputStreamWriter(mSocket.getOutputStream()))
val bufferedReader = BufferedReader(InputStreamReader(mSocket.getInputStream()))
bufferedWriter.write(myCmd + "\r\n")
bufferedWriter.flush()
val stringBuilder = StringBuilder()
var line: String? = null
while ((bufferedReader.readLine().also { line = it }) != null) {
stringBuilder.append(line + "\n")
}
//retString = bufferedReader.readLine();
retString = stringBuilder.toString()
bufferedReader.close()
bufferedWriter.close()
retString = ShellUtils.execRootCmdAndGetResult(cmd)
// //创建socket
// val myCmd = "SU|$cmd"
//
// val mSocket = Socket()
// val inetSocketAddress = InetSocketAddress("127.0.0.1", 12345)
// mSocket.connect(inetSocketAddress)
// val bufferedWriter = BufferedWriter(OutputStreamWriter(mSocket.getOutputStream()))
// val bufferedReader = BufferedReader(InputStreamReader(mSocket.getInputStream()))
// bufferedWriter.write(myCmd + "\r\n")
// bufferedWriter.flush()
// val stringBuilder = StringBuilder()
// var line: String? = null
// while ((bufferedReader.readLine().also { line = it }) != null) {
// stringBuilder.append(line + "\n")
// }
// //retString = bufferedReader.readLine();
// retString = stringBuilder.toString()
// bufferedReader.close()
// bufferedWriter.close()
} catch (eeeee: Exception) {
eeeee.printStackTrace()
}
@ -40,25 +41,26 @@ object MockTools {
fun execRead(cmd: String): String {
var retString = ""
try {
//创建socket
val myCmd = "SU_1|$cmd"
val mSocket = Socket()
val inetSocketAddress = InetSocketAddress("127.0.0.1", 12345)
mSocket.connect(inetSocketAddress)
val bufferedWriter = BufferedWriter(OutputStreamWriter(mSocket.getOutputStream()))
val bufferedReader = BufferedReader(InputStreamReader(mSocket.getInputStream()))
bufferedWriter.write(myCmd + "\r\n")
bufferedWriter.flush()
val stringBuilder = StringBuilder()
var line: String? = null
while ((bufferedReader.readLine().also { line = it }) != null) {
stringBuilder.append(line + "\n")
}
retString = stringBuilder.toString()
//retString = bufferedReader.readLine();
bufferedReader.close()
bufferedWriter.close()
retString = ShellUtils.execRootCmdAndGetResult(cmd)
// //创建socket
// val myCmd = "SU_1|$cmd"
//
// val mSocket = Socket()
// val inetSocketAddress = InetSocketAddress("127.0.0.1", 12345)
// mSocket.connect(inetSocketAddress)
// val bufferedWriter = BufferedWriter(OutputStreamWriter(mSocket.getOutputStream()))
// val bufferedReader = BufferedReader(InputStreamReader(mSocket.getInputStream()))
// bufferedWriter.write(myCmd + "\r\n")
// bufferedWriter.flush()
// val stringBuilder = StringBuilder()
// var line: String? = null
// while ((bufferedReader.readLine().also { line = it }) != null) {
// stringBuilder.append(line + "\n")
// }
// retString = stringBuilder.toString()
// //retString = bufferedReader.readLine();
// bufferedReader.close()
// bufferedWriter.close()
} catch (eeeee: Exception) {
eeeee.printStackTrace()
}

View File

@ -8,6 +8,7 @@ import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi
@ -106,7 +107,7 @@ class NotificationPermissionHandler(
fun requestNotificationPermission() {
// 保存当前权限状态,用于比较设置后是否发生变化
lastPermissionState = areNotificationsEnabled()
Log.d(TAG, "requestNotificationPermission: ")
when {
// Android 13+ - 使用运行时权限请求
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
@ -198,22 +199,23 @@ class NotificationPermissionHandler(
}
val activity = context as? AppCompatActivity ?: return
Log.d(TAG, "requestPermissionApi33: ")
when {
// 已经拥有权限
areNotificationsEnabled() -> {
callback(PermissionResult.GRANTED)
}
// 需要显示权限解释
ActivityCompat.shouldShowRequestPermissionRationale(
activity,
Manifest.permission.POST_NOTIFICATIONS
) -> {
showPermissionRationaleDialog()
}
// ActivityCompat.shouldShowRequestPermissionRationale(
// activity,
// Manifest.permission.POST_NOTIFICATIONS
// ) -> {
// showPermissionRationaleDialog()
// }
// 请求权限
else -> {
permissionRequestPending = true
Log.d(TAG, "requestPermissionApi33: launch")
permissionLauncher?.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
@ -276,28 +278,36 @@ class NotificationPermissionHandler(
}
companion object {
private const val TAG = "NotificationPermissionH"
/**
* 快速检查当前设备的通知权限状态
*/
@JvmStatic
fun checkPermissionState(context: Context): PermissionResult {
Log.d(TAG, "checkPermissionState: --------->")
return when {
// Android 13+ 需要运行时权限
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> {
Log.d(TAG, "checkPermissionState: Android 13+")
if (ContextCompat.checkSelfPermission(
context,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "checkPermissionState: Granted")
PermissionResult.GRANTED
} else {
Log.d(TAG, "checkPermissionState: Denied")
PermissionResult.DENIED
}
}
// Android 8.0+ 检查通知设置
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
Log.d(TAG, "checkPermissionState: Android 8.0+")
if (NotificationManagerCompat.from(context).areNotificationsEnabled()) {
Log.d(TAG, "checkPermissionState: Granted")
PermissionResult.GRANTED
} else {
Log.d(TAG, "checkPermissionState: Denied")
PermissionResult.NEEDS_SETTINGS
}
}

View File

@ -102,7 +102,7 @@ public class ShellUtils {
}
public static String execRootCmdAndGetResult(String cmd) {
Log.d("ShellUtils", "execRootCmdAndGetResult - Started execution for command: " + cmd);
// Log.d("ShellUtils", "execRootCmdAndGetResult - Started execution for command: " + cmd);
if (cmd == null || cmd.trim().isEmpty()) {
LogUtils.e(Log.ERROR, "ShellUtils", "Unsafe or empty command. Aborting execution.", null);
throw new IllegalArgumentException("Unsafe or empty command.");
@ -116,18 +116,18 @@ public class ShellUtils {
ExecutorService executor = Executors.newFixedThreadPool(2);
try {
Log.d("ShellUtils", "Determining appropriate shell for execution...");
// Log.d("ShellUtils", "Determining appropriate shell for execution...");
if (hasBin("su")) {
Log.d("ShellUtils", "'su' binary found, using 'su' shell.");
// Log.d("ShellUtils", "'su' binary found, using 'su' shell.");
process = Runtime.getRuntime().exec("su");
} else if (hasBin("xu")) {
Log.d("ShellUtils", "'xu' binary found, using 'xu' shell.");
// Log.d("ShellUtils", "'xu' binary found, using 'xu' shell.");
process = Runtime.getRuntime().exec("xu");
} else if (hasBin("vu")) {
Log.d("ShellUtils", "'vu' binary found, using 'vu' shell.");
// Log.d("ShellUtils", "'vu' binary found, using 'vu' shell.");
process = Runtime.getRuntime().exec("vu");
} else {
Log.d("ShellUtils", "No specific binary found, using 'sh' shell.");
// Log.d("ShellUtils", "No specific binary found, using 'sh' shell.");
process = Runtime.getRuntime().exec("sh");
}
@ -137,7 +137,7 @@ public class ShellUtils {
BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
BufferedReader errorReader = new BufferedReader(new InputStreamReader(errorStream, StandardCharsets.UTF_8))) {
Log.d("ShellUtils", "Starting separate thread to process error stream...");
// Log.d("ShellUtils", "Starting separate thread to process error stream...");
executor.submit(() -> {
String line;
try {
@ -149,28 +149,28 @@ public class ShellUtils {
}
});
Log.d("ShellUtils", "Writing the command to the shell...");
// Log.d("ShellUtils", "Writing the command to the shell...");
os.write((cmd + "\n").getBytes());
os.write("exit\n".getBytes());
os.flush();
Log.d("ShellUtils", "Command written to shell. Waiting for process to complete.");
// Log.d("ShellUtils", "Command written to shell. Waiting for process to complete.");
StringBuilder output = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
Log.d("ShellUtils", "Shell Output: " + line);
// Log.d("ShellUtils", "Shell Output: " + line);
output.append(line).append("\n");
}
Log.d("ShellUtils", "Awaiting process termination...");
// Log.d("ShellUtils", "Awaiting process termination...");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!process.waitFor(10, TimeUnit.SECONDS)) {
LogUtils.e(Log.ERROR, "ShellUtils", "Process execution timed out. Destroying process.", null);
// LogUtils.e(Log.ERROR, "ShellUtils", "Process execution timed out. Destroying process.", null);
process.destroyForcibly();
throw new RuntimeException("Shell command execution timeout.");
}
} else {
Log.d("ShellUtils", "Using manual time tracking method for process termination (API < 26).");
// Log.d("ShellUtils", "Using manual time tracking method for process termination (API < 26).");
long startTime = System.currentTimeMillis();
while (true) {
try {
@ -178,7 +178,7 @@ public class ShellUtils {
break;
} catch (IllegalThreadStateException e) {
if (System.currentTimeMillis() - startTime > 10000) { // 10 seconds
LogUtils.e(Log.ERROR, "ShellUtils", "Process execution timed out (manual tracking). Destroying process.", null);
// LogUtils.e(Log.ERROR, "ShellUtils", "Process execution timed out (manual tracking). Destroying process.", null);
process.destroy();
throw new RuntimeException("Shell command execution timeout.");
}

View File

@ -73,7 +73,7 @@ object Util {
private const val sendRefer = true
var isNeedRestored: Boolean = false
const val AUTO_PACKAGENAME: String = "com.play4u.luabox"
const val AUTO_JSPACKAGENAME: String = "org.autojs.autojs"
const val AUTO_JSPACKAGENAME: String = "org.autojs.autojs6"
const val proxy_packagename: String = "com.tunnelworkshop.postern"
const val AUTO_CLASSNAME: String = "com.cyjh.elfin.activity.SplashActivity"
private const val hookPackageName = "com.affsystem.androidhooker"
@ -696,8 +696,8 @@ object Util {
val result: String? = MyPost.postData(" ".toByteArray(charset = Charsets.UTF_8),
"$url?$params"
)
if (result != null && result.length > 0) {
LogUtils.e("IOSTQ:execReloginTask->result:$result")
if (result != null && result.isNotEmpty()) {
taskJson = JSONObject(result).apply {
val code = getInt("code")
if (code == 1) {
@ -749,9 +749,9 @@ object Util {
"$url?$params"
)
printStr("request result : $result")
LogUtils.e("request result : $result")
if (result != null && result.length > 0) {
if (result != null && result.isNotEmpty()) {
taskJson = JSONObject(result)
val code = taskJson!!.getInt("code")
@ -1045,7 +1045,7 @@ object Util {
val ret: String? = MyPost.postData("".toByteArray(), url)
Log.i(TAG, "ret:$ret")
val jo = JSONObject(ret)
val jo = JSONObject(ret?:"")
if (jo.getInt("code") == 1) {
regEmailJson = jo.getJSONObject("emailInfo")
@ -1554,11 +1554,13 @@ object Util {
fun openRecordApp(context: Context) {
if (scriptOpenApp == 0) {
recordPackageName?.let {
execTargetApp(
context,
recordPackageName!!
it
)
}
}
if (!isCanAuto || canAutoLc.length <= 10) {
Handler(Looper.getMainLooper()).postDelayed(Runnable {
@ -1618,10 +1620,12 @@ object Util {
if (!file.exists()) {
val parent = file.parentFile
if (parent!!.exists()) {
if (parent?.exists() == true) {
file.mkdir()
} else {
if (parent != null) {
forceCreteDir(parent)
}
file.mkdir()
}
}
@ -1631,7 +1635,8 @@ object Util {
if (!file.exists()) {
val parent = file.parentFile
if (!parent!!.exists()) {
parent?.exists()?.let {
if (!it) {
MockTools.exec("mkdir $parent")
forceMakeDir(parent)
// file.mkdirs();
@ -1640,6 +1645,7 @@ object Util {
}
}
}
}
fun writeFile1(context: Context?, dirName: String, fileName: String, contents: String) {
val fs = File("$dirName/$fileName")
@ -1764,7 +1770,11 @@ object Util {
}
val create_dir = file.parentFile
forceMakeDir(create_dir!!)
if (create_dir != null && !create_dir.exists()){
forceMakeDir(create_dir)
}else if (create_dir == null){
return false
}
val fileLength = 0L
@ -1777,7 +1787,7 @@ object Util {
try {
conn = url.openConnection() as HttpURLConnection
`is` = conn!!.inputStream
`is` = conn.inputStream
fos = FileOutputStream(file)
val buf = ByteArray(256)
conn.connect()
@ -1806,15 +1816,15 @@ object Util {
e.printStackTrace()
} finally {
try {
conn!!.disconnect()
conn?.disconnect()
} catch (e: Exception) {
}
try {
fos!!.close()
fos?.close()
} catch (e: Exception) {
}
try {
`is`!!.close()
`is`?.close()
} catch (e: Exception) {
}
}
@ -2046,17 +2056,19 @@ object Util {
}
fun installApks4Tmp(apkName: String?, context: Context?): Boolean {
fun installApks4Tmp(apkName: String?, context: Context): Boolean {
var result = MockTools.execRead("pm install-create")
Log.d(TAG, "installApks4Tmp: successMsg $result")
val session = result.substring(result.indexOf("[") + 1, result.indexOf("]"))
Log.d(TAG, "installApks4Tmp: session $session")
val file = File("/sdcard/apks/$apkName")
val file = File(getRecordDataDirName(context))
Log.d(TAG, "installApks4Tmp: ${file.absolutePath}")
val files = file.listFiles()
var bool = true
var currentApkFile = 1
for (f in files) {
files?.let {
for (f in it) {
val extraName = f.name.substring(f.name.lastIndexOf('.') + 1)
Log.d(
TAG,
@ -2075,6 +2087,8 @@ object Util {
}
}
}
}
if (bool) {
result = MockTools.execRead("pm install-commit $session")
if (!result.contains("Success")) {
@ -2083,9 +2097,11 @@ object Util {
} else {
result = MockTools.execRead("pm install-abandon $session")
}
for (f in files) {
files?.let {
for (f in it) {
MockTools.execRead("rm -rf $f")
}
}
setInstallRet(bool)
return bool
}
@ -2420,7 +2436,7 @@ object Util {
}
tags = filterStr(tags)
// Log.e(TAG, "getCid:*"+tags+"*");
return tags!!
return tags?:""
}
fun getPropertiesFromAssets(context: Context, fileName: String): Properties {

View File

@ -10,6 +10,7 @@ import androidx.work.CoroutineWorker
import androidx.work.WorkerParameters
import com.android.grape.service.MyAccessibilityService
import androidx.core.content.edit
import com.android.grape.job.MonitorService
class CheckAccessibilityWorker(
context: Context,