mirror of
https://github.com/jkcoxson/idevice.git
synced 2026-03-02 14:36:16 +01:00
feat(springboard): add get_icon_state and set_icon_state methods (#63)
* feat(springboard): add get_icon_state method for reading home screen layout Add get_icon_state() method to SpringBoardServicesClient that retrieves the current home screen icon layout from iOS devices. Features: - Read complete home screen layout including icon positions and folders - Support for optional formatVersion parameter - Works on all iOS versions (tested on iOS 18.7.3) - Comprehensive documentation with usage examples Note: This PR intentionally does NOT include set_icon_state() as that functionality is non-operational on iOS 18+ (see issue #62 for details). Tested on: - Device: iPhone 16,2 (iPhone 15 Pro) - iOS: 18.7.3 (Build 22H217) * feat(springboard): add set_icon_state method with date precision fix - Implement set_icon_state() to modify home screen layout - Implement set_icon_state_with_version() with format_version parameter - Add truncate_dates_to_seconds() to convert nanosecond precision dates to second precision - Fix iOS compatibility issue where high-precision dates were rejected - Successfully tested on iOS 18.7.3 (previously believed to be restricted) - Follows pymobiledevice3 implementation pattern * refactor(utils): extract truncate_dates_to_seconds to utils::plist module - Move date truncation logic from springboardservices to reusable utils::plist module - Add comprehensive unit tests for date truncation functionality - Add public API documentation for the utility function - This makes the date normalization logic available for other services that may need it * perf(springboard): normalize dates on read instead of write - Move date truncation from set_icon_state to get_icon_state - Eliminates unnecessary clone() operation in set_icon_state - Better performance when setting icon state multiple times - Cleaner API: data from get_icon_state is directly usable in set_icon_state - Users don't need to worry about date precision issues * refactor(springboard): address PR feedback - use Option<&str> and add error validation - Change format_version parameter from Option<String> to Option<&str> for consistency - Remove outdated iOS 18+ restriction comments since setIconState works on iOS 18+ - Add error validation to get_icon_state method similar to get_icon_pngdata - Update documentation to reflect accurate iOS compatibility * Fix cargo clippy warnings * Fix clippy warnings in plist.rs * Add springboard CLI commands --------- Co-authored-by: Jackson Coxson <jkcoxson@gmail.com>
This commit is contained in:
@@ -42,6 +42,7 @@ mod process_control;
|
||||
mod remotexpc;
|
||||
mod restore_service;
|
||||
mod screenshot;
|
||||
mod springboardservices;
|
||||
mod syslog_relay;
|
||||
|
||||
mod pcap;
|
||||
@@ -120,6 +121,7 @@ async fn main() {
|
||||
.with_subcommand("remotexpc", remotexpc::register())
|
||||
.with_subcommand("restore_service", restore_service::register())
|
||||
.with_subcommand("screenshot", screenshot::register())
|
||||
.with_subcommand("springboard", springboardservices::register())
|
||||
.with_subcommand("syslog_relay", syslog_relay::register())
|
||||
.subcommand_required(true)
|
||||
.collect()
|
||||
@@ -236,6 +238,9 @@ async fn main() {
|
||||
"screenshot" => {
|
||||
screenshot::main(sub_args, provider).await;
|
||||
}
|
||||
"springboard" => {
|
||||
springboardservices::main(sub_args, provider).await;
|
||||
}
|
||||
"syslog_relay" => {
|
||||
syslog_relay::main(sub_args, provider).await;
|
||||
}
|
||||
|
||||
76
tools/src/springboardservices.rs
Normal file
76
tools/src/springboardservices.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
// Jackson Coxson
|
||||
|
||||
use idevice::{
|
||||
IdeviceService, provider::IdeviceProvider, springboardservices::SpringBoardServicesClient,
|
||||
};
|
||||
use jkcli::{CollectedArguments, JkArgument, JkCommand, JkFlag};
|
||||
use plist_macro::{plist_value_to_xml_bytes, pretty_print_plist};
|
||||
|
||||
pub fn register() -> JkCommand {
|
||||
JkCommand::new()
|
||||
.help("Manage the springboard service")
|
||||
.with_subcommand(
|
||||
"get_icon_state",
|
||||
JkCommand::new()
|
||||
.help("Gets the icon state from the device")
|
||||
.with_argument(
|
||||
JkArgument::new()
|
||||
.with_help("Version to query by")
|
||||
.required(false),
|
||||
)
|
||||
.with_flag(
|
||||
JkFlag::new("save")
|
||||
.with_help("Path to save to")
|
||||
.with_argument(JkArgument::new().required(true)),
|
||||
),
|
||||
)
|
||||
.with_subcommand(
|
||||
"set_icon_state",
|
||||
JkCommand::new().help("Sets the icon state").with_argument(
|
||||
JkArgument::new()
|
||||
.with_help("plist to set based on")
|
||||
.required(true),
|
||||
),
|
||||
)
|
||||
.subcommand_required(true)
|
||||
}
|
||||
|
||||
pub async fn main(arguments: &CollectedArguments, provider: Box<dyn IdeviceProvider>) {
|
||||
let mut sbc = SpringBoardServicesClient::connect(&*provider)
|
||||
.await
|
||||
.expect("Failed to connect to springboardservices");
|
||||
|
||||
let (sub_name, sub_args) = arguments.first_subcommand().expect("No subcommand passed");
|
||||
let mut sub_args = sub_args.clone();
|
||||
|
||||
match sub_name.as_str() {
|
||||
"get_icon_state" => {
|
||||
let version: Option<String> = sub_args.next_argument();
|
||||
let version = version.as_deref();
|
||||
let state = sbc
|
||||
.get_icon_state(version)
|
||||
.await
|
||||
.expect("Failed to get icon state");
|
||||
println!("{}", pretty_print_plist(&state));
|
||||
|
||||
if let Some(path) = sub_args.get_flag::<String>("save") {
|
||||
tokio::fs::write(path, plist_value_to_xml_bytes(&state))
|
||||
.await
|
||||
.expect("Failed to save to path");
|
||||
}
|
||||
}
|
||||
"set_icon_state" => {
|
||||
let load_path = sub_args.next_argument::<String>().unwrap();
|
||||
let load = tokio::fs::read(load_path)
|
||||
.await
|
||||
.expect("Failed to read plist");
|
||||
let load: plist::Value =
|
||||
plist::from_bytes(&load).expect("Failed to parse bytes as plist");
|
||||
|
||||
sbc.set_icon_state(load)
|
||||
.await
|
||||
.expect("Failed to set icon state");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user