Блок смс на 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, вы увидите, что сообщение действительно было удалено. Блокировать их не так просто.
- Bullein. В SpringBoard вам нужно подключить
BBServer
методpublishBulletin:destinations:alwaysOnLockScreen:
, Первый аргумент - объект BBBulletin. Если это входящее сообщение, этоsection
собственность равняетсяcom.apple.MobileSMS
, Чтобы заблокировать бюллетень, просто вернитесь из этого метода и не вызывайте оригинальную реализацию. - Значок приложения MobileSMS. Существует ChatKit.serviceBundle, который загружается в SpringBoard при поступлении входящих SMS. Вам нужно подключить два метода в
MessagesBadgeController
-_madridChatRegistered:
а также_madridUnreadCountChanged:
, Их первый аргументNSNotification
объект сobject
свойство, содержащееIMChat
объект. Опять же, просто вернитесь из этих методов, чтобы предотвратить изменения значка. - Приложение 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