Using Private iOS APIs

Guides | Tutorial By 4 years ago

For the most part iOS will let you code anything you want, however occasionally you will find the need to do something out of the ordinary, or reuse an existing class. Trying to do this with public APIs can be a headache, and often requires tons of code. You may heave heard of private APIs, and also may have heard about how apps get rejected from the AppStore for using them. This is often true, but if you know how to safely and properly use private APIs then you can harness their power.

Note that if you use a private API, make sure you create a fallback so if it stops working in the future your app will still function.


Subview hunting

You are not prevented from modifying a view that is part of a UIKit object, you just need to do it publicly. The -[UIView subviews] method is public, and you can use this to dig through the view hierarchy looking for a private view to change, no private method calls required. Alternatively if the view is added directly to the UIKit object, you can subclass it, override -[UIView didAddSubview:] and check each view that gets added. And to compare views? You don’t have a class declaration for the private classes, but that’s fine, instead you can evaluate that it is correct based on class string description, [[[subview class] description] isEqualToString:@”UIShadowView”]. I wrote a blog showing how to do this a while ago.


Private headers

You can use a tool like class-dump or a private class reference to see every Objective-C method each class in iOS has – the truth is nothing in Objective-C is truly ‘private’, you can see any method compiled into the binary. If you see one that looks interesting there’s nothing stopping you from calling it within your app, just remember that private APIs are somewhat dangerous as they may change behaviour or be removed without notice, so it’s not such a good idea having something important depend solely on a private API. I also recommend wrapping any private API calls in respondsToSelector: and performSelector: calls, and checking the class type of anything returned.


Accessing instance variables

Class instance variables can all be accessed, even the ones marked with @private. Use keyValue paths. For the example below, [xxxx valueForKey:@”_internal”] will give me the private _internal variable. As above, double check the returned value’s class type. You can mix this method with the private headers method to get further methods for the returned class, UIWebViewInternal in this example

NS_CLASS_AVAILABLE_IOS(2_0) @interface UIWebView : UIView  { 
    UIWebViewInternal *_internal;

Just know that if you request a value for a key that doesn’t exist, the app will crash. To get around this subclass the target class or categorise NSObject and override the following:

- (id) valueForUndefinedKey:(NSString *)key
	//	No crashes please...
	return nil;


Method Swizzling

Method Swizzling lets you inject code in the middle of two existing classes, which can be a lot more beneficial compared to a subclass that will only add your code on top of one class that must be subclassed. For example if you wanted to force every UIView‘s background red, with just one method and swizzling you could inject code after UIView‘s own init method. See a previous blog I wrote for a further example of this.


Private enums

Some enum values exist that developers aren’t supposed to know about. Fortunately for us an enum is just a number, practically impossible to detect and perfectly fine to use (unless the number changes of course). Try this example, which creates a back style button, which is reserved for value 101.

UIButton* back = [UIButton buttonWithType:101];
[back sizeToFit];
[back setTitle:@"Back" forState:UIControlStateNormal];


The line of doom —————————————————————————————–

(anything described below this line will probably get you rejected or has a good chance of crashing your app, but it’s worth while knowing about)


C methods

One half of Objective-C is pure C, and with that all the tricks to incorporate private C APIs into your app, such as defining external functions. While there probably aren’t as many C functions as you will need compared to Objective-C, some of them are powerful and very useful. Because you are directly linking to them (compared to Objective-C which is done at runtime) they are far easier to spot, and will probably show up when you submit your app and give you an auto rejection. Try this example in your own app, it will take a screenshot of the screen and save it to disk:

CGImageRef screenshot = UIGetScreenImage();
UIImage* image = [UIImage imageWithCGImage:screenshot];

[UIImagePNGRepresentation(image) writeToFile:@"/maybe-change-this.png" atomically:NO];


Overriding private methods and classes

This wont get you rejected but is a sure fire way to make your app volatile. If you go down this path, get on top of every beta developer release and keep checking your app works. You can override private methods for both public and private classes. If it’s a private class you can create an fake interface for it and categorise it, this will prevent compilation errors.

See this example, I don’t have any interface for UIStatusBar so I just make one up:

@interface UIStatusBar : UIView

@interface UIStatusBar (Override)

@implementation UIStatusBar (Override)

- (void) drawRect:(CGRect)rect
	NSArray* subviews = self.subviews;

	if(subviews.count < 2)

	UIView* background = [subviews objectAtIndex:0];
	UIView* foreground = [subviews objectAtIndex:1];

	[UIView animateWithDuration:2 animations:^{

		[self setTransform:CGAffineTransformMakeTranslation(0, 100)];

		[background setTransform:CGAffineTransformMakeTranslation(-160, 0)];
		[foreground setTransform:CGAffineTransformMakeTranslation(160, 0)];

  • UnNamed

    May I set custom text in Carrier, time battery label???

  • Waqas Naseem

    Can I mute/umute phone from my app? Using the private api?

    • Tom

      Not that I know of

  • Steve

    Is it possible to log out or auth a user from Game Center using a private API?

  • Suhail Ranger

    Hi Tom,

    I want to connect BLE devices from my app and want to use BluetoothManager.framework which is private API.
    Wanted to know how can i prevent app to be rejected.

    Or do you have any suggestion for me to connect BLE devices from app?