2

I am trying to print the view hierarchy of the application's visible and hidden windows. Here is a part of my code inside a subclass of MFMessageComposeViewController:

NSArray *windows = [[UIApplication sharedApplication] windows];

for(UIWindow *aWindow in windows) {
    if([aWindow isMemberOfClass:NSClassFromString(@"UITextEffectsWindow")]) {
        sendButton = [self findButtonInView:aWindow];
            break;
    }
}

The findButtonInView: method is searching recursively a UIButton in the current UIWindow.

This is working as expected when testing with iOS4.3 and iOS 5.1 (the expected UIButton is found successfully), but does not work with iOS6. Here are the results of the view hierarchy prints from both tests:

iOS 4.3:

<UITextEffectsWindow: 0x1e32a0; frame = (0 0; 320 480); opaque = NO; layer = <CALayer: 0x1e33d0>>
   | <UIPeripheralHostView: 0x1e4a80; frame = (0 224; 320 256); autoresizesSubviews = NO; layer = <UIPeripheralHostLayer: 0x1e4e60>>
   |    | <UIKeyboardAutomatic: 0x1ad300; frame = (0 40; 320 216); opaque = NO; layer = <CALayer: 0x1ad3b0>>
   |    |    | <UIKeyboardImpl: 0x1ad520; frame = (0 0; 320 216); opaque = NO; layer = <CALayer: 0x1ad6c0>>
   |    |    |    | <UIKeyboardLayoutStar: 0x1d47c0; frame = (0 0; 320 216); layer = <CALayer: 0x19ca40>>
   |    |    |    |    | <UIKBKeyplaneView: 0x1df880; frame = (0 0; 320 216); layer = <CALayer: 0x1df900>>
   |    |    |    |    |    | <UIKBKeyView: 0x1dfe00; frame = (1 119; 40 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1dffd0>>
   |    |    |    |    |    | <UIKBKeyView: 0x1e0090; frame = (279 119; 40 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1e00e0>>
   |    |    |    |    |    | <UIKBKeyView: 0x1e01e0; frame = (1 173; 38 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1e0230>>
   |    |    |    |    |    | <UIKBKeyView: 0x1dbfb0; frame = (41 173; 38 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1dc050>>
   |    |    |    |    |    | <UIKBKeyView: 0x1e0330; frame = (81 173; 158 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1e0380>>
   |    |    |    |    |    | <UIKBKeyView: 0x1e0440; frame = (241 173; 78 42); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1e0490>>
   |    | <CKMessageEntryView: 0x182500; baseClass = UIImageView; frame = (0 0; 320 40); opaque = NO; autoresize = W+TM; layer = <CALayer: 0x1837c0>>
   |    |    | <UIButton: 0x1878c0; frame = (6 8; 26 27); hidden = YES; opaque = NO; autoresize = RM+TM; layer = <CALayer: 0x182e60>>
   |    |    |    | <UIImageView: 0x1e56f0; frame = (0 0; 26 27); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1e5720>>
   |    |    | <UIView: 0x184dd0; frame = (7 0; 245 40); autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x185130>>
   |    |    | <CKContentEntryView: 0x188a50; baseClass = UIScrollView; frame = (6 0; 249 40); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x187230>; contentOffset: {-0, -10}>
   |    |    |    | <CKRichContentView: 0x193790; baseClass = UITextContentView; frame = (0 0; 249 20); text = ''; autoresize = W; layer = <CALayer: 0x1938a0>>
   |    |    |    |    | <UIWebDocumentView: 0xaef200; frame = (0 0; 249 20); text = '
'; opaque = NO; userInteractionEnabled = NO; layer = <UIWebLayer: 0x196c20>>
   |    |    |    |    | <UITextSelectionView: 0x1a5b60; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x1a5c00>>
   |    |    |    | <UIImageView: 0x189fa0; frame = (242 10; 7 20); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x189ff0>>
   |    |    |    | <UIImageView: 0x189eb0; frame = (242 23; 7 7); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x189f00>>
   |    |    | <UIImageView: 0x18a190; frame = (7 0; 245 40); opaque = NO; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x18a510>>
   |    |    | <UILabel: 0x18a6b0; frame = (245 13; 73 15); text = 'TEST'; clipsToBounds = YES; hidden = YES; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x18a720>>
   |    |    | <UIButton: 0x180d00; frame = (252 8; 61 27); opaque = NO; autoresize = LM+TM; layer = <CALayer: 0x184e00>>
   |    |    |    | <UIImageView: 0x1ad460; frame = (0 0; 61 27); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x1ad490>>
   |    |    |    | <UIButtonLabel: 0x1871c0; frame = (11 3; 39 20); text = 'Send'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x187280>>

iOS 6.0:

<UIWindow: 0x1fd81f80; frame = (0 0; 320 480); opaque = NO; autoresize = RM+BM; layer = <UIWindowLayer: 0x1fd82080>>
   | <UILayoutContainerView: 0x1fd94d50; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x1fd94df0>>
   |    | <UINavigationTransitionView: 0x1fd9a450; frame = (0 0; 320 480); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x1fd9a520>>
   |    |    | <UIViewControllerWrapperView: 0x1fdac9a0; frame = (0 20; 320 460); autoresize = W+H; layer = <CALayer: 0x1fdaca30>>
   |    |    |    | <UIView: 0x1fda8cb0; frame = (0 0; 320 460); autoresize = W+H; layer = <CALayer: 0x1fda8c70>>
   |    |    |    |    | <_UISizeTrackingView: 0x1fda6430; frame = (0 0; 320 460); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x1fda6510>>
   |    |    |    |    |    | <_UIRemoteView: 0x1fda6700; frame = (0 0; 320 480); transform = [0.5, -0, 0, 0.5, -0, 0]; userInteractionEnabled = NO; layer = <CALayerHost: 0x1fda6850>>

My question is how the needed UIButton can be found inside UITextEffectsWindow?

It seems that the view hierarchy in iOS6 is somehow changed...

I would appreciate any help. Thanks!

oistanchev
  • 97
  • 1
  • 2

1 Answers1

1

It is likely that is it changed. You are accessing undocumented elements presented in the UI, which is not guaranteed to be consistent across system updates. If you would like to change the appearance of the UI elements presented in the MFMailComposeViewController class, use the IUAppearance API. You are not supposed to access much of the mail controller class.

Important The mail composition interface itself is not customizable and must not be modified by your application. In addition, after presenting the interface, your application is not allowed to make further changes to the email content. The user may still edit the content using the interface, but programmatic changes are ignored. Thus, you must set the values of content fields before presenting the interface.

J2theC
  • 4,412
  • 1
  • 12
  • 14
  • So many of these answers assume you are writing in an App that will be in the App store, and even running on an iPad/iPhone that belongs to the user. Some of us work on internal applications, or even kiosk's, where access to parts of the interface (like recient TO: reciepents) is actually a privacy issue in some countries (eg. France). So, what do we do? We hack the Mail Composer... Or, at least we did. It's now VERY opaque in iOS6. I'd create a topic for this, but I'm sure I'd get 10k thumbs down. -e – eric Nov 28 '12 at 21:43
  • You would probably get more thumbs down, and the reason for this is that your "hack" is doing something without user's consent. You really want to send an email with the user's email account? implement your own mail client, ask the user for the credentials, and send all emails you want to send. – J2theC Nov 29 '12 at 00:23
  • Ah, if only the client would go for that. It was my first, and strongest choice, originally, and the 2 OS upgrades they've paid me to keep re-hacking it... but, in the end, the client is "always right". We'll see, as this is now NOT an option for iOS6, hopefully I'll get that REST call to pass the email they want sent from the Kiosk... I was just trying to point out, many answers make assumptions that maybe shouldn't be made. :-) – eric Nov 29 '12 at 08:17