Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
594949d3f0 | ||
|
|
8fd34b5258 | ||
|
|
1161482a5b | ||
|
|
8a123e7a0d | ||
|
|
4ef3a20929 | ||
|
|
16c2e9b694 | ||
|
|
c9a9d310ef | ||
|
|
84996a5652 | ||
|
|
115afc5735 | ||
|
|
2ae75e876d |
No files matched your search
@@ -35,8 +35,15 @@ class MainActivity : BaseActivity() {
|
||||
stopClashService()
|
||||
} else {
|
||||
val vpnRequest = startClashService()
|
||||
if (vpnRequest != null)
|
||||
startActivityForResult(vpnRequest, REQUEST_CODE)
|
||||
if (vpnRequest != null) {
|
||||
val resolved = packageManager.resolveActivity(vpnRequest, 0)
|
||||
if ( resolved != null ) {
|
||||
startActivityForResult(vpnRequest, REQUEST_CODE)
|
||||
}
|
||||
else {
|
||||
makeSnackbarException(getString(R.string.missing_vpn_component), null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -149,7 +149,10 @@ class ProfileEditActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
if (url == null || url == Uri.EMPTY ||
|
||||
(url.scheme != "http" && url.scheme != "https" && url.scheme != "content")
|
||||
(!url.scheme.equals("http", ignoreCase = true)
|
||||
&& !url.scheme.equals("https", ignoreCase = true)
|
||||
&& !url.scheme.equals("content", ignoreCase = true)
|
||||
&& !url.scheme.equals("file", ignoreCase = true))
|
||||
) {
|
||||
Snackbar.make(rootView, R.string.invalid_url, Snackbar.LENGTH_LONG).show()
|
||||
return@setOnClickListener
|
||||
|
||||
@@ -268,7 +268,7 @@ class ProxiesActivity : BaseActivity(), ScrollBinding.Callback {
|
||||
scrollBinding.scrollMaster(selected)
|
||||
}
|
||||
|
||||
delay(200)
|
||||
delay(500)
|
||||
|
||||
refreshMutex.unlock()
|
||||
}
|
||||
|
||||
@@ -19,6 +19,14 @@ class SettingsNetworkActivity : BaseActivity() {
|
||||
Snackbar.make(rootView, R.string.options_unavailable, Snackbar.LENGTH_INDEFINITE).show()
|
||||
}
|
||||
|
||||
override suspend fun onClashStopped(reason: String?) {
|
||||
recreate()
|
||||
}
|
||||
|
||||
override suspend fun onClashStarted() {
|
||||
recreate()
|
||||
}
|
||||
|
||||
override val activityLabel: CharSequence?
|
||||
get() = getText(R.string.network)
|
||||
}
|
||||
}
|
||||
@@ -72,8 +72,7 @@ suspend fun Pipeline<List<ProxyGroup>>.sort(): Pipeline<List<ProxyGroup>> {
|
||||
suspend fun Pipeline<List<ProxyGroup>>.toAdapterElement(
|
||||
prefixMerged: Map<ProxyEntry, ProxyMerged>,
|
||||
general: General
|
||||
):
|
||||
List<ProxyAdapter.ProxyGroupInfo> {
|
||||
): List<ProxyAdapter.ProxyGroupInfo> {
|
||||
return input.map { group ->
|
||||
val proxies = group.proxies.map { proxy ->
|
||||
val merged = prefixMerged[ProxyEntry(group.name, proxy.name)]?.takeIf {
|
||||
|
||||
@@ -5,25 +5,24 @@ import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.ServiceConnection
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.IBinder
|
||||
import android.os.RemoteException
|
||||
import androidx.core.content.edit
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import com.github.kr328.clash.ApkBrokenActivity
|
||||
import com.github.kr328.clash.Constants
|
||||
import com.github.kr328.clash.dump.LogcatDumper
|
||||
import com.github.kr328.clash.service.ClashManagerService
|
||||
import com.github.kr328.clash.service.IClashManager
|
||||
import com.github.kr328.clash.service.IProfileService
|
||||
import com.github.kr328.clash.service.ProfileService
|
||||
import com.github.kr328.clash.service.util.intent
|
||||
import com.microsoft.appcenter.crashes.Crashes
|
||||
import com.microsoft.appcenter.crashes.ingestion.models.ErrorAttachmentLog
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import java.io.File
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
object Remote {
|
||||
@@ -91,7 +90,11 @@ object Remote {
|
||||
handler.removeMessages(0)
|
||||
|
||||
GlobalScope.launch {
|
||||
if (!verifyApk(application)) {
|
||||
val valid = withContext(Dispatchers.IO) {
|
||||
verifyApk(application)
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
application.startActivity(
|
||||
ApkBrokenActivity::class.intent
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
@@ -135,28 +138,45 @@ object Remote {
|
||||
})
|
||||
}
|
||||
|
||||
private suspend fun verifyApk(application: Application) = withContext(Dispatchers.IO) {
|
||||
val sp = application.getSharedPreferences(
|
||||
Constants.PREFERENCE_NAME_APP,
|
||||
Context.MODE_PRIVATE
|
||||
)
|
||||
val pkg = application.packageManager.getPackageInfo(application.packageName, 0)
|
||||
private fun verifyApk(application: Application): Boolean {
|
||||
return try {
|
||||
val sp = application.getSharedPreferences(
|
||||
Constants.PREFERENCE_NAME_APP,
|
||||
Context.MODE_PRIVATE
|
||||
)
|
||||
val pkg = application.packageManager.getPackageInfo(application.packageName, 0)
|
||||
|
||||
if (sp.getLong(Constants.PREFERENCE_KEY_LAST_INSTALL, 0) == pkg.lastUpdateTime)
|
||||
return@withContext true
|
||||
if (sp.getLong(Constants.PREFERENCE_KEY_LAST_INSTALL, 0) == pkg.lastUpdateTime)
|
||||
return true
|
||||
|
||||
val info = application.applicationInfo
|
||||
val sources =
|
||||
info.splitSourceDirs ?: arrayOf(info.sourceDir) ?: return@withContext false
|
||||
val info = application.applicationInfo
|
||||
val sources =
|
||||
info.splitSourceDirs ?: arrayOf(info.sourceDir) ?: return false
|
||||
|
||||
for (apk in sources) {
|
||||
if (ZipFile(apk).entries().asSequence().any { it.name.endsWith("libgojni.so") }) {
|
||||
val regexNativeLibrary = Regex("lib/(\\S+)/libgojni.so")
|
||||
val availableAbi = Build.SUPPORTED_ABIS.toSet()
|
||||
val apkAbi =
|
||||
sources
|
||||
.asSequence()
|
||||
.filter { File(it).exists() }
|
||||
.flatMap { ZipFile(it).entries().asSequence() }
|
||||
.mapNotNull { regexNativeLibrary.matchEntire(it.name) }
|
||||
.mapNotNull { it.groups[1]?.value }
|
||||
.toSet()
|
||||
|
||||
if (availableAbi.intersect(apkAbi).isNotEmpty()) {
|
||||
sp.edit {
|
||||
putLong(Constants.PREFERENCE_KEY_LAST_INSTALL, pkg.lastUpdateTime)
|
||||
}
|
||||
return@withContext true
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Crashes.trackError(e)
|
||||
|
||||
false
|
||||
}
|
||||
return@withContext false
|
||||
}
|
||||
}
|
||||
@@ -130,4 +130,5 @@
|
||||
<string name="learn_more_about_split_apks">了解更多关于分包机制</string>
|
||||
<string name="reinstall_from_google_play">重新从 Google Play 安装</string>
|
||||
<string name="download_from_github_releases">从 Github Release 下载</string>
|
||||
<string name="missing_vpn_component">系统 VPN 组件缺失</string>
|
||||
</resources>
|
||||
@@ -172,4 +172,5 @@
|
||||
<string name="github_releases_url" translatable="false">https://github.com/Kr328/ClashForAndroid/releases</string>
|
||||
|
||||
<string name="format_proxy_group_title" translatable="false">%s - %s</string>
|
||||
<string name="missing_vpn_component">Missing VPN Components</string>
|
||||
</resources>
|
||||
+2
-2
@@ -8,8 +8,8 @@ buildscript {
|
||||
gMinSdkVersion = 24
|
||||
gTargetSdkVersion = 29
|
||||
|
||||
gVersionCode = 10107
|
||||
gVersionName = "1.1.7"
|
||||
gVersionCode = 10110
|
||||
gVersionName = "1.1.10"
|
||||
|
||||
gKotlinVersion = '1.3.61'
|
||||
gKotlinCoroutineVersion = '1.3.3'
|
||||
|
||||
Submodule core/src/main/golang/clash updated: 7b5fd83bad...c8ab24edb0.
@@ -64,7 +64,8 @@ class ProfileProcessor(private val context: Context) {
|
||||
target.parentFile?.mkdirs()
|
||||
baseDir.mkdirs()
|
||||
|
||||
if (source.scheme == "content" || source.scheme == "file") {
|
||||
if (source.scheme.equals("content", ignoreCase = true)
|
||||
|| source.scheme.equals("file", ignoreCase = true)) {
|
||||
val parcelFileDescriptor = context.contentResolver.openFileDescriptor(source, "r")
|
||||
?: throw FileNotFoundException("Unable to open file $source")
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ class ProfileService : BaseService() {
|
||||
ClashProfileEntity(
|
||||
requireNotNull(request.name),
|
||||
requireNotNull(request.type),
|
||||
requireNotNull(request.url).toString().toLowerCase(Locale.getDefault()),
|
||||
requireNotNull(request.url).toString(),
|
||||
request.source?.toString(),
|
||||
false,
|
||||
0,
|
||||
|
||||
Reference in new issue
Block a user