The Signer struct orchestrates the complete iOS app signing process, including bundle modification, provisioning profile generation, and code signing.
Signer struct
pub struct Signer {
certificate : Option < CertificateIdentity >,
pub options : SignerOptions ,
pub provisioning_files : Vec < MobileProvision >,
}
certificate
Option<CertificateIdentity>
Code signing certificate and private key (not needed for adhoc signing)
Configuration for the signing operation
Provisioning profiles generated or loaded during signing
Creating a signer
Basic signer
With certificate
For specific app
use plume_utils :: { Signer , SignerOptions };
let options = SignerOptions :: default ();
let signer = Signer :: new ( None , options );
Methods
new
pub fn new (
certificate : Option < CertificateIdentity >,
options : SignerOptions
) -> Self
Creates a new signer instance with the specified certificate and options.
modify_bundle
pub async fn modify_bundle (
& mut self ,
bundle : & Bundle ,
team_id : & Option < String >,
) -> Result <(), Error >
Modifies the app bundle according to the signer options. This includes:
Changing app name, version, and bundle identifier
Setting minimum OS version
Enabling features (file sharing, iPad fullscreen, game mode, ProMotion)
Injecting custom icons
Installing tweaks and ElleKit
Embedding certificate for sideloading apps
Liquid Glass support (SDK version modification)
Show Supported modifications
Changes CFBundleDisplayName and CFBundleName
Changes CFBundleShortVersionString and CFBundleVersion
Changes CFBundleIdentifier for main app and nested bundles
Replaces app icons with custom image
features.support_file_sharing
Enables UIFileSharingEnabled and UISupportsDocumentBrowser
features.support_game_mode
Enables GCSupportsGameMode
features.support_pro_motion
Enables CADisableMinimumFrameDurationOnPhone for 120Hz displays
features.support_liquid_glass
Modifies SDK version for dynamic island support
Installs ElleKit tweak injection framework
let mut signer = Signer :: new ( None , options );
let bundle = Bundle :: new ( "/path/to/App.app" ) ? ;
signer . modify_bundle ( & bundle , & Some ( team_id )) . await ? ;
register_bundle
pub async fn register_bundle (
& mut self ,
bundle : & Bundle ,
session : & DeveloperSession ,
team_id : & String ,
is_refresh : bool ,
) -> Result <(), Error >
Registers the app bundle with Apple’s Developer API and generates provisioning profiles. This method:
Creates app IDs for the main app and extensions
Enables required capabilities based on entitlements
Creates and assigns app groups
Generates provisioning profiles
Embeds profiles in the bundle
The app bundle to register
Authenticated developer session
Whether this is refreshing an existing app (preserves app group names)
use plume_core :: developer :: DeveloperSession ;
let session = DeveloperSession :: using_account ( account ) . await ? ;
let teams = session . qh_list_teams () . await ? ;
let team_id = & teams . teams[ 0 ] . team_id;
signer . register_bundle (
& bundle ,
& session ,
team_id ,
false // not a refresh
) . await ? ;
sign_bundle
pub async fn sign_bundle ( & self , bundle : & Bundle ) -> Result <(), Error >
Performs code signing on the bundle and all nested components. Signs in the correct order (deepest bundles first):
Frameworks and dylibs
App extensions
Main app bundle
signer . sign_bundle ( & bundle ) . await ? ;
println! ( "Bundle signed successfully" );
Signing modes
pub enum SignerMode {
Pem , // Sign with Apple Developer account
Adhoc , // Adhoc signing (no developer account)
None , // No modifications
}
Full signing with Apple Developer provisioning profiles. Requires DeveloperSession.
Local adhoc signing without Apple Developer account. Apps work on jailbroken devices only.
Skip signing, only apply modifications from SignerOptions.
Signing options
pub struct SignerOptions {
pub custom_name : Option < String >,
pub custom_identifier : Option < String >,
pub custom_version : Option < String >,
pub custom_icon : Option < PathBuf >,
pub custom_entitlements : Option < PathBuf >,
pub features : SignerFeatures ,
pub embedding : SignerEmbedding ,
pub mode : SignerMode ,
pub install_mode : SignerInstallMode ,
pub tweaks : Option < Vec < PathBuf >>,
pub app : SignerApp ,
pub refresh : bool ,
}
SignerFeatures
pub struct SignerFeatures {
pub support_minimum_os_version : bool ,
pub support_file_sharing : bool ,
pub support_ipad_fullscreen : bool ,
pub support_game_mode : bool ,
pub support_pro_motion : bool ,
pub support_liquid_glass : bool ,
pub support_ellekit : bool ,
pub remove_url_schemes : bool ,
}
SignerEmbedding
pub struct SignerEmbedding {
pub single_profile : bool , // Use one profile for all bundles
}
SignerApp
pub enum SignerApp {
Default ,
Antrag ,
Feather ,
Protokolle ,
AltStore ,
SideStore ,
LiveContainer ,
LiveContainerAndSideStore ,
StikDebug ,
SparseBox ,
EnsWilde ,
ByeTunes ,
StikStore ,
}
Special handling for specific sideloading apps (certificate embedding, pairing file paths, etc.).
Complete example
use plume_core :: auth :: Account ;
use plume_core :: developer :: DeveloperSession ;
use plume_utils :: {
Bundle , Signer , SignerOptions , SignerMode ,
SignerFeatures , SignerApp
};
use omnisette :: AnisetteConfiguration ;
#[tokio :: main]
async fn main () -> Result <(), Box < dyn std :: error :: Error >> {
// 1. Authenticate
let account = Account :: login (
|| Ok (( "[email protected] " . to_string (), "password" . to_string ())),
|| Ok ( "123456" . to_string ()),
AnisetteConfiguration :: default ()
) . await ? ;
// 2. Get developer session and team
let session = DeveloperSession :: using_account ( account ) . await ? ;
let teams = session . qh_list_teams () . await ? ;
let team_id = teams . teams[ 0 ] . team_id . clone ();
// 3. Load bundle
let bundle = Bundle :: new ( "/path/to/MyApp.app" ) ? ;
// 4. Configure options
let mut options = SignerOptions :: default ();
options . mode = SignerMode :: Pem ;
options . custom_name = Some ( "Custom Name" . to_string ());
options . custom_version = Some ( "1.0.0" . to_string ());
options . features . support_file_sharing = true ;
options . features . support_pro_motion = true ;
options . app = SignerApp :: Default ;
// 5. Create signer and sign
let mut signer = Signer :: new ( None , options );
// Modify bundle (name, version, features)
signer . modify_bundle ( & bundle , & Some ( team_id . clone ())) . await ? ;
// Register with Apple and get provisioning profiles
signer . register_bundle ( & bundle , & session , & team_id , false ) . await ? ;
// Sign all bundles
signer . sign_bundle ( & bundle ) . await ? ;
println! ( "✓ Bundle signed successfully!" );
Ok (())
}
Special app support
The signer has special handling for popular sideloading apps:
SideStore support
LiveContainer support
let mut options = SignerOptions :: new_for_app ( SignerApp :: SideStore );
// Automatically:
// - Embeds certificate for app refresh
// - Sets single_profile = true
// - Configures pairing file path