feat(sp_client) : impl springboard_services_client

This commit is contained in:
uncor3
2026-06-08 20:44:32 +00:00
parent c1f2d7eed4
commit bef33171cf
2 changed files with 91 additions and 0 deletions
+35
View File
@@ -1,10 +1,14 @@
use crate::device_ctx;
use crate::query_sqlite::Query;
use crate::service_manager::ServiceManager;
use crate::springboard_services::SpringBoardServices;
use crate::utils::{empty_qjsvalue, engine_ptr_new_object, vend_app_documents};
use crate::{afc_services::AfcServices, run_sync};
use idevice::IdeviceService;
use idevice::afc::AfcClient;
use idevice::{provider::IdeviceProvider, springboardservices::SpringBoardServicesClient};
use qmetaobject::{QJSValue, prelude::*};
use std::ffi::c_void;
use std::sync::Arc;
@@ -25,6 +29,7 @@ pub struct ServiceFactory {
qt_method!(fn(&self, udid: QString, bundle_id: QString) -> QJSValue),
create_service_manager: qt_method!(fn(&self, udid: QString, ios_version: u32) -> QJSValue),
create_sqlite_query_backend: qt_method!(fn(&self, udid: QString, ios_version: u32) -> QJSValue),
create_springboard_services_client: qt_method!(fn(&self, udid: QString) -> QJSValue),
}
impl ServiceFactory {
@@ -36,6 +41,7 @@ impl ServiceFactory {
create_hause_arrest_afc_client: Default::default(),
create_service_manager: Default::default(),
create_sqlite_query_backend: Default::default(),
create_springboard_services_client: Default::default(),
}
}
@@ -154,4 +160,33 @@ impl ServiceFactory {
let obj_ptr = qmetaobject::into_leaked_cpp_ptr(mng);
engine_ptr_new_object(engine_ptr, obj_ptr)
}
fn create_springboard_services_client(&self, udid: QString) -> QJSValue {
let engine_ptr: *mut c_void = self.engine_ptr;
if engine_ptr.is_null() {
eprintln!("ServiceFactory: engine_ptr is null");
return empty_qjsvalue();
}
let udid_clone = udid.to_string();
let sp_res: anyhow::Result<SpringBoardServicesClient> = run_sync(async move {
let device = device_ctx::get_device(udid).await?;
let provider_guard = device.provider.lock().await;
let provider_ref: &dyn IdeviceProvider = provider_guard.as_ref();
Ok(SpringBoardServicesClient::connect(provider_ref).await?)
});
match sp_res {
Ok(sp) => {
let sp_wrapper = SpringBoardServices::new_with_sp_client(sp);
let obj_ptr = qmetaobject::into_leaked_cpp_ptr(sp_wrapper);
engine_ptr_new_object(engine_ptr, obj_ptr)
}
Err(err) => {
println!(
"Failed to create SpringBoardServicesClient for device {}: {}",
udid_clone, err
);
empty_qjsvalue()
}
}
}
}
+56
View File
@@ -0,0 +1,56 @@
use crate::device_ctx;
use crate::{RUNTIME, qt_threading::QtThreading, qvariantmap_insert};
use base64::{Engine as _, engine::general_purpose};
use idevice::services::core_device_proxy::CoreDeviceProxy;
use idevice::springboardservices::SpringBoardServicesClient;
use macros::QtThreading;
use qmetaobject::prelude::*;
use qttypes::{QStringList, QVariantMap};
use std::sync::Arc;
use tokio::sync::Mutex;
#[derive(QObject, QtThreading)]
pub struct SpringBoardServices {
base: qt_base_class!(trait QObject),
springboard_client: Arc<Mutex<SpringBoardServicesClient>>,
app_icon_loaded: qt_signal!(bundle_id: QString, icon_data: QString),
fetch_app_icon: qt_method!(fn(bundle_id: QString)),
}
impl SpringBoardServices {
pub fn new_with_sp_client(sp: SpringBoardServicesClient) -> Self {
Self {
springboard_client: Arc::new(Mutex::new(sp)),
app_icon_loaded: Default::default(),
fetch_app_icon: Default::default(),
base: Default::default(),
}
}
fn fetch_app_icon(&self, bundle_id: QString) {
let qt_t = self.qt_thread();
let bundle_id_owned = bundle_id.clone();
let sb_client = self.springboard_client.clone();
RUNTIME.spawn(async move {
let mut sb = sb_client.lock().await;
match sb.get_icon_pngdata(bundle_id_owned.to_string()).await {
Ok(icon_data) => {
qt_t.queue(move |t| {
let icon_base64_string = general_purpose::STANDARD.encode(&icon_data);
t.app_icon_loaded(
bundle_id_owned,
QString::from(format!("data:image/png;base64,{}", icon_base64_string)),
);
});
}
Err(e) => {
eprintln!(
"fetch_app_icon: Failed to fetch app icon for bundle ID {}: {e}",
bundle_id_owned
);
}
};
});
}
}