mirror of
https://github.com/MatsuriDayo/NekoBoxForAndroid.git
synced 2025-12-18 22:20:06 +08:00
dev check update
This commit is contained in:
parent
7736548e4f
commit
56fd9df2e9
@ -20,6 +20,8 @@ import go.Seq
|
||||
import io.nekohasekai.sagernet.bg.SagerConnection
|
||||
import io.nekohasekai.sagernet.database.DataStore
|
||||
import io.nekohasekai.sagernet.ktx.Logs
|
||||
import io.nekohasekai.sagernet.ktx.isOss
|
||||
import io.nekohasekai.sagernet.ktx.isPreview
|
||||
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher
|
||||
import io.nekohasekai.sagernet.ui.MainActivity
|
||||
import io.nekohasekai.sagernet.utils.*
|
||||
@ -194,6 +196,18 @@ class SagerNet : Application(),
|
||||
|
||||
var underlyingNetwork: Network? = null
|
||||
|
||||
var appVersionNameForDisplay = lazy {
|
||||
var n = BuildConfig.VERSION_NAME
|
||||
if (isPreview) {
|
||||
n += " " + BuildConfig.PRE_VERSION_NAME
|
||||
} else if (!isOss) {
|
||||
n += " ${BuildConfig.FLAVOR}"
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
n += " DEBUG"
|
||||
}
|
||||
n
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import android.os.PowerManager
|
||||
import android.provider.Settings
|
||||
import android.text.util.Linkify
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.component1
|
||||
import androidx.activity.result.component2
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
@ -28,6 +29,12 @@ import io.nekohasekai.sagernet.utils.PackageCache
|
||||
import io.nekohasekai.sagernet.widget.ListListener
|
||||
import libcore.Libcore
|
||||
import moe.matsuri.nb4a.plugin.Plugins
|
||||
import androidx.core.net.toUri
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import io.nekohasekai.sagernet.SagerNet
|
||||
import io.nekohasekai.sagernet.database.DataStore
|
||||
import moe.matsuri.nb4a.utils.Util
|
||||
import org.json.JSONObject
|
||||
|
||||
class AboutFragment : ToolbarFragment(R.layout.layout_about) {
|
||||
|
||||
@ -65,128 +72,133 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) {
|
||||
}
|
||||
|
||||
override fun getMaterialAboutList(activityContext: Context): MaterialAboutList {
|
||||
|
||||
var versionName = BuildConfig.VERSION_NAME
|
||||
if (!isOss) {
|
||||
versionName += " ${BuildConfig.FLAVOR}"
|
||||
}
|
||||
if (BuildConfig.DEBUG) {
|
||||
versionName += " DEBUG"
|
||||
}
|
||||
|
||||
return MaterialAboutList.Builder()
|
||||
.addCard(
|
||||
MaterialAboutCard.Builder()
|
||||
.outline(false)
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_update_24)
|
||||
.text(R.string.app_version)
|
||||
.subText(versionName)
|
||||
.setOnClickAction {
|
||||
requireContext().launchCustomTab(
|
||||
"https://github.com/MatsuriDayo/NekoBoxForAndroid/releases"
|
||||
)
|
||||
}
|
||||
.build())
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_layers_24)
|
||||
.text(getString(R.string.version_x, "sing-box"))
|
||||
.subText(Libcore.versionBox())
|
||||
.setOnClickAction { }
|
||||
.build())
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_card_giftcard_24)
|
||||
.text(R.string.donate)
|
||||
.subText(R.string.donate_info)
|
||||
.setOnClickAction {
|
||||
requireContext().launchCustomTab(
|
||||
"https://matsuridayo.github.io/index_docs/#donate"
|
||||
)
|
||||
}
|
||||
.build())
|
||||
.apply {
|
||||
PackageCache.awaitLoadSync()
|
||||
for ((_, pkg) in PackageCache.installedPluginPackages) {
|
||||
try {
|
||||
val pluginId =
|
||||
pkg.providers?.get(0)?.loadString(Plugins.METADATA_KEY_ID)
|
||||
if (pluginId.isNullOrBlank()) continue
|
||||
addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_nfc_24)
|
||||
.text(
|
||||
getString(
|
||||
R.string.version_x,
|
||||
pluginId
|
||||
) + " (${Plugins.displayExeProvider(pkg.packageName)})"
|
||||
.outline(false)
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_update_24)
|
||||
.text(R.string.app_version)
|
||||
.subText(SagerNet.appVersionNameForDisplay.value)
|
||||
.setOnClickAction {
|
||||
requireContext().launchCustomTab(
|
||||
"https://github.com/MatsuriDayo/NekoBoxForAndroid/releases"
|
||||
)
|
||||
.subText("v" + pkg.versionName)
|
||||
.setOnClickAction {
|
||||
startActivity(Intent().apply {
|
||||
action =
|
||||
Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
data = Uri.fromParts(
|
||||
"package", pkg.packageName, null
|
||||
}
|
||||
.build())
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.text(R.string.check_update_release)
|
||||
.setOnClickAction {
|
||||
checkUpdate(false)
|
||||
}
|
||||
.build())
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.text(R.string.check_update_preview)
|
||||
.setOnClickAction {
|
||||
checkUpdate(true)
|
||||
}
|
||||
.build())
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_layers_24)
|
||||
.text(getString(R.string.version_x, "sing-box"))
|
||||
.subText(Libcore.versionBox())
|
||||
.setOnClickAction { }
|
||||
.build())
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_card_giftcard_24)
|
||||
.text(R.string.donate)
|
||||
.subText(R.string.donate_info)
|
||||
.setOnClickAction {
|
||||
requireContext().launchCustomTab(
|
||||
"https://matsuridayo.github.io/index_docs/#donate"
|
||||
)
|
||||
}
|
||||
.build())
|
||||
.apply {
|
||||
PackageCache.awaitLoadSync()
|
||||
for ((_, pkg) in PackageCache.installedPluginPackages) {
|
||||
try {
|
||||
val pluginId =
|
||||
pkg.providers?.get(0)?.loadString(Plugins.METADATA_KEY_ID)
|
||||
if (pluginId.isNullOrBlank()) continue
|
||||
addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_nfc_24)
|
||||
.text(
|
||||
getString(
|
||||
R.string.version_x,
|
||||
pluginId
|
||||
) + " (${Plugins.displayExeProvider(pkg.packageName)})"
|
||||
)
|
||||
})
|
||||
}
|
||||
.build())
|
||||
} catch (e: Exception) {
|
||||
Logs.w(e)
|
||||
.subText("v" + pkg.versionName)
|
||||
.setOnClickAction {
|
||||
startActivity(Intent().apply {
|
||||
action =
|
||||
Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
data = Uri.fromParts(
|
||||
"package", pkg.packageName, null
|
||||
)
|
||||
})
|
||||
}
|
||||
.build())
|
||||
} catch (e: Exception) {
|
||||
Logs.w(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.apply {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val pm = app.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
if (!pm.isIgnoringBatteryOptimizations(app.packageName)) {
|
||||
addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_running_with_errors_24)
|
||||
.text(R.string.ignore_battery_optimizations)
|
||||
.subText(R.string.ignore_battery_optimizations_sum)
|
||||
.setOnClickAction {
|
||||
requestIgnoreBatteryOptimizations.launch(
|
||||
Intent(
|
||||
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
|
||||
Uri.parse("package:${app.packageName}")
|
||||
)
|
||||
)
|
||||
}
|
||||
.build())
|
||||
.apply {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val pm = app.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
if (!pm.isIgnoringBatteryOptimizations(app.packageName)) {
|
||||
addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_running_with_errors_24)
|
||||
.text(R.string.ignore_battery_optimizations)
|
||||
.subText(R.string.ignore_battery_optimizations_sum)
|
||||
.setOnClickAction {
|
||||
requestIgnoreBatteryOptimizations.launch(
|
||||
Intent(
|
||||
Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
|
||||
"package:${app.packageName}".toUri()
|
||||
)
|
||||
)
|
||||
}
|
||||
.build())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.build())
|
||||
.build())
|
||||
.addCard(
|
||||
MaterialAboutCard.Builder()
|
||||
.outline(false)
|
||||
.title(R.string.project)
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_sanitizer_24)
|
||||
.text(R.string.github)
|
||||
.setOnClickAction {
|
||||
requireContext().launchCustomTab(
|
||||
"https://github.com/MatsuriDayo/NekoBoxForAndroid"
|
||||
.outline(false)
|
||||
.title(R.string.project)
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_baseline_sanitizer_24)
|
||||
.text(R.string.github)
|
||||
.setOnClickAction {
|
||||
requireContext().launchCustomTab(
|
||||
"https://github.com/MatsuriDayo/NekoBoxForAndroid"
|
||||
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
.build())
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_qu_shadowsocks_foreground)
|
||||
.text(R.string.telegram)
|
||||
.setOnClickAction {
|
||||
requireContext().launchCustomTab(
|
||||
"https://t.me/MatsuriDayo"
|
||||
)
|
||||
}
|
||||
.build())
|
||||
.build())
|
||||
.addItem(
|
||||
MaterialAboutActionItem.Builder()
|
||||
.icon(R.drawable.ic_qu_shadowsocks_foreground)
|
||||
.text(R.string.telegram)
|
||||
.setOnClickAction {
|
||||
requireContext().launchCustomTab(
|
||||
"https://t.me/MatsuriDayo"
|
||||
)
|
||||
}
|
||||
.build())
|
||||
.build())
|
||||
.build()
|
||||
|
||||
}
|
||||
@ -199,6 +211,69 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) {
|
||||
}
|
||||
}
|
||||
|
||||
fun checkUpdate(checkPreview: Boolean) {
|
||||
runOnIoDispatcher {
|
||||
try {
|
||||
val client = Libcore.newHttpClient().apply {
|
||||
modernTLS()
|
||||
keepAlive()
|
||||
trySocks5(DataStore.mixedPort)
|
||||
}
|
||||
val response = client.newRequest().apply {
|
||||
if (checkPreview) {
|
||||
setURL("https://api.github.com/repos/MatsuriDayo/NekoBoxForAndroid/releases/tags/preview")
|
||||
} else {
|
||||
setURL("https://api.github.com/repos/MatsuriDayo/NekoBoxForAndroid/releases/latest")
|
||||
}
|
||||
}.execute()
|
||||
val release = JSONObject(Util.getStringBox(response.contentString))
|
||||
val releaseName = release.getString("name")
|
||||
val releaseUrl = release.getString("html_url")
|
||||
var haveUpdate = releaseName.isNotBlank()
|
||||
haveUpdate = if (isPreview) {
|
||||
if (checkPreview) {
|
||||
haveUpdate && releaseName != BuildConfig.PRE_VERSION_NAME
|
||||
} else {
|
||||
// User: 1.3.9 pre-1.4.0 Stable: 1.3.9 -> No update
|
||||
haveUpdate && releaseName != BuildConfig.VERSION_NAME
|
||||
}
|
||||
} else {
|
||||
// User: 1.4.0 Preview: pre-1.4.0 -> No update
|
||||
// User: 1.4.0 Preview: pre-1.4.1 -> Update
|
||||
// User: 1.4.0 Stable: 1.4.0 -> No update
|
||||
// User: 1.4.0 Stable: 1.4.1 -> Update
|
||||
haveUpdate && !releaseName.contains(BuildConfig.VERSION_NAME)
|
||||
}
|
||||
runOnMainDispatcher {
|
||||
if (haveUpdate) {
|
||||
val context = requireContext()
|
||||
MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.update_dialog_title)
|
||||
.setMessage(
|
||||
context.getString(
|
||||
R.string.update_dialog_message,
|
||||
SagerNet.appVersionNameForDisplay.value,
|
||||
releaseName
|
||||
)
|
||||
)
|
||||
.setPositiveButton(R.string.yes) { _, _ ->
|
||||
val intent = Intent(Intent.ACTION_VIEW, releaseUrl.toUri())
|
||||
context.startActivity(intent)
|
||||
}
|
||||
.setNegativeButton(R.string.no, null)
|
||||
.show()
|
||||
} else {
|
||||
Toast.makeText(app, R.string.check_update_no, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
runOnMainDispatcher {
|
||||
Toast.makeText(app, e.readableMessage, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,6 +6,7 @@ import android.os.Build
|
||||
import android.util.Log
|
||||
import com.jakewharton.processphoenix.ProcessPhoenix
|
||||
import io.nekohasekai.sagernet.BuildConfig
|
||||
import io.nekohasekai.sagernet.SagerNet
|
||||
import io.nekohasekai.sagernet.database.preference.PublicDatabase
|
||||
import io.nekohasekai.sagernet.ktx.Logs
|
||||
import io.nekohasekai.sagernet.ktx.app
|
||||
@ -61,7 +62,7 @@ object CrashHandler : Thread.UncaughtExceptionHandler {
|
||||
|
||||
fun buildReportHeader(): String {
|
||||
var report = ""
|
||||
report += "NekoBox for Andoird ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE}) ${BuildConfig.FLAVOR.uppercase()}\n"
|
||||
report += "NekoBox for Android ${SagerNet.appVersionNameForDisplay} (${BuildConfig.VERSION_CODE})\n"
|
||||
report += "Date: ${getCurrentMilliSecondUTCTimeStamp()}\n\n"
|
||||
report += "OS_VERSION: ${getSystemPropertyWithAndroidAPI("os.version")}\n"
|
||||
report += "SDK_INT: ${Build.VERSION.SDK_INT}\n"
|
||||
@ -102,7 +103,7 @@ object CrashHandler : Thread.UncaughtExceptionHandler {
|
||||
report += "\n"
|
||||
report += pair.key + ": " + pair.toString()
|
||||
}
|
||||
}catch (e: Exception) {
|
||||
} catch (e: Exception) {
|
||||
report += "Export settings failed: " + formatThrowable(e)
|
||||
}
|
||||
|
||||
@ -136,7 +137,8 @@ object CrashHandler : Thread.UncaughtExceptionHandler {
|
||||
if (matcher.matches()) {
|
||||
key = matcher.group(1)
|
||||
value = matcher.group(2)
|
||||
if (key != null && value != null && !key.isEmpty() && !value.isEmpty()) systemProperties[key] = value
|
||||
if (key != null && value != null && !key.isEmpty() && !value.isEmpty()) systemProperties[key] =
|
||||
value
|
||||
}
|
||||
}
|
||||
bufferedReader.close()
|
||||
|
||||
@ -488,4 +488,9 @@
|
||||
<string name="wake_reset_connections">当设备从睡眠状态唤醒时重置出站连接</string>
|
||||
<string name="preview_version">预览版</string>
|
||||
<string name="preview_version_hint">本应用为预览版,可能存在诸多问题。若您不愿参与测试,请前往GitHub下载正式发布版本!</string>
|
||||
<string name="check_update_preview">检查预览版更新</string>
|
||||
<string name="check_update_release">检查正式版</string>
|
||||
<string name="update_dialog_title">发现新版本</string>
|
||||
<string name="update_dialog_message">当前版本:%1$s\n可升级版本:%2$s\n是否前往下载?</string>
|
||||
<string name="check_update_no">检查成功,但没有更新。</string>
|
||||
</resources>
|
||||
@ -568,4 +568,9 @@
|
||||
<string name="wake_reset_connections">Reset outbound connections when device wake from sleep</string>
|
||||
<string name="preview_version">Preview version</string>
|
||||
<string name="preview_version_hint">This application is a preview version and may contain many problems. If you do not want to test it, please go to GitHub to download the Release version!</string>
|
||||
<string name="check_update_preview">Check for preview version updates</string>
|
||||
<string name="check_update_release">Check for release version updates</string>
|
||||
<string name="update_dialog_title">New version available</string>
|
||||
<string name="update_dialog_message">Current version: %1$s\nAvailable version: %2$s\nDo you want to download it?</string>
|
||||
<string name="check_update_no">Check successful, but no updates.</string>
|
||||
</resources>
|
||||
@ -14,33 +14,6 @@ private val Project.android get() = extensions.getByName<ApplicationExtension>("
|
||||
|
||||
private lateinit var metadata: Properties
|
||||
private lateinit var localProperties: Properties
|
||||
private lateinit var flavor: String
|
||||
|
||||
fun Project.requireFlavor(): String {
|
||||
if (::flavor.isInitialized) return flavor
|
||||
if (gradle.startParameter.taskNames.isNotEmpty()) {
|
||||
val taskName = gradle.startParameter.taskNames[0]
|
||||
when {
|
||||
taskName.contains("assemble") -> {
|
||||
flavor = taskName.substringAfter("assemble")
|
||||
return flavor
|
||||
}
|
||||
|
||||
taskName.contains("install") -> {
|
||||
flavor = taskName.substringAfter("install")
|
||||
return flavor
|
||||
}
|
||||
|
||||
taskName.contains("bundle") -> {
|
||||
flavor = taskName.substringAfter("bundle")
|
||||
return flavor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flavor = ""
|
||||
return flavor
|
||||
}
|
||||
|
||||
fun Project.requireMetadata(): Properties {
|
||||
if (!::metadata.isInitialized) {
|
||||
@ -156,8 +129,6 @@ fun Project.setupAppCommon() {
|
||||
keyPassword = pwd
|
||||
}
|
||||
}
|
||||
} else if (requireFlavor().contains("(Oss|Expert|Play)Release".toRegex())) {
|
||||
exitProcess(0)
|
||||
}
|
||||
buildTypes {
|
||||
val key = signingConfigs.findByName("release")
|
||||
@ -178,6 +149,7 @@ fun Project.setupApp() {
|
||||
applicationId = pkgName
|
||||
versionCode = verCode
|
||||
versionName = verName
|
||||
buildConfigField("String", "PRE_VERSION_NAME", "\"\"")
|
||||
}
|
||||
}
|
||||
setupAppCommon()
|
||||
@ -209,7 +181,13 @@ fun Project.setupApp() {
|
||||
create("oss")
|
||||
create("fdroid")
|
||||
create("play")
|
||||
create("preview")
|
||||
create("preview") {
|
||||
buildConfigField(
|
||||
"String",
|
||||
"PRE_VERSION_NAME",
|
||||
"\"${requireMetadata().getProperty("PRE_VERSION_NAME")}\""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
applicationVariants.all {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
PACKAGE_NAME=moe.nb4a
|
||||
VERSION_NAME=1.3.9
|
||||
PRE_VERSION_NAME=pre-1.4.0-20250902-1
|
||||
VERSION_CODE=43
|
||||
|
||||
Loading…
Reference in New Issue
Block a user