Change UIAlertView with swizzling - ios

I've recently been handed a private hardware SDK to integrate into my company's mobile app. Everything works great except they are using a UIAlertView as the result of some opaque method call, and my design team wants to brand this. I don't have access to the SDK's source code. Is there a way I can safely swizzle UIAlertView to preserve all functionality and simply modify the appearance of the UIAlertView so it's more branded/consistent with the app appearance? If so, would I overload drawRect or something else, and how would I figure out what the names of the labels in UIAlertView are so that I can draw them with the size, shape, and color that I want?
for added detail, the app does not currently use UIAlertView or UIAlertViewController so in theory swizzling would only affect whatever is going on with this closed-source SDK.

That wouldn't be straightforward at all.
If the SDK is using UIAlertView, then try swizzling the show method.
Your implementation should do approximately the following:
1) Do not let the original UIAlertView to show -- it is very hard to customize it.
2) Keep reference of old .delegate to be able to notify it when needed.
3) Create your own custom UIView and use [[UIApplication sharedApplication].keyWindow addSubview:myCustomAlertView];.
4) I believe you can get all of the previous UIAlertView variables (i.e. button titles, textFields, etc), using its properties such as
#property(nonatomic,copy) NSString *title;
#property(nullable,nonatomic,copy) NSString *message;
- (nullable NSString *)buttonTitleAtIndex:(NSInteger)buttonIndex;
#property(nonatomic,readonly) NSInteger numberOfButtons;
#property(nonatomic) NSInteger cancelButtonIndex;
5) Create your own designs and call corresponding delegate methods when needed.
Other approach is to use Apple's Private API, but this may lead to bad results.
This is a VERY HACKY approach. Firstly, you have no guarantees that it would even work. Secondly, your app may be rejected. Therefore, I wouldn't really recommend it...
However, if you really want to go with this approach, then try doing this:
After [myAlertView show]; look at its properties after some delay (i.e. 0.01 sec is enough):
Now look for suspicious properties (probably of UIView class), which might have UI-related information. For example, __representer looks quite interesting -- it has constraints, it has labelContainerView... Try playing with those properties.
In order to get that __representer, use KVC and KVO (i.e. start with id theAlertController = [myAlertView valueForKey:#"_alertController"];). Then dive deeper and deeper.
Hopefully, you would be able to find useful properties and would be able to change their values via KVC.

Related

Is this a good way to add protocols to a class I'm hooking in?

I'm trying to write a test tweak for iOS 8.3 using Theos.
This tweak will show a UIAlertView with two choices when the user taps on an application's icon.
I want to distinguish between the buttons, and to do so I need to add the UIAlertViewDelegate.
Following this example written by DHowett, I've adapted his code to run under iOS 8.3.
The code compiles and loads fine but no action is triggered when I tap on any icon.
If I simply hook into SBApplicationIcon with the correct method, action is triggered but this way I'm not able to distinguish button press.
Is this still a good way to add protocols?
You can cast the class you're hooking into to id<ProtocolName> when setting the delegate.
For instance, in your case it would be something like:
[alert setDelegate: (id<UIAlertViewDelegate>) self];

Edit exisiting class propertys or make system wide changes to a class

I have problem with iOS 8 and the SKLabelNode Class.
I used in my Project lot of SKLabelNodes(We speak about 120 nodes) and in iOS8 Apple has changed the built in FontType and now all my Labels hardly readable. I would like to change back, but I dont want to edit all the Nodes by one. I would like to change the SKLabelNode Class Defaults Font type. Is it possible? Or any other solution?
Sounds like your best bet would be to use a category Apple Category Docs
Or take a look at swizzling. There's a good tutorial here Swizzling
I think your best bet is actually method swizzling to replace the getter or modify the category to add a new init that sets a default font. Hope this helps.

Does hiding "Legal" in MKMapView result in an App Store rejection?

I'm displaying an MKMapView in a somewhat small square. It's small enough that the "Legal" text pretty much blocks half the map, so I'd like to get rid of it.
Is this allowed:
for (UIView *view in mapView.subviews) {
if ([NSStringFromClass([view class]) isEqualToString:#"MKAttributionLabel"]) {
view.hidden = YES;
break;
}
}
Not sure if I am risking App Store rejection by hiding it or using this method?
Yes, it will probably get rejected. Either because having the link is a legal requirement, or it'll be detected that you're using a private class (MKAttributionLabel).
That being said, you might get away with it for a few releases, if they don't notice.
Have you thought about using a static image instead of an MKMapView?
You are using undocumented features/classes. Since your map feature is very limited, you are better off using google's static map api instead of linking to a full feature framework just to show a small square of a map.

iOS5 Custom Window rotation issue

So I'm creating and showing a custom window in my iOS app because I'm writing a dynamic alert view that also functions like a growl/toast alert. It works AWESOMELY in ios6 (Hopefully I can open source this baby and you can all check it out)
But anyway, when I run this in ios5, the window that my alerts exist on doesn't seem to rotate with the device/simulator. No matter what, my custom window stays in portrait mode.
The UIWindow is just a UIView subclass, so there's no nice 'shouldRotate' delegate method.
I'm kinda stumped on why this is happening in ios5 but not 6. Any help would be GREATLY appreciated ^_^
My window has a rootviewcontroller, which I completely forgot about. I just needed to implement
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return YES;
}
To get it to work.
:-D
It's usually not recommended two use multiple instances of UIWindow in one iOS app. The only valid reason to do so is to support external screens. You should use a UIView instead, ideally managed by a UIViewController.
I assume, (since you didn't provide any code, I can only assume) the reason why your window doesn't 'rotate' is, that it's simply not getting any notifications about device rotation. Only the keyWindow receives them by default.
I would highly recommend to redesign your app to use a properly managed UIView instead. If you desperately don't want that for some reason, you would have to register your instance of UIWindow to receive the UIDeviceOrientationDidChangeNotification and then (in the handler) evaluate what the new orientation is and change the window's frame accordingly (plus maybe other things that need to be done in response to the orientation change)

When is -[UITextInput selectionRectsForRange:] called?

I have an app with a custom text editor that implements the UITextInput protocol. In iOS 6, Apple added one new required method to the protocol:
- (NSArray *)selectionRectsForRange:(UITextRange *)range
I've implemented this, but I can't seem to find a way to trigger it. At least in the way my app works, it seems to never get called by the text system. Does anyone know what it's used for?
This method is only used by subclasses of UITextView. This is the only method that would give you the system selection and loupe. This is what I was told at WWDC.
I am working on my own DTRichTextEditor as well and I implemented it nevertheless, maybe one day we get the selection/loupes also for our own UIViews that are not derived from UITextView.

Resources