Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically Mocking iOS Dynamic Type System Text Size (UIContentSizeCategory)

I'd like to easily test my app with different selections of system text size, including accessibility sizes. These can be set in the Settings app (Display & Brightness => Text Size or General => Accessibility => Larger Text).

The only way I can find to currently do this is to go into Settings and change the value with the UI (edit: partial solution described below). This is slow and cumbersome. I suspect there's a way to dynamically alter it using private APIs, but I can't figure out how. Since my goal is to only use this for debugging, private API use and swizzling is fine (this code won't be making its way to production).

To try to find a private API to do this, I looked at some reverse engineering resources. I'm new to disassemblers, symbol tables, class dumps, and finding private APIs I can use, but this is what I've tried so far:

  • I successfully swizzled -[UIApplication preferredContentSizeCategory] (other posts said this worked in the past), but this doesn't affect the result returned from +[UIFont preferredFontForTextStyle:].

  • Using the disassembler IDA I discovered that +[UIFont preferredFontForTextStyle:] is in the private framework UIFoundation.framework. (-[UIApplication preferredContentSizeCategory] is in UIKit.framework but the disassembly didn't look at all useful).

  • Just as I started writing this question (it always happens that way), I discovered a partial solution. One can set a launch argument in the scheme to set the value on launch. This is useful, but not what I'm after.

  • Through the above answer, I found the value for the user's preference is apparently stored in "the com.apple.UIKit.plist file located in the Simulator's data/Library/Preferences directory". The value we're after can be set from the command line utility plutil. This is also an improvement! But I'd like to dynamically alter it at runtime.

More on my results from IDA:

I don't really know how to read disassembly, but +[UIFont preferredFontForTextStyle:] seems to point to a symbol called ___UIFontForTextStyle which seems to point to some interesting-sounding symbols called _getUIContentSizeCategoryUnspecified and _getUIContentSizeCategoryPreferenceClass

Disassembly for <code>___UIFontForTextStyle</code>

I also found these symbols using the command-line utility nm on UIFoundation.framework. They were marked with the lowercase letter "s" meaning, apparently, "The symbol is in an uninitialized data section for small objects.". I have no idea what this means (all I've gathered is that they're not a class or method).

Searching the web for the _getUIContentSizeCategory... symbols yields nothing, but nearby there's another symbol _getUIApplicationClass. I searched for that one since it sounded a bit more general, and found something similar in some WebKit source. Could be nothing, but maybe it's an internal Apple convention. Regardless, the example doesn't really help me solve the problem.

Anyway thanks for reading so far. If you're still here, my question is:

I'd like to be able to dynamically mock the value for the dynamic type size preference. These disassembly symbols might help, but maybe I'm on the wrong track. It feels like the solution is close but I just can't put all the pieces together.

Setting this value as a launch argument is nice, but doesn't fully solve my problem. Similarly, modifying the Simulator's value in the plist is also nice for automation, but doesn't solve my problem.

Is there a way to dynamically alter this value at runtime?

like image 737
Tim Arnold Avatar asked May 09 '17 20:05

Tim Arnold


Video Answer


1 Answers

How embarrassing! I was looking at some out-of-date iOS 9.x documentation and missed that UITraitCollection gained init(preferredContentSizeCategory: UIContentSizeCategory) and var preferredContentSizeCategory: UIContentSizeCategory in iOS 10, which was helpfully pointed out to me by Brandon Williams. This addresses my needs perfectly.

like image 175
Tim Arnold Avatar answered Oct 02 '22 20:10

Tim Arnold