This commit is contained in:
parent
ce0933ee94
commit
5772b91b9a
|
@ -1,21 +1,47 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
-keep class com.google.gson.** { *; }
|
||||
-keep class com.google.gson.stream.** { *; }
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
# 保留所有注解
|
||||
-keepattributes *Annotation*
|
||||
-keepattributes Signature
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
# 保留枚举类
|
||||
-keepclassmembers enum * {
|
||||
public static **[] values();
|
||||
public static ** valueOf(java.lang.String);
|
||||
}
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
# 保留所有模型类(根据你的包结构调整)
|
||||
-keep class com.android.grape.pad.** { *; }
|
||||
-keep class com.android.grape.net.ApiResponse{ *; }
|
||||
-keep class com.android.grape.net.ApiResponseList{ *; }
|
||||
|
||||
# 保留所有使用 @SerializedName 注解的字段
|
||||
-keepclassmembers class * {
|
||||
@com.google.gson.annotations.SerializedName <fields>;
|
||||
}
|
||||
|
||||
# 保留所有模型类的无参构造函数
|
||||
-keepclassmembers class com.android.grape.pad.** {
|
||||
public <init>();
|
||||
}
|
||||
|
||||
# 保留类型适配器
|
||||
-keep class * extends com.google.gson.TypeAdapter {
|
||||
public com.google.gson.TypeAdapter create(com.google.gson.Gson, com.google.gson.reflect.TypeToken);
|
||||
}
|
||||
# 保留 Gson 创建的类
|
||||
-keep class com.google.gson.examples.android.model.** { *; }
|
||||
-keepattributes Signature
|
||||
|
||||
# 保留 TypeToken 类及其子类
|
||||
-keep class com.google.gson.reflect.TypeToken { *; }
|
||||
-keep class * extends com.google.gson.reflect.TypeToken
|
||||
|
||||
-keep class sun.misc.Unsafe { *; }
|
||||
|
||||
# 保留注解信息
|
||||
-keepattributes *Annotation*
|
||||
|
||||
# 保留 Kotlin 元数据(如果使用 Kotlin)
|
||||
-keepclassmembers class **$TypeToken { *; }
|
|
@ -1,19 +0,0 @@
|
|||
package com.android.grape.data
|
||||
|
||||
class AfInfo {
|
||||
var advertiserId: String? = null
|
||||
var model: String? = null
|
||||
var brand: String? = null
|
||||
var androidId: String? = null
|
||||
var xPixels: Int = 0
|
||||
var yPixels: Int = 0
|
||||
var densityDpi: Int = 0
|
||||
var country: String? = null
|
||||
var batteryLevel: String? = null
|
||||
var stackInfo: String? = null
|
||||
var product: String? = null
|
||||
var network: String? = null
|
||||
var langCode: String? = null
|
||||
var cpuAbi: String? = null
|
||||
var yDp: Long = 0
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package com.android.grape.data
|
||||
|
||||
class BigoInfo {
|
||||
var cpuClockSpeed: String? = null
|
||||
var gaid: String? = null
|
||||
var userAgent: String? = null
|
||||
var osLang: String? = null
|
||||
var osVer: String? = null
|
||||
var tz: String? = null
|
||||
var systemCountry: String? = null
|
||||
var simCountry: String? = null
|
||||
var romFreeIn: Long = 0
|
||||
var resolution: String? = null
|
||||
var vendor: String? = null
|
||||
var batteryScale: Int = 0
|
||||
var net: String? = null
|
||||
var dpi: Long = 0
|
||||
var romFreeExt: Long = 0
|
||||
var dpiF: String? = null
|
||||
var cpuCoreNum: Long = 0
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package com.android.grape.data
|
||||
|
||||
class DeviceInfo {
|
||||
var lang: String? = null
|
||||
var roProductBrand: String? = null
|
||||
var roProductModel: String? = null
|
||||
var roProductManufacturer: String? = null
|
||||
var roProductDevice: String? = null
|
||||
var roProductName: String? = null
|
||||
var roBuildVersionIncremental: String? = null
|
||||
var roBuildFingerprint: String? = null
|
||||
var roOdmBuildFingerprint: String? = null
|
||||
var roProductBuildFingerprint: String? = null
|
||||
var roSystemBuildFingerprint: String? = null
|
||||
var roSystemExtBuildFingerprint: String? = null
|
||||
var roVendorBuildFingerprint: String? = null
|
||||
var roBuildPlatform: String? = null
|
||||
var persistSysCloudDrmId: String? = null
|
||||
var persistSysCloudBatteryCapacity: Int = 0
|
||||
var persistSysCloudGpuGlVendor: String? = null
|
||||
var persistSysCloudGpuGlRenderer: String? = null
|
||||
var persistSysCloudGpuGlVersion: String? = null
|
||||
var persistSysCloudGpuEglVendor: String? = null
|
||||
var persistSysCloudGpuEglVersion: String? = null
|
||||
}
|
|
@ -23,9 +23,8 @@ class DownloadAppJobService : JobIntentService() {
|
|||
|
||||
if (succ) {
|
||||
errTime = 0L
|
||||
InstallService.onEvent(this)
|
||||
// StartVpnServerJobService.onEvent(this)
|
||||
// StartVpnPortJobService.onEvent(this)
|
||||
// InstallService.onEvent(this)
|
||||
StartVpnPortJobService.onEvent(this)
|
||||
} else {
|
||||
Util.isClickRet = false
|
||||
Util.setInstallRet(false)
|
||||
|
|
|
@ -6,13 +6,17 @@ import android.os.Handler
|
|||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import androidx.core.app.JobIntentService
|
||||
import com.android.grape.net.MyGet
|
||||
import com.android.grape.util.ClashUtil
|
||||
import com.android.grape.util.ClashUtil.getProxyPort
|
||||
import com.android.grape.util.Util
|
||||
import java.util.Locale
|
||||
|
||||
class StartVpnPortJobService : JobIntentService() {
|
||||
override fun onHandleWork(intent: Intent) {
|
||||
Log.i(TAG, "start to handle work")
|
||||
if (ClashUtil.checkProxy( this)) {
|
||||
ClashUtil.switchProxyGroup("PROXY", "DIRECT", "http://127.0.0.1:6170")
|
||||
if (exec()) {
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
StartVpnServerJobService.onEvent(
|
||||
this@StartVpnPortJobService
|
||||
|
@ -25,6 +29,28 @@ class StartVpnPortJobService : JobIntentService() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun exec(): Boolean {
|
||||
try {
|
||||
val port = getProxyPort()
|
||||
var nRetryCount = 0
|
||||
do {
|
||||
val url =
|
||||
"http://39.103.73.250/tt/test/testProxy.jsp?port=$port&country=" + Util.proxyCountry
|
||||
?.lowercase(Locale.getDefault())
|
||||
val result: String = MyGet.get(url)
|
||||
Log.d(TAG, "request url == $url result$result")
|
||||
if (result.contains("ok")) {
|
||||
return true
|
||||
}
|
||||
} while (nRetryCount++ < 3)
|
||||
return false
|
||||
} catch (err: Exception) {
|
||||
err.printStackTrace()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private const val TAG = "IOSTQ:StartVpnPort"
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.util.Log
|
|||
import androidx.core.app.JobIntentService
|
||||
import com.android.grape.MainApplication
|
||||
import com.android.grape.util.ClashUtil
|
||||
import com.android.grape.util.CountryCode
|
||||
import com.android.grape.util.Util
|
||||
|
||||
/**
|
||||
|
@ -27,19 +28,12 @@ class StartVpnServerJobService : JobIntentService() {
|
|||
onEvent(
|
||||
this@StartVpnServerJobService
|
||||
)
|
||||
}, 1000L)
|
||||
}, 2000L)
|
||||
}
|
||||
}
|
||||
|
||||
private fun exec(): Boolean {
|
||||
ClashUtil.startProxy(MainApplication.instance)
|
||||
ClashUtil.switchProxyGroup("GLOBAL", Util.proxyCountry, "http://127.0.0.1:6170")
|
||||
if (!ClashUtil.checkProxy(MainApplication.instance)) {
|
||||
println("IOSTQ:start vpn error")
|
||||
return false
|
||||
}
|
||||
println("IOSTQ:start vpn ok")
|
||||
return true
|
||||
return ClashUtil.switchProxyGroup("PROXY", "my-socks5-proxy", "http://127.0.0.1:6170")
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -2,16 +2,51 @@ package com.android.grape.net
|
|||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
object MyGet {
|
||||
private const val TAG = "MyGet"
|
||||
val affHttpClient: OkHttpClient = OkHttpClient()
|
||||
|
||||
fun getAffHttpClient(): OkHttpClient {
|
||||
affHttpClient.dispatcher.maxRequests = 1000
|
||||
affHttpClient.dispatcher.maxRequestsPerHost = 1000
|
||||
return affHttpClient
|
||||
}
|
||||
|
||||
fun get(url_: String): String {
|
||||
var response: Response? = null
|
||||
val client: OkHttpClient = getAffHttpClient().newBuilder()
|
||||
.connectTimeout(5, TimeUnit.SECONDS)
|
||||
.readTimeout(5, TimeUnit.SECONDS)
|
||||
.build()
|
||||
val request = Request.Builder()
|
||||
.url(url_)
|
||||
.addHeader("User-Agent", "PostmanRuntime/7.29.0")
|
||||
.addHeader("Accept", "*/*")
|
||||
.addHeader("Accept-Encoding", "gzip, deflate, br")
|
||||
.addHeader("Connection", "keep-alive")
|
||||
.build()
|
||||
try {
|
||||
response = client.newCall(request).execute()
|
||||
return response.body?.string()?:""
|
||||
} catch (e: java.lang.Exception) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
response?.close()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
fun getData(url_: String, ua: String?): String? {
|
||||
return getData(url_, ua, 0)
|
||||
|
@ -31,7 +66,7 @@ object MyGet {
|
|||
httpUrlConnection = url.openConnection() as HttpURLConnection
|
||||
|
||||
httpUrlConnection.allowUserInteraction = true
|
||||
httpUrlConnection!!.doOutput = false
|
||||
httpUrlConnection.doOutput = false
|
||||
httpUrlConnection.doInput = true
|
||||
httpUrlConnection.useCaches = false
|
||||
httpUrlConnection.setRequestProperty("Connection", "close") //add 20200428
|
||||
|
|
|
@ -4,24 +4,35 @@ import android.content.BroadcastReceiver
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
import okhttp3.Call
|
||||
import okhttp3.Callback
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.FileReader
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
object ClashUtil {
|
||||
private val sharedClient: OkHttpClient = OkHttpClient.Builder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS) // 连接超时
|
||||
.readTimeout(30, TimeUnit.SECONDS) // 读取超时
|
||||
.addInterceptor(HttpLoggingInterceptor().apply {
|
||||
level = HttpLoggingInterceptor.Level.BODY
|
||||
})
|
||||
.build()
|
||||
|
||||
fun startProxy(context: Context) {
|
||||
val intent = Intent("com.github.kr328.clash.intent.action.SESSION_CREATE")
|
||||
intent.putExtra("profile", "default") // 可选择您在 Clash 中配置的 Profile
|
||||
|
@ -35,6 +46,66 @@ object ClashUtil {
|
|||
}.start()
|
||||
}
|
||||
|
||||
fun getProxyPort(): Int {
|
||||
val scriptDir = File(Environment.getExternalStorageDirectory(), "script")
|
||||
val portFile = File(scriptDir, "ip.port.json")
|
||||
val text = StringBuilder()
|
||||
try {
|
||||
BufferedReader(FileReader(portFile)).use { br ->
|
||||
var line: String?
|
||||
while ((br.readLine().also { line = it }) != null) {
|
||||
text.append(line).append('\n')
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e("TAG", "getProxyPort: ", e)
|
||||
return -1
|
||||
}
|
||||
var port = -1
|
||||
try {
|
||||
Log.d("TAG", "getProxyPort: $text")
|
||||
val config = JSONObject(text.toString())
|
||||
port = config.optInt("port", -1)
|
||||
} catch (e: java.lang.Exception) {
|
||||
Log.e("TAG", "getProxyPort: ", e)
|
||||
}
|
||||
return port
|
||||
}
|
||||
|
||||
fun switchProxyWithPort(country: String?) {
|
||||
val port = getProxyPort()
|
||||
// 安全构建 URL
|
||||
val url = "http://39.103.73.250/tt/test/testProxy.jsp".toHttpUrl()
|
||||
.newBuilder()
|
||||
.addQueryParameter("port", port.toString() + "")
|
||||
.addQueryParameter("country", country)
|
||||
.build()
|
||||
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.build()
|
||||
|
||||
try {
|
||||
sharedClient.newCall(request).execute().use { response ->
|
||||
// 读取并记录响应内容
|
||||
val responseBody = response.body?.string() ?: "Empty response body"
|
||||
if (response.isSuccessful) {
|
||||
Log.d(
|
||||
"ClashUtil",
|
||||
"switchProxyGroup: Success | Status: " + response.code + " | Response: " + responseBody
|
||||
)
|
||||
} else {
|
||||
Log.d(
|
||||
"ClashUtil",
|
||||
"switchProxyGroup: Failed | Status: " + response.code + " | Response: " + responseBody
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: java.lang.Exception) {
|
||||
Log.d("ClashUtil", "switchProxyGroup: Unexpected error", e)
|
||||
}
|
||||
}
|
||||
|
||||
var isRunning: Boolean = false
|
||||
|
||||
val clashStatusReceiver: BroadcastReceiver = object : BroadcastReceiver() {
|
||||
|
@ -90,26 +161,7 @@ object ClashUtil {
|
|||
}
|
||||
|
||||
|
||||
fun switchProxyGroup(groupName: String?, proxyName: String?, controllerUrl: String) {
|
||||
if (groupName == null || groupName.trim { it <= ' ' }
|
||||
.isEmpty() || proxyName == null || proxyName.trim { it <= ' ' }.isEmpty()) {
|
||||
LogUtils.log(
|
||||
Log.ERROR,
|
||||
"ClashUtil",
|
||||
"switchProxyGroup: Invalid arguments",
|
||||
null
|
||||
)
|
||||
throw IllegalArgumentException("Group name and proxy name must not be empty")
|
||||
}
|
||||
if (!controllerUrl.matches("^https?://.*".toRegex())) {
|
||||
LogUtils.log(
|
||||
Log.ERROR,
|
||||
"ClashUtil",
|
||||
"switchProxyGroup: Invalid controller URL",
|
||||
null
|
||||
)
|
||||
throw IllegalArgumentException("Invalid controller URL")
|
||||
}
|
||||
fun switchProxyGroup(groupName: String?, proxyName: String?, controllerUrl: String): Boolean {
|
||||
|
||||
val client = OkHttpClient()
|
||||
val json = JSONObject()
|
||||
|
@ -133,39 +185,27 @@ object ClashUtil {
|
|||
.put(requestBody)
|
||||
.build()
|
||||
|
||||
client.newCall(request).enqueue(object : Callback {
|
||||
override fun onFailure(call: Call, e: IOException) {
|
||||
LogUtils.log(
|
||||
Log.ERROR,
|
||||
"ClashUtil",
|
||||
"switchProxyGroup: Failed to switch proxy",
|
||||
e
|
||||
)
|
||||
println("Failed to switch proxy: " + e.message)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
try {
|
||||
if (response.body != null) {
|
||||
LogUtils.log(
|
||||
Log.INFO,
|
||||
val result = sharedClient.newCall(request).execute().use { response ->
|
||||
// 读取并记录响应内容
|
||||
val responseBody = if (response.body != null) response.body?.string() else "Empty response body"
|
||||
val isSuccess = if (response.isSuccessful) {
|
||||
LogUtils.d(
|
||||
"ClashUtil",
|
||||
"switchProxyGroup: Switch proxy response",
|
||||
null
|
||||
)
|
||||
"switchProxyGroup: Success | Status: " + response.code + " | Response: " + responseBody)
|
||||
true
|
||||
} else {
|
||||
LogUtils.log(
|
||||
Log.ERROR,
|
||||
LogUtils.d(
|
||||
"ClashUtil",
|
||||
"switchProxyGroup: Response body is null",
|
||||
null
|
||||
)
|
||||
"switchProxyGroup: Failed | Status: " + response.code + " | Response: " + responseBody)
|
||||
false
|
||||
}
|
||||
} finally {
|
||||
response.close()
|
||||
return isSuccess
|
||||
}
|
||||
return result
|
||||
} catch (e: Exception) {
|
||||
LogUtils.d("ClashUtil", "switchProxyGroup: Unexpected error", e)
|
||||
}
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.android.grape.util
|
||||
|
||||
import android.util.Log
|
||||
import com.blankj.utilcode.util.LogUtils
|
||||
|
||||
object CountryCode {
|
||||
const val DEVICE_TYPE: Int = 2
|
||||
const val US: String = "US"
|
||||
const val RU: String = "RU"
|
||||
val DEFAULT: String = US
|
||||
var currentCountry: String = DEFAULT
|
||||
|
||||
fun switchCountry(): String {
|
||||
currentCountry = if (currentCountry == US) RU else US
|
||||
LogUtils.d("TAG", "Switched country to: $currentCountry")
|
||||
return currentCountry
|
||||
}
|
||||
}
|
|
@ -946,8 +946,6 @@ object Util {
|
|||
videoProxy = extJo.getString("videoProxy")
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (extJo.has("proxy") && !extJo.isNull("proxy")) {
|
||||
val proxyJo = extJo.getJSONObject("proxy")
|
||||
proxyIp = proxyJo.getString("proxyIp")
|
||||
|
|
Loading…
Reference in New Issue