[Из песочницы] Как позвонить на iOS7 [jailbreak] из приложения?

a75e249279f74ee6b634d37ba78c86f5.pngУ меня появилась задача позвонить с iPhone на iOS7. На предыдущих версиях iOS (6 и ранее) было достаточно воспользоваться private API и все работало, но на iOS7 этот подход перестал работать. В этом посте я хочу рассказать как сделать звонок и получить собственный номер телефона из приложения.

Код проекта на github.

JailbreakПервым делом, что бы все работало необходимо сделать Jailbreak. Для последней версии iOS 7.1.2 он отлично делается с помощью en.pangu.io — jailbreak tool Инструкцию по jalibreak можно посмотреть, например, здесь. Я проделал это с iPhone4, iOS 7.1.2 на Windows 8.1 После того, как сделан jailbreak устанавливаем OpenSSH через Cydia.ee210cd42c894f62918aa2d6e2cd63a1.png

Заходим на iPhone по ssh и меняем пароль для root [default password: alpine]

$ssh root@10.231.65.56 $passwd Телефон готов. Подготовим приложение, которое будет звонить. В приложении мы будем использовать следующие private APIs:

void CTCallListDisconnectAll (); // for ending call header: CTCall.h CTCallRef CTCallDial (CFStringRef number); // for calling header: CTCall.h CFStringRef CTSettingCopyMyPhoneNumber (); // for getting own number header: CTSetting.h Заголовочные файлыCTCall.h, CTSetting.h можно найти в репозитории на GitHubТеперь рассмотрим код, который без проблем работает на iOS 6.1.4 и без jailbreak.

Метод старта звонка  — (IBAction)onPlaceCall:(id)sender {

NSString *numberToCall = [self.tfNumberToCall text];

NSLog (@«Open CoreTelephony»); void *ptrCoreTelephone = dlopen (»/System/Library/Framework/CoreTelephony.framework/CoreTelephony», RTLD_LAZY);

if (ptrCoreTelephone == nil){ NSLog (@«ptrCoreTelephone is nil»); return; }

NSLog (@«Get CTCallDial from CoreTelephony»); int (*pCTCallDial)(NSString*) = dlsym (ptrCoreTelephone, «CTCallDial»);

if (pCTCallDial!= nil) { int error = pCTCallDial (numberToCall); NSLog (@«pCTCallDial error: %d», error); } NSLog (@«Close CoreTelephony»); dlclose (ptrCoreTelephone); } Метод прерывания завонка  — (IBAction)onStopCall:(id)sender { NSLog (@«onStopCall»); void *ptrCoreTelephone = dlopen (»/System/Library/Framework/CoreTelephony.framework/CoreTelephony», RTLD_LAZY);

if (ptrCoreTelephone == nil){ NSLog (@«ptrCoreTelephone is nil»); return; }

NSLog (@«Get CTCallListDisconnectAll from CoreTelephony»); int (*pCTCallListDisconnectAll)() = dlsym (ptrCoreTelephone, «CTCallListDisconnectAll»); if (pCTCallListDisconnectAll!= nil) { int error = pCTCallListDisconnectAll (); NSLog (@«pCTCallListDisconnectAll error: %d», error); } dlclose (ptrCoreTelephone); } Метод получения номера -(NSString*) getMyNumber { NSLog (@«Open CoreTelephony»); void *lib = dlopen (»/Symbols/System/Library/Framework/CoreTelephony.framework/CoreTelephony», RTLD_LAZY); NSLog (@«Get CTSettingCopyMyPhoneNumber from CoreTelephony»); NSString* (*pCTSettingCopyMyPhoneNumber)() = dlsym (lib, «CTSettingCopyMyPhoneNumber»); NSLog (@«Get CTSettingCopyMyPhoneNumber from CoreTelephony»);

if (pCTSettingCopyMyPhoneNumber == nil) { NSLog (@«pCTSettingCopyMyPhoneNumber is nil»); return nil; } NSString* ownPhoneNumber = pCTSettingCopyMyPhoneNumber (); dlclose (lib); return ownPhoneNumber; } Теперь самое интересное. Этот же код будет работать на iOS7 если добавить entitlements приложению и переподписать его с этими entitlements. Для этого нужно проделать следующее.

Собрать приложение без подписи Подготовить и подложить приложение xml файл с entitlements Подписать приложение и положить на телефон Сборка приложения без подписи Для этого нужно в XCode в Build Settings выставить следующее: 64bd5b6473424fd6959edcda9239cce5.pngP

Затем запуситить сборку.

Подготовка xml файла с entitlements Нужно создать файл со следующим содержимым: com.apple.coretelephony.Calls.allow com.apple.coretelephony.Identity.get com.apple.coretelephony.Calls.allow — для звонковcom.apple.coretelephony.Identity.get — для получения номераПоложить его нужно в тоже место, откуда будет запущена команда подписи.

Подпись и установка Для подписи нам понадобиться папка с бинарниками. Понять, куда их кладет XCode, можно запустив команду: $ls -la ~/Library/Developer/Xcode/DerivedData/ | grep JBCall Путь будет примерно таким:

/Users/username/Library/Developer/Xcode/DerivedData/JBCall-cktasembftvbmqaaiiunvljdwocs/Build/Products/Debug-iphoneos/JBCall.app Копируем JBCall.app в отдельную папку, кладем рядом сней entitlements.xml:

JBCall.app entitlements.xml Теперь нужно подписать бинарники следующей командой:

$codesign --sign='iPhone Developer: FirstName SecondName (XXXXXXXX)» --entitlements entitlements.xml JBCall.app iPhone Developer: FirstName SecondName (XXXXXXXX) — название сертификата, котоырй можно посмотреть в keychain.d1976cd5a02d4b8d9a2ea8bcd3d727f6.png

После проделанных действий можно установить приложение и пользоваться. В данном случае установка заключается в копировании папки *.app на iPhone и перезапуск SpringBoard. Я сделал это через scp в скрпте:

DST_DIR='/Applications' APP_NAME='JBCall.app' USER='root' PASSWD='mypass' IP='10.231.65.56' APP_ON_MAC=»/Users/username/Library/Developer/Xcode/DerivedData/JBCall-cktasembftvbmqaaiiunvljdwocs/Build/Products/Debug-iphoneos/JBCall.app» sshpass -p $PASSWD scp -r $APP_NAME $USER@$IP:$DST_DIR В скрипте нужно поменять только значения переременных под себя и можно запускать. Путь тоже нужно обновить:

/Users/username/Library/Developer/Xcode/DerivedData/JBCall-cktasembftvbmqaaiiunvljdwocs/Build/Products/Debug-iphoneos/JBCall.app

Перезапуск SpringBoard:

$sshpass -p $PASSWD ssh $USER@$IP su mobile -c uicache 1>/dev/null 2>&1 Отдельная команда перезапуска с девайса:

$su mobile -c uicache 1>/dev/null 2>&1 Конечно должны быть установлены sshpass и scp.Все описанные действия по установки оформлены в виде скриптаВсе, теперь приложение может звонить, класть трубку, показывать номер телефона.

Скриншоты с iOS 6.1.4 34ef74e0eba3434ca9c06d4e63c04b4b.pngСкриншоты с iOS 7.1.2 134e29d3f1d54d86af5b2f4b96c4a179.pngИтог В итоге мы получили приложение, которое звонит на последней версии iOS с jailbreak. Надеюсь кому-нибудь пригодиться данный опыт.Как я узнал об entitlements? Спасибо ползователю creker на stackoverflow за подсказку о entitlements, которая была им обнаружена в файле:/System/Library/CoreServices/SpringBoard.app/SpringBoardДействительно, взглянув на бинарник можно найти текстовые строки: com.apple.coretelephony.Calls.allowcom.apple.coretelephony.Identity.get

74f2580530d74900b455c8f2a1024378.png

Ссылки

© Habrahabr.ru