Merge pull request #6512 from menloresearch/mobile/thinning_app
Feat: Mobile App Optimization and Backend Integration
This commit is contained in:
commit
f90398e29a
@ -91,3 +91,16 @@ windows-sys = { version = "0.60.2", features = ["Win32_Storage_FileSystem"] }
|
||||
tauri-plugin-updater = "2"
|
||||
once_cell = "1.18"
|
||||
tauri-plugin-single-instance = { version = "2.0.0", features = ["deep-link"] }
|
||||
|
||||
# Release profile optimizations for minimal binary size
|
||||
[profile.release]
|
||||
opt-level = "z" # Optimize for size
|
||||
lto = "fat" # Aggressive Link Time Optimization
|
||||
strip = "symbols" # Strip debug symbols for smaller binary
|
||||
codegen-units = 1 # Reduce parallel codegen for better optimization
|
||||
panic = "abort" # Don't unwind on panic, saves space
|
||||
overflow-checks = false # Disable overflow checks for size
|
||||
debug = false # No debug info
|
||||
debug-assertions = false # No debug assertions
|
||||
incremental = false # Disable incremental compilation for release
|
||||
rpath = false # Don't include rpath
|
||||
|
||||
@ -38,11 +38,23 @@ android {
|
||||
}
|
||||
getByName("release") {
|
||||
isMinifyEnabled = true
|
||||
isShrinkResources = true // Remove unused resources
|
||||
signingConfig = signingConfigs.getByName("release")
|
||||
proguardFiles(
|
||||
*fileTree(".") { include("**/*.pro") }
|
||||
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
|
||||
.toList().toTypedArray()
|
||||
)
|
||||
// Additional size optimizations
|
||||
packaging {
|
||||
resources.excludes.addAll(listOf(
|
||||
"META-INF/LICENSE*",
|
||||
"META-INF/NOTICE*",
|
||||
"META-INF/*.RSA",
|
||||
"META-INF/*.SF",
|
||||
"META-INF/*.DSA"
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
kotlinOptions {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 0 B After Width: | Height: | Size: 60 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 23 KiB |
@ -45,6 +45,7 @@ pub fn get_vulkan_gpus(lib_path: &str) -> Vec<GpuInfo> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
fn parse_c_string_u8(buf: &[u8]) -> String {
|
||||
unsafe { std::ffi::CStr::from_ptr(buf.as_ptr() as *const std::ffi::c_char) }
|
||||
.to_str()
|
||||
|
||||
@ -14,12 +14,12 @@ pub async fn start_server<R: Runtime>(
|
||||
api_key: String,
|
||||
trusted_hosts: Vec<String>,
|
||||
proxy_timeout: u64,
|
||||
) -> Result<bool, String> {
|
||||
) -> Result<u16, String> {
|
||||
let server_handle = state.server_handle.clone();
|
||||
let plugin_state: State<LlamacppState> = app_handle.state();
|
||||
let sessions = plugin_state.llama_server_process.clone();
|
||||
|
||||
proxy::start_server(
|
||||
let actual_port = proxy::start_server(
|
||||
server_handle,
|
||||
sessions,
|
||||
host,
|
||||
@ -31,7 +31,7 @@ pub async fn start_server<R: Runtime>(
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
Ok(true)
|
||||
Ok(actual_port)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
@ -632,7 +632,7 @@ pub async fn start_server(
|
||||
proxy_api_key: String,
|
||||
trusted_hosts: Vec<Vec<String>>,
|
||||
proxy_timeout: u64,
|
||||
) -> Result<bool, Box<dyn std::error::Error + Send + Sync>> {
|
||||
) -> Result<u16, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let mut handle_guard = server_handle.lock().await;
|
||||
if handle_guard.is_some() {
|
||||
return Err("Server is already running".into());
|
||||
@ -667,7 +667,8 @@ pub async fn start_server(
|
||||
});
|
||||
|
||||
let server = Server::bind(&addr).serve(make_svc);
|
||||
log::info!("Jan API server started on http://{}", addr);
|
||||
let actual_addr = server.local_addr();
|
||||
log::info!("Jan API server started on http://{}", actual_addr);
|
||||
|
||||
let server_task = tokio::spawn(async move {
|
||||
if let Err(e) = server.await {
|
||||
@ -678,7 +679,9 @@ pub async fn start_server(
|
||||
});
|
||||
|
||||
*handle_guard = Some(server_task);
|
||||
Ok(true)
|
||||
let actual_port = actual_addr.port();
|
||||
log::info!("Jan API server started successfully on port {}", actual_port);
|
||||
Ok(actual_port)
|
||||
}
|
||||
|
||||
pub async fn stop_server(
|
||||
|
||||
@ -14,7 +14,10 @@ use tokio::sync::Mutex;
|
||||
|
||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||
pub fn run() {
|
||||
#[cfg(desktop)]
|
||||
let mut builder = tauri::Builder::default();
|
||||
#[cfg(mobile)]
|
||||
let builder = tauri::Builder::default();
|
||||
#[cfg(desktop)]
|
||||
{
|
||||
builder = builder.plugin(tauri_plugin_single_instance::init(|_app, argv, _cwd| {
|
||||
|
||||
11
src-tauri/tauri.android.conf.json
Normal file
11
src-tauri/tauri.android.conf.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"build": {
|
||||
"devUrl": null,
|
||||
"frontendDist": "../web-app/dist"
|
||||
},
|
||||
"app": {
|
||||
"security": {
|
||||
"capabilities": ["default"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,12 @@
|
||||
{
|
||||
"app": {
|
||||
"security": {
|
||||
"capabilities": ["default"]
|
||||
}
|
||||
},
|
||||
"bundle": {
|
||||
"iOS": {
|
||||
"developmentTeam": "<DEVELOPMENT_TEAM_ID>"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -40,7 +40,8 @@ export const useLocalApiServer = create<LocalApiServerState>()(
|
||||
setEnableOnStartup: (value) => set({ enableOnStartup: value }),
|
||||
serverHost: '127.0.0.1',
|
||||
setServerHost: (value) => set({ serverHost: value }),
|
||||
serverPort: 1337,
|
||||
// Use port 0 (auto-assign) for mobile to avoid conflicts, 1337 for desktop
|
||||
serverPort: (typeof window !== 'undefined' && (window as any).IS_ANDROID) || (typeof window !== 'undefined' && (window as any).IS_IOS) ? 0 : 1337,
|
||||
setServerPort: (value) => set({ serverPort: value }),
|
||||
apiPrefix: '/v1',
|
||||
setApiPrefix: (value) => set({ apiPrefix: value }),
|
||||
|
||||
@ -8,6 +8,47 @@ import { routeTree } from './routeTree.gen'
|
||||
import './index.css'
|
||||
import './i18n'
|
||||
|
||||
// Mobile-specific viewport and styling setup
|
||||
const setupMobileViewport = () => {
|
||||
// Check if running on mobile platform (iOS/Android via Tauri)
|
||||
const isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent) ||
|
||||
window.matchMedia('(max-width: 768px)').matches
|
||||
|
||||
if (isMobile) {
|
||||
// Update viewport meta tag to disable zoom
|
||||
let viewportMeta = document.querySelector('meta[name="viewport"]')
|
||||
if (viewportMeta) {
|
||||
viewportMeta.setAttribute('content',
|
||||
'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover'
|
||||
)
|
||||
}
|
||||
|
||||
// Add mobile-specific styles for status bar
|
||||
const style = document.createElement('style')
|
||||
style.textContent = `
|
||||
body {
|
||||
padding-top: env(safe-area-inset-top);
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
padding-left: env(safe-area-inset-left);
|
||||
padding-right: env(safe-area-inset-right);
|
||||
}
|
||||
|
||||
#root {
|
||||
min-height: calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
/* Prevent zoom on input focus */
|
||||
input, textarea, select {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
`
|
||||
document.head.appendChild(style)
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize mobile setup
|
||||
setupMobileViewport()
|
||||
|
||||
// Create a new router instance
|
||||
const router = createRouter({ routeTree })
|
||||
|
||||
|
||||
@ -31,6 +31,7 @@ export function DataProvider() {
|
||||
enableOnStartup,
|
||||
serverHost,
|
||||
serverPort,
|
||||
setServerPort,
|
||||
apiPrefix,
|
||||
apiKey,
|
||||
trustedHosts,
|
||||
@ -173,7 +174,11 @@ export function DataProvider() {
|
||||
proxyTimeout: proxyTimeout,
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
.then((actualPort: number) => {
|
||||
// Store the actual port that was assigned (important for mobile with port 0)
|
||||
if (actualPort && actualPort !== serverPort) {
|
||||
setServerPort(actualPort)
|
||||
}
|
||||
setServerStatus('running')
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
|
||||
@ -48,6 +48,7 @@ function LocalAPIServerContent() {
|
||||
setEnableOnStartup,
|
||||
serverHost,
|
||||
serverPort,
|
||||
setServerPort,
|
||||
apiPrefix,
|
||||
apiKey,
|
||||
trustedHosts,
|
||||
@ -162,7 +163,11 @@ function LocalAPIServerContent() {
|
||||
proxyTimeout: proxyTimeout,
|
||||
})
|
||||
})
|
||||
.then(() => {
|
||||
.then((actualPort: number) => {
|
||||
// Store the actual port that was assigned (important for mobile with port 0)
|
||||
if (actualPort && actualPort !== serverPort) {
|
||||
setServerPort(actualPort)
|
||||
}
|
||||
setServerStatus('running')
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user