Динамический Mocking iOS Динамический тип Размер текста системы (UIContentSizeCategory)

Я бы хотел легко проверить свое приложение с различными вариантами размера системного текста, включая размеры доступности. Их можно установить в приложении "Настройки" ( "Экран" и "Яркость" > "Размер текста" или "Общий" > "Доступность" > "Большой текст" ).

Единственный способ, который я могу найти в настоящее время, - это перейти в Настройки и изменить значение с помощью пользовательского интерфейса (edit: частичное решение, описанного ниже). Это медленный и громоздкий. Я подозреваю, что есть способ динамически изменить его с помощью частных API, но я не могу понять, как это сделать. Поскольку моя цель состоит в том, чтобы использовать это только для отладки, использование частного API и swizzling прекрасное (этот код не будет работать).

Чтобы попытаться найти частный API для этого, я посмотрел на некоторые обратные инженерные ресурсы. Я новичок в дизассемблерах, таблицах символов, дампах классов и поиске частных API, которые я могу использовать, но это то, что я пробовал до сих пор:

  • Я успешно swizzled -[UIApplication preferredContentSizeCategory] (другие сообщения говорили, что это сработало в прошлом), но это не влияет на результат, возвращаемый с +[UIFont preferredFontForTextStyle:].

  • Использование дизассемблера IDA Я обнаружил, что +[UIFont preferredFontForTextStyle:] находится в частной структуре UIFoundation.framework. (-[UIApplication preferredContentSizeCategory] находится в UIKit.framework, но разборка не выглядела бесполезной).

  • Так же, как я начал писать этот вопрос (так всегда бывает), я обнаружил частичное решение . Можно задать параметр запуска в схеме, чтобы установить значение при запуске. Это полезно, но не то, что мне нужно.

  • В приведенном выше ответе я нашел значение для предпочтения пользователя, по-видимому, хранится в "файле com.apple.UIKit.plist, расположенном в каталоге Simulator data/Library/Preferences". Значение, которое мы получаем, можно установить из утилиты командной строки plutil. Это тоже улучшение! Но я бы хотел динамически изменить его во время выполнения.

Подробнее о моих результатах от IDA:

Я действительно не знаю, как читать разборку, но +[UIFont preferredFontForTextStyle:], кажется, указывает на символ с именем ___UIFontForTextStyle, который, как представляется, указывает на некоторые интересные звуковые символы, называемые _getUIContentSizeCategoryUnspecified и _getUIContentSizeCategoryPreferenceClass

Разборка для <code> ___ UIFontForTextStyle </code>

Я также нашел эти символы, используя утилиту командной строки nm в UIFoundation.framework. Они были отмечены строчной буквой "s", что означает, по-видимому, "Символ находится в неинициализированной секции данных для небольших объектов" .. Я понятия не имею, что это значит (все, что я собрал, это то, что они не являются классом или методом).

Поиск в Интернете для символов _getUIContentSizeCategory... ничего не дает, но рядом с ним есть еще один символ _getUIApplicationClass. Я искал это, так как это звучало немного более общее, и нашел нечто похожее в некотором источнике WebKit. Не может быть ничего, но, возможно, это внутреннее соглашение Apple. Несмотря на это, этот пример не помогает мне решить проблему.

В любом случае спасибо за чтение до сих пор. Если вы все еще здесь, мой вопрос:

Я хотел бы иметь возможность динамически оценивать значение для предпочтения размера динамического типа. Эти символы разборки могут помочь, но, возможно, я ошибаюсь. Похоже, что решение близко, но я просто не могу собрать все части.

Установка этого значения в качестве аргумента запуска хороша, но не полностью решает мою проблему. Аналогично, изменение значения Simulator в plist также хорошо для автоматизации, но не решает мою проблему.

Есть ли способ динамически изменять это значение во время выполнения?

Ответ 1

Как смущающе! Я смотрел какую-то устаревшую документацию iOS 9.x и пропустил этот UITraitCollection полученный init(preferredContentSizeCategory: UIContentSizeCategory) и var preferredContentSizeCategory: UIContentSizeCategory в iOS 10, который мне был полезен Брэндон Уильямс. Это прекрасно удовлетворяет мои потребности.

Ответ 2

Один простой способ - написать обертку вокруг UIFontMetrics и UIContentSizeCategoryDidChange через UIContentSizeCategoryDidChange все уведомления UIContentSizeCategoryDidChange. Это позволяет для модульного/пользовательского интерфейса тестировать различные настройки динамического типа. Я написал об этом здесь.