Блок смс на ios6

Я строю для сломанного устройства и хочу заблокировать входящие сообщения. Я пытаюсь подключить _ingestIncomingCTMessage, но это не имеет никакого результата (кажется, не работает на ios6). Как еще я могу заблокировать смс в ios6?

3 ответа

Решение

Это довольно сложно. Apple сделала серьезные изменения в этой области. На iOS 5 это очень просто, но на iOS 6 я пока не смог найти простой способ сделать это. Во-первых, вам нужно наблюдать __kIMChatItemsDidChangeNotification уведомление с помощью CTTelephonyCenter. Я делаю это в dylib, введенном в SpringBoard. Не уверен, но это может быть важно.

CTTelephonyCenterAddObserver(CTTelephonyCenterGetDefault(), NULL, Callback, NULL, NULL, CFNotificationSuspensionBehaviourHold);

void Callback(CFNotificationCenterRef, void*, NSString* notification, const void*, NSDictionary* userInfo)
{
    if (![notification isEqualToString:@"__kIMChatItemsDidChangeNotification"])
    {
        return;
    }

    for (IMChatItem* chatItem in userInfo[@"__kIMChatItemsKey"])
    {
        IMMessage* msg = [chatItem message];//Incoming message object
        NSString* text = [[msg text] string];//message text
        NSString* sender = [[msg sender] ID];//message sender

        [[IMDMessageStore sharedInstance] performBlock:^{
            IMDChatRecordDeleteChatForGUID([NSString stringWithFormat:@"SMS;-;%@", sender]);
        }];
    }
}

Последний бит очень важен. Вы не можете просто удалить сообщение. Вам нужно сделать это в определенном внутреннем потоке, иначе вы получите ошибку. Вот почему я использую IMDMessageStore, Это performBlock: Метод выполняет блок в этом специальном потоке. IMDChatRecordDeleteChatForGUID Функция может быть найдена в IMDPersistence.framework. Удаляет все дерево сообщений (чат / разговор) с определенным GUID. Я не смог найти способ получить этот GUID, поэтому я создаю его вручную, используя GUID из базы данных SMS sqlite в качестве примера.

Чтобы удалить только одно сообщение, вы можете использовать IMDMessageRecordDeleteMessagesForGUIDs([NSArray arrayWithObject:[msg guid]]);

IMChatItem а также IMMessage можно найти в IMCore.framework, IMDMessageStore в IMDaemonCore.framework,

Это легкая часть. Теперь, когда вы получите сообщение и заблокируете его таким образом, вы увидите, что оно по-прежнему отображается в приложении MobileSMS, вы все равно можете получить уведомление о буллине, вы все равно получите значок, сообщающий, что есть непрочитанное сообщение. Но если вы откроете базу данных SMS sqlite, вы увидите, что сообщение действительно было удалено. Блокировать их не так просто.

  1. Bullein. В SpringBoard вам нужно подключить BBServer метод publishBulletin:destinations:alwaysOnLockScreen:, Первый аргумент - объект BBBulletin. Если это входящее сообщение, это section собственность равняется com.apple.MobileSMS, Чтобы заблокировать бюллетень, просто вернитесь из этого метода и не вызывайте оригинальную реализацию.
  2. Значок приложения MobileSMS. Существует ChatKit.serviceBundle, который загружается в SpringBoard при поступлении входящих SMS. Вам нужно подключить два метода в MessagesBadgeController - _madridChatRegistered: а также _madridUnreadCountChanged:, Их первый аргумент NSNotification объект с object свойство, содержащее IMChat объект. Опять же, просто вернитесь из этих методов, чтобы предотвратить изменения значка.
  3. Приложение MobileSMS. Чтобы не показывать уже удаленные сообщения, я подключаю довольно много методов. Я просто дам вам список:SMSApplication _receivedMessage:, CKTranscriptController _messageReceived:, CKConversationList _handleRegistryDidRegisterChatNotification:, _handleRegistryDidLoadChatNotification:, hasActiveConversations, unreadCount, CKConversationController _chatParticipantsChangedNotification:, updateConversationList, CKMessagesController showConversation:animate:forceToTranscript:

О ChatKit.serviceBundle. Чтобы перехватить его классы, вам нужно подождать, когда SpringBoard действительно загрузит его. Это сделано в SBPluginManager loadPluginBundle:, Идентификатор пакета должен быть равен com.apple.SMSPlugin, Только тогда вы можете подключить методы.

Вот и все. Довольно много работы, но она работает отлично - никаких признаков входящего сообщения, даже если вы были в приложении MobileSMS, когда пришло сообщение.

Я уверен, что есть более простой способ сделать это. Существует демон com.apple.imagent, который отправляет уведомления различным компонентам iOS. Это очень важно в системе обмена сообщениями iOS 6. Хорошее место для начала.

Нашел гораздо лучше и проще. Как я и думал com.apple.imagent демон очень важен, и именно он управляет kCTMessageReceivedNotification, Вот почему мы получаем пустой объект сообщения при обработке kCTMessageReceivedNotification сам - com.apple.imagent удаляет его из CTMessageCenter,

Нам нужно подключить только два метода, но найти и подключить их довольно сложно. Оба метода подключены com.apple.imagent демон.

Первый, SMSServiceSession -(void)_processReceivedMessage:(CTMessage*)msg, Здесь исходное сообщение обрабатывается, сохраняется в базе данных SMS и передается всем остальным компонентам iOS. Проблема в том, что нигде нет информации об этом API. com.apple.imagent кажется, что не использует его, если вы разберете его. Это потому, что он загружается вручную во время выполнения.

когда com.apple.imagent запущен он загружает несколько плагинов. Тот, который нам нужен, находится в /System/Library/Messages/PlugIns/SMS.imservice/ - это где SMSServiceSession реализовано. Вы не найдете там двоичного файла, потому что, как и все фреймворки, в которые он скомпилирован /System/Library/Caches/com.apple.dyld/dyld_shared_cache_armv7, IDA распознает этот файл и позволяет вам выбрать, какой двоичный файл внутри него вы хотите разобрать.

Для удаления входящего сообщения и предотвращения любых уведомлений о нем необходимо позвонить [[CTMessageCenter sharedMessageCenter] acknowledgeIncomingMessageWithId:[msg messageId]] и вернуться из _processReceivedMessage: без вызова оригинальной реализации. призвание CTMessageCenter Метод важен, потому что он ставит в очередь входящие сообщения.

Теперь нам нужно найти способ узнать, когдаSMS.imservice плагин на самом деле загружается. Первоначально Imagent только создает NSBundle объекты без загрузки какого-либо кода. Таким образом, вы не можете подключить какие-либо методы, потому что классы еще не загружены из плагинов. Чтобы решить это, мы можем подключить IMDService -(void)loadServiceBundle метод из частного IMDaemonCore.framework, Вызовите оригинальную реализацию, и вы можете подключить методы внутри плагина. Чтобы определить, какой плагин загружается, вы можете проверить идентификатор пакета в IMDService -(NSBundle*)bundle,

Этот метод работает только с SMS и MMS сообщениями. iMessages обрабатываются аналогичным образом, но с другим плагином - /System/Library/Messages/PlugIns/iMessage.imservice, Зацепление MessageServiceSession -(void)_handler:(id) incomingMessage:(id) encryptionType:(id) messageID:(id) fromIdentifier:(id) fromToken:(id) timeStamp:(id) storageContext:(id) allowRetry:(char) completionBlock:(id) должен сделать свое дело.

ОБНОВИТЬ

Работает на iOS 7

ОБНОВЛЕНИЕ 2

На iOS 8 все работает одинаково, за исключением того, что нужно подключать разные SMSServiceSession метод - -(void)_processReceivedDictionary:(NSDictionary*)msg, Словарь будет содержать все содержимое SMS-сообщения.

Если вы не хотите переписывать все для iOS 8, вы можете использовать старый код. Входящее SMS-уведомление обрабатывается скрытой неэкспортированной функцией обратного вызова C - вы не можете перехватить ее. Во-первых, это вызывает SMSServiceSession -(id)_convertCTMessageToDictionary:(CTMessage*)msg requiresUpload:(BOOL*)upload преобразовать объект SMS-сообщения в словарь. Тогда это вызывает SMSServiceSession -(void)_processReceivedDictionary:(NSDictionary*)msg обработать сообщение. Наконец, это вызывает SMSServiceSession -(BOOL)relayDictionaryToPeers:(NSDictionary*)msg requiresUpload:(BOOL)upload уведомить все другие компоненты iOS о входящем сообщении.

Чтобы заблокировать смс нужно подключить _convertCTMessageToDictionary где вы можете использовать тот же код, который вы использовали в предыдущих версиях iOS. Вам также нужно подключить оба _processReceivedDictionary а также relayDictionaryToPeers фактически заблокировать входящее сообщение. Просто вернитесь от них, не вызывая оригинальную реализацию. Вы можете установить некоторую глобальную переменную в _convertCTMessageToDictionary и проверить и сбросить его другими способами. Это совершенно безопасно, так как эти методы вызываются синхронно. Эта функция обратного вызова C является единственным местом, где эти методы вызываются.

У меня есть лучшее решение, чтобы заблокировать все SMS-сообщения

%hook CKConversationListController

- (void)viewDidLoad
{
    %orig;

    CKConversationList *list = MSHookIvar<CKConversationList *>(self, "_conversationList");

    if ([list count]) {
        [deleteAll release];
    }
}

%new
- (void)deleteAll:(id)sender {

    CKConversationList *list = MSHookIvar<CKConversationList *>(self, "_conversationList");
    UITableView *messages = MSHookIvar<UITableView *>(self, "_table");

    for (unsigned int i = 0; i < [[list conversations] count]; i++) {
        [list deleteConversationAtIndex:i];
    }

    [messages reloadData];
}
%end
Другие вопросы по тегам