添加自动切换节点
This commit is contained in:
parent
7c964af900
commit
38f5963797
|
|
@ -29,6 +29,7 @@ import com.yingmao.clash.R
|
|||
import com.yingmao.clash.base.BaseActivity
|
||||
import com.cncat.vpn.common.constants.Intents
|
||||
import com.cncat.vpn.common.log.Log
|
||||
import com.cncat.vpn.service.ProfileManager
|
||||
import com.yingmao.clash.conf.BZYConstants
|
||||
import com.yingmao.clash.conf.Conf
|
||||
import com.yingmao.clash.entity.ClashNodebBean
|
||||
|
|
@ -38,8 +39,11 @@ import com.yingmao.clash.remote.Resource
|
|||
import com.cncat.vpn.service.model.Profile
|
||||
import com.cncat.vpn.service.remote.IProfileManager
|
||||
import com.cncat.vpn.service.remote.IRemoteService
|
||||
import com.cncat.vpn.service.remote.wrap
|
||||
import com.yingmao.clash.BuildConfig
|
||||
import com.yingmao.clash.app.MainApplication
|
||||
import com.yingmao.clash.fragment.home.HomeFragment
|
||||
import com.yingmao.clash.util.CommonUtils
|
||||
import com.yingmao.clash.util.Utils
|
||||
import com.yingmao.clash.view.RxToast
|
||||
import com.yingmao.clash.view.adapter.NodeListAdapter
|
||||
|
|
@ -100,6 +104,8 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
|
||||
private fun initData() {
|
||||
// clash = MainApplication.getApp()?.let { ClashManager(it) }
|
||||
// profileBinder =
|
||||
// MainApplication.getApp()?.let { ProfileManager(it).wrap() as IProfileManager }
|
||||
cacheNodeStr = MMKV.defaultMMKV().decodeString(BZYConstants.NODE_All_ITEM_NAME_KEY, "");
|
||||
|
||||
val intentFilter = IntentFilter(Intents.ACTION_NODE_LIST)
|
||||
|
|
@ -233,14 +239,21 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
var nowSubUrl: String = ""
|
||||
private fun updateProfile(isDelete: Boolean) {
|
||||
// showLoading("正在获取...", this@ChangeNodeActivity)
|
||||
|
||||
try {
|
||||
|
||||
|
||||
launch(Dispatchers.IO) {
|
||||
UIMainActivity.profileBinder?.let { profileManager ->
|
||||
var mProfile = profileManager.queryAll().find {
|
||||
it.name == Conf.getClashConfName(this@ChangeNodeActivity.applicationContext)
|
||||
// var mProfile = profileManager.queryAll().find {
|
||||
// it.name == Conf.getClashConfName(this@ChangeNodeActivity.applicationContext)
|
||||
// }
|
||||
var mProfile: Profile? = null
|
||||
Log.d("queryAll().size ==>${profileManager.queryAll().size}")
|
||||
profileManager.queryAll().forEach { it_pf ->
|
||||
var confName =
|
||||
Conf.getClashConfName(this@ChangeNodeActivity.applicationContext)
|
||||
Log.d(" it_pf.name ==>${it_pf.name}, confName==>${confName}")
|
||||
if (confName == it_pf.name) {
|
||||
mProfile = it_pf
|
||||
}
|
||||
}
|
||||
|
||||
if (mProfile == null) {
|
||||
|
|
@ -256,16 +269,16 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
Log.d("ChangeNode22 uuid==>${profile.uuid}")
|
||||
if (isDelete) {
|
||||
Log.d("gogogogogo isDelete")
|
||||
profileManager.delete(profile.uuid)
|
||||
// profileManager.delete(profile.uuid)
|
||||
MMKV.defaultMMKV()
|
||||
.removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY)
|
||||
setSub2(profileManager, nowSubUrl)
|
||||
|
||||
} else {
|
||||
Log.d("gogogogogo update")
|
||||
profileManager.setActive(profile)
|
||||
delay(500)
|
||||
Log.d("updateProfile pro.source==>${profile.source}, url==>${nowSubUrl}")
|
||||
if (!TextUtils.isEmpty(profile.source)) {
|
||||
// Log.d("updateProfile pro.source==>${profile.source}, url==>${nowSubUrl}")
|
||||
|
||||
if (profile.source != nowSubUrl) {
|
||||
Log.d("updateProfile patch")
|
||||
profileManager.patch(
|
||||
|
|
@ -280,6 +293,17 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
}
|
||||
Log.d("updateProfile patch 2")
|
||||
}
|
||||
} else {
|
||||
profileManager.patch(
|
||||
profile.uuid,
|
||||
profile.name,
|
||||
nowSubUrl,
|
||||
1800000L
|
||||
)
|
||||
Log.d("updateProfile patch new 1")
|
||||
profileManager.commit(profile.uuid) { status ->
|
||||
Log.d("updateProfile new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress)
|
||||
}
|
||||
}
|
||||
Log.d("updateProfile go update")
|
||||
profileManager.update(profile.uuid)
|
||||
|
|
@ -318,23 +342,29 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
UIMainActivity.subUrl?.let {
|
||||
nowSubUrl = it
|
||||
}
|
||||
doProfile()
|
||||
doProfile(false)
|
||||
|
||||
}
|
||||
|
||||
fun doProfile() {
|
||||
fun doProfile(isDelete: Boolean) {
|
||||
Log.d("doProfile....")
|
||||
if (TextUtils.isEmpty(cacheNodeStr)) {
|
||||
|
||||
}
|
||||
showLoading("正在获取...", this@ChangeNodeActivity)
|
||||
startTimer()
|
||||
updateProfile(false)
|
||||
// updateProfile(isDelete)
|
||||
|
||||
launch(Dispatchers.IO) {
|
||||
UIMainActivity.setSub2(nowSubUrl)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun changeSubUrl(originalUrl: String, newUrl: String) {
|
||||
if (!originalUrl.isNullOrEmpty() && !newUrl.isNullOrEmpty()) {
|
||||
nowSubUrl = originalUrl.replace(Regex("https://[^/]+/"), "$newUrl/")
|
||||
UIMainActivity.subUrl = nowSubUrl
|
||||
MMKV.defaultMMKV().encode(BZYConstants.PROFILE_SUB_URL, nowSubUrl)
|
||||
}
|
||||
}
|
||||
|
|
@ -393,7 +423,6 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private fun setNewData(nodes: MutableList<ClashNodebBean>?) {
|
||||
runOnUiThread {
|
||||
if (nodes != null) {
|
||||
|
|
@ -449,13 +478,25 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
}
|
||||
|
||||
private fun createProfile() {
|
||||
cleanProfile()
|
||||
launch(Dispatchers.IO) {
|
||||
UIMainActivity.profileBinder?.let { pro ->
|
||||
uuid?.let { uu ->
|
||||
pro.delete(uu)
|
||||
delay(500)
|
||||
setSub2(pro, UIMainActivity.subUrl)
|
||||
createMyProfile(pro, nowSubUrl)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun cleanProfile() {
|
||||
launch(Dispatchers.IO) {
|
||||
UIMainActivity.profileBinder?.let { pm ->
|
||||
pm.queryAll().forEach { profile ->
|
||||
Log.d("changeNode cleanProfile go delete name==>${profile.name}, uuid==>${profile.uuid}")
|
||||
pm.delete(profile.uuid)
|
||||
}
|
||||
} ?: let {
|
||||
Log.d("changeNode profileBinder is null")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -466,10 +507,6 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
com.cncat.vpn.common.log.Log.d("setSub2 url isEmpty")
|
||||
return
|
||||
}
|
||||
|
||||
com.cncat.vpn.common.log.Log.d("setSub2 2")
|
||||
|
||||
|
||||
com.cncat.vpn.common.log.Log.d("setSub2 3")
|
||||
val pro = pm.queryAll().find {
|
||||
it.name == Conf.getClashConfName(this@ChangeNodeActivity.applicationContext)
|
||||
|
|
@ -502,11 +539,40 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
"new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress
|
||||
)
|
||||
}
|
||||
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun createMyProfile(pm: IProfileManager, url: String) {
|
||||
var uuid: UUID = pm.create(
|
||||
Profile.Type.Url, Conf.getClashConfName(this@ChangeNodeActivity.applicationContext)
|
||||
)
|
||||
delay(500)
|
||||
pm.queryByUUID(uuid)?.let { qPro ->
|
||||
Log.d("createMyProfile url==>${url}")
|
||||
pm.setActive(qPro)
|
||||
pm.patch(
|
||||
qPro.uuid, qPro.name,
|
||||
// "https://mojie0201.xn--8stx8olrwkucjq3b.com/api/v1/client/subscribe?token=169110d2674c49604b7e5b5cea341579",
|
||||
// "https://www.otcopusapp.cc/lx3af288h5i8pz380/api/v1/client/subscribe?token=d6bc98c7ea53099fa5bd1a3ea415ebb6",
|
||||
// "https://reg.bazhuayujiasu.cc/api/v1/client/subscribe?token=7f0f025ab341bcec4822d2c90aadf8b0",
|
||||
url, 1800000L
|
||||
)
|
||||
// coroutineScope {
|
||||
pm.commit(qPro.uuid) { status ->
|
||||
android.util.Log.d(
|
||||
Conf.TAG,
|
||||
"new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress
|
||||
)
|
||||
}
|
||||
|
||||
// UIMainActivity.profileBinder = pm
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
var isCreate: Boolean = false
|
||||
private var timerJob: Job? = null
|
||||
private fun startTimer() {
|
||||
|
|
@ -514,15 +580,42 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
timerJob = launch {
|
||||
repeat(16) {
|
||||
Log.d("GetNodeTimeOutNum==>$GetNodeTimeOutNum")
|
||||
|
||||
if (GetNodeTimeOutNum == 0) {
|
||||
hideLoading()
|
||||
Log.d("stopTimer...")
|
||||
RxToast.error("获取节点失败...请尝试切换其他地址")
|
||||
showDomainList()
|
||||
RxToast.error("获取节点失败...正在切换其他地址")
|
||||
// showDomainList()
|
||||
// var mmkv = MMKV.defaultMMKV()
|
||||
// var currentHost = mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "")
|
||||
if (setNewData()) {
|
||||
timerJob?.cancel()
|
||||
// cleanProfile()
|
||||
MMKV.defaultMMKV()
|
||||
.removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY)
|
||||
// createProfile()
|
||||
saveSubUrl()
|
||||
|
||||
MainApplication.restartApp(this@ChangeNodeActivity, object :
|
||||
MainApplication.OnRestartButtonListener {
|
||||
|
||||
override fun enterButton() {
|
||||
|
||||
}
|
||||
|
||||
override fun cancelButton() {
|
||||
doProfile(false)
|
||||
}
|
||||
|
||||
})
|
||||
// doProfile(false)
|
||||
// isCreate=true
|
||||
} else {
|
||||
timerJob?.cancel()
|
||||
RxToast.error("获取全部线路失败...请切换网络重试")
|
||||
}
|
||||
// delay(1000)
|
||||
// this@ChangeNodeActivity.finish()
|
||||
|
||||
}
|
||||
GetNodeTimeOutNum--
|
||||
delay(1000)
|
||||
|
|
@ -545,7 +638,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
DialogDoMainChoose.OnTryButtonListener {
|
||||
override fun tryButton() {
|
||||
saveSubUrl()
|
||||
doProfile()
|
||||
doProfile(false)
|
||||
dialogDoMainChoose?.dismiss()
|
||||
}
|
||||
|
||||
|
|
@ -567,7 +660,7 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
}
|
||||
|
||||
override fun cancelButton() {
|
||||
doProfile()
|
||||
doProfile(false)
|
||||
dialogDoMainChoose?.dismiss()
|
||||
}
|
||||
|
||||
|
|
@ -585,10 +678,90 @@ class ChangeNodeActivity : BaseActivity(), View.OnClickListener {
|
|||
}
|
||||
}
|
||||
|
||||
private fun setNewData(): Boolean {
|
||||
var mmkv = MMKV.defaultMMKV()
|
||||
val originalUrl =
|
||||
mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url)
|
||||
var newUrlString = originalUrl
|
||||
var isChange = false
|
||||
val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet())
|
||||
var switchFinshSet = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_Switch_Finsh_Set, HashSet())
|
||||
routerHost?.let {
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// if (!isNetworkAvailable(this@BaseActivity)){
|
||||
// return isChange
|
||||
// }
|
||||
// }
|
||||
if (it.isEmpty()) {
|
||||
android.util.Log.d(Conf.TAG, "routerHost isEmpty")
|
||||
return isChange
|
||||
}
|
||||
com.cncat.vpn.common.log.Log.d("switchFinshSet.size==>${switchFinshSet?.size!!} , routerHost.size==>${routerHost.size}")
|
||||
//次数已满
|
||||
if (switchFinshSet?.size!! >= routerHost.size) {
|
||||
return isChange
|
||||
}
|
||||
android.util.Log.d(Conf.TAG, "routerHost not empty")
|
||||
for (url in it) {
|
||||
// com.cncat.vpn.common.log.Log.d("url==>$url")
|
||||
|
||||
if (url == originalUrl) {
|
||||
switchFinshSet?.add(url)
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet)
|
||||
continue
|
||||
}
|
||||
|
||||
if (switchFinshSet?.contains(url) == true) {
|
||||
continue
|
||||
} else {
|
||||
isChange = true
|
||||
android.util.Log.e("Retry", "切换到新url:$url")
|
||||
newUrlString = url
|
||||
switchFinshSet?.add(newUrlString)
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet)
|
||||
// mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, newUrlString)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// val iterator = it.iterator()
|
||||
// while (iterator.hasNext()) {
|
||||
// val newUrl = iterator.next()
|
||||
// android.util.Log.e(
|
||||
// "Data",
|
||||
// "遍历备用的url:$newUrl, contains==>${switchFinshSet?.contains(newUrl)}"
|
||||
// )
|
||||
// if (newUrl == originalUrl) {
|
||||
// switchFinshSet?.add(newUrl)
|
||||
// iterator.remove()
|
||||
// continue
|
||||
// }
|
||||
// if (switchFinshSet?.contains(newUrl) == true) {
|
||||
// iterator.remove()
|
||||
// } else {
|
||||
// android.util.Log.e("Retry", "切换到新url:$newUrl")
|
||||
// newUrlString = newUrl
|
||||
// iterator.remove()
|
||||
// if (originalUrl != null) {
|
||||
// switchFinshSet?.add(originalUrl)
|
||||
// mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet)
|
||||
// mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, originalUrl)
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// mmkv.encode(BZYConstants.MMKV_KEY_ROUTER_HOST, routerHost)
|
||||
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString)
|
||||
|
||||
}
|
||||
return isChange
|
||||
}
|
||||
|
||||
private fun saveSubUrl() {
|
||||
var currentHost = MMKV.defaultMMKV()
|
||||
.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "")
|
||||
// com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}")
|
||||
com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}")
|
||||
var oldUrl = nowSubUrl
|
||||
currentHost?.let { changeSubUrl(oldUrl, it) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -362,7 +362,19 @@ class MemberRechargeActivity : BaseActivity() {
|
|||
override fun httpFailure(httpStatus: HttpStatus.Failure) {
|
||||
when (httpStatus.reqType) {
|
||||
HttpReqType.GET_RECHARGE_INFO -> {
|
||||
showDomainList()
|
||||
// showDomainList()
|
||||
if (super.switchServer2()) {
|
||||
val username =
|
||||
MMKV.defaultMMKV()
|
||||
.decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")!!
|
||||
val phToken =
|
||||
MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN, "")!!
|
||||
val userId = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_USER_ID)!!
|
||||
viewModel.getPhRechargeInfo(username, phToken, userId)
|
||||
} else {
|
||||
// super.switchFinshSet?.clear()
|
||||
}
|
||||
|
||||
Logger.d("获取充值续费信息异常${httpStatus.msg}")
|
||||
swipeLayout.isRefreshing = false
|
||||
RxToast.error(resources.getString(R.string.DataError))
|
||||
|
|
|
|||
|
|
@ -128,8 +128,8 @@ class NewMainActivity : BaseActivity() {
|
|||
|
||||
// private var profile: ProfileManager? = null
|
||||
// private var clashManager: ClashManager? = null
|
||||
var clashBinder: IClashManager? = null
|
||||
var profileBinder: IProfileManager? = null
|
||||
private var clashBinder: IClashManager? = null
|
||||
private var profileBinder: IProfileManager? = null
|
||||
var newMainActGlo: Boolean = false
|
||||
var isUpload: Boolean = false
|
||||
var hostsMem: ArrayList<String> = ArrayList()
|
||||
|
|
@ -1187,6 +1187,7 @@ class NewMainActivity : BaseActivity() {
|
|||
|
||||
|
||||
suspend fun createMyProfile(pm: IProfileManager, url: String) {
|
||||
Log.d("createMyProfile")
|
||||
var uuid: UUID = pm.create(
|
||||
Profile.Type.Url, Conf.getClashConfName(this@NewMainActivity.applicationContext)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ class SettingActivity : BaseActivity() {
|
|||
showLoading(resources.getString(R.string.UnderRepair), this@SettingActivity)
|
||||
|
||||
launch(Dispatchers.IO) {
|
||||
NewMainActivity.profileBinder?.let { pm ->
|
||||
UIMainActivity.profileBinder?.let { pm ->
|
||||
pm.queryAll().forEach { profile ->
|
||||
Log.d("setting profile delete ==>${profile.name}")
|
||||
pm.delete(profile.uuid)
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ class SplashHelper(private val splashAtyVM: PublicViewMode) {
|
|||
third: (AsyncCallback) -> Unit,
|
||||
callback: (Boolean) -> Unit
|
||||
) {
|
||||
first(createCallback("getHost method success", "getHostByGithub method failed", callback) {
|
||||
first(createCallback("getHost method success", "getHost method failed", callback) {
|
||||
second(createCallback("getHostByAWS method success", "getHostByAWS method failed", callback) {
|
||||
third(createCallback("getHost method success", "getHost methods failed", callback) {
|
||||
third(createCallback("getHostByGithub method success", "getHostByGithub methods failed", callback) {
|
||||
callback(false) // 所有方法都失败
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -239,6 +239,11 @@ class SplashActivity : BaseActivity() {
|
|||
com.cncat.vpn.common.log.Log.d("si==>${si}, ss1==>${ss1}, ss2==>${ss2}")
|
||||
MainApplication.KEY2 = ss1
|
||||
MainApplication.IV2 = ss2
|
||||
|
||||
|
||||
// val byteArrayToHexStr =
|
||||
// AESUtil.byteArrayToHexStr(AESUtil.encrypt("https://api.kuaifei.net+https://api.wfvpnpro.com+https://wf.jimao.xyz+https://api.msljsqpro.com+https://api.mashanglianjsq.com"))
|
||||
// android.util.Log.i("AAAAAAAAAAAAAAAA","data::"+byteArrayToHexStr+"::")
|
||||
// 太子
|
||||
// com.cncat.vpn.common.log.Log.d("tz encrypt:"+ AESUtil.byteArrayToHexStr(AESUtil.encrypt("")))
|
||||
// 八爪鱼 com.cncat.vpn.common.log.Log.d("bzy encrypt:"+ AESUtil.byteArrayToHexStr(AESUtil.encrypt("")))
|
||||
|
|
@ -817,6 +822,7 @@ class SplashActivity : BaseActivity() {
|
|||
val expired = checkLoginRsp.data?.expired
|
||||
val isPerfect = checkLoginRsp.data?.isPerfect
|
||||
val userCommand = checkLoginRsp.data?.userCommand
|
||||
val logSwitch = checkLoginRsp.data?.logSwitch
|
||||
val mmkv = MMKV.defaultMMKV()
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_VPN_EXPIRED, expired ?: true)
|
||||
mmkv.encode(
|
||||
|
|
@ -825,11 +831,8 @@ class SplashActivity : BaseActivity() {
|
|||
)
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_IS_PERFECT, isPerfect ?: true)
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_VPN_UserCommand, userCommand ?: "")
|
||||
|
||||
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_VPN_LogSwitch, logSwitch ?: "")
|
||||
toMainPage()
|
||||
|
||||
|
||||
} else {
|
||||
toLoginPage()
|
||||
}
|
||||
|
|
@ -903,56 +906,56 @@ class SplashActivity : BaseActivity() {
|
|||
rlPb.visibility = View.GONE
|
||||
pb_web?.visibility = View.INVISIBLE
|
||||
com.cncat.vpn.common.log.Log.d("httpFailure HttpReqType.REGISTER")
|
||||
try {
|
||||
RxToast.error("检测到网络异常,请尝试切换其他地址.")
|
||||
if (dialogDoMainChoose == null) {
|
||||
dialogDoMainChoose = DialogDoMainChoose(this@SplashActivity)
|
||||
}
|
||||
if (dialogDoMainChoose?.isShowing == false) {
|
||||
dialogDoMainChoose?.setOnTryButtonListener(object :
|
||||
DialogDoMainChoose.OnTryButtonListener {
|
||||
override fun tryButton() {
|
||||
var currentHost = MMKV.defaultMMKV()
|
||||
.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "")
|
||||
// com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}")
|
||||
doRegisterByEncryption()
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
com.cncat.vpn.common.log.Log.d("tryButton REGISTER cancel")
|
||||
dialogDoMainChoose?.dismiss()
|
||||
dialogDoMainChoose = null
|
||||
}
|
||||
})
|
||||
dialogDoMainChoose?.setOnListItemListener(object :
|
||||
DialogDoMainChoose.OnListItemListener {
|
||||
override fun listItemClick() {
|
||||
doRegisterByEncryption()
|
||||
dialogDoMainChoose?.dismiss()
|
||||
}
|
||||
|
||||
})
|
||||
dialogDoMainChoose?.show()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
// if (super.switchServer()) {//切换服务器并直接重试
|
||||
//// doRegister()
|
||||
// doRegisterByEncryption()
|
||||
// } else {
|
||||
// MaterialDialog(this@SplashActivity).show {
|
||||
// message(text = initErrMsg)
|
||||
// positiveButton(R.string.retry) {
|
||||
//// doRegister()
|
||||
// try {
|
||||
// RxToast.error("检测到网络异常,请尝试切换其他地址.")
|
||||
// if (dialogDoMainChoose == null) {
|
||||
// dialogDoMainChoose = DialogDoMainChoose(this@SplashActivity)
|
||||
// }
|
||||
// if (dialogDoMainChoose?.isShowing == false) {
|
||||
// dialogDoMainChoose?.setOnTryButtonListener(object :
|
||||
// DialogDoMainChoose.OnTryButtonListener {
|
||||
// override fun tryButton() {
|
||||
// var currentHost = MMKV.defaultMMKV()
|
||||
// .decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, "")
|
||||
//// com.cncat.vpn.common.log.Log.d("tryButton currentHost==>${currentHost}")
|
||||
// doRegisterByEncryption()
|
||||
// }
|
||||
// negativeButton(R.string.cancel) {
|
||||
// it.dismiss()
|
||||
// finish()
|
||||
//
|
||||
// override fun cancel() {
|
||||
// com.cncat.vpn.common.log.Log.d("tryButton REGISTER cancel")
|
||||
// dialogDoMainChoose?.dismiss()
|
||||
// dialogDoMainChoose = null
|
||||
// }
|
||||
// })
|
||||
// dialogDoMainChoose?.setOnListItemListener(object :
|
||||
// DialogDoMainChoose.OnListItemListener {
|
||||
// override fun listItemClick() {
|
||||
// doRegisterByEncryption()
|
||||
// dialogDoMainChoose?.dismiss()
|
||||
// }
|
||||
//
|
||||
// })
|
||||
// dialogDoMainChoose?.show()
|
||||
// }
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
if (super.switchServer2()) {//切换服务器并直接重试
|
||||
// doRegister()
|
||||
doRegisterByEncryption()
|
||||
} else {
|
||||
MaterialDialog(this@SplashActivity).show {
|
||||
message(text = initErrMsg)
|
||||
positiveButton(R.string.retry) {
|
||||
// doRegister()
|
||||
doRegisterByEncryption()
|
||||
}
|
||||
negativeButton(R.string.cancel) {
|
||||
it.dismiss()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HttpReqType.LOGIN -> {
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ class UIMainActivity : BaseActivity() {
|
|||
private var newMainActGlo: Boolean = false
|
||||
private var homeFragment: HomeFragment? = null
|
||||
private var settingFragment: SettingFragment? = null
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
|
||||
private var activityDialog: ActivityViewDialog? = null
|
||||
|
|
@ -113,6 +114,69 @@ class UIMainActivity : BaseActivity() {
|
|||
var hostsMem: ArrayList<String> = ArrayList()
|
||||
var isSubed = false
|
||||
var newMainActGlo: Boolean = false
|
||||
public suspend fun setSub2(url: String) {
|
||||
profileBinder?.let { pm ->
|
||||
pm.queryAll().forEach { itemPro ->
|
||||
Log.d("uimain setSub2 itemPro.name==${itemPro.name}")
|
||||
if (itemPro.name != Conf.getClashConfName(MainApplication.getApp()?.applicationContext)) {
|
||||
Log.d("setSub2 delete ==>${itemPro.name}")
|
||||
pm.delete(itemPro.uuid)
|
||||
}
|
||||
}
|
||||
var mProfile = pm.queryAll().find {
|
||||
it.name == Conf.getClashConfName(MainApplication.getApp()?.applicationContext)
|
||||
}
|
||||
|
||||
mProfile?.let {
|
||||
var actname = it.name
|
||||
Log.d("new main actname==>" + actname)
|
||||
Log.d("setSub2 pro 已存在 ==>")
|
||||
pm.setActive(it)
|
||||
delay(500)
|
||||
//判断配置文件source
|
||||
if (!TextUtils.isEmpty(mProfile.source)) {
|
||||
Log.d("setSub2 pro.source==>${mProfile.source}, url==>${url}")
|
||||
//订阅链接不同就更换
|
||||
if (mProfile.source != url) {
|
||||
pm.patch(
|
||||
mProfile.uuid, mProfile.name,
|
||||
url, 1800000L
|
||||
)
|
||||
pm.commit(mProfile.uuid) { status ->
|
||||
android.util.Log.d(
|
||||
Conf.TAG,
|
||||
"new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
pm.update(it.uuid)
|
||||
newUuid = mProfile.uuid.toString()
|
||||
isSubbed = true
|
||||
} ?: run {
|
||||
Log.d("setSub2 go create")
|
||||
val uuid: UUID = pm.create(
|
||||
Profile.Type.Url, Conf.getClashConfName(MainApplication.getApp()?.applicationContext)
|
||||
)
|
||||
delay(500)
|
||||
pm.queryByUUID(uuid)?.let { qPro ->
|
||||
pm.setActive(qPro)
|
||||
pm.patch(
|
||||
qPro.uuid, qPro.name,
|
||||
url, 1800000L
|
||||
)
|
||||
pm.commit(qPro.uuid) { status ->
|
||||
android.util.Log.d(
|
||||
Conf.TAG,
|
||||
"new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress
|
||||
)
|
||||
}
|
||||
newUuid = qPro.uuid.toString()
|
||||
isSubbed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -148,6 +212,7 @@ class UIMainActivity : BaseActivity() {
|
|||
if (homeFragment == null) homeFragment = HomeFragment()
|
||||
showFragment(homeFragment!!)
|
||||
}
|
||||
|
||||
R.id.navigation_setting -> {
|
||||
if (settingFragment == null) settingFragment = SettingFragment()
|
||||
showFragment(settingFragment!!)
|
||||
|
|
@ -163,6 +228,7 @@ class UIMainActivity : BaseActivity() {
|
|||
transaction.replace(R.id.fragmentContainer, fragment)
|
||||
transaction.commit()
|
||||
}
|
||||
|
||||
private fun showFragment(fragment: Fragment) {
|
||||
val fragmentManager = supportFragmentManager
|
||||
val transaction = fragmentManager.beginTransaction()
|
||||
|
|
@ -179,6 +245,7 @@ class UIMainActivity : BaseActivity() {
|
|||
}
|
||||
transaction.commit()
|
||||
}
|
||||
|
||||
override fun httpLoading(httpStatus: HttpStatus.Loading) {
|
||||
if (httpStatus.reqType == HttpReqType.HEARTBEAT) {
|
||||
Logger.d("心跳中")
|
||||
|
|
@ -196,25 +263,26 @@ class UIMainActivity : BaseActivity() {
|
|||
}
|
||||
data.data.let { url ->
|
||||
android.util.Log.e("Data", "机场URL:=${url}")
|
||||
var url2="https://api.ymvpnpro11.cc:8700/7air2vr7ikiqzgvxz/api/v1/client/subscribe?token=22f3d75079ec6fa546c1862c4354e448"
|
||||
// if (url.isNotEmpty()) {
|
||||
// subUrl = url
|
||||
// lifecycleScope.launch(Dispatchers.IO) {
|
||||
// setSub2(url)
|
||||
// }
|
||||
// }
|
||||
if (url.isNotEmpty()) {
|
||||
if (url2.isNotEmpty()) {
|
||||
//todo 判断订阅地址是否修改过,未修改就用接口返回的地址反之使用本地修改的地址
|
||||
var pro_sub_url =
|
||||
MMKV.defaultMMKV().decodeString(BZYConstants.PROFILE_SUB_URL, "")
|
||||
// Log.d("pro_sub_url==>${pro_sub_url}")
|
||||
if (!TextUtils.isEmpty(pro_sub_url)) {
|
||||
if (pro_sub_url == url) {
|
||||
subUrl = url
|
||||
if (pro_sub_url == url2) {
|
||||
subUrl = url2
|
||||
} else {
|
||||
subUrl = pro_sub_url
|
||||
}
|
||||
} else {
|
||||
subUrl = url
|
||||
subUrl = url2
|
||||
}
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
// setSub(url)
|
||||
|
|
@ -263,8 +331,10 @@ class UIMainActivity : BaseActivity() {
|
|||
val expired = checkLoginRsp.data.expired
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_VPN_EXPIRED, expired ?: true)
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_VPN_VALID_PERIOD, nowExpireTime)
|
||||
val hf = supportFragmentManager.findFragmentById(R.id.fragmentContainer) as? HomeFragment
|
||||
val sf = supportFragmentManager.findFragmentById(R.id.fragmentContainer) as? SettingFragment
|
||||
val hf =
|
||||
supportFragmentManager.findFragmentById(R.id.fragmentContainer) as? HomeFragment
|
||||
val sf =
|
||||
supportFragmentManager.findFragmentById(R.id.fragmentContainer) as? SettingFragment
|
||||
hf?.setExpireDate()
|
||||
sf?.setExpireDate()
|
||||
checkPayResultDia?.dismiss()
|
||||
|
|
@ -343,6 +413,7 @@ class UIMainActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showLoadingDialog(msg: String) {
|
||||
payResultLoading = RxDialogShapeLoading(this)
|
||||
payResultLoading!!.setMessage(msg)
|
||||
|
|
@ -356,7 +427,11 @@ class UIMainActivity : BaseActivity() {
|
|||
MMKV.defaultMMKV().removeValueForKey(BZYConstants.NODE_SELECTED_NAME_KEY)
|
||||
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_VPN_UserCommand)
|
||||
MMKV.defaultMMKV().removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY)
|
||||
MMKV.defaultMMKV().removeValueForKey(BZYConstants.PROFILE_SUB_URL)
|
||||
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_Switch_Finsh_Set)
|
||||
Log.d("cleanUserInfo clashRunning==>${clashRunning}")
|
||||
//清除源切换记录
|
||||
|
||||
if (clashRunning) {
|
||||
fragments.filterIsInstance<HomeFragment>().forEach { it.stopClash() }
|
||||
}
|
||||
|
|
@ -401,61 +476,7 @@ class UIMainActivity : BaseActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun setSub2(url: String) {
|
||||
profileBinder?.let { pm ->
|
||||
pm.queryAll().forEach { itemPro ->
|
||||
if (itemPro.name != Conf.getClashConfName(this@UIMainActivity.applicationContext)) {
|
||||
pm.delete(itemPro.uuid)
|
||||
}
|
||||
}
|
||||
val pro = pm.queryActive()
|
||||
|
||||
pro?.let {
|
||||
pm.setActive(it)
|
||||
delay(500)
|
||||
//判断配置文件source
|
||||
if (!TextUtils.isEmpty(pro.source)) {
|
||||
Log.d("setSub2 pro.source==>${pro.source}, url==>${url}")
|
||||
//订阅链接不同就更换
|
||||
if (pro.source != url) {
|
||||
pm.patch(
|
||||
pro.uuid, pro.name,
|
||||
url, 1800000L
|
||||
)
|
||||
pm.commit(pro.uuid) { status ->
|
||||
android.util.Log.d(
|
||||
Conf.TAG,
|
||||
"new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
pm.update(it.uuid)
|
||||
newUuid = pro.uuid.toString()
|
||||
isSubbed = true
|
||||
} ?: run {
|
||||
val uuid: UUID = pm.create(
|
||||
Profile.Type.Url, Conf.getClashConfName(this@UIMainActivity.applicationContext)
|
||||
)
|
||||
delay(500)
|
||||
pm.queryByUUID(uuid)?.let { qPro ->
|
||||
pm.setActive(qPro)
|
||||
pm.patch(
|
||||
qPro.uuid, qPro.name,
|
||||
url, 1800000L
|
||||
)
|
||||
pm.commit(qPro.uuid) { status ->
|
||||
android.util.Log.d(
|
||||
Conf.TAG,
|
||||
"new updateStatus: " + Gson().toJson(status.args) + ", pro==>" + status.progress
|
||||
)
|
||||
}
|
||||
newUuid = qPro.uuid.toString()
|
||||
isSubbed = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun startLog() {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package com.yingmao.clash.app
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
import android.app.NotificationChannel
|
||||
|
|
@ -10,7 +9,6 @@ import android.content.Intent
|
|||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.content.ContextCompat.getString
|
||||
import androidx.core.content.getSystemService
|
||||
import com.cncat.vpn.common.Global
|
||||
import com.cncat.vpn.common.compat.currentProcessName
|
||||
|
|
@ -18,7 +16,6 @@ import com.cncat.vpn.common.log.Log
|
|||
import com.github.gzuliyujiang.oaid.DeviceID
|
||||
import com.github.gzuliyujiang.oaid.DeviceIdentifier
|
||||
import com.github.gzuliyujiang.oaid.IGetter
|
||||
|
||||
import com.jakewharton.processphoenix.ProcessPhoenix
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.stripe.android.PaymentConfiguration
|
||||
|
|
@ -29,14 +26,16 @@ import com.yingmao.clash.conf.BZYConstants
|
|||
import com.yingmao.clash.entity.UserData
|
||||
import com.yingmao.clash.util.CrashCatchHandler
|
||||
import com.yingmao.clash.util.clashDir
|
||||
import com.yingmao.clash.view.RxToast
|
||||
import com.yingmao.clash.view.dialog.DialogDoMainChoose
|
||||
import com.yingmao.clash.view.dialog.DialogSureRestartChoose
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
|
||||
|
||||
|
|
@ -154,10 +153,27 @@ class MainApplication : Application() {
|
|||
// if (privacyPolicyAgreed) {
|
||||
|
||||
// }
|
||||
|
||||
// Thread.setDefaultUncaughtExceptionHandler { thread, throwable ->
|
||||
// logException(throwable)
|
||||
// // 可选择上报到服务器或写入本地文件
|
||||
// }
|
||||
|
||||
}
|
||||
fun logException(e: Throwable) {
|
||||
val log = StringWriter().also { e.printStackTrace(PrintWriter(it)) }.toString()
|
||||
Log.d("MainApplication logException==>${log}")
|
||||
|
||||
// val directory: File? = applicationContext.getExternalFilesDir("CrashLog")
|
||||
// if (directory != null) {
|
||||
// if (!directory.isDirectory) {
|
||||
// directory.delete()
|
||||
// }
|
||||
// if (!directory.exists()) {
|
||||
// directory.mkdirs()
|
||||
// }
|
||||
// }
|
||||
// File(directory, "crash_${System.currentTimeMillis()}.log").writeText(log)
|
||||
}
|
||||
fun updateActivity(language: String, locale: Locale) {
|
||||
MMKV.defaultMMKV().encode(BZYConstants.languageInfo, language)
|
||||
val resources = this.resources
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import android.content.Context
|
|||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Configuration
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
|
|
@ -13,7 +16,9 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.*
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.collection.arraySetOf
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import com.orhanobut.logger.Logger
|
||||
import com.tencent.mmkv.MMKV
|
||||
|
|
@ -55,6 +60,10 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
|
|||
var baseLoading: RxDialogShapeLoading? = null
|
||||
val serStore by lazy { ServiceStore(this) }
|
||||
|
||||
companion object {
|
||||
// var switchFinshSet: MutableSet<String>? = null
|
||||
}
|
||||
|
||||
sealed class RequestTunnel {
|
||||
object ReloadAll : RequestTunnel()
|
||||
object ReLaunch : RequestTunnel()
|
||||
|
|
@ -265,6 +274,7 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
|
|||
val mmkv = MMKV.defaultMMKV()
|
||||
val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet())
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun switchServer(): Boolean {
|
||||
var isChange = false
|
||||
|
|
@ -303,4 +313,95 @@ open class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope(), Br
|
|||
|
||||
return isChange
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
fun isNetworkAvailable(context: Context): Boolean {
|
||||
val connectivityManager =
|
||||
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
|
||||
val network = connectivityManager.activeNetwork ?: return false
|
||||
val capabilities = connectivityManager.getNetworkCapabilities(network) ?: return false
|
||||
|
||||
return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun switchServer2(): Boolean {
|
||||
var isChange = false
|
||||
val mmkv = MMKV.defaultMMKV()
|
||||
val originalUrl =
|
||||
mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url)
|
||||
var newUrlString = originalUrl
|
||||
val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet())
|
||||
var switchFinshSet = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_Switch_Finsh_Set, HashSet())
|
||||
routerHost?.let {
|
||||
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
// if (!isNetworkAvailable(this@BaseActivity)){
|
||||
// return isChange
|
||||
// }
|
||||
// }
|
||||
if (it.isEmpty()) {
|
||||
Log.d(Conf.TAG, "routerHost isEmpty")
|
||||
return isChange
|
||||
}
|
||||
com.cncat.vpn.common.log.Log.d("switchFinshSet.size==>${switchFinshSet?.size!!} , routerHost.size==>${routerHost.size}")
|
||||
//次数已满
|
||||
if (switchFinshSet?.size!! >= routerHost.size) {
|
||||
return isChange
|
||||
}
|
||||
|
||||
Log.d(Conf.TAG, "routerHost not empty")
|
||||
// val iterator = it.iterator()
|
||||
// while (iterator.hasNext()) {
|
||||
// val newUrl = iterator.next()
|
||||
// Log.e(
|
||||
// "Data",
|
||||
// "遍历备用的url:$newUrl, contains==>${switchFinshSet?.contains(newUrl)}"
|
||||
// )
|
||||
// if (newUrl == originalUrl) {
|
||||
// switchFinshSet?.add(newUrl)
|
||||
// iterator.remove()
|
||||
// continue
|
||||
// }
|
||||
// if (switchFinshSet?.contains(newUrl) == true) {
|
||||
// iterator.remove()
|
||||
// } else {
|
||||
// Log.e("Retry", "切换到新url:$newUrl")
|
||||
// isChange = true
|
||||
// newUrlString = newUrl
|
||||
// iterator.remove()
|
||||
// if (originalUrl != null) {
|
||||
// switchFinshSet?.add(originalUrl)
|
||||
// mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, originalUrl)
|
||||
// }
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
for (url in it) {
|
||||
|
||||
if (url == originalUrl) {
|
||||
switchFinshSet?.add(url)
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet)
|
||||
continue
|
||||
}
|
||||
|
||||
if (switchFinshSet?.contains(url) == true) {
|
||||
continue
|
||||
} else {
|
||||
isChange = true
|
||||
android.util.Log.e("Retry", "切换到新url:$url")
|
||||
newUrlString = url
|
||||
switchFinshSet?.add(newUrlString)
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_Switch_Finsh_Set, switchFinshSet)
|
||||
// mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, newUrlString)
|
||||
break
|
||||
}
|
||||
}
|
||||
// mmkv.encode(BZYConstants.MMKV_KEY_ROUTER_HOST, routerHost)
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString)
|
||||
}
|
||||
|
||||
return isChange
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +1,37 @@
|
|||
package com.yingmao.clash.base
|
||||
|
||||
import android.os.Build
|
||||
import android.text.TextUtils
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.google.gson.Gson
|
||||
import com.cncat.vpn.common.log.Log
|
||||
import com.google.gson.Gson
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.yingmao.clash.BuildConfig
|
||||
import com.yingmao.clash.app.MainApplication
|
||||
import com.yingmao.clash.conf.BZYConstants
|
||||
import com.yingmao.clash.net.http.HttpApi
|
||||
import com.yingmao.clash.net.http.HttpReqType
|
||||
import com.yingmao.clash.net.http.HttpStatus
|
||||
import com.yingmao.clash.net.http.HttpStatusDownLoad
|
||||
import com.yingmao.clash.net.http.NetService
|
||||
import com.yingmao.clash.net.http.entity.BaseRsp
|
||||
import com.yingmao.clash.util.AESUtil
|
||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
open class BaseViewMode : ViewModel() {
|
||||
|
||||
|
|
@ -24,9 +41,13 @@ open class BaseViewMode : ViewModel() {
|
|||
|
||||
fun doAsync(reqType: HttpReqType, doInAsync: suspend () -> Any) {
|
||||
viewModelScope.launch(
|
||||
CoroutineExceptionHandler { _,
|
||||
exception ->
|
||||
Log.e("BaseViewMode_doAsync:${exception.toString()}", exception)
|
||||
CoroutineExceptionHandler {
|
||||
_,
|
||||
exception,
|
||||
->
|
||||
Log.e("BaseViewMode_doAsync:${exception.localizedMessage}", exception)
|
||||
|
||||
logException(exception)
|
||||
statusData.value =
|
||||
if (exception.message.isNullOrBlank()) HttpStatus.Failure(
|
||||
reqType,
|
||||
|
|
@ -52,10 +73,80 @@ open class BaseViewMode : ViewModel() {
|
|||
}
|
||||
}
|
||||
|
||||
fun doAsync2(reqType: HttpReqType, doInAsync: suspend () -> Any) {
|
||||
fun logException(e: Throwable) {
|
||||
var logSwitch = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_VPN_LogSwitch, "")
|
||||
if ("on" == logSwitch) {
|
||||
val log = StringWriter().also { e.printStackTrace(PrintWriter(it)) }.toString()
|
||||
Log.d("logException==>${log}")
|
||||
val username =
|
||||
MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_REMEMBER_USERNAME, "")!!
|
||||
var json = JSONObject()
|
||||
val androidVersion = Build.VERSION.RELEASE // 系统版本号,例如 "13"
|
||||
val sdkInt = Build.VERSION.SDK_INT // SDK 级别,例如 33
|
||||
val manufacturer = Build.MANUFACTURER // 厂商,例如 "Xiaomi"
|
||||
val model = Build.MODEL // 机型,例如 "MI 11"
|
||||
val brand = Build.BRAND // 品牌,例如 "Xiaomi"
|
||||
val device = Build.DEVICE // 设备代号,例如 "venus"
|
||||
val hardware = Build.HARDWARE // 硬件名称,例如 "qcom"
|
||||
|
||||
// val nowTime = SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒E", Locale.getDefault())
|
||||
var ja_streams = JSONArray()
|
||||
var jo_streams_item = JSONObject()
|
||||
var jo_stream = JSONObject()
|
||||
var ja_values = JSONArray()
|
||||
jo_stream.put("phoneNumber", username)
|
||||
jo_stream.put("appVersion", BuildConfig.VERSION_NAME)
|
||||
jo_stream.put("androidVersion", androidVersion)
|
||||
jo_stream.put("sdkInt", sdkInt)
|
||||
jo_stream.put("manufacturer", manufacturer)
|
||||
jo_stream.put("model", model)
|
||||
jo_stream.put("brand", brand)
|
||||
jo_stream.put("device", device)
|
||||
jo_stream.put("hardware", hardware)
|
||||
|
||||
ja_values.put(0, System.currentTimeMillis().toString() + "000000")
|
||||
//错误信息
|
||||
ja_values.put(1, log)
|
||||
jo_streams_item.put("stream", jo_stream)
|
||||
var ja_values_item = JSONArray()
|
||||
ja_values_item.put(0, ja_values)
|
||||
jo_streams_item.put("values", ja_values_item)
|
||||
ja_streams.put(0, jo_streams_item)
|
||||
json.put("streams", ja_streams)
|
||||
|
||||
Log.d("json==>${json}")
|
||||
val httpApi = NetService.instances.createHttps(HttpApi::class.java)
|
||||
val requestBody: RequestBody = json.toString().toRequestBody("application/json; charset=utf-8".toMediaType())
|
||||
doAsync2(HttpReqType.APPSHAREINFO) {
|
||||
httpApi.postErrLog(requestBody)
|
||||
}
|
||||
// val directory: File? = MainApplication.getApp()?.applicationContext?.getExternalFilesDir("CrashLog")
|
||||
// if (directory != null) {
|
||||
// if (!directory.isDirectory) {
|
||||
// directory.delete()
|
||||
// }
|
||||
// if (!directory.exists()) {
|
||||
// directory.mkdirs()
|
||||
// }
|
||||
// }
|
||||
// File(directory, "crash_${System.currentTimeMillis()}.log").writeText(json.toString())
|
||||
}
|
||||
}
|
||||
fun postErrLog(phone: String) {
|
||||
|
||||
val phToken = MMKV.defaultMMKV().decodeString(BZYConstants.MMKV_KEY_PH_TOKEN,"")!!
|
||||
val params = mutableMapOf(
|
||||
"phoneNumber" to phone,
|
||||
"phToken" to phToken
|
||||
)
|
||||
|
||||
}
|
||||
fun doAsync2(reqType: HttpReqType, doInAsync: suspend () -> Any?) {
|
||||
viewModelScope.launch(
|
||||
CoroutineExceptionHandler { _,
|
||||
exception ->
|
||||
CoroutineExceptionHandler {
|
||||
_,
|
||||
exception,
|
||||
->
|
||||
Log.e("BaseViewMode_doAsync:${exception.toString()}", exception)
|
||||
statusData.value =
|
||||
if (exception.message.isNullOrBlank()) HttpStatus.Failure(
|
||||
|
|
@ -114,11 +205,13 @@ open class BaseViewMode : ViewModel() {
|
|||
fun doAsyncDelay(
|
||||
reqType: HttpReqType,
|
||||
delayTimeMillis: Long,
|
||||
doInAsync: suspend () -> BaseRsp
|
||||
doInAsync: suspend () -> BaseRsp,
|
||||
) {
|
||||
viewModelScope.launch(
|
||||
CoroutineExceptionHandler { _,
|
||||
exception ->
|
||||
CoroutineExceptionHandler {
|
||||
_,
|
||||
exception,
|
||||
->
|
||||
Log.e("BaseViewMode_doAsyncDelay:${exception.toString()}", exception)
|
||||
statusData.value =
|
||||
if (exception.message.isNullOrBlank()) HttpStatus.Failure(
|
||||
|
|
@ -149,8 +242,10 @@ open class BaseViewMode : ViewModel() {
|
|||
|
||||
fun doAsyncStrResult(reqType: HttpReqType, doInAsync: suspend () -> String) {
|
||||
viewModelScope.launch(
|
||||
CoroutineExceptionHandler { _,
|
||||
exception ->
|
||||
CoroutineExceptionHandler {
|
||||
_,
|
||||
exception,
|
||||
->
|
||||
Log.e("BaseViewMode_doAsyncStrResult:${exception.toString()}", exception)
|
||||
|
||||
|
||||
|
|
@ -170,11 +265,13 @@ open class BaseViewMode : ViewModel() {
|
|||
fun doAsyncEncodeStr(
|
||||
reqType: HttpReqType,
|
||||
classOfT: Class<out BaseRsp>,
|
||||
doInAsync: suspend () -> String
|
||||
doInAsync: suspend () -> String,
|
||||
) {
|
||||
viewModelScope.launch(
|
||||
CoroutineExceptionHandler() { _,
|
||||
exception ->
|
||||
CoroutineExceptionHandler() {
|
||||
_,
|
||||
exception,
|
||||
->
|
||||
Log.e("BaseViewMode_doAsyncEncodeStr:${exception.toString()}", exception)
|
||||
statusData.value =
|
||||
if (exception.message.isNullOrBlank()) HttpStatus.Failure(
|
||||
|
|
@ -191,8 +288,6 @@ open class BaseViewMode : ViewModel() {
|
|||
val result = async { doInAsync() }
|
||||
val rspStr = result.await()
|
||||
Log.i("doAsyncEncodeStr 加密请求结果:$rspStr")
|
||||
|
||||
|
||||
if (!TextUtils.isEmpty(rspStr)) {
|
||||
var decodeRspStr = AESUtil.decrypt(rspStr)
|
||||
Log.d("doAsyncEncodeStr 请求结果:$decodeRspStr")
|
||||
|
|
@ -213,11 +308,13 @@ open class BaseViewMode : ViewModel() {
|
|||
|
||||
suspend fun doAsyncEncodeStrBg(
|
||||
classOfT: Class<out BaseRsp>,
|
||||
doInAsync: suspend () -> String
|
||||
doInAsync: suspend () -> String,
|
||||
): BaseRsp? {
|
||||
return viewModelScope.async(
|
||||
CoroutineExceptionHandler() { _,
|
||||
exception ->
|
||||
CoroutineExceptionHandler() {
|
||||
_,
|
||||
exception,
|
||||
->
|
||||
Log.e("BaseViewMode_doAsyncEncodeStrBg:${exception.toString()}", exception)
|
||||
})
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,11 +33,11 @@ open class PublicViewMode : BaseViewMode() {
|
|||
try { //TODO bug 会引起崩溃
|
||||
val host = when {
|
||||
BuildConfig.is_ym -> {
|
||||
rt.getHostGithub()
|
||||
rt.getHost()
|
||||
}
|
||||
|
||||
BuildConfig.is_tz -> {
|
||||
rt.getTzHostGithub()
|
||||
rt.getTzHostTZ()
|
||||
}
|
||||
|
||||
BuildConfig.is_yunti -> {
|
||||
|
|
@ -45,7 +45,7 @@ open class PublicViewMode : BaseViewMode() {
|
|||
}
|
||||
|
||||
else -> {
|
||||
rt.getBzyHostGithub()
|
||||
rt.getBzyHostDef()
|
||||
}
|
||||
}
|
||||
// Log.e("data", "2:$host")
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ class BZYConstants {
|
|||
const val MMKV_KEY_OLD_CURRENT_HOST = "old_current_host"
|
||||
//备用地址
|
||||
const val MMKV_KEY_ROUTER_HOST ="router_host"
|
||||
const val MMKV_KEY_Switch_Finsh_Set ="MMKV_KEY_Switch_Finsh_Set"
|
||||
const val MMKV_KEY_FIRST_HOST ="first_host"
|
||||
const val MMKV_KEY_Airport_Base64 ="airport_base64"
|
||||
//注册地址
|
||||
|
|
@ -47,6 +48,7 @@ class BZYConstants {
|
|||
const val MMKV_KEY_VPN_EXPIRED = "expired"
|
||||
|
||||
const val MMKV_KEY_VPN_UserCommand = "userCommand"
|
||||
const val MMKV_KEY_VPN_LogSwitch = "logSwitch"
|
||||
|
||||
//vpn过期时间
|
||||
const val MMKV_KEY_VPN_VALID_PERIOD = "vpn_valid_period"
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ data class UserData(
|
|||
@field:SerializedName("userCommand")
|
||||
val userCommand: String? = null,
|
||||
|
||||
@field:SerializedName("logSwitch")
|
||||
val logSwitch: String? = null,
|
||||
|
||||
@field:SerializedName("intervalTime")
|
||||
val intervalTime: Int? = null,
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.yingmao.clash.fragment
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
|
@ -9,9 +10,14 @@ import android.widget.ImageView
|
|||
import android.widget.RelativeLayout
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.yingmao.clash.BuildConfig
|
||||
import com.yingmao.clash.R
|
||||
import com.yingmao.clash.base.BaseViewMode
|
||||
import com.yingmao.clash.conf.BZYConstants
|
||||
import com.yingmao.clash.conf.Conf
|
||||
import com.yingmao.clash.net.http.HttpStatus
|
||||
import java.util.HashSet
|
||||
|
||||
|
||||
abstract class BaseFragment :Fragment() {
|
||||
|
|
@ -58,4 +64,44 @@ abstract class BaseFragment :Fragment() {
|
|||
open fun httpSuccess(httpStatus: HttpStatus.Success){}
|
||||
|
||||
open fun httpFailure(httpStatus: HttpStatus.Failure){}
|
||||
|
||||
@Synchronized
|
||||
fun switchServer(): Boolean {
|
||||
var isChange = false
|
||||
val mmkv = MMKV.defaultMMKV()
|
||||
val originalUrl =
|
||||
mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url)
|
||||
var newUrlString = originalUrl
|
||||
val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet())
|
||||
routerHost?.let {
|
||||
// it.forEach { url ->
|
||||
// com.cncat.vpn.common.log.Log.d("url==>$url")
|
||||
// }
|
||||
if (it.isEmpty()) {
|
||||
Log.d(Conf.TAG, "routerHost isEmpty")
|
||||
return isChange
|
||||
}
|
||||
Log.d(Conf.TAG, "routerHost not empty")
|
||||
val iterator = it.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val newUrl = iterator.next()
|
||||
Log.e("Data", "遍历备用的url:$newUrl")
|
||||
if (newUrl == originalUrl) {
|
||||
iterator.remove()
|
||||
} else {
|
||||
Log.e("Retry", "切换到新url:$newUrl")
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_OLD_CURRENT_HOST, originalUrl)
|
||||
isChange = true
|
||||
newUrlString = newUrl
|
||||
iterator.remove()
|
||||
break
|
||||
}
|
||||
}
|
||||
// mmkv.encode(BZYConstants.MMKV_KEY_ROUTER_HOST, routerHost)
|
||||
mmkv.encode(BZYConstants.MMKV_KEY_CURRENT_HOST, newUrlString)
|
||||
}
|
||||
|
||||
return isChange
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -33,6 +33,7 @@ import com.yingmao.clash.act.NewMainActivity
|
|||
import com.yingmao.clash.act.NewMainActivity.Companion.isSubed
|
||||
import com.yingmao.clash.act.NewMainActivity.Companion.newUuid
|
||||
import com.yingmao.clash.act.ProxyModeActivity
|
||||
import com.yingmao.clash.act.UIMainActivity
|
||||
import com.yingmao.clash.conf.BZYConstants
|
||||
import com.yingmao.clash.conf.Conf
|
||||
import com.yingmao.clash.entity.ClashNodebBean
|
||||
|
|
@ -294,7 +295,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
|
|||
// return
|
||||
// }
|
||||
launch {
|
||||
NewMainActivity.profileBinder?.let { pm ->
|
||||
UIMainActivity.profileBinder?.let { pm ->
|
||||
val active = pm.queryActive()
|
||||
if (active == null) {
|
||||
com.cncat.vpn.common.log.Log.d("startClash: 未选择")
|
||||
|
|
@ -707,7 +708,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
|
|||
} else {
|
||||
if (clashRunning) {
|
||||
delay(1000)
|
||||
NewMainActivity.clashBinder?.let { cm ->
|
||||
UIMainActivity.clashBinder?.let { cm ->
|
||||
val names = cm.queryProxyGroupNames(false)
|
||||
Log.i("checkGlo names==>${names}")
|
||||
if (names.isNotEmpty()) {
|
||||
|
|
@ -771,7 +772,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
|
|||
var nodeName = proListItem[0].name
|
||||
if (!TextUtils.isEmpty(nodeName)) {
|
||||
launch(Dispatchers.IO) {
|
||||
NewMainActivity.clashBinder?.let { cm ->
|
||||
UIMainActivity.clashBinder?.let { cm ->
|
||||
|
||||
val o = cm.queryOverride(Clash.OverrideSlot.Session)
|
||||
o.mode = TunnelState.Mode.Global
|
||||
|
|
@ -812,7 +813,7 @@ class NewAccFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatch
|
|||
})
|
||||
}
|
||||
} else {
|
||||
NewMainActivity.clashBinder?.let { cm ->
|
||||
UIMainActivity.clashBinder?.let { cm ->
|
||||
val o = cm.queryOverride(Clash.OverrideSlot.Session)
|
||||
o.mode = TunnelState.Mode.Global
|
||||
cm.patchOverride(Clash.OverrideSlot.Session, o)
|
||||
|
|
|
|||
|
|
@ -628,104 +628,7 @@ class RechargeFragment : BaseFragment() {
|
|||
noVerticalPadding = true,
|
||||
horizontalPadding = false
|
||||
)
|
||||
// for (index in data.payType!!) {
|
||||
// if (index.payModel == 10) {
|
||||
// findViewById<LinearLayout>(R.id.llAggregatePayment).visibility =
|
||||
// View.VISIBLE
|
||||
// val JUhePay = findViewById<TextView>(R.id.JUhePay)
|
||||
// JUhePay.visibility = View.VISIBLE
|
||||
// JUhePay.text = index.payChannel
|
||||
// if (index.payType == 1) {
|
||||
// val ivAlipay = findViewById<AppCompatImageView>(R.id.ivAlipay)
|
||||
// ivAlipay.visibility = View.VISIBLE
|
||||
// ivAlipay.setOnClickListener {
|
||||
// val payModel = index.payModel
|
||||
// val payType = index.payType
|
||||
// val payParam = index.payParam
|
||||
// if (payModel != null && payType != null && payParam != null) {
|
||||
// viewModel.orderPayment(data, payModel, payType, payParam)
|
||||
// } else {
|
||||
// viewModel.orderPayment(data, 10, 1, "ip@影猫充值")
|
||||
// }
|
||||
// }
|
||||
// } else if (index.payType == 2) {
|
||||
// val ivWechatPay = findViewById<AppCompatImageView>(R.id.ivWechatPay)
|
||||
// ivWechatPay.visibility = View.VISIBLE
|
||||
// ivWechatPay.setOnClickListener {
|
||||
// val payModel = index.payModel
|
||||
// val payType = index.payType
|
||||
// val payParam = index.payParam
|
||||
// if (payModel != null && payType != null && payParam != null) {
|
||||
// viewModel.orderPayment(data, payModel, payType, payParam)
|
||||
// } else {
|
||||
// viewModel.orderPayment(data, 10, 2, "ip@影猫充值")
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// } else if (index.payModel == 11) {
|
||||
// findViewById<LinearLayout>(R.id.llQuickPayment).visibility =
|
||||
// View.VISIBLE
|
||||
// val KJPay = findViewById<TextView>(R.id.KJPay)
|
||||
// KJPay.visibility = View.VISIBLE
|
||||
// KJPay.text = index.payChannel
|
||||
// if (index.payType == 1) {
|
||||
// val ivQuickPayment =
|
||||
// findViewById<AppCompatImageView>(R.id.ivQuickPayment)
|
||||
// ivQuickPayment.visibility = View.VISIBLE
|
||||
// ivQuickPayment.setOnClickListener {
|
||||
// val payModel = index.payModel
|
||||
// val payType = index.payType
|
||||
// val payParam = index.payParam
|
||||
// if (payModel != null && payType != null && payParam != null) {
|
||||
// viewModel.orderPayment(data, payModel, payType, payParam)
|
||||
// } else {
|
||||
// viewModel.orderPayment(data, 11, 1, "ip@影猫充值")
|
||||
// }
|
||||
// }
|
||||
// } else if (index.payType == 2) {
|
||||
// val ivQPWechatPay =
|
||||
// findViewById<AppCompatImageView>(R.id.ivQPWechatPay)
|
||||
// ivQPWechatPay.visibility = View.VISIBLE
|
||||
// ivQPWechatPay.setOnClickListener {
|
||||
// val payModel = index.payModel
|
||||
// val payType = index.payType
|
||||
// val payParam = index.payParam
|
||||
// if (payModel != null && payType != null && payParam != null) {
|
||||
// viewModel.orderPayment(data, payModel, payType, payParam)
|
||||
// } else {
|
||||
// viewModel.orderPayment(data, 11, 1, "ip@影喵充值")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else if (index.payModel == 7) {
|
||||
// findViewById<LinearLayout>(R.id.llStripe).visibility = View.VISIBLE
|
||||
// findViewById<LinearLayout>(R.id.llStripePay).visibility = View.VISIBLE
|
||||
// var payinfo = findViewById<TextView>(R.id.tvStripePay)
|
||||
// payinfo.visibility = View.VISIBLE
|
||||
//
|
||||
// payinfo.text = index.payChannel
|
||||
// findViewById<AppCompatImageView>(R.id.ivStripeAlipay).visibility =
|
||||
// View.VISIBLE
|
||||
// findViewById<AppCompatImageView>(R.id.ivStripeAlipay).setOnClickListener {
|
||||
// if (selectedGradeID != 0) {
|
||||
// if (!PayUtils.isAlipayInstalled(requireActivity())) {
|
||||
// RxToast.error(resources.getString(R.string.AlipayNotInstalled))
|
||||
// return@setOnClickListener
|
||||
// }
|
||||
// dismiss()
|
||||
// showLoading(
|
||||
// resources.getString(R.string.PaymentIn),
|
||||
// requireActivity()
|
||||
// )
|
||||
// Log.i("PayGradeID:", "PayGradeID:${selectedGradeID}")
|
||||
// viewModel.getPayClientSecret(selectedGradeID)
|
||||
// } else {
|
||||
// RxToast.info(getString(R.string.NoPaymentReceipt))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
getCustomView().findViewById<AppCompatImageView>(R.id.ivBack)
|
||||
.setOnClickListener {
|
||||
dismiss()
|
||||
|
|
@ -735,76 +638,7 @@ class RechargeFragment : BaseFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
// private fun goWebViewStartPayClient(rsp: BaseRsp, isPayWeb: Boolean) {
|
||||
// (rsp as BiLaiNormalRsp).let {
|
||||
// if (it.code != "1000") {
|
||||
// RxToast.error(if (it.message.isNullOrBlank()) "获取支付信息失败(${it.code})" else "${it.code}:${it.message}")
|
||||
// } else {
|
||||
// if (isPayWeb) {
|
||||
// activity?.let {
|
||||
// if (rsp.data != null) {
|
||||
//// goWebPay(it, rsp.data!!)
|
||||
//// goWebPay(it, newUrl)
|
||||
// } else {
|
||||
// RxToast.error("未能获取到支付信息,请联系客服")
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// val gson = Gson().fromJson(it.data!!, BiLaiRsp::class.java)
|
||||
// Logger.d("跳转支付宝支付页面:" + gson.payurl)
|
||||
// var realPayUrl = ""
|
||||
// var isNeedScan = false
|
||||
// if (gson.payurl != null) {
|
||||
// realPayUrl = gson.payurl!!
|
||||
// isNeedScan = false
|
||||
// } else if (gson.qrcode != null) {
|
||||
// realPayUrl = gson.qrcode!!
|
||||
// isNeedScan = true
|
||||
// } else {
|
||||
// realPayUrl = gson.urlscheme!!
|
||||
// isNeedScan = true
|
||||
// }
|
||||
// // Log.e("data==", "html:" + realPayUrl);
|
||||
//
|
||||
//
|
||||
// activity?.let {
|
||||
// if (!isNeedScan) {
|
||||
//// goWebPay(it, newUrl)
|
||||
// } else {
|
||||
// //二维码支付
|
||||
// qrPayDialog = MaterialDialog(it).show {
|
||||
// this.cancelable(false)
|
||||
// cornerRadius(res = R.dimen.dp_10)
|
||||
// customView(R.layout.qrpay_dialog_layout, scrollable = false, noVerticalPadding = true, horizontalPadding = false)
|
||||
// getCustomView().findViewById<TextView>(R.id.tv_qr_pay_note).setText(R.string.qr_pay_note_wx)
|
||||
//
|
||||
// val ivQr = getCustomView().findViewById<ImageView>(R.id.iv_qr)
|
||||
//
|
||||
// val writer = MultiFormatWriter()
|
||||
// val matrix = writer.encode(realPayUrl, BarcodeFormat.QR_CODE, 300, 300)
|
||||
// val encoder = BarcodeEncoder()
|
||||
// val bitmap = encoder.createBitmap(matrix)
|
||||
// ivQr.setImageBitmap(bitmap)
|
||||
//
|
||||
// getCustomView().findViewById<TextView>(R.id.tv_pay_finish).setOnClickListener {
|
||||
// showLoadingDialog("正在查询支付结果...")
|
||||
// viewModel.codePayStatus(outTradeNo)
|
||||
// }
|
||||
//
|
||||
// getCustomView().findViewById<TextView>(R.id.tv_pay_cancle).setOnClickListener {
|
||||
// if (bitmap != null && !bitmap.isRecycled) {
|
||||
// bitmap.recycle()
|
||||
// dismiss()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }/
|
||||
|
||||
|
||||
fun goWebPay(it: Activity, realPayUrl: String) {
|
||||
val intent = Intent(context, BZYWebViewNormal::class.java)
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ import com.yingmao.clash.act.UIMainActivity.Companion.newUuid
|
|||
import com.yingmao.clash.act.UIMainActivity.Companion.profileBinder
|
||||
import com.yingmao.clash.act.UIMainActivity.Companion.subUrl
|
||||
import com.yingmao.clash.app.MainApplication
|
||||
import com.yingmao.clash.base.BaseActivity
|
||||
import com.yingmao.clash.conf.BZYConstants
|
||||
import com.yingmao.clash.conf.Conf
|
||||
import com.yingmao.clash.entity.CheckLoginRsp
|
||||
|
|
@ -636,6 +637,10 @@ class SettingFragment : BaseFragment(), CoroutineScope by CoroutineScope(Dispatc
|
|||
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_VPN_UserCommand)
|
||||
MMKV.defaultMMKV().removeValueForKey(BZYConstants.NODE_All_ITEM_NAME_KEY)
|
||||
MMKV.defaultMMKV().removeValueForKey(BZYConstants.PROFILE_SUB_URL)
|
||||
MMKV.defaultMMKV().removeValueForKey(BZYConstants.MMKV_KEY_Switch_Finsh_Set)
|
||||
|
||||
//清除源切换记录
|
||||
|
||||
Log.d("cleanUserInfo clashRunning==>${clashRunning}")
|
||||
if (clashRunning) {
|
||||
fragments.filterIsInstance<HomeFragment>().forEach { it.stopClash() }
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ import com.yingmao.clash.net.http.entity.UploadParamData
|
|||
import com.yingmao.clash.net.http.entity.VipSignRsp
|
||||
import okhttp3.RequestBody
|
||||
import retrofit2.Call
|
||||
import retrofit2.Response
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
|
|
@ -75,6 +76,7 @@ interface HttpApi {
|
|||
@POST("/netbarcloud/vpn/octopusRegister.do")
|
||||
suspend fun register(@QueryMap params: Map<String, String>): RegisterRsp
|
||||
|
||||
|
||||
//加密注册
|
||||
@Headers(
|
||||
"User-Agent: Octopus_Android"
|
||||
|
|
@ -94,7 +96,6 @@ interface HttpApi {
|
|||
): RegisterRsp
|
||||
|
||||
|
||||
|
||||
//显示赠送时长 :
|
||||
@Headers(
|
||||
"User-Agent: Octopus_Android"
|
||||
|
|
@ -218,8 +219,10 @@ interface HttpApi {
|
|||
|
||||
@GET("/taiziregister.txt")
|
||||
suspend fun getTzRegister(): String
|
||||
|
||||
@GET("/taiziregister_182269.txt")
|
||||
suspend fun getTz182269Register(): String
|
||||
|
||||
@GET("/bzyregister.txt")
|
||||
suspend fun getBzyRegister(): String
|
||||
|
||||
|
|
@ -631,4 +634,16 @@ interface HttpApi {
|
|||
BZYConstants.MMKV_KEY_TOKEN
|
||||
).toString(),
|
||||
): AppStopStatus
|
||||
|
||||
@Headers(
|
||||
"User-Agent: Octopus_Android",
|
||||
"Authorization: Basic Z20yMXdvcGc6eDVjZXlzbTY="
|
||||
)
|
||||
@POST("/netbarcloud/api/v1/push")
|
||||
suspend fun postErrLog(
|
||||
@Body requestBody: RequestBody,
|
||||
@Header("token") string: String = MMKV.defaultMMKV().decodeString(
|
||||
BZYConstants.MMKV_KEY_TOKEN
|
||||
).toString(),
|
||||
): Response<NormalRsp>
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ import okhttp3.Callback
|
|||
import okhttp3.Cookie
|
||||
import okhttp3.CookieJar
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
|
@ -72,6 +73,37 @@ class NetService private constructor() : INetService {
|
|||
var httpClient: OkHttpClient? = null;
|
||||
var downHttpClient: OkHttpClient? = null;
|
||||
|
||||
class ExceptionLoggingInterceptor : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
return try {
|
||||
val response = chain.proceed(request)
|
||||
// 如果需要也可记录非 2xx 的响应
|
||||
if (!response.isSuccessful) {
|
||||
logHttpError(request, response.code, null)
|
||||
}
|
||||
response
|
||||
} catch (e: Exception) {
|
||||
logHttpError(request, null, e)
|
||||
throw e // 抛出异常让上层处理
|
||||
}
|
||||
}
|
||||
|
||||
private fun logHttpError(request: Request, code: Int?, e: Exception?) {
|
||||
val log = buildString {
|
||||
append("URL: ${request.url}\n")
|
||||
append("Method: ${request.method}\n")
|
||||
append("Headers: ${request.headers}\n")
|
||||
append("Body: ${request.body}\n")
|
||||
code?.let { append("Response Code: $code\n") }
|
||||
e?.let { append("Exception: ${e.message}\n${e.stackTraceToString()}") }
|
||||
}
|
||||
|
||||
// 这里可以上传到服务端,或者保存到本地文件
|
||||
println("❌ 网络请求异常:\n$log")
|
||||
// FirebaseCrashlytics.getInstance().recordException(e) // 如果用了 Firebase
|
||||
}
|
||||
}
|
||||
override fun httpsClient(connTO:Long,readTO:Long,writeTO:Long): OkHttpClient {
|
||||
|
||||
var loggingInterceptor = HttpLoggingInterceptor(
|
||||
|
|
@ -79,8 +111,10 @@ class NetService private constructor() : INetService {
|
|||
override fun log(message: String) {
|
||||
Log.d("loggingInterceptor==>$message")
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
|
||||
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
|
||||
var builder = OkHttpClient.Builder()
|
||||
.retryOnConnectionFailure(true)
|
||||
|
|
@ -95,6 +129,7 @@ class NetService private constructor() : INetService {
|
|||
.hostnameVerifier(getHostnameVerifier()!!)
|
||||
if (BuildConfig.DEBUG) {
|
||||
builder.addInterceptor(loggingInterceptor)
|
||||
// builder.addInterceptor(ExceptionLoggingInterceptor())
|
||||
}
|
||||
// builder.addInterceptor(loggingInterceptor)
|
||||
return builder.build()
|
||||
|
|
@ -161,6 +196,7 @@ class NetService private constructor() : INetService {
|
|||
.addConverterFactory(ScalarsConverterFactory.create())//json解析器Gson
|
||||
.baseUrl(baseUrl) //设置BaseURL需以'/'结尾
|
||||
.build() //创建Retrofit对象
|
||||
|
||||
return retrofit.create(HttpApi::class.java)
|
||||
}
|
||||
fun createFreeBaseUrl2(): HttpApi {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,112 @@
|
|||
package com.yingmao.clash.view.dialog
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.tencent.mmkv.MMKV
|
||||
import com.yingmao.clash.BuildConfig
|
||||
import com.yingmao.clash.R
|
||||
import com.yingmao.clash.conf.BZYConstants
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @author tamsiree
|
||||
* @date 2016/7/19
|
||||
* 确认 取消 Dialog
|
||||
*/
|
||||
open class DialogAutoDoMainChoose : RxDialog {
|
||||
lateinit var titleView: TextView
|
||||
private set
|
||||
lateinit var but_try: TextView
|
||||
private set
|
||||
lateinit var but_cancel: TextView
|
||||
private set
|
||||
lateinit var domainRecyclerView: RecyclerView
|
||||
private set
|
||||
lateinit var onTryListener: OnTryButtonListener
|
||||
|
||||
lateinit var onDomainListItemListener: OnListItemListener
|
||||
|
||||
var domainFininshSet = mutableSetOf<String>();
|
||||
|
||||
constructor(context: Context?, themeResId: Int) : super(context!!, themeResId) {
|
||||
initView()
|
||||
}
|
||||
|
||||
constructor(
|
||||
context: Context?,
|
||||
cancelable: Boolean,
|
||||
cancelListener: DialogInterface.OnCancelListener?,
|
||||
) : super(context!!, cancelable, cancelListener) {
|
||||
initView()
|
||||
}
|
||||
|
||||
constructor(context: Context?) : super(context!!) {
|
||||
initView()
|
||||
}
|
||||
|
||||
constructor(context: Activity?) : super(context!!) {
|
||||
initView()
|
||||
}
|
||||
|
||||
constructor(context: Context?, alpha: Float, gravity: Int) : super(context, alpha, gravity) {
|
||||
initView()
|
||||
}
|
||||
|
||||
|
||||
private fun initView() {
|
||||
val dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_domain_choose, null)
|
||||
titleView = dialogView.findViewById(R.id.tv_title)
|
||||
but_try = dialogView.findViewById(R.id.but_try)
|
||||
but_cancel = dialogView.findViewById(R.id.but_cancel)
|
||||
domainRecyclerView = dialogView.findViewById(R.id.domian_list)
|
||||
|
||||
but_try.setOnClickListener {
|
||||
onTryListener.tryButton()
|
||||
}
|
||||
but_cancel.setOnClickListener { onTryListener.cancel() }
|
||||
|
||||
setContentView(dialogView)
|
||||
setCancelable(false)
|
||||
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
setNewData()
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private fun setNewData() {
|
||||
var mmkv = MMKV.defaultMMKV()
|
||||
val originalUrl =
|
||||
mmkv.decodeString(BZYConstants.MMKV_KEY_CURRENT_HOST, BuildConfig.service_url)
|
||||
var newUrlString = originalUrl
|
||||
|
||||
val routerHost = mmkv.decodeStringSet(BZYConstants.MMKV_KEY_ROUTER_HOST, HashSet())
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun setOnTryButtonListener(listener: OnTryButtonListener) {
|
||||
this.onTryListener = listener
|
||||
}
|
||||
|
||||
|
||||
private fun changeSubUrl(originalUrl: String, newUrl: String): String {
|
||||
return originalUrl.replace(Regex("https://[^/]+/"), "$newUrl/")
|
||||
|
||||
}
|
||||
|
||||
interface OnTryButtonListener {
|
||||
fun tryButton()
|
||||
fun cancel()
|
||||
}
|
||||
|
||||
interface OnListItemListener {
|
||||
fun listItemClick()
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -106,7 +106,6 @@ open class DialogDoMainChoose : RxDialog {
|
|||
}
|
||||
domainListAdapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun setOnTryButtonListener(listener: OnTryButtonListener) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue