diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart
index 2ca608bd6..78f519008 100644
--- a/flutter/lib/models/server_model.dart
+++ b/flutter/lib/models/server_model.dart
@@ -120,12 +120,11 @@ class ServerModel with ChangeNotifier {
     _serverId = IDTextEditingController(text: _emptyIdShow);
 
     timerCallback() async {
-      var status = await bind.mainGetOnlineStatue();
-      if (status > 0) {
-        status = 1;
-      }
-      if (status != _connectStatus) {
-        _connectStatus = status;
+      final connectionStatus =
+          jsonDecode(await bind.mainGetConnectStatus()) as Map<String, dynamic>;
+      final statusNum = connectionStatus['status_num'] as int;
+      if (statusNum != _connectStatus) {
+        _connectStatus = statusNum;
         notifyListeners();
       }
 
diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs
index b6445eea7..785be96ee 100644
--- a/libs/hbb_common/src/config.rs
+++ b/libs/hbb_common/src/config.rs
@@ -44,7 +44,7 @@ lazy_static::lazy_static! {
     static ref CONFIG: Arc<RwLock<Config>> = Arc::new(RwLock::new(Config::load()));
     static ref CONFIG2: Arc<RwLock<Config2>> = Arc::new(RwLock::new(Config2::load()));
     static ref LOCAL_CONFIG: Arc<RwLock<LocalConfig>> = Arc::new(RwLock::new(LocalConfig::load()));
-    pub static ref ONLINE: Arc<Mutex<HashMap<String, i64>>> = Default::default();
+    static ref ONLINE: Arc<Mutex<HashMap<String, i64>>> = Default::default();
     pub static ref PROD_RENDEZVOUS_SERVER: Arc<RwLock<String>> = Arc::new(RwLock::new(match option_env!("RENDEZVOUS_SERVER") {
         Some(key) if !key.is_empty() => key,
         _ => "",
@@ -309,6 +309,11 @@ pub struct TransferSerde {
     pub read_jobs: Vec<String>,
 }
 
+#[inline]
+pub fn get_online_statue() -> i64 {
+    *ONLINE.lock().unwrap().values().max().unwrap_or(&0)
+}
+
 #[cfg(not(any(target_os = "android", target_os = "ios")))]
 fn patch(path: PathBuf) -> PathBuf {
     if let Some(_tmp) = path.to_str() {
diff --git a/libs/scrap/examples/capture_mag.rs b/libs/scrap/examples/capture_mag.rs
index 047020899..281c99328 100644
--- a/libs/scrap/examples/capture_mag.rs
+++ b/libs/scrap/examples/capture_mag.rs
@@ -1,20 +1,21 @@
 extern crate repng;
 extern crate scrap;
 
-use std::fs::File;
-
-use scrap::{i420_to_rgb, Display};
+use scrap::Display;
 #[cfg(windows)]
-use scrap::{CapturerMag, TraitCapturer};
+use scrap::{i420_to_rgb, CapturerMag, TraitCapturer};
+#[cfg(windows)]
+use std::fs::File;
 
 fn main() {
     let n = Display::all().unwrap().len();
-    for i in 0..n {
+    for _i in 0..n {
         #[cfg(windows)]
-        record(i);
+        record(_i);
     }
 }
 
+#[cfg(windows)]
 fn get_display(i: usize) -> Display {
     Display::all().unwrap().remove(i)
 }
diff --git a/libs/virtual_display/dylib/src/lib.rs b/libs/virtual_display/dylib/src/lib.rs
index 3b83d297c..f2997da16 100644
--- a/libs/virtual_display/dylib/src/lib.rs
+++ b/libs/virtual_display/dylib/src/lib.rs
@@ -1,7 +1,8 @@
 #[cfg(windows)]
 pub mod win10;
-
-use hbb_common::{bail, lazy_static, ResultType};
+#[cfg(windows)]
+use hbb_common::lazy_static;
+use hbb_common::{bail, ResultType};
 use std::path::Path;
 
 #[cfg(windows)]
diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs
index b3c011c2b..9a3f1abab 100644
--- a/src/flutter_ffi.rs
+++ b/src/flutter_ffi.rs
@@ -14,12 +14,11 @@ use flutter_rust_bridge::{StreamSink, SyncReturn};
 #[cfg(not(any(target_os = "android", target_os = "ios")))]
 use hbb_common::allow_err;
 use hbb_common::{
-    config::{self, LocalConfig, PeerConfig, PeerInfoSerde, ONLINE},
+    config::{self, LocalConfig, PeerConfig, PeerInfoSerde},
     fs, log,
     message_proto::KeyboardMode,
     ResultType,
 };
-use serde_json::json;
 use std::{
     collections::HashMap,
     ffi::{CStr, CString},
@@ -680,14 +679,18 @@ pub fn main_get_lan_peers() -> String {
 }
 
 pub fn main_get_connect_status() -> String {
-    let status = get_connect_status();
-    // (status_num, key_confirmed, mouse_time, id)
-    let mut m = serde_json::Map::new();
-    m.insert("status_num".to_string(), json!(status.0));
-    m.insert("key_confirmed".to_string(), json!(status.1));
-    m.insert("mouse_time".to_string(), json!(status.2));
-    m.insert("id".to_string(), json!(status.3));
-    serde_json::to_string(&m).unwrap_or("".to_string())
+    #[cfg(not(any(target_os = "android", target_os = "ios")))]
+    {
+        serde_json::to_string(&get_connect_status()).unwrap_or("".to_string())
+    }
+    #[cfg(any(target_os = "android", target_os = "ios"))]
+    {
+        let mut state = hbb_common::config::get_online_statue();
+        if state > 0 {
+            state = 1;
+        }
+        serde_json::json!({ "status_num": state }).to_string()
+    }
 }
 
 pub fn main_check_connect_status() {
@@ -995,10 +998,6 @@ pub fn main_get_fingerprint() -> String {
     get_fingerprint()
 }
 
-pub fn main_get_online_statue() -> i64 {
-    ONLINE.lock().unwrap().values().max().unwrap_or(&0).clone()
-}
-
 pub fn cm_get_clients_state() -> String {
     crate::ui_cm_interface::get_clients_state()
 }
@@ -1194,7 +1193,14 @@ pub fn main_check_mouse_time() {
 }
 
 pub fn main_get_mouse_time() -> f64 {
-    get_mouse_time()
+    #[cfg(not(any(target_os = "android", target_os = "ios")))]
+    {
+        get_mouse_time()
+    }
+    #[cfg(any(target_os = "android", target_os = "ios"))]
+    {
+        0.0
+    }
 }
 
 pub fn main_wol(id: String) {
diff --git a/src/ipc.rs b/src/ipc.rs
index 83a48107c..6a426e37d 100644
--- a/src/ipc.rs
+++ b/src/ipc.rs
@@ -186,6 +186,7 @@ pub enum Data {
     },
     SystemInfo(Option<String>),
     ClickTime(i64),
+    #[cfg(not(any(target_os = "android", target_os = "ios")))]
     MouseMoveTime(i64),
     Authorize,
     Close,
@@ -332,6 +333,7 @@ async fn handle(data: Data, stream: &mut Connection) {
             let t = crate::server::CLICK_TIME.load(Ordering::SeqCst);
             allow_err!(stream.send(&Data::ClickTime(t)).await);
         }
+        #[cfg(not(any(target_os = "android", target_os = "ios")))]
         Data::MouseMoveTime(_) => {
             let t = crate::server::MOUSE_MOVE_TIME.load(Ordering::SeqCst);
             allow_err!(stream.send(&Data::MouseMoveTime(t)).await);
@@ -345,13 +347,7 @@ async fn handle(data: Data, stream: &mut Connection) {
             }
         }
         Data::OnlineStatus(_) => {
-            let x = config::ONLINE
-                .lock()
-                .unwrap()
-                .values()
-                .max()
-                .unwrap_or(&0)
-                .clone();
+            let x = config::get_online_statue();
             let confirmed = Config::get_key_confirmed();
             allow_err!(stream.send(&Data::OnlineStatus(Some((x, confirmed)))).await);
         }
diff --git a/src/server/connection.rs b/src/server/connection.rs
index 88d7220eb..f747e47c1 100644
--- a/src/server/connection.rs
+++ b/src/server/connection.rs
@@ -63,6 +63,7 @@ lazy_static::lazy_static! {
     static ref SWITCH_SIDES_UUID: Arc::<Mutex<HashMap<String, (Instant, uuid::Uuid)>>> = Default::default();
 }
 pub static CLICK_TIME: AtomicI64 = AtomicI64::new(0);
+#[cfg(not(any(target_os = "android", target_os = "ios")))]
 pub static MOUSE_MOVE_TIME: AtomicI64 = AtomicI64::new(0);
 
 #[cfg(all(feature = "flutter", feature = "plugin_framework"))]
@@ -163,6 +164,7 @@ pub struct Connection {
     // by peer
     disable_audio: bool,
     // by peer
+    #[cfg(windows)]
     enable_file_transfer: bool,
     // by peer
     audio_sender: Option<MediaSender>,
@@ -291,6 +293,7 @@ impl Connection {
             show_remote_cursor: false,
             ip: "".to_owned(),
             disable_audio: false,
+            #[cfg(windows)]
             enable_file_transfer: false,
             disable_clipboard: false,
             disable_keyboard: false,
@@ -1112,6 +1115,7 @@ impl Connection {
         self.audio && !self.disable_audio
     }
 
+    #[cfg(windows)]
     fn file_transfer_enabled(&self) -> bool {
         self.file && self.enable_file_transfer
     }
diff --git a/src/ui.rs b/src/ui.rs
index 94ae30cf6..10eab22cb 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -362,9 +362,9 @@ impl UI {
     fn get_connect_status(&mut self) -> Value {
         let mut v = Value::array(0);
         let x = get_connect_status();
-        v.push(x.0);
-        v.push(x.1);
-        v.push(x.3);
+        v.push(x.status_num);
+        v.push(x.key_confirmed);
+        v.push(x.id);
         v
     }
 
diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs
index 7e46fd314..b61598251 100644
--- a/src/ui_cm_interface.rs
+++ b/src/ui_cm_interface.rs
@@ -454,10 +454,10 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
                     }
                 }
                 Some(data) = self.rx.recv() => {
-                    if let Data::SwitchPermission{name, enabled} = &data {
+                    if let Data::SwitchPermission{name: _name, enabled: _enabled} = &data {
                         #[cfg(windows)]
-                        if name == "file" {
-                            self.file_transfer_enabled = *enabled;
+                        if _name == "file" {
+                            self.file_transfer_enabled = *_enabled;
                         }
                     }
                     if self.stream.send(&data).await.is_err() {
diff --git a/src/ui_interface.rs b/src/ui_interface.rs
index b9514dd2d..ec9fcaad1 100644
--- a/src/ui_interface.rs
+++ b/src/ui_interface.rs
@@ -1,9 +1,3 @@
-use std::{
-    collections::HashMap,
-    process::Child,
-    sync::{Arc, Mutex},
-};
-
 #[cfg(any(target_os = "android", target_os = "ios"))]
 use hbb_common::password_security;
 use hbb_common::{
@@ -11,16 +5,21 @@ use hbb_common::{
     config::{self, Config, LocalConfig, PeerConfig},
     directories_next, log, tokio,
 };
+use hbb_common::{
+    config::{CONNECT_TIMEOUT, RENDEZVOUS_PORT},
+    futures::future::join_all,
+    rendezvous_proto::*,
+};
 #[cfg(not(any(target_os = "android", target_os = "ios")))]
 use hbb_common::{
     sleep,
     tokio::{sync::mpsc, time},
 };
-
-use hbb_common::{
-    config::{CONNECT_TIMEOUT, RENDEZVOUS_PORT},
-    futures::future::join_all,
-    rendezvous_proto::*,
+use serde_derive::Serialize;
+use std::{
+    collections::HashMap,
+    process::Child,
+    sync::{Arc, Mutex},
 };
 
 use crate::common::SOFTWARE_UPDATE_URL;
@@ -32,10 +31,28 @@ use crate::ipc;
 type Message = RendezvousMessage;
 
 pub type Children = Arc<Mutex<(bool, HashMap<(String, String), Child>)>>;
-type Status = (i32, bool, i64, String); // (status_num, key_confirmed, mouse_time, id)
+
+#[derive(Clone, Debug, Serialize)]
+pub struct UiStatus {
+    pub status_num: i32,
+    #[cfg(not(feature = "flutter"))]
+    pub key_confirmed: bool,
+    #[cfg(not(any(target_os = "android", target_os = "ios")))]
+    pub mouse_time: i64,
+    #[cfg(not(feature = "flutter"))]
+    pub id: String,
+}
 
 lazy_static::lazy_static! {
-    static ref UI_STATUS : Arc<Mutex<Status>> = Arc::new(Mutex::new((0, false, 0, "".to_owned())));
+    static ref UI_STATUS : Arc<Mutex<UiStatus>> = Arc::new(Mutex::new(UiStatus{
+        status_num: 0,
+        #[cfg(not(feature = "flutter"))]
+        key_confirmed: false,
+        #[cfg(not(any(target_os = "android", target_os = "ios")))]
+        mouse_time: 0,
+        #[cfg(not(feature = "flutter"))]
+        id: "".to_owned(),
+    }));
     static ref ASYNC_JOB_STATUS : Arc<Mutex<String>> = Default::default();
     static ref TEMPORARY_PASSWD : Arc<Mutex<String>> = Arc::new(Mutex::new("".to_owned()));
 }
@@ -115,12 +132,12 @@ pub fn get_license() -> String {
 pub fn get_option<T: AsRef<str>>(key: T) -> String {
     #[cfg(not(any(target_os = "android", target_os = "ios")))]
     {
-    let map = OPTIONS.lock().unwrap();
-    if let Some(v) = map.get(key.as_ref()) {
-        v.to_owned()
-    } else {
-        "".to_owned()
-    }
+        let map = OPTIONS.lock().unwrap();
+        if let Some(v) = map.get(key.as_ref()) {
+            v.to_owned()
+        } else {
+            "".to_owned()
+        }
     }
     #[cfg(any(target_os = "android", target_os = "ios"))]
     {
@@ -200,14 +217,14 @@ pub fn using_public_server() -> bool {
 #[inline]
 pub fn get_options() -> String {
     let options = {
-    #[cfg(not(any(target_os = "android", target_os = "ios")))]
-    {
-    OPTIONS.lock().unwrap()
-    }
-    #[cfg(any(target_os = "android", target_os = "ios"))]
-    {
-        Config::get_options()
-    }
+        #[cfg(not(any(target_os = "android", target_os = "ios")))]
+        {
+            OPTIONS.lock().unwrap()
+        }
+        #[cfg(any(target_os = "android", target_os = "ios"))]
+        {
+            Config::get_options()
+        }
     };
     let mut m = serde_json::Map::new();
     for (k, v) in options.iter() {
@@ -273,8 +290,8 @@ pub fn get_sound_inputs() -> Vec<String> {
 pub fn set_options(m: HashMap<String, String>) {
     #[cfg(not(any(target_os = "android", target_os = "ios")))]
     {
-    *OPTIONS.lock().unwrap() = m.clone();
-    ipc::set_options(m).ok();
+        *OPTIONS.lock().unwrap() = m.clone();
+        ipc::set_options(m).ok();
     }
     #[cfg(any(target_os = "android", target_os = "ios"))]
     Config::set_options(m);
@@ -308,13 +325,13 @@ pub fn set_option(key: String, value: String) {
     }
     #[cfg(not(any(target_os = "android", target_os = "ios")))]
     {
-    let mut options = OPTIONS.lock().unwrap();
-    if value.is_empty() {
-        options.remove(&key);
-    } else {
-        options.insert(key.clone(), value.clone());
-    }
-    ipc::set_options(options.clone()).ok();
+        let mut options = OPTIONS.lock().unwrap();
+        if value.is_empty() {
+            options.remove(&key);
+        } else {
+            options.insert(key.clone(), value.clone());
+        }
+        ipc::set_options(options.clone()).ok();
     }
     #[cfg(any(target_os = "android", target_os = "ios"))]
     Config::set_option(key, value);
@@ -408,10 +425,9 @@ pub fn is_installed_lower_version() -> bool {
 }
 
 #[inline]
+#[cfg(not(any(target_os = "android", target_os = "ios")))]
 pub fn get_mouse_time() -> f64 {
-    let ui_status = UI_STATUS.lock().unwrap();
-    let res = ui_status.2 as f64;
-    return res;
+    UI_STATUS.lock().unwrap().mouse_time as f64
 }
 
 #[inline]
@@ -424,10 +440,9 @@ pub fn check_mouse_time() {
 }
 
 #[inline]
-pub fn get_connect_status() -> Status {
-    let ui_statue = UI_STATUS.lock().unwrap();
-    let res = ui_statue.clone();
-    res
+#[cfg(not(any(target_os = "android", target_os = "ios")))]
+pub fn get_connect_status() -> UiStatus {
+    UI_STATUS.lock().unwrap().clone()
 }
 
 #[inline]
@@ -872,10 +887,13 @@ pub fn get_hostname() -> String {
 #[cfg(not(any(target_os = "android", target_os = "ios")))]
 #[tokio::main(flavor = "current_thread")]
 async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver<ipc::Data>) {
+    #[cfg(not(feature = "flutter"))]
     let mut key_confirmed = false;
     let mut rx = rx;
     let mut mouse_time = 0;
+    #[cfg(not(feature = "flutter"))]
     let mut id = "".to_owned();
+    #[cfg(target_os = "windows")]
     let mut enable_file_transfer = "".to_owned();
 
     loop {
@@ -889,9 +907,10 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver<ipc:
                                 log::error!("ipc connection closed: {}", err);
                                 break;
                             }
+                            #[cfg(not(any(target_os = "android", target_os = "ios")))]
                             Ok(Some(ipc::Data::MouseMoveTime(v))) => {
                                 mouse_time = v;
-                                UI_STATUS.lock().unwrap().2 = v;
+                                UI_STATUS.lock().unwrap().mouse_time = v;
                             }
                             Ok(Some(ipc::Data::Options(Some(v)))) => {
                                 *OPTIONS.lock().unwrap() = v;
@@ -908,17 +927,31 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver<ipc:
                             }
                             Ok(Some(ipc::Data::Config((name, Some(value))))) => {
                                 if name == "id" {
-                                    id = value;
+                                    #[cfg(not(feature = "flutter"))]
+                                    {
+                                        id = value;
+                                    }
                                 } else if name == "temporary-password" {
                                     *TEMPORARY_PASSWD.lock().unwrap() = value;
                                 }
                             }
-                            Ok(Some(ipc::Data::OnlineStatus(Some((mut x, c))))) => {
+                            Ok(Some(ipc::Data::OnlineStatus(Some((mut x, _c))))) => {
                                 if x > 0 {
                                     x = 1
                                 }
-                                key_confirmed = c;
-                                *UI_STATUS.lock().unwrap() = (x as _, key_confirmed, mouse_time, id.clone());
+                                #[cfg(not(feature = "flutter"))]
+                                {
+                                    key_confirmed = _c;
+                                }
+                                *UI_STATUS.lock().unwrap() = UiStatus {
+                                    status_num: x as _,
+                                    #[cfg(not(feature = "flutter"))]
+                                    key_confirmed: _c,
+                                    #[cfg(not(any(target_os = "android", target_os = "ios")))]
+                                    mouse_time,
+                                    #[cfg(not(feature = "flutter"))]
+                                    id: id.clone(),
+                                };
                             }
                             _ => {}
                         }
@@ -942,18 +975,26 @@ async fn check_connect_status_(reconnect: bool, rx: mpsc::UnboundedReceiver<ipc:
                 .insert("ipc-closed".to_owned(), "Y".to_owned());
             break;
         }
-        *UI_STATUS.lock().unwrap() = (-1, key_confirmed, mouse_time, id.clone());
+        *UI_STATUS.lock().unwrap() = UiStatus {
+            status_num: -1,
+            #[cfg(not(feature = "flutter"))]
+            key_confirmed,
+            #[cfg(not(any(target_os = "android", target_os = "ios")))]
+            mouse_time,
+            #[cfg(not(feature = "flutter"))]
+            id: id.clone(),
+        };
         sleep(1.).await;
     }
 }
 
 #[allow(dead_code)]
 pub fn option_synced() -> bool {
-    #[cfg(not(any(target_os = "android", target_os= "ios")))]
+    #[cfg(not(any(target_os = "android", target_os = "ios")))]
     {
         OPTION_SYNCED.lock().unwrap().clone()
     }
-    #[cfg(any(target_os = "android", target_os= "ios"))]
+    #[cfg(any(target_os = "android", target_os = "ios"))]
     {
         true
     }