diff --git a/src/service_factory.rs b/src/service_factory.rs index c89c6ac..286d5ed 100644 --- a/src/service_factory.rs +++ b/src/service_factory.rs @@ -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 = 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() + } + } + } } diff --git a/src/springboard_services.rs b/src/springboard_services.rs new file mode 100644 index 0000000..d11b61a --- /dev/null +++ b/src/springboard_services.rs @@ -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>, + 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 + ); + } + }; + }); + } +}