Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,5 @@ src-tauri/gen/*

*.node

content
content
debugging
25 changes: 0 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,31 +134,6 @@ Compared to the original, Risuko v0.3.0 has:
- ~70% less memory usage (taking nearest tenth, ~425MB -> ~125MB)
- ~90% less peak CPU usage (~145% -> ~15%)

This is achieved by using rust build params:
```
[profile.release]
opt-level = 3
strip = "symbols"
lto = true
codegen-units = 1
panic = "abort"
```
It tells `rustc` to prioritize the binary over patience:

`opt-level = 3`
Enables every LLVM optimization pass. builds get noticeably slower; program gets faster
`strip = "symbols"`
Strips debug symbols before shipping. The file shrinks, but if it crashes in production, we're staring at assembly
`lto = true`
Link Time Optimization across all crates. LLVM inlines across boundaries and deletes dead code
`codegen-units = 1`
Forces the compiler to use a single translation unit. No parallel codegen, but LLVM sees the whole program for better optimization
`panic = "abort"`
Crash immediately on panic—no unwinding, no cleanup. Smaller binaries, but destructors don't run

The small bundle size, cpu and memory performance is also acheived by removing aria2, and replace by native rust codes.


| Original | Next | Risuko v0.3.0 |
| ------- | ---- | ----------- |
| ![orignal_mem](./static/readme/Original_Memory.png) | ![0.0.4_mem](./static/readme/v0.0.4_Memory.png) | ![0.3.0_mem](./static/readme/v0.3.0_Memory.png) |
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 21 additions & 12 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = ["risuko-engine", "risuko-bt", "risuko-cli", "risuko-napi", "risuko-http", "risuko-cookies"]
members = ["risuko-engine", "risuko-bt", "risuko-cli", "risuko-napi", "risuko-http", "risuko-cookies", "risuko-webview-upgrade"]

[workspace.package]
version = "0.4.2"
Expand All @@ -12,6 +12,7 @@ risuko-engine = { path = "risuko-engine" }
risuko-bt = { path = "risuko-bt" }
risuko-http = { path = "risuko-http" }
risuko-cookies = { path = "risuko-cookies" }
risuko-webview-upgrade = { path = "risuko-webview-upgrade" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tokio = { version = "1", features = ["process", "sync", "time", "rt", "net", "macros", "signal", "io-util"] }
Expand Down Expand Up @@ -101,5 +102,8 @@ tauri-plugin-single-instance = "2"
# wildcard-MIME apps like Messages intercept any content URI we send.
jni = "0.22"
ndk-context = "0.1"
# Wires the Android WebView kernel-upgrade library into the Gradle build (via
# its `links` key) and provides the no-op `init()` registered in `run()`.
risuko-webview-upgrade = { workspace = true }

[dev-dependencies]
3 changes: 3 additions & 0 deletions src-tauri/risuko-cookies/src/browser/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#[cfg(not(target_os = "android"))]
pub mod chromium;

#[cfg(not(target_os = "android"))]
pub mod firefox;

#[cfg(target_os = "macos")]
Expand Down
1 change: 1 addition & 0 deletions src-tauri/risuko-cookies/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub struct Cookie {
pub expires: Option<u64>,
}

#[cfg(not(target_os = "android"))]
impl From<browser::chromium::Cookie> for Cookie {
fn from(c: browser::chromium::Cookie) -> Self {
Self {
Expand Down
2 changes: 2 additions & 0 deletions src-tauri/risuko-cookies/src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
#[cfg(not(target_os = "android"))]
pub mod paths;
#[cfg(not(target_os = "android"))]
pub mod time;
5 changes: 5 additions & 0 deletions src-tauri/risuko-webview-upgrade/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/android/.gradle
/android/build
/android/.tauri
/android/local.properties
/android/src/main/java/app/risuko/webview_upgrade/WebViewUpgradeConfig.kt
17 changes: 17 additions & 0 deletions src-tauri/risuko-webview-upgrade/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: Missing [lib] section - all other workspace library crates explicitly declare one.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src-tauri/risuko-webview-upgrade/Cargo.toml, line 1:

<comment>Missing `[lib]` section - all other workspace library crates explicitly declare one.</comment>

<file context>
@@ -0,0 +1,17 @@
+[package]
+name = "risuko-webview-upgrade"
+description = "Swap the in-process Android WebView kernel to a newer installed Chrome / Google WebView when the system WebView is too old to render Risuko."
</file context>

name = "risuko-webview-upgrade"
description = "Swap the in-process Android WebView kernel to a newer installed Chrome / Google WebView when the system WebView is too old to render Risuko."
version.workspace = true
authors.workspace = true
edition.workspace = true
rust-version.workspace = true
# `links` is the hook that makes the host app's `tauri-build` discover this
# plugin's Android library and wire it into the generated Gradle project. It
# must be unique across the whole dependency graph.
links = "risuko-webview-upgrade"

[dependencies]
tauri = { version = "2" }

[build-dependencies]
tauri-plugin = { version = "2", features = ["build"] }
132 changes: 132 additions & 0 deletions src-tauri/risuko-webview-upgrade/android/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import groovy.json.JsonSlurper
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
}

android {
namespace = "app.risuko.webview_upgrade"
compileSdk = 36

defaultConfig {
minSdk = 24
consumerProguardFiles("consumer-rules.pro")
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}

sourceSets["main"].kotlin.srcDir(
layout.buildDirectory.dir("generated/source/webview-upgrade")
)
}

dependencies {
implementation(project(":tauri-android"))
}

val defaultMinUpgradeMajor = 106
val defaultMinSupportedMajor = 75

@Suppress("UNCHECKED_CAST")
fun parsePluginBlock(block: Map<String, Any?>?): Pair<Int, Int> {
if (block == null) return defaultMinUpgradeMajor to defaultMinSupportedMajor
val upgrade = (block["minUpgradeMajor"] as? Number)?.toInt() ?: defaultMinUpgradeMajor
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
val supported = (block["minSupportedMajor"] as? Number)?.toInt() ?: defaultMinSupportedMajor
require(upgrade > 0) { "minUpgradeMajor must be > 0, got $upgrade" }
require(supported > 0) { "minSupportedMajor must be > 0, got $supported" }
require(supported <= upgrade) { "minSupportedMajor ($supported) must be <= minUpgradeMajor ($upgrade)" }
return upgrade to supported
}
Comment on lines +48 to +56

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fail fast on invalid threshold config instead of silently defaulting.

Line 50-Line 52 and Line 95 currently coerce malformed/invalid explicit config into defaults, which can silently ship wrong swap thresholds. Treat malformed env/plugin values as build errors, and validate bounds (> 0, minSupportedMajor <= minUpgradeMajor).

Suggested fix
+import org.gradle.api.GradleException
 import groovy.json.JsonSlurper
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@@
 `@Suppress`("UNCHECKED_CAST")
 fun parsePluginBlock(block: Map<String, Any?>?): Pair<Int, Int> {
     if (block == null) return defaultMinUpgradeMajor to defaultMinSupportedMajor
-    val upgrade = (block["minUpgradeMajor"] as? Number)?.toInt() ?: defaultMinUpgradeMajor
-    val supported = (block["minSupportedMajor"] as? Number)?.toInt() ?: defaultMinSupportedMajor
+    val upgrade = (block["minUpgradeMajor"] as? Number)?.toInt() ?: defaultMinUpgradeMajor
+    val supported = (block["minSupportedMajor"] as? Number)?.toInt() ?: defaultMinSupportedMajor
+    if (upgrade <= 0 || supported <= 0) {
+        throw GradleException("webview-upgrade config values must be positive: minUpgradeMajor=$upgrade, minSupportedMajor=$supported")
+    }
+    if (supported > upgrade) {
+        throw GradleException("webview-upgrade config is invalid: minSupportedMajor ($supported) must be <= minUpgradeMajor ($upgrade)")
+    }
     return upgrade to supported
 }
@@
         val (minUpgrade, minSupported, source) = when {
-            !envJson.isNullOrBlank() ->
-                readFromEnv(envJson)?.let { Triple(it.first, it.second, "TAURI_WEBVIEW_UPGRADE_PLUGIN_CONFIG env var") }
-                    ?: Triple(defaultMinUpgradeMajor, defaultMinSupportedMajor, "defaults (env var unparseable)")
+            !envJson.isNullOrBlank() -> {
+                val parsed = readFromEnv(envJson)
+                    ?: throw GradleException("TAURI_WEBVIEW_UPGRADE_PLUGIN_CONFIG is not valid JSON object for webview-upgrade config")
+                Triple(parsed.first, parsed.second, "TAURI_WEBVIEW_UPGRADE_PLUGIN_CONFIG env var")
+            }
             tauriConfFile != null ->
                 readFromTauriConf(tauriConfFile)?.let { Triple(it.first, it.second, "tauri.conf.json at $tauriConfFile") }
                     ?: Triple(defaultMinUpgradeMajor, defaultMinSupportedMajor, "defaults (tauri.conf.json had no block)")

Also applies to: 92-99

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src-tauri/risuko-webview-upgrade/android/build.gradle.kts` around lines 48 -
53, The parsePluginBlock function and similar configuration parsing code
(referenced at lines 92-99) silently default to fallback values when
configuration is malformed or invalid, which can hide configuration errors.
Modify parsePluginBlock to validate that both parsed values are greater than 0
and that minSupportedMajor is less than or equal to minUpgradeMajor, throwing a
clear build error with a descriptive message when validation fails instead of
using the elvis operator to default. Apply the same validation logic to the
other configuration parsing code mentioned in the comment at lines 92-99.


@Suppress("UNCHECKED_CAST")
fun readFromEnv(jsonText: String?): Pair<Int, Int>? {
if (jsonText.isNullOrBlank()) return null
return try {
val parsed = JsonSlurper().parseText(jsonText) as? Map<String, Any?> ?: return null
parsePluginBlock(parsed)
} catch (e: Exception) {
logger.warn("TAURI_WEBVIEW_UPGRADE_PLUGIN_CONFIG parse error: ${e.message}; using defaults")
null
}
}

@Suppress("UNCHECKED_CAST")
fun readFromTauriConf(file: File): Pair<Int, Int>? {
val root = JsonSlurper().parse(file) as? Map<String, Any?> ?: return null
val plugins = root["plugins"] as? Map<String, Any?> ?: return null
val block = plugins["webview-upgrade"] as? Map<String, Any?> ?: return null
return parsePluginBlock(block)
}

fun findTauriConf(start: File): File? {
var current: File? = start
while (current != null) {
val candidate = File(current, "tauri.conf.json")
if (candidate.exists()) return candidate
current = current.parentFile
}
return null
}

val generatedConfigDir = layout.buildDirectory.dir("generated/source/webview-upgrade")

val generateWebViewUpgradeConfig = tasks.register("generateWebViewUpgradeConfig") {
val envJson = System.getenv("TAURI_WEBVIEW_UPGRADE_PLUGIN_CONFIG")
val tauriConfFile = findTauriConf(projectDir)
if (envJson.isNullOrBlank() && tauriConfFile != null) {
inputs.file(tauriConfFile)
}
inputs.property("envJson", envJson ?: "")
outputs.dir(generatedConfigDir)

doLast {
val (minUpgrade, minSupported, source) = when {
!envJson.isNullOrBlank() ->
readFromEnv(envJson)?.let { Triple(it.first, it.second, "TAURI_WEBVIEW_UPGRADE_PLUGIN_CONFIG env var") }
?: Triple(defaultMinUpgradeMajor, defaultMinSupportedMajor, "defaults (env var unparseable)")
tauriConfFile != null ->
readFromTauriConf(tauriConfFile)?.let { Triple(it.first, it.second, "tauri.conf.json") }
?: Triple(defaultMinUpgradeMajor, defaultMinSupportedMajor, "defaults (tauri.conf.json had no block)")
else -> Triple(defaultMinUpgradeMajor, defaultMinSupportedMajor, "defaults (no config found)")
}
val outDir = generatedConfigDir.get().asFile
val pkgDir = File(outDir, "app/risuko/webview_upgrade")
pkgDir.mkdirs()
File(pkgDir, "WebViewUpgradeConfig.kt").writeText(
"""
// Generated by build.gradle.kts at build time. Do not edit by hand.
// Source: $source
package app.risuko.webview_upgrade

internal object WebViewUpgradeConfig {
const val MIN_UPGRADE_MAJOR: Int = $minUpgrade
const val MIN_SUPPORTED_MAJOR: Int = $minSupported
}
""".trimIndent() + "\n"
)
logger.lifecycle(
"WebViewUpgradeConfig: minUpgradeMajor=$minUpgrade, minSupportedMajor=$minSupported (from $source)"
)
}
}

tasks.withType<KotlinCompile>().configureEach {
dependsOn(generateWebViewUpgradeConfig)
}
3 changes: 3 additions & 0 deletions src-tauri/risuko-webview-upgrade/android/consumer-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Applied automatically to the host app's R8 step
-keep class app.risuko.webview_upgrade.** { *; }
-keepattributes RuntimeVisibleAnnotations,RuntimeVisibleParameterAnnotations,AnnotationDefault
2 changes: 2 additions & 0 deletions src-tauri/risuko-webview-upgrade/android/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-keep class app.risuko.webview_upgrade.** { *; }
-keepattributes RuntimeVisibleAnnotations,RuntimeVisibleParameterAnnotations,AnnotationDefault
Loading
Loading