改机参数新增

This commit is contained in:
Administrator 2025-07-12 10:23:59 +08:00
parent 0239820321
commit e2800ffe8e
14 changed files with 401 additions and 9 deletions

View File

@ -48,6 +48,11 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.AndroidGrape" android:theme="@style/Theme.AndroidGrape"
tools:targetApi="31"> tools:targetApi="31">
<provider
android:name=".provider.DeviceInfoProvider"
android:authorities="com.android.grape.deviceinfo.provider"
android:exported="true">
</provider>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true"> android:exported="true">

View File

@ -13,6 +13,8 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
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.provider.DeviceDataAccessor
import com.android.grape.provider.DeviceInfoHelper
import com.android.grape.util.ClashUtil import com.android.grape.util.ClashUtil
import com.android.grape.util.MockTools import com.android.grape.util.MockTools
import com.android.grape.util.NotificationPermissionHandler import com.android.grape.util.NotificationPermissionHandler
@ -22,6 +24,7 @@ import com.android.grape.util.StoragePermissionHelper
import com.android.grape.util.Util import com.android.grape.util.Util
import com.android.grape.util.Util.AUTO_JSPACKAGENAME import com.android.grape.util.Util.AUTO_JSPACKAGENAME
import com.android.grape.util.Util.killRecordProcess import com.android.grape.util.Util.killRecordProcess
import com.google.gson.Gson
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private val viewModel by viewModels<MainViewModel>() private val viewModel by viewModels<MainViewModel>()
@ -42,9 +45,13 @@ class MainActivity : AppCompatActivity() {
ScriptUtil.registerScriptResultReceiver() ScriptUtil.registerScriptResultReceiver()
viewBinding.start.setOnClickListener { viewBinding.start.setOnClickListener {
MonitorService.onEvent(MainApplication.instance) MonitorService.onEvent(MainApplication.instance)
// DeviceDataAccessor.saveDeviceInfo(this, DeviceInfoHelper.getDeviceId(this))
} }
viewBinding.stop.setOnClickListener { viewBinding.stop.setOnClickListener {
killRecordProcess(this, packageName) killRecordProcess(this, packageName)
// DeviceDataAccessor.deleteDeviceInfo(this, DeviceInfoHelper.getDeviceId(this))
// val deviceInfo = DeviceDataAccessor.getDeviceInfo(this, DeviceInfoHelper.getDeviceId(this))
// Log.d("TAG", "onCreate: ${Gson().toJson(deviceInfo?:"")}")
} }
} }

View File

@ -2,6 +2,8 @@ package com.android.grape.data
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import org.json.JSONArray
import org.json.JSONObject
data class Device( data class Device(
var advertiserId: String = "", var advertiserId: String = "",
@ -110,4 +112,32 @@ data class Device(
var vendingVersionName: String = "", var vendingVersionName: String = "",
@SerializedName("web_ua") @SerializedName("web_ua")
var webUa: String = "" var webUa: String = ""
) ){
fun toJson(): String {
return JSONObject().apply {
put("sensors", JSONArray(sensor))
put("arch", arch)
put("cpu_abi", cpuAbi)
put("cpu_abi2", cpuAbi2)
put("size", dim.size)
put("xdp", dim.xdp)
put("ydp", dim.ydp)
put("y_px", dim.yPx)
put("x_px", dim.xPx)
put("d_dpi", dim.dDpi)
put("btch", btch)
put("btl", batteryLevel)
put("disk", disk)
put("sdk", sdk)
put("network", network)
put("api_ver", vendingVersionCode)
put("api_ver_name", vendingVersionName)
put("carrier", carrier)
put("product", product)
put("last_boot_time", lastBootTime)
put("install_source_info", installerPackage)
put("advertiserId", advertiserId)
}.toString()
}
}

View File

@ -9,4 +9,6 @@ data class Sensor(
var sV: String = "", var sV: String = "",
var sVE: List<Double> = listOf(), var sVE: List<Double> = listOf(),
var sVS: List<Double> = listOf() var sVS: List<Double> = listOf()
) ) {
companion object
}

View File

@ -15,7 +15,7 @@ class AutoJobService : JobIntentService() {
Handler(Looper.getMainLooper()).postDelayed({ Handler(Looper.getMainLooper()).postDelayed({
ScriptUtil.execScript( ScriptUtil.execScript(
this@AutoJobService, this@AutoJobService,
"/sdcard/autojs/main.js" "/sdcard/script/main.js"
) )
}, 2000L) }, 2000L)
} else { } else {

View File

@ -0,0 +1,100 @@
package com.android.grape.provider
import android.content.ContentValues
import android.content.Context
import android.net.Uri
import com.android.grape.data.Device
// DeviceDataAccessor.kt
object DeviceDataAccessor {
// 保存设备信息到提供方
fun saveDeviceInfo(context: Context, device: Device): Uri? {
val resolver = context.contentResolver
val actualDeviceId = DeviceInfoHelper.getDeviceId()
val values = ContentValues().apply {
put(DeviceInfoContract.DeviceInfoEntry.COLUMN_DEVICE_ID, actualDeviceId)
put(DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA, device.toJson())
}
// 尝试更新现有记录
val updateCount = resolver.update(
getDeviceUri(actualDeviceId),
values,
null,
null
)
// 如果没有更新记录,则插入新记录
return if (updateCount == 0) {
resolver.insert(DeviceInfoContract.CONTENT_URI, values)
} else {
getDeviceUri(actualDeviceId)
}
}
// 读取设备信息
fun getDeviceInfo(context: Context, deviceId: String? = null): String? {
val resolver = context.contentResolver
val actualDeviceId = deviceId ?: DeviceInfoHelper.getDeviceId()
val cursor = resolver.query(
getDeviceUri(actualDeviceId),
arrayOf(DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA),
null,
null,
null
)
return cursor?.use {
if (it.moveToFirst()) {
val json =
it.getString(it.run { it.getColumnIndex(DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA) })
json
} else {
null
}
}
}
// 获取所有设备信息
fun getAllDeviceInfo(context: Context): List<String> {
val resolver = context.contentResolver
val deviceList = mutableListOf<String>()
resolver.query(
DeviceInfoContract.CONTENT_URI,
arrayOf(DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA),
null,
null,
"${DeviceInfoContract.DeviceInfoEntry.COLUMN_TIMESTAMP} DESC"
)?.use { cursor ->
val dataIndex = cursor.getColumnIndex(DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA)
while (cursor.moveToNext()) {
val json = cursor.getString(dataIndex)
deviceList.add(json)
}
}
return deviceList
}
// 删除设备信息
fun deleteDeviceInfo(context: Context, deviceId: String? = null): Int {
val actualDeviceId = deviceId ?: DeviceInfoHelper.getDeviceId()
return context.contentResolver.delete(
getDeviceUri(actualDeviceId),
null,
null
)
}
private fun getDeviceUri(deviceId: String): Uri {
return Uri.withAppendedPath(
DeviceInfoContract.CONTENT_URI,
"device/$deviceId"
)
}
}

View File

@ -0,0 +1,27 @@
package com.android.grape.provider
import android.net.Uri
import androidx.core.net.toUri
object DeviceInfoContract {
const val AUTHORITY = "com.android.grape.deviceinfo.provider"
val CONTENT_URI: Uri = "content://$AUTHORITY/device_info".toUri()
object DeviceInfoEntry {
const val TABLE_NAME = "device_info"
const val COLUMN_DEVICE_ID = "device_id"
const val COLUMN_DATA = "data"
const val COLUMN_TIMESTAMP = "timestamp"
// JSON 键名
const val KEY_CPU_ABI = "cpu_abi"
const val KEY_DIM = "dim"
const val KEY_BTCH = "btch"
const val KEY_ARCH = "arch"
const val KEY_BTL = "btl"
const val KEY_CPU_ABI2 = "cpu_abi2"
const val KEY_DISK = "disk"
const val KEY_SDK = "sdk"
const val KEY_NETWORK = "network"
}
}

View File

@ -0,0 +1,33 @@
package com.android.grape.provider
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
import android.provider.BaseColumns
class DeviceInfoDbHelper(context: Context) : SQLiteOpenHelper(
context, DATABASE_NAME, null, DATABASE_VERSION
) {
companion object {
const val DATABASE_NAME = "device_info.db"
const val DATABASE_VERSION = 1
const val SQL_CREATE_ENTRIES = """
CREATE TABLE ${DeviceInfoContract.DeviceInfoEntry.TABLE_NAME} (
${BaseColumns._ID} INTEGER PRIMARY KEY,
${DeviceInfoContract.DeviceInfoEntry.COLUMN_DEVICE_ID} TEXT UNIQUE,
${DeviceInfoContract.DeviceInfoEntry.COLUMN_DATA} TEXT NOT NULL,
${DeviceInfoContract.DeviceInfoEntry.COLUMN_TIMESTAMP} INTEGER NOT NULL DEFAULT (strftime('%s','now'))
)
"""
}
override fun onCreate(db: SQLiteDatabase) {
db.execSQL(SQL_CREATE_ENTRIES)
}
override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
db.execSQL("DROP TABLE IF EXISTS ${DeviceInfoContract.DeviceInfoEntry.TABLE_NAME}")
onCreate(db)
}
}

View File

@ -0,0 +1,8 @@
package com.android.grape.provider
object DeviceInfoHelper {
// 获取设备唯一ID
fun getDeviceId(): String {
return "d1b3e7f8c9a04b8e9f2c1d5e6f7a8b9c"
}
}

View File

@ -0,0 +1,148 @@
package com.android.grape.provider
import android.content.ContentProvider
import android.content.ContentUris
import android.content.ContentValues
import android.content.UriMatcher
import android.database.Cursor
import android.database.sqlite.SQLiteQueryBuilder
import android.net.Uri
import android.provider.BaseColumns
import java.sql.SQLException
// DeviceInfoProvider.kt
class DeviceInfoProvider : ContentProvider() {
private lateinit var dbHelper: DeviceInfoDbHelper
private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH).apply {
addURI(DeviceInfoContract.AUTHORITY, "device_info", 1)
addURI(DeviceInfoContract.AUTHORITY, "device_info/#", 2)
addURI(DeviceInfoContract.AUTHORITY, "device_info/device/*", 3)
}
override fun onCreate(): Boolean {
dbHelper = DeviceInfoDbHelper(context!!)
return true
}
override fun query(
uri: Uri,
projection: Array<String>?,
selection: String?,
selectionArgs: Array<String>?,
sortOrder: String?
): Cursor? {
val db = dbHelper.readableDatabase
val qb = SQLiteQueryBuilder().apply {
tables = DeviceInfoContract.DeviceInfoEntry.TABLE_NAME
}
when (uriMatcher.match(uri)) {
1 -> {} // 查询所有
2 -> qb.appendWhere("${BaseColumns._ID} = ${uri.lastPathSegment}")
3 -> qb.appendWhere("${DeviceInfoContract.DeviceInfoEntry.COLUMN_DEVICE_ID} = '${uri.lastPathSegment}'")
else -> throw IllegalArgumentException("Unknown URI: $uri")
}
return qb.query(db, projection, selection, selectionArgs, null, null, sortOrder).apply {
setNotificationUri(context!!.contentResolver, uri)
}
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val db = dbHelper.writableDatabase
val now = System.currentTimeMillis() / 1000
// 添加时间戳
values?.put(DeviceInfoContract.DeviceInfoEntry.COLUMN_TIMESTAMP, now)
val rowId = db.insert(DeviceInfoContract.DeviceInfoEntry.TABLE_NAME, null, values)
if (rowId > 0) {
val newUri = ContentUris.withAppendedId(DeviceInfoContract.CONTENT_URI, rowId)
context?.contentResolver?.notifyChange(newUri, null)
return newUri
}
return null
}
override fun update(
uri: Uri,
values: ContentValues?,
selection: String?,
selectionArgs: Array<String>?
): Int {
val db = dbHelper.writableDatabase
val now = System.currentTimeMillis() / 1000
// 更新时间戳
values?.put(DeviceInfoContract.DeviceInfoEntry.COLUMN_TIMESTAMP, now)
val count = when (uriMatcher.match(uri)) {
1 -> db.update(
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
values, selection, selectionArgs
)
2 -> {
val id = uri.lastPathSegment
db.update(
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
values,
"${BaseColumns._ID} = ?",
arrayOf(id)
)
}
3 -> {
val deviceId = uri.lastPathSegment
db.update(
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
values,
"${DeviceInfoContract.DeviceInfoEntry.COLUMN_DEVICE_ID} = ?",
arrayOf(deviceId)
)
}
else -> throw IllegalArgumentException("Unknown URI: $uri")
}
context?.contentResolver?.notifyChange(uri, null)
return count
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
val db = dbHelper.writableDatabase
val count = when (uriMatcher.match(uri)) {
1 -> db.delete(
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
selection, selectionArgs
)
2 -> {
val id = uri.lastPathSegment
db.delete(
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
"${BaseColumns._ID} = ?",
arrayOf(id)
)
}
3 -> {
val deviceId = uri.lastPathSegment
db.delete(
DeviceInfoContract.DeviceInfoEntry.TABLE_NAME,
"${DeviceInfoContract.DeviceInfoEntry.COLUMN_DEVICE_ID} = ?",
arrayOf(deviceId)
)
}
else -> throw IllegalArgumentException("Unknown URI: $uri")
}
context?.contentResolver?.notifyChange(uri, null)
return count
}
override fun getType(uri: Uri): String? {
return when (uriMatcher.match(uri)) {
1 -> "${DeviceInfoContract.AUTHORITY}/device_info"
2, 3 -> "vnd.android.cursor.item/vnd.example.deviceinfo"
else -> throw IllegalArgumentException("Unknown URI: $uri")
}
}
}

View File

@ -7,6 +7,7 @@ import com.android.grape.MainApplication
import com.android.grape.data.Device import com.android.grape.data.Device
import com.android.grape.net.Api import com.android.grape.net.Api
import com.android.grape.net.ChangeCallBack import com.android.grape.net.ChangeCallBack
import com.android.grape.provider.DeviceDataAccessor
import com.android.grape.util.Util.paramsJson import com.android.grape.util.Util.paramsJson
import com.blankj.utilcode.util.LogUtils import com.blankj.utilcode.util.LogUtils
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -28,6 +29,7 @@ object ChangeDeviceInfoUtil {
return return
} }
val device = GsonUtils.fromJsonObject(deviceObject.toString(), Device::class.java) val device = GsonUtils.fromJsonObject(deviceObject.toString(), Device::class.java)
DeviceDataAccessor.saveDeviceInfo(MainApplication.instance, device)
val padCode = ShellUtils.execRootCmdAndGetResult("getprop ro.boot.pad_code") val padCode = ShellUtils.execRootCmdAndGetResult("getprop ro.boot.pad_code")
Log.d("TAG", "changeDevice: $padCode") Log.d("TAG", "changeDevice: $padCode")
val jsonString = JSONObject().apply { val jsonString = JSONObject().apply {

View File

@ -1,6 +1,8 @@
package com.android.grape.util package com.android.grape.util
import android.os.Environment
import android.util.Log import android.util.Log
import com.blankj.utilcode.util.LogUtils
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.BufferedReader import java.io.BufferedReader
@ -16,6 +18,7 @@ import java.io.InputStreamReader
import java.io.OutputStream import java.io.OutputStream
import java.io.RandomAccessFile import java.io.RandomAccessFile
import java.io.UnsupportedEncodingException import java.io.UnsupportedEncodingException
import java.nio.charset.StandardCharsets
import java.util.Enumeration import java.util.Enumeration
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipFile import java.util.zip.ZipFile
@ -387,4 +390,31 @@ object FileUtils {
output.close() output.close()
input.close() input.close()
} }
fun writePackageName(packageName: String) {
val file = File(
Environment.getExternalStorageDirectory(),
"script/packagesname.txt"
)
val parentDir = file.getParentFile()
if (parentDir != null && !parentDir.exists()) {
val dirsCreated = parentDir.mkdirs()
if (!dirsCreated) {
Log.e("FileWrite", "Failed to create directories: $parentDir")
return
}
}
LogUtils.d("TAG", "writePackageName: $packageName", null)
try {
BufferedOutputStream(
FileOutputStream(file)
).use { bos ->
bos.write(packageName.toByteArray(StandardCharsets.UTF_8))
bos.flush() // 确保数据写入磁盘
}
} catch (e: IOException) {
Log.e("FileWrite", "Failed to write package name: $packageName", e)
// 6. 可以考虑添加重试机制或通知用户
}
}
} }

View File

@ -185,9 +185,9 @@ public class ShellUtils {
public static void execRootCmd(String cmd) { public static void execRootCmd(String cmd) {
// 校验命令是否安全 // 校验命令是否安全
if (!isCommandSafe(cmd)) { // if (!isCommandSafe(cmd)) {
return; // return;
} // }
List<String> cmds = new ArrayList<>(); List<String> cmds = new ArrayList<>();
cmds.add(cmd); cmds.add(cmd);

View File

@ -1140,7 +1140,7 @@ object Util {
return false return false
} }
unzipAPkSh(script_path, "/sdcard/autojs/") unzipAPkSh(script_path, "/sdcard/script/")
delFileSh(script_path) delFileSh(script_path)
} }
return isDownload return isDownload
@ -2571,9 +2571,9 @@ object Util {
*/ */
//当本应用位于后台时,则将它切换到最前端 //当本应用位于后台时,则将它切换到最前端
fun setTopApp(context: Context) { fun setTopApp(context: Context) {
// Log.i(TAG, "start to setTopApp"); Log.i(TAG, "start to setTopApp");
if (isRunningForeground(context)) { if (isRunningForeground(context)) {
// Log.i(TAG, "app isRunningForeground"); Log.i(TAG, "app isRunningForeground");
return; return;
} }
//获取ActivityManager //获取ActivityManager