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

от автора

У меня появилась задача позвонить с 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.

Заходим на 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 выставить следующее:

P

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

Подготовка xml файла с entitlements

Нужно создать файл со следующим содержимым:

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0">     <dict>         <key>com.apple.coretelephony.Calls.allow</key>         <true/>         <key>com.apple.coretelephony.Identity.get</key>         <true/>     </dict> </plist> 

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.

После проделанных действий можно установить приложение и пользоваться. В данном случае установка заключается в копировании папки *.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

Скриншоты с iOS 7.1.2

Итог

В итоге мы получили приложение, которое звонит на последней версии iOS с jailbreak. Надеюсь кому-нибудь пригодиться данный опыт.

Как я узнал об entitlements?

Спасибо ползователю creker на stackoverflow за подсказку о entitlements, которая была им обнаружена в файле:
/System/Library/CoreServices/SpringBoard.app/SpringBoard

Действительно, взглянув на бинарник можно найти текстовые строки:
com.apple.coretelephony.Calls.allow
com.apple.coretelephony.Identity.get

Ссылки

ссылка на оригинал статьи http://habrahabr.ru/post/233295/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *