I am using a iOS 6 iphone 4S and I want to be able to send the unnoticed sms messages.
So using the standard view controller won't work in this case.
I tried using
- (BOOL)sendSMSWithText:(id)arg1 serviceCenter:(id)arg2 toAddress:(id)arg3;
but it doesn't send anything and returns NO. I used nil for arg2.
Can someone suggest a way to do it on iOS 6?(for jailbroken devices)
Found out why - (BOOL)sendSMSWithText:(id)arg1 serviceCenter:(id)arg2 toAddress:(id)arg3; is not working since iOS 6.
This API is protected by the entitlement com.apple.CommCenter.Messages-send. Just sign your app with this entitlement set to true. It's much better than my another answer here (XPC method) because of the two main reasons:
sendSMSWithText tells you whethere message was sent successfully
Messages sent using sendSMSWithText are not being saved in the SMS database and can't be seen anywhere. On the other hand, messages sent using XPC method are being saved in SMS database and can be seen in Messages application.
So, win win. I strongly suggest dropping XPC method also because it's using pretty low level API that can change easily in new iOS version. sendSMSWithText can be found even in iOS 7 and I don't think it will be dropped any time soon.
UPDATE
In order to use this API on iOS 7 and above you need to add another entitlement with bool value set to true - com.apple.coretelephony.Identity.get.
Straight from ChatKit.framework
dispatch_queue_t queue = dispatch_queue_create("com.apple.chatkit.clientcomposeserver.xpc_connection_queue", DISPATCH_QUEUE_SERIAL);
xpc_connection_t connection = xpc_connection_create_mach_service("com.apple.chatkit.clientcomposeserver.xpc", queue, 0);
xpc_connection_set_event_handler(connection, ^(xpc_object_t){});
xpc_connection_resume(connection);
dispatch_release(queue);
xpc_object_t dictionary = xpc_dictionary_create(0, 0, 0);
xpc_dictionary_set_int64(dictionary, "message-type", 0);
NSData* recipients = [NSPropertyListSerialization dataWithPropertyList:[NSArray arrayWithObject:#"12212"] format:NSPropertyListBinaryFormat_v1_0 options:0 error:NULL];
xpc_dictionary_set_data(dictionary, "recipients", recipients.bytes, recipients.length);
xpc_dictionary_set_string(dictionary, "markup", "SMS text");
xpc_connection_send_message(connection, dictionary);
xpc_release(dictionary);
recipients holds serialized property list with array of phone numbers to which you want to send your SMS - 12212 is just an example of phone number. Instead of SMS text you should put actual SMS text. Unfortunately, I couldn't find a way to check whether SMS was sent successfully.
To send message using this code your application entitlements should have com.apple.messages.composeclient key with boolean value set to true. Otherwise you get error in console saying application lacks entitlement.
Related
I am new to iOS and I'm facing an issue with the SMS and Call spam reporting extension for iOS 14.6. I've implemented the extension and when I select one or more messages and click the button to report the sender, the sender's phone number is getting reported, but with a string appended to its number. For example:
example screenshot
The numbers that should be displayed are "orange" and "+40 753878811", but instead "filtered" is appended to every number. In this case, the numbers are not actually blocked and I am still able to receive messages and calls from them.
Any meaningful piece of code that I use is in the classificationResponse method:
override func classificationResponse(for request:ILClassificationRequest) -> ILClassificationResponse {
return ILClassificationResponse(action: .reportJunkAndBlockSender)
}
Basically, what I'm trying to do is to block any user that I click on, either from the messages app or from the contacts.
Does anybody know why is this happening?
Thank you in advance for your help!
I'm setting up registrations for notifications of iCloud changes.
Say a new device is added to the icloud account, I'm just wondering how that device will get the private database records.
Do I need to do a one off query?
I'm hoping that notifications will be used at all other times.
Let's start with some relevant characteristics of subscription notifications:
First: Subscription Notifications are specific to a user + device pair. If I install you app on my phone, I start getting notifications. I won't get the notifications on another device until I install the app there, too.
Second: Notifications are unreliable. Apple docs are quite clear that they do not guarantee delivery. When you receive a notification, there could have been several prior notifications. Thus, Apple offer's two mechanisms to track which notifications you've seen:
Read/unread status: you can mark notifs as read. Apple's docs contradict themselves about what this actually does. This page says
If you mark one or more notifications as read using a CKMarkNotificationsReadOperation object, those notifications are not returned, even if you specify nil for previousServerChangeToken.
However, this isn't true. The fetch operation clearly returns both read and unread notifications. WWDC 2014 Video 231 (Advanced Cloudkit) contradicts the documentation page, explaining that unread tokens are always returned as well as read tokens so multiple devices can sync up. The video gives a specific example that shows the benefits of this behavior. This behavior is also documented on SO: CKFetchNotificationChangesOperation returning old notifications
change token: each fetch operation will return a change token that you can cache. If you pass the token to a fetch, the fetch will only return tokens from that point, whether read or unread.
At first glance, it would seem that Apple is providing for the behavior you want: install the app on one device, start processing notifications, install the app on a second device, and fetch all those prior notifications in order to catch up.
Unfortunately, as I've documented in CKFetchNotificationChangesOperation: why are READ notifications all nil?, any time I fetch notifications, the ones previously marked as "read" all have nil contents. All the info in the read notifications is lost.
In my scenario, I chose to:
Always fetch the latest record(s) at startup
Fetch notifications using the previously saved change token (if it exists)
Process the new notifications
Mark the notifications as read
save the latest change token for use on the next fetch
For your scenario, you could try:
Fetch notifications using the previously saved change token (if it exists)
process the notifications (DO NOT MARK THEM AS READ)
save the latest change token for use on the next fetch
Your first device will ignore old notifications on each subsequent fetch because you're starting each fetch from the change token point. Your second device will start with a nil change token on the first execution, and thus pick up all of the old notifications.
One word of caution: even though aforementioned WWDC video clearly says Apple keeps all the old notifications, I have found no documentation that says how long they hold this info. It may be forever, it may not.
updated with notification fetch example
Here's how I'm fetching notifications, marking them read, and caching the change token:
#property CKServerChangeToken *notificationServerChangeToken;
Then...
-(void)checkForUnreadNotifications
{
//check for unread cloudkit messages
CKFetchNotificationChangesOperation *op = [[CKFetchNotificationChangesOperation alloc] initWithPreviousServerChangeToken:_notificationServerChangeToken];
op.notificationChangedBlock = ^(CKNotification *notification)
{
//this fires for each received notification. Take action as needed.
};
//maintain a pointer to the op. We will need to look at a property on the
//op from within the completion block. Use __weak to prevent retain problems
__weak CKFetchNotificationChangesOperation *operationLocal = op;
op.fetchNotificationChangesCompletionBlock = ^(CKServerChangeToken *newServerChangeToken, NSError *opError)
{
//this fires once, at the end, after all notifications have been returned.
//this is where I mark the notifications as read, for example. I've
//omitted that step because it probably doesn't fit your scenario.
//update the change token so we know where we left off
[self setNotificationServerChangeToken:newServerChangeToken];
if (operationLocal.moreComing)
{
//more notifications are waiting, recursively keep reading
[self checkForUnreadNotifications];
return;
}
};
[[CKContainer defaultContainer] addOperation:op];
}
To set and retrieve the cached change token from the user defaults, I use the following two functions:
-(void)setNotificationServerChangeToken:(CKServerChangeToken *)newServerChangeToken
{
//update the change token so we know where we left off
_notificationServerChangeToken = newServerChangeToken;
NSData *encodedServerChangeToken = [NSKeyedArchiver archivedDataWithRootObject:newServerChangeToken];
NSUserDefaults *userSettings = [NSUserDefaults standardUserDefaults];
[userSettings setObject:encodedServerChangeToken forKey:UD_KEY_NOTIFICATION_TOKEN_CKSERVERCHANGETOKEN_PROD];
//Note, the development and production cloudkit environments have separate change tokens. Depending on your needs, you may need to save both.
}
and...
-(void)getNotificationServerChangeToken
{
NSUserDefaults *userSettings = [NSUserDefaults standardUserDefaults];
NSData *encodedServerChangeToken = [userSettings objectForKey:UD_KEY_NOTIFICATION_TOKEN_CKSERVERCHANGETOKEN_PROD];
_notificationServerChangeToken = [NSKeyedUnarchiver unarchiveObjectWithData:encodedServerChangeToken];
}
Trigger.io provides a forge.notification.setBadgeNumber method to set the ios badge number. Is it possible to retrieve the badge number with trigger.io?
My use case is that I have a messaging system where the badge number is the number of unread message - I want to decrease the badge number when the user reads a message. To do that, I need to know the current badge number...
Suggestion on better ways to implement this will also be appreciated.
You could easily write your own native module to get the current badge count in Trigger.io apps. I have one in use and the relevant function looks like this:
+ (void)getBadgeNumber:(ForgeTask*)task {
NSNumber *count = [NSNumber numberWithInt:[[UIApplication sharedApplication] applicationIconBadgeNumber]];
[task success:count];
}
UPDATE:
It seems like Trigger.io added the getBadgeNumber call to their notifications module. Available methods are:
forge.notification.setBadgeNumber(number, success, error)
forge.notification.getBadgeNumber(success, error)
If you're using the Parse module for push notifications you can even retrieve and set the badge number on the Parse server as of now.
is it possible to intercept outgoing SMS messages on a jailbroken iOS 6 device? What I want to do is reroute SMS messages via a free service, but still "reuse" the entire Messages.app UI.
I have seen some info about intercepting SMS on iOS, but they all talk about incoming messages, not outgoing messages.
First, you need to inject your code in MobileSMS application.
Now you can hook -send: method in CKTranscriptController. This method is called when you press "Send" button in MobileSMS. It's argument doesn't contain any information about message being sent so we need to find it manually:
1) Text and subject. CKTranscriptController has instance variable CKMessageEntryView *_entryView.
CKContentEntryView *contentEntryView = [_entryView entryField];
CKMessageStandaloneComposition *composition = [contentEntryView messageComposition];
NSString* subject = [composition subject];
NSString* text = [composition textString];
2) Recipients. CKTranscriptController has instance variable CKRecipientSelectionView *_recipientSelectionView. It's -recipients method returns array of MFComposeRecipient objects. Call MFComposeRecipient instance method -rawAddress to get address string.
Most of the classes can be found in private ChatKit.framework. MFComposeRecipient located in private 'MessageUI.framework'.
I have an RFID scanner attached to a RedPark serial cable connected to an iPad app. When people scan their RFID cards, I get a callback with -readBytesAvailable:. However, sometimes it doesn't give me the entire RFID in one call. Sometimes it send it in two calls.
How can I determine if I've received everything? When my code takes the first callback's data and tries to use it, I get an error, because let's say the RFID was "123456789" sometimes I'll get one call with #"12" and a second call with #"3456789". So I try to process #"12" and get a user not found error, then I try to process #"3456789" and get a user not found error.
How can I tell if I'm done reading data? The lengths of the RFIDs can vary from vendor to vendor, so I can't just assume I need to read a certain number of digits.
This is the method I use to receive the data from the scanner through the RedPark:
- (void) readBytesAvailable:(UInt32)length {
NSLog(#"readBytesAvailable: %lu", length);
UInt8 rxLoopBuff[LOOPBACK_TEST_LEN];
[self.rfidManager read:rxLoopBuff Length:length];
NSString *rfid = [[NSString alloc] initWithBytes:rxLoopBuff length:length encoding:NSUTF8StringEncoding];
NSLog(#"rfid=%#", rfid);
[self receivedScanOfRFID:rfid];
}
Serial port gives you no control over packetization. Data is just a stream of bytes with no way to predict which bytes appear in each read call. You have to parse the data stream itself to interpret the contents and understand start/end of your messages. You either need to look for a reliable terminating character or potentially use a timeout approach where you do multiple reads until you get no more data for some period of time. I don't recommend the timeout approach.