Theos пишемо твік для iOS SpringBoard
Доброго скороноворічного вечора шановним хабралюдям!
Сьогодні я розповім про створення твіка для iOS SpringBoard за допомогою theos. Навіщо? Як цікавий рисерч і тренування. Наприкінці туторіалу ми отримаємо приблизно таку штуку прямо на екрані блокування нашого i-девайсу:

Створення проекту та налаштування theos
Починаємо: створюємо порожню папку, в неї кидаємо теос (я кинув у вигляді гітового сабмодуля).
Далі, створюємо новий проект за допомогою NIC:
Тепер у нас є папка ihabrtweak, в якій лежать потрібні нам файли.
Тепер запускаємо make та бачимо помилки: не все так просто! Наша система не повністю готова до випробування на theos.
Що ж, треба вводити налаштування, необхідні для нормального збирання:
ARCHS нам вказує, що збиратимемо тільки для armv7, а на armv6 заб'ємо. TARGET нам вказує, що збиратимемо для iOS з використанням останнього (в системі) SDK та сумісністю з версією 4.3. Інші три самоочевидні.
Тепер у нас є наша чудова динамічна бібліотека, яка поки що зовсім нічого не вміє робити! Зате ми можемо встановити наш твік на девайс:
Власне, твік готовий! Ставиться, але нічого не робить. Будемо це правити. Почнемо з теорії theos-а та його твиків. Як ви вже помітили, у проекті ми маємо файл Tweak.xm, який є нашим головним вихідником.
%hook та %end
Основа твиків у theos – хуки. Вони засновані на найбагатшому рантаймі мови Objective-C, що дозволяє заміну методів у довільного класу. Власне, використовується це так:
Тут Ми впроваджуємо (підміняємо) метод "someMethod" у класу "SomeClass". Наприклад, ми можемо впроваджувати наш код у SpringBoard, наприклад, можемо додавати свої юшки наекран блокування.
%orig та %new
Що ж, метод ми перевизначили, ну а як викликати оригінальний? Та також дуже просто! І тому є макрос %orig. Будучи викликаним без параметрів, цей макрос перенаправляє функції-оригіналу самі параметри, що й прийшли в наш хук. Але можна і передати будь-які свої:
Якщо прості визначення методів усередині хуків перевизначає вже існуючі, то додавання нових методів можна використовувати макрос %new. По суті, це роздільник між методами, які ми підмінюємо, та методами, які ми додаємо. Всі методи, що йдуть після %new, будуть додані. Приклад:
Але з таким підходом ми не зможемо викликати наш новий метод із перевизначеного: theos трактує ворнінги як помилки та не дасть зібрати проект. Адже ми нашого методу не оголосили! Але це можна виправити, просто додамо ось це в наш файлик:
Макрос %log дозволяє записати у системний лог факт виклику функції. Зазвичай використовується для налагодження.
Інші макроси можна побачити тут.
Пишемо щось корисне
У комплекті до theos-у ми отримуємо хедери системних фреймворків. У нашому проекті вони лежать у theos/include. Якщо ж не лежать, не забуваємо зробити так:
Там знаходимо папку SpringBoard, а в ній купу хедерів. Що ж, пройдемося за іменами класів. Зауважимо цікавий клас SBAwayView, який якраз і є основною юшкою екрану блокування. Що ж, ставитимемо хуки саме в нього. Для початку треба зловити момент його створення:
Можемо поставити %log та переконатися після складання-установки, що цей метод дійсно викликається. Тепер ми можемо додавати нові юшки! Тільки куди? Давайте їх додаватимемо на фонову картинку. Знаходимо ivar UIImageView *_backgroundView у класу SBSlidingAlertDisplay, від якого успадковуєтьсяSBAwayView, там же знаходимо метод -(CGRect)middleFrame; . Але як нам отримати значення ivar? Погуглим. Знайдемо функцію MSHookIvar, яка все й зробить:
Запускаємо та насолоджуємося видовищем!

Картинку треба покласти в бандл SpringBoard.app, а краще, якщо картинка туди сама скопіюється під час установки пакета. Для цього ми реорганізуємо структуру проекту: створимо папку Layout, в ній - папку DEBIAN, куди перемістимо вже наявний файл control, поряд з папкою DEBIAN зробимо System/Library/CoreServices/SpringBoard.app, куди і помістимо нашу картинку:
Тепер можна і написати фінальний новорічний код:
І - милуємося на красу, що вийшла:
Повний вихідник, як завжди, прошу брати на гітхабі.
Усіх з наступаючим! Радості та удач у наступному році! =)