Explore the iOS SDK and use undocumented APIs

    From this chapter, and from this whole book, it is clear that the most tidbits of iOS programming are included in public frameworks, but not in the SDK. Apple's unofficial policy about this is simple: you can use all this, but only at your own peril and risk. Your code may break during the next firmware update. You yourself have to find a compromise between risk and profit.

    Erica Sadun, The iPhone Developer's CookBook
    Original
    As you've seen in this chapter, and throughout this book, some of the nicest bits of iPhone programming are included in the public iPhone frameworks but not in the SDK. Apple's unofficial policy on this is clear: You can use these items in your programs, but you do so at your own risk. Your code may break at each firmware release. Striking the balance between risk and reward is up to you.

    Disclaimers


    • The pieces of code given here work on regular iPhone (including 4S) and iPad (including new iPad) and do not require jailbreak.
    • All solutions are written and tested on iOS 5. All solutions are also tested for compatibility with iOS 4.3, i.e. work with iOS 4 unless stated otherwise. The main part of the article was written before the release of iOS 6, so these solutions were not tested for compatibility with iOS 6.
    • Using undocumented APIs may result in your application not being allowed into the AppStore. Or maybe not :-)
      For those who are interested in how Apple defines the use of private APIs: “How does Apple know that you are using private APIs?”
    • Apple may change the implementation with the next release of iOS, and something will break in your code. However, this is solvable, and does not fundamentally differ from the implementation of backward compatibility for documented APIs. Below I examined this problem in more detail.
    • I can not guarantee that the APIs I found have no side effects. Use at your own risk.
    • Apple Developer Program license agreement prohibits reverse engineering for iOS.
    • The article is being finalized. Constructive criticism is welcome!

    Quick Search Guide in the SDK


    Let's say you need to do something that goes beyond the scope of official documentation. For example, change the backlight level (before iOS 5 this was not in the documented part of the SDK). It is known that Apple programmers usually give meaningful and expressive names to functions and variables, which we will use to search the SDK. To do this, select a few words related to the topic, for example, brightness, level, screen. Run the script LookSDKForSymbol.sh (this is my wrapper over nm; this script and other used tools are described later in the Tools section ) with keywords as parameters. The script returns the characters found in the object file (i.e. names of classes, functions, variables). Issue example:
    LookSDKForSymbol.sh light level $
    the U _UIBacklightLevelChangedNotification
    the Found in ./System/Library/CoreServices/SpringBoard.app/SpringBoard

    001b43c4 t - [UIApplication backlightLevel]
    001b4360 t - [UIApplication setBacklightLevel:]
    0025ce54 t - [UIDevice _backlightLevel]
    0025ce40 t - [UIDevice _setBacklightLevel:]
    ... and a few dozen more characters

    Most of the results can be immediately discarded, for example, -[UIApplication backlightLevel] returns the backlight value, but does not set it.

    The remaining, if there are no more than a few dozen, you can try to feed Google. It happens that someone has already been researching the API associated with the characters found, and in this case, consider the problem solved. In more complex cases, you have to do reverse engineering, that is, find out how the found functions work, how to use the found alerts, and the like.

    Character strings issued by the utility are divided into the following categories:
    1. Objective-C and C ++ functions, classes, structures, and so on. Everything related to Objective-C contains square brackets ([]) or dollar signs ($). C ++ functions are usually contained in some namespace, and therefore their name contains the namespace resolution symbol, two colons (: :).
    2. Objective-C blocks. They have the following general appearance:
      	___{число}{вызывающая данный блок функция}_block_invoke_{число2}
      

      For instance:
      	___22-[AXSystemServer init]_block_invoke_0
      
    3. Pure C features.
    4. Objective-C alerts. End with Notification, for example _SBMenuButtonPressedNotification.
    5. Keys / constants. Usually begin with k, for example: _ kCFUserNotificationAlternateButtonTitleKey.

    Further actions depend on the symbol category.
    1. We generate the header file for this framework:
      class-dump-z Foundation> $ / iOS_private_headers / Foundation.h

      In most cases, the generated header file is enough: class inheritance hierarchies, structures, methods, etc. should be described fairly well, so that after spending a little time you can figure out the API and use it in your proposal.

      Unfortunately, sometimes the information contained in the header file is not enough to make the code work, and then you have to analyze the assembler code generated by otool.

      Hint on disassembling Objective-C code: almost certainly you will encounter function calls like objc_msgSend (sending a message to an object). The first parameter is always a pointer to an object, and the second is a pointer to a selector, i.e. a pointer to a string that is the name of the method (the rest of the "normal" arguments are the third, fourth, etc. arguments). Determining what message is sent in this case will help hexdump.
    2. You can immediately forget about it. Blocks are (usually) local, they cannot be called from their code.
    3. The most difficult option. In the simplest cases, you can choose the signature for the function, in the rest - only disassembly. You can learn more about this in the section "How to find out the signature of an unknown function?" .
    4. Let's start by trying to catch alerts in one of the three main alert centers (Local, Darwin, and CoreTelephony). If alerts of this type do not arrive, the matter can be in one of two things:
      - Alerts of this type come in a separate, special alert center. You should search for traces of such a notification center in the same framework to which the found alert belongs.
      - Alert delivery is disabled. Try to find a mechanism to enable delivery of alerts of this type.
    5. In this case, most likely there is either a function that accepts this constant as a parameter, or a dictionary in which this constant is the key. In any case, you should look for a function or method whose name begins with the same word (for example: constant kLockdownDeviceColorKey-> function lockdown_copy_value(...);

    How to find out the signature of an unknown function?


    1. Find on the Internet, as it is not commonplace. I quite often came across Chinese sites, there were Korean and Japanese sites with very useful information. Usually the code itself is already enough to understand what is happening and how this function, this class, etc. are used. Thanks to the verbosity and expressiveness of Objective-C!
    2. For many simple functions, you can try to guess the signature. Caution , this can be quite dangerous.
    Using some simple functions, such as GSEventSetBackLightLevel, is self-evident.
    void GSEventSetBackLightLevel (float level);

    For many others, I used the following trick (using the SBGetRingerSwitchState function example):

    	SInt32 ret = 5, out1 = 1, out2 = 2, out3 = 3, out4 = 4;
    	void *libHandle = dlopen(SPRINGBOARD_SERVICES_PATH, RTLD_LAZY);
    	SInt32 (*SBGetRingerSwitchState)(SInt32*,SInt32*,SInt32*,SInt32*) = dlsym(libHandle, "SBGetRingerSwitchState");
    	ret = SBGetRingerSwitchState(&out1, &out2, &out3, &out4);
    	NSLog(@"%x %x %x %x %x", ret, out1, out2, out3, out4);
    

    As a result of this code, it turned out that
    1) the function returned a value 0x10000003that does not depend on the actual position of the switch.
    2) The variable out2has changed its value to self. The return value is also independent of the switch.
    3) The remaining variables have not changed their value.

    From 1) I concluded that the function returns a value of type kern_return_t, since it 0x10000003corresponds to a MACH_SEND_INVALID_ system errorDEST. Apparently, the error pointed to the wrong port [in this case, the port is an abstraction of the mach kernel (mach kernel), characterizing the rights and priority of the process]. As a rule, if a port number is used in a function call, then it is the first argument. From 2) it follows that through the second argument, the function returns a certain value by reference.

    As a result of these simple actions, the following signature is obtained:
    	kern_return_t SBGetRingerSwitchState(mach_port_t port, SInt32 *state);
    


    By the way, if the word get contains the name of the function, then according to naming conventions Objective-C this function should return a value by reference. This is also evident from the above example.

    3. Disassembly. On the example of the same SBGetRingerSwitchState. We use otool:

    $ otool -p _SBGetRingerSwitchState -tV -arch armv6 SpringBoardServices | less
    000038cc b5f0 push {r4, r5, r6, r7, lr}
    000038ce af03 add r7, sp, # 12
    000038d0 b092 sub sp, # 72
    000038d2 aa06 add r2, sp, # 24 // the value of register r2 is
    erased 000038d4 9205 str r2 , [sp, # 20]
    000038d6 ac08 add r4, sp, # 32 // ... as well as register r4
    000038d8 ab0f add r3, sp, # 60 // ... and r3
    000038da 9304 str r3, [sp, # 16]
    000038dc 9103 str r1, [sp, # 12] // the r1 value is stored on the stack
    000038de 4925 ldr r1, [pc, # 148] (0x3974)
    000038e0 6011 str r1, [r2, # 0]
    000038e2 6020 str r0, [r4, # 0] // the value of r0 is also stored on the stack
    ...


    From this code, using even superficial knowledge of arm assembler, we can assume that the function takes two arguments of the word type.
    It turns out that the function has two arguments. We go further, to the very end.

    ...
    00003964 9e04 ldr r6, [sp, # 16]
    00003966 6836 ldr r6, [r6, # 0]
    00003968 9903 ldr r1, [sp, # 12]
    0000396a 600e str r6, [r1, # 0]
    // approximately corresponds to ( in terms of the C language): * r1 = r6; those. at the address stored in r1, the value from r6 is written;
    // This means that the function returns the value by reference
    0000396c 462e mov r6, r5
    0000396e 4630 mov r0, r6
    // the result of the function is placed in r0
    00003970 b012 add sp, # 72
    00003972 bdf0 pop {r4, r5, r6, r7, pc}
    ...


    The bottom line is:
    int SBGetRingerSwitchState(int arg1, int* arg2);
    


    Continuing to analyze this assembly code, we clarify the types and come to the final version:
    kern_return_t SBGetRingerSwitchState(mach_port_t port, SInt32 *state);
    


    Different firmware and different devices: what can break and how to fix it?

    It’s clear that undocumented APIs do not necessarily work the same on all devices. In my experience, most often nothing changes, and the API works the same on all devices and all firmware. So, for example, all the functions of the UIDevice-IOKitExtensions extension (except for the definition of IMEI) work equally well on all devices and all firmware. What changes can happen when updating iOS?
    Here are some practical options.
    • An officially documented programming interface may appear, while an undocumented interface, as a rule, continues to work. Example:
      void GSEventSetBacklightLevel(float level); // работает во всех версиях iOS
      -[UIDevice setBrightness: (CGFloat)brightness]; // появилось в iOS 5.0
      

    • Program interfaces are transferred to another framework. Apple can merge several frameworks into one, rename or delete the framework. For example, functions for working with WiFi (Apple80211Open, Apple80211Close, and so on) were transferred from Aeropuerto.dylib to IPConfiguration.dylib.
    • APIs can simply be removed, especially if it is related to a vulnerability.


    In order to avoid compatibility problems, follow simple rules: check for functions (for example, using -[NSObject respondsToSelector:]), classes ( NSClassFromString(@"SomeClass")will return nilif there is no class SomeClass), etc., and also think in advance what the program should do if the API is missing . When using dynamic link library, you should also always check the return values ​​of dlsym (...) and dlopen (...) for equality NULL.

    Examples
    Example 1:
    Determining the position of the side switch vibro (aka Ring / Silent switch, Mute switch)

    One of the tasks that stood before me was to determine the position of the side switch, which in the original is called ring / silent switch. This switch is used to switch between “quiet” and normal / “loud” modes in the iPhone and iPad. A search on StackOverflow gave a solution:

    #import 
    ...
    /*
    Возвращаемое значение:
    	0: тихий режим
    	1: обычный режим  
    */
    int switchState() 
    {
    	// ...
    	// Инициализируем и активируем аудиосессию, устанавливаем 
    	// категорию в значение kAudioSessionCategoryAmbient
    	// ...
    	UInt32 size = sizeof(CFStringRef));
    	CFStringRef route;
    	AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &size, &route); 
    	// Получаем описание текущего аудиовыхода
    	CFIndex len = CFStringGetLength(route);
    	return (len > 0); // Если результат - пустая строка, значит телефон находится в "тихом" режиме
    }
    


    Which, however, does not work in iOS 5. Using the newer API (kAudioSessionProperty_AudioRouteDescription), which gives extended information about audio inputs and outputs, did not work either. (AUDIOROUTE)

    My further search on StackOverflow brought me to this post . It describes the library function AudioServicesAddSystemSoundCompletion (), whose non-standard behavior was considered by developers as a bug.

    #import 
    ...
    void playSound()
    {
    	AudioServicesAddSystemSoundCompletion(MySoundId, NULL, NULL, MyAudioServicesSystemSoundCompletionProc, 
    	AudioServicesPlaySystemSound(MySoundId);
    }
    void MyAudioServicesSystemSoundCompletionProc (SystemSoundID  ssID, void *clientData)
    {
    	// Проигрывание звука завершено
    	NSLog(@"Playback has been finished");
    }
    


    The non-standard behavior is that the callback of the MyAudioServicesSystemSoundCompletionProc callback will take place at the end of playing sound in normal mode, but immediately after calling AudioServicesPlaySystemSound in "silent" mode. This creates a loophole for determining the current state of the switch. If, for example, the length of the audio file that we play is 1 s, then the time difference between calling MyAudioServicesSystemSoundCompletionProc () in silent and loud mode is 1 s. On this, I built my second, asynchronous solution for determining the position of the side switch. Here it is:

    #import 
    #import "MuteSwitchTet.h"
    ...
    enum MuteSwitchStates {
    	kMuteSwitchUndefined = -1,
    	kSoundless = 0,
    	kSound = 1
    };
    @implementation MuteSwitchTest
    ...
    void MyAudioServicesSystemSoundCompletionProc (SystemSoundID  ssID, void *clientData)
    {
    	// "тихий" режим
    	MuteSwitchTest *self = (MuteSwitchTest*)clientData;
    	[NSObject cancelPreviousPerformRequestsWithTarget:self];
    	self.muteSwitchState = kSoundless;
    }
    - (void) cancelSystemSoundCompletion
    {
    	// "громкий" режим
    	AudioServicesRemoveSystemSoundCompletion(SoundID);
    	self.muteSwitchState = kSound;
    }
    - (void) startPlayback
    {
    	AudioServicesAddSystemSoundCompletion(SoundID, NULL, NULL, MyAudioServicesSystemSoundCompletionProc, self);
    	AudioServicesPlaySystemSound(SoundID);
    	[self performSelector:@selector(cancelSystemSoundCompletion) withObject:nil afterDelay:0.1];
    }
    ...
    @end
    


    Although this new solution was working, it did not suit me for several reasons. Firstly, it was asynchronous and worked with a noticeable delay (about 1/10 second). Reducing the delay led to false positives. Secondly, there was a side effect - the played sound itself, which sounded loud enough to confuse the user. Later, I artificially turned the volume to zero in the audio editor. Thirdly, it was already too much like a dirty hack, although this, for example, did not prevent the creators of VSSilentSwitch from selling their solution, apparently based on the same effect.

    About a month later, I returned to this problem. I started using the nm command to search for characters in object files, based on it I wrote a simple shell script, a listing of which can be found below (in the "Tools" section). The script is run with one, two or three parameters, each of which represents a keyword.

    Sh ~ $ / the Documents / LookSDKForSymbol.sh RingerSwitch
    # of the results omitted
    0000d738 the S _kGSRingerSwitchCapability
    the Found in ./System/Library/PrivateFrameworks/GraphicsServices.framework/GraphicsServices
    000038cc T _SBGetRingerSwitchState
    0000370c T _SBGetRingerSwitchState
    the Found in ./System/Library/PrivateFrameworks/SpringBoardServices. framework / SpringBoardServices


    The function with the name SBGetRingerSwitchStatelooked promising.

    To obtain the desired port, the function was used:
    mach_port_t SBSSpringBoardServerPort();
    

    from the same framework.

    Here is the result:
    @implementation MuteSwitchTest
    ...
    - (int) switchState
    {
    	// Функции SBSSpringBoardServerPort и SBGetRingerSwitchState 
    	// загружается при инициализации объекта MuteSwitchTest
    	mach_port_t port = SBSSpringBoardServerPort();
    	SInt32 state;
    	SBGetRingerSwitchState(port, &state);
    	return (int)state;
    }
    

    Example 2:
    Definition IMEI

    IMEI (International Mobile Equipment Identity) is a unique identification
    code assigned to each phone, a kind of MAC address of the phone (although the phone also has a MAC address)

    I don’t remember how I came out of the Erica Sadun uidevice-extension project , but as I dealt with him, he seemed to me more and more like a sort of programmer's “gold mine”.

    One of the categories, UIDeviсe (IOKit_Extensions) contains functions for defining IMEI. I tested these features on iPhone 4 with iOS 5.1 and iPad with iOS 4.3, everything worked and I moved on to other tasks. But during beta testing, it turned out that the function for determining IMEI does not work on new devices: iPad 2, the new iPad and iPhone 4S. To find out the reasons, I went to StackOverflow, where my fears were confirmed. Searches led me then to a framework called CoreTelephony.

    $ nm -g ./CoreTelephony | grep -i imei
    U _kCFAbsoluteTimeIntervalSince1970
    00053b28 S _kCTMobileEquipmentInfoIMEI
    00053ad4 S _kCTPostponementInfoIMEI
    00053ac4 S _kCTPostponementStatusErrorDefaultIMEI
    $ nm -g ./CoreTelephony | MobileEquipment grep
    000260e4 T __CTServerConnectionCopyMobileEquipmentInfo
    00053b34 S _kCTMobileEquipmentInfo1xIMSI
    00053b20 S _kCTMobileEquipmentInfoCurrentMobileId
    00053b24 S _kCTMobileEquipmentInfoCurrentSubscriberId
    00053b40 S _kCTMobileEquipmentInfoERIVersion
    00053b2c S _kCTMobileEquipmentInfoICCID
    00053b28 S _kCTMobileEquipmentInfoIMEI
    00053b30 S _kCTMobileEquipmentInfoIMSI
    00053b38 S _kCTMobileEquipmentInfoMEID
    00053b44 S _kCTMobileEquipmentInfoMIN
    00053b3c S _kCTMobileEquipmentInfoPRLVersion

    We can assume that the function (_CTServerConnectionCopyMobileEquipmentInfo (...)) returns a dictionary (CFDictionaryRef) with keys of the form kCTMobileEquipmentInfo * and their corresponding values. Fortunately, this time I did not have to restore the signature. Google search for _CTServerConnectionCopyMobileEquipmentInfo led me to this page , and soon the function for determining IMEI was ready.

    
    // Заголовочный файл с декларациями недокументированных функций и констант	
    #include "CoreTelephony.h" 
    ...
    NSString* CTGetIMEI
    {
    	struct CTResult it;
    	NSMutableDictionary *dict;
    	CTServerConnectionRef conn;
    	conn = _CTServerConnectionCreate(kCFAllocatorDefault, ConnectionCallback, NULL);
    	_CTServerConnectionCopyMobileEquipmentInfo(&it, conn, &(CFMutableDictionaryRef)dict);
    	CFRelease(conn);
    	[dict autorelease];
    	return [dict objectForKey: kCTMobileEquipmentInfoIMEI];
    }
    

    This IMEI detection method works on all devices.
    Later I found another method for determining IMEI (via lockdownd).

    Example 3:
    Use of undocumented alerts: volume buttons.

    Initially, I naively believed that any character constant ending in "Notification" is the name of a system alert and can be used by simply registering an observer using [NSNotificationCenter defaultCenter].
    Sh ~ $ / Documents / LookSDKForSymbol.sh volume change notification $
    001dbe60 S _MPAVControllerVolumeDidChangeNotification
    001dbe64 S _MPAVControllerVolumeMutedDidChangeNotification
    001dc4f8 S _MPMusicPlayerControllerVolumeDidChangeNotification
    001dc314 S _MPVolumeViewRouteButtonChangedNotification
    001dc310 S _MPVolumeViewVisibilityChangedNotification
    Found in ./System/Library/Frameworks/MediaPlayer.framework/MediaPlayer

    000d6d24 D _AVController_EffectiveVolumeDidChangeNotification
    000d6d60 D _AVController_VolumeDidChangeNotification
    000d6fec D _AVSystemController_CurrentRouteHasVolumeControlDidChangeNotification
    000d6ffc D _AVSystemController_EffectiveVolumeDidChangeNotification
    000d6fdc D _AVSystemController_SystemVolumeDidChangeNotification
    Found in ./System/Library/PrivateFrameworks/Celestial.framework/Celestial
    … и еще около десятка из других фреймворков

    Написав тестовую программу, я принялся проверять, какие оповещения приходили в ответ на нажатия клавиш громкости.
    Из составленного мной довольно большого списка опопвещений приходили только вот эти 2:

    AVController_EffectiveVolumeDidChangeNotification
    AVController_VolumeDidChangeNotification

    Недостаток этих оповещений в том, что
    1) Нельзя напрямую определить, какая из двух кнопок была нажата
    2) Нельзя отследить, когда нажата и когда отпущена каждая из кнопок

    Ищу по другим ключевым словам:
    Sh ~ $ / Documents / LookSDKForSymbol.sh volume button
    001b221c t - [UIApplication setWantsVolumeButtonEvents:]
    003cce5c t _SBSetWantsVolumeButtonEvents $ shim
    0054478c S __UIApplicationVolumeDownButtonDownNotification
    00544790 S __UIApplicationVolumeDownButtonUpNotification
    00544784 S __UIApplicationVolumeUpButtonDownNotification
    00544788 __UIApplicationVolumeUpButtonUpNotification S
    Found in ./System/Library/Frameworks/UIKit.framework/ UIKit
    ... and a few dozen more from different frameworks

    Four alerts from UIKit did not work right away: it was necessary to issue a command related to them.
    	[[UIApplication sharedApplication] setWantsVolumeButtonEvents: YES];
    

    After that, notifications about pressing the corresponding buttons began to come.
    Side effect: calling this function causes the volume buttons to no longer adjust the volume, so when you finish working with the buttons, you should call
    	[[UIApplication sharedApplication] setWantsVolumeButtonEvents: NO];
    

    Example 4:
    Using undocumented alerts: tracking the status of the SIM card

    We work according to the proven scheme:
    $ sh ~/Documents/LookSDKForSymbol.sh notification$ SIM

    00052560 S _kCTSIMSupportSIMInsertionNotification
    00052564 S _kCTSIMSupportSIMStatusChangeNotification

    000525bc S _kCTSIMSupportSIMTrayStatusNotification

    Found in ./System/Library/Frameworks/CoreTelephony.framework/CoreTelephony

    Found in ./System/Library/PrivateFrameworks/FTServices.framework/FTServices
    $


    The most suitable alerts seemed to me under the names:
    1) kCTSIMSupportSIMInsertionNotification
    2) kCTSIMSupportSIMStatusChangeNotification
    3) kCTSIMSupportSIMTrayStatusNotification

    The simplest test program showed that notifications called (1) only arrived at the time of insertion of the SIM card (I could have guessed 2 (I could ) came exactly when I needed (when inserting and removing), alerts (3) did not come at all. Later I learned that alerts (3) belong to a special alert center called CTTelephonyCenter. You can read about using CTTelephonyCenter here .

    SIM Status Alerts:

    #include "CoreTelephony.h" 
    - (void) notificationCallback:(NSNotification)notification
    {
    	...
    }
    - (void) startUpdateSIMStatus
    {
    	[[NSNotificationCenter defaultCenter]
    		 addObserver:self
    		 selector:@selector(notificationCallback:)
    		 name:kCTSIMSupportSIMStatusChangeNotification
    		 object:nil
    	];
    }
    - (void) stopUpdateSIMStatus 
    {
    	[[NSNotificationCenter defaultCenter] 
    	 removeObserver:self 
    	 name:kCTSIMSupportSIMStatusChangeNotification 
    	 object:nil];
    }
    


    Additions

    1. Using system sounds in your application

    www.iphonedevwiki.net/index.php/AudioServices - here are described undocumented constants like SystemSoundID for playing standard short (<30sec) sounds, such as button presses. You can find them all yourself, simply sorting through the values ​​from 1000 in a cycle.

    You can still play standard ringtones:

    - (void) playDefaultRingTone
    {
    	NSURL *defaultRingTone = [NSURL URLWithString:@"/System/Library/CoreServices/SpringBoard.app/ring.m4r"];
    	AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:defaultRingTone error:nil];
    	[player play];
    }
    

    2. Recursive search in the UIView hierarchy

    As you know, objects of the UIView class usually have a parent view (superview) and there can be child views (subviews). The top (as we will see later, the tops) of this hierarchy are the UIWindow object (s). What if you go through the entire hierarchy? There is only one subtlety here: oddly enough, a program can have more than one object of type UIWindow.
    To get __ all__ windows, I used an undocumented function

    	+ [UIWindow allWindowsIncludingInternalWindows: onlyVisibleWindows:]
    


    With the help of it, I was able to find that in the most ordinary application there can be up to four windows! (UIWindow)
    1) a normal program window
    2) a window for the status bar (it can also be obtained using - [UIApplication statusBarWindow])
    3) a window for UIAlertView (Parent view for objects of type UIAlertView).
    4) a window for the on-screen keyboard.

    How can we benefit from this?

    Obviously, we can handle the objects of the last three types in the same way as with the first.
    In particular, we can:
    - change the appearance of the UIAlertView, add text fields, radio buttons, etc.
    - change the appearance of the status bar, add your own indicators and delete the standard ones.
    - change the appearance of the on-screen keyboard: for example, change the appearance of buttons, add your own buttons, switches, etc.

    But this is not all, there are also unexpected side effects. Some graphic elements can be directly connected with one or another deeper functionality.
    @interface UIStatusBarSignalStrengthItemView : UIStatusBarItemView {
    @private
    	int _signalStrengthRaw;
    	int _signalStrengthBars;
    	BOOL _enableRSSI;
    	BOOL _showRSSI;
    }
    -(id)_stringForRSSI;
    -(float)extraRightPadding;
    -(void)touchesEnded:(id)ended withEvent:(id)event;
    -(id)contentsImageForStyle:(int)style;
    -(BOOL)updateForNewData:(id)newData actions:(int)actions;
    @end
    

    So, for example, after gaining access to the UIStatusBarSignalStrengthItemView, we are able to legally receive the RSSI (received signal strength) values ​​of the cellular network, and display it in any convenient form.

    A complete listing of code recursively describing all visible objects in a program. Called through [UIView completeDescription]:
    
    @interface UIView (RecursiveDescription)
    - (void) recursiveDescription;
    + (void) completeDescription
    @end
    @implementation UIView (RecursiveDescription)
    - (void) recursiveDescription
    {
    	NSLog(@"______________________________________");
    	NSLog(@"%@", self);
    	NSArray *subviews_ = [self subviews];
    	if ([subviews_ count] > 0) {
    		for (UIView *subview_ in subviews_) {
    			[subview_ recursiveDescription];
    		}
    	}
    }
    - (void)completeDescription
    {
    	NSArray *windows = [UIWindow allWindowsIncludingInternalWindows:YES onlyVisibleWindows:NO];
    	for (UIView *view in windows) {
    		[view recursiveDescription];
    	}
    }
    @end
    

    3. Some important low-level iOS subsystems


    Subsystem MIG (MIG-subsystem, Mach Interface Generator) - an interface for interacting with the kernel of the operating system (the so-called "Mach kernel"). The implementation of the MIG-subsystem for Mac OS X lies somewhere here: www.opensource.apple.com/source/xnu/xnu-1228.0.2/libsyscall/mach . See also the list of known low-level messages: www.iphonedevwiki.net/index.php/MIG_subsystem .

    IORegistry, I / O registry - input-output registry; A tree structure describing iPhone hardware and interacting with hardware components. Examples of using IORegistry can be found in Erica Sadun's projects (see UIDevice-IOKitExtensions ).

    Instruments

    nm is a UNIX utility that displays the symbol table of an object new file.
    Based on nm, I wrote a simple (and rather dumb) bash script that searches all libraries and object files inside the iOS SDK.

    LookSDKForSymbol.sh:
    	#!/bin/bash
    	SDK=/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk
    	PrivateFrameworks=$SDK/System/Library/PrivateFrameworks
    	Frameworks=$SDK/System/Library/Frameworks 
    	Lib=$SDK/usr/lib 
    	cd $SDK
    	for i in $(find -f .); do
    		test -f $i && nm $i | c++filt | grep -i "$1" | grep -i "$2" | grep -i "$3" && echo "Found in $i
    		";
    	done
    

    c ++ filt - restoration ( demangling ) of names. For C ++ only; the names objective-C and simply C go immediately in human-readable form.
    otool is a standard utility for analyzing and disassembling object files.
    hexdump - dump it dump is :-)
    class-dump-z is a super useful utility. Allows you to generate a header file from an object file. A description of all structures, protocols, classes, categories, their methods, properties, and so on.
    Repository on Google Code - here you can find a more detailed description and download the source code of this project.

    Hex-Rays ARM Decompiler - plugin for HEX-Rays IDA, ARM code decompiler. Official site.
    Utilities Erica Sadun - Erica’s website has several useful utilities, for example, a utility for analyzing alerts.

    Useful resources, sources

    Wiki

    www.iphonedevwiki.net
    The only wiki I know about jailbreak development. Although the information is outdated
    (iOS 3.x, iOS 4.x), but still it is an extremely useful resource.

    Persons

    1. Jay Freeman, saurik
    www.saurik.com

    2. Erica Sadun is the author of The iPhone Developer's CookBook and The iOS 5 Developer's Cookbook: Core Concepts and Essential Recipes for iOS Programmers, as well as many useful utilities. Her books describe some of the undocumented features of public frameworks.
    ericasadun.com

    Some Erica Sadun projects:
    github.com/erica/iOS-5-Cookbook
    github.com/erica/iphone-3.0-cookbook-

    github.com/erica/uidevice-extension

    3. KennyTM / networkpx is the creator of class-dump-z, an active member of StackOverflow.com in matters related to the undocumented
    networkpx.blogspot.com API
    code.google.com/p/networkpx
    github. com / kennytm
    stackoverflow.com/users/224671/kennytm

    github.com/kennytm/iphone-private-frameworks
    Information is very outdated (iOS 3).

    Books

    “The iPhone Developer's CookBook” (also “The iOS 5 Developer's Cookbook: Core Concepts and Essential Recipes for iOS Programmers”) is a book about iOS development, with a focus on iOS undocumented features.
    Russian translation:
    translated.by/you/iphone-developers-cookbook-development-native-applications-for-the-iphone/into-ru/trans

    Also popular now: