I am developing an application in which i need to send 100+ of messages. After going through few threads i came to know there is limitation on sending messages like 100 messages can be send in an hour. To do so i divide my recipient list into chunks and place delay of 5 seconds between each chunk and 3 seconds delay in every message. The delay between chunks increase after every chunk and when it gets to 100 seconds it will reset to 5 seconds. After that it worked OK for 50 messages but when i raise recipient list it causing issues some messages didn't go at first place and shown as error messages in native.
Is there any standard way to achieve this i may need to send 100+ messages , how can i send multiple messages without any failure at once. If i need to place delay what should be the appropriate delay between chunks or messages.
Thanks in advance.
private final int MAX_SMS_IN_ONE_TIME = 10;
private final int DELAY_BETWEEN_CHUNKS = 5000;
public void sendMessage(arguments){
// Send long messages in chunk of 20 messages and put gap of increasing 5 seconds till 50 seconds and then reset.
final Iterator iterator = messageChunks.iterator();
new Thread(new Runnable() {
#Override
public void run(){
int interval =1;
while (iterator.hasNext()) {
for (final Contact contact :
(List<Contact>) iterator.next()) {
sendSMS(body, contact.getmMobileNumbers().get(0));
App.trackEvent("Message", "Sent", "Messages from our sms app");
}
}
try {
Log.i("chunk", "chunk # " + interval + " delay is " + DELAY_BETWEEN_CHUNKS);
Thread.sleep(DELAY_BETWEEN_CHUNKS * interval);
interval++;
if (interval == 10) {
interval = 1;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
public void sendSMS(final String message, final String phoneNo) {
try {
String SENT = "com.ebryx.smscustommessagegeneration"+""+System.currentTimeMillis()+""+((int)this.getmMessageId());
Intent intentMessageASendStatus = new Intent(SENT);
final PendingIntent pi = PendingIntent.getBroadcast(App.getContext(), ((int)this.getmMessageId()),
intentMessageASendStatus, PendingIntent.FLAG_CANCEL_CURRENT);
final ArrayList<PendingIntent> sentPI = new ArrayList<PendingIntent>(){{add(pi);}};
App.getContext().registerReceiver(new BroadcastReceiver(){
#Override
public void onReceive(Context arg0, Intent arg1) {
switch (getResultCode())
{
case Activity.RESULT_OK:
Log.i("tag","sent successfully ");
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
Log.i("tag","Generic Failure");
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
Log.i("tag","No service failure");
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
Log.i("tag","Airplane mode failure");
break;
}
}
}, new IntentFilter(SENT));
final SmsManager smsManager = SmsManager.getDefault();
final ArrayList<String> parts = smsManager.divideMessage(message);
new Timer().schedule(new TimerTask() {
#Override
public void run() {
smsManager.sendMultipartTextMessage(phoneNo, null, parts, sentPI, null);
}}, 3000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
There appears to be no official documentation for SMS send limits, from what I could find and the following site either.
Unfortunately there appears to be no public documentation from
Google’s Android development team on the issue.
This is from May 17, 2017
The only figures on sms limits I've been able to find are from Commonsware's site:
SMS Sending Limitations
Apps running on Android 1.x and 2.x devices are limited to sending 100 SMS messages an hour, before the
user starts getting prompted with each SMS message request to confirm
that they do indeed wish to send it.
Apps running on Android 4.x devices, the limits are now 30 SMS
messages in 30 minutes .../...
There appears to be no way around increasing that limit without rooting the phone. Where you need to change the following settings. The following will allow 1000 SMS to be sent per 180000ms == 30 minutes.
SMS_OUTGOING_CHECK_MAX_COUNT 1000
SMS_OUTGOING_CHECK_INTERVAL_MS 1800000
The usual (frustrating) Android issues with varying performance across devices also applies. One phone may perform at a different level to another.
This company has determined the maximum SMS capacities for some handsets with their product. SMS sending limits with FrontlineSync and Android. They also advise that rooting the phone may be needed to increase limits.
Related resources:
Check android package SMS limit?
is there a limit to the number of numbers to send an SMS?
Android Java: How To Send SMS & Receive SMS & Get SMS Messages dated 30 August, 2017.
Related
In my project, I want to send all receiving messages to an email address. I successfully did that when the app is open. but when the app is closed, I can't send themail.
how to detect the message is received when the app is closed.
I used the worker for the email sending.
Also, I want to get the message data to the worker class to send the email.
Worker Class
public class MessageSenderWorker extends Worker {
#NonNull
#Override
public Result doWork() {
try {
new Thread(new Runnable() {
#Override
public void run() {
GMailSender sender = new GMailSender("emailaddredd",
"password");
try {
sender.sendMail("datafrom mesaage", "datafrom mesaage",
"emailaddress", "emailaddress");
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
return Result.SUCCESS;
} catch (Exception e) {
return Result.FAILURE;
}
}
}
My Broadcast Reciever
public class MessageReceiver extends BroadcastReceiver {
private static MessageListener mListener;
#Override
public void onReceive(Context context, Intent intent) {
Bundle data = intent.getExtras();
Object[] pdus = (Object[]) data.get("pdus");
for(int i=0; i<pdus.length; i++){
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
String message = "Sender : " + smsMessage.getDisplayOriginatingAddress()
+ "Email From: " + smsMessage.getEmailFrom()
+ "Emal Body: " + smsMessage.getEmailBody()
+ "Display message body: " + smsMessage.getDisplayMessageBody()
+ "Time in millisecond: " + smsMessage.getTimestampMillis()
+ "Message: " + smsMessage.getMessageBody();
mListener.messageReceived(message);
NotificationWorker notificationWorker = new NotificationWorker();
PeriodicWorkRequest.Builder dataCheckBuilder = new PeriodicWorkRequest.Builder(notificationWorker.getClass(), 1, TimeUnit.MINUTES).setConstraints(networkConstraints());
PeriodicWorkRequest dataCheckWork = dataCheckBuilder.build();
WorkManager.getInstance().enqueue(dataCheckWork);
}
}
If user turn screen OFF then you must use AlarmManager only (based on my practise) no more than 1 time in 30 minutes. For example you can use custom Broadcast Reciever and call it by AlarmManager. Custom Broadcast Reciever set new Alarm etc. Also you have to create Boot Broadcast Reciever to start Alarm.
To "wake up" a device, because of Doze Mode and app stand-by, the only reliable (and battery-friendly) is to use a high priority Firebase Cloud Message (FCM).
Your app can then handle this message retrieving the email you sent. An option there is that, when you receive the FCM, you enqueue a worker that will then download the message/email.
Everything else will be impacted by Doze Mode and other battery optimization systems in Android. Also, using an FCM is the most battery friendly solution for these cases.
Workers already run on a background thread - you shouldn't create your own inside them. They're also for synchronous work - meaning by the time you return a result, your work should have been completed. Take out all the "new Thread" code and put the contents of the Thread directly in the Worker. You'll also want to read this: https://developer.android.com/topic/libraries/architecture/workmanager/advanced/threading
I have a python server and about 10 android clients, using sockets. It is really important that when the server sends a message, all clients receive it at the same time (say 1/10th of a second of difference).
But the connection is over Wifi, and some devices get the message later than others, which gives a very messy result. I don't want to get the latency of every device because this is a very unreliable approach. I want something as accurate as possible.
For example, in FPS games, it is common to have a countdown at the start of the round, and every player can start playing at the same time. What kind of logic lies behind this?
As for what my code currently looks like:
I use a BufferedReader in android to read every line sent by the server. The server is a console application in which you can type a message, and when you press enter, every listed client receives it with a new thread for every client.
java method receiving messages:
private void readMessage() throws IOException {
String data;
while ((data = mBufferedReader.readLine()) != null) {
data = data.toUpperCase();
if (data.startsWith("POSITION")) {
String[] splitData = data.split("/");
Log.d(Constants.TAG, splitData[1]);
mMainActivity.setDevicePosition(Integer.parseInt(splitData[1]));
} else {
String message = data.substring(data.indexOf('/') + 1, data.length());
int devices = Integer.parseInt(data.substring(0, data.indexOf('/')));
if (message.length() >= devices) {
message += " ";
} else {
int difference = devices - message.length();
for (int i = 0; i < difference; i++) {
message += " ";
}
}
mMainActivity.printMessage(message);
}
}
}
python line :
for cl in clients_list:
start_new_thread(send_message_thread, (cl, message,))
I have a situation where I want to send a long message (around 600 characters) to approximately 10 people. The problem message of 600 characters means 4 SMS so the final count comes to 40 messages.
I would usually do something like this for long messages:
String phoneNo = etPhoneNo.getText().toString();
String msg = etMsg.getText().toString();
try {
SmsManager smsManager = SmsManager.getDefault();
ArrayList<String> msgArray = smsManager.divideMessage(msg);
smsManager.sendMultipartTextMessage(phoneNo, null, msgArray, null, null);
Toast.makeText(getApplicationContext(), "Message Sent", Toast.LENGTH_LONG).show();
} catch (Exception ex) {
Toast.makeText(getApplicationContext(), ex.getMessage().toString(), Toast.LENGTH_LONG).show();
ex.printStackTrace();
}
The problem is of course if I trigger this 10 times, I will send 40 messages at the same time. I don't want that as there is limitation on sms messages. On KitKat it's 30 messages in 30 minutes.
How can I accomplish to send next message 30-40 seconds after previous message was successfully sent? My goal is to receive some confirmation that message is sent and then start sending another message.
You possibly need a AlarmManager to send message every few second (in case your app is in background). If your app is always in foreground, you can use thread and timertask.
If you want to make sure that sms is sent successfully, you may refer to this post:
Java android, how to know if a sms is successfully sent?
All you need is Threading technique. Make a thread that sleep with given delay.
Aproach
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
// put code to execute send SMS here
try {
// and make delay 5 second
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// execute thread
thread.start();
I want to send to multiple number of recepients.
I also want to use the built in SMS mechanism without being prompt for a required App (Whatsapp, etc.)
In order to acomplish this, I am using Android's SmsManager.
The for loop iterates through the mobileList array of mobile numbers and send SMS to each one of them, one by one.
The indication for delivered SMS is retrieved by the BroadcastReceiver for the deliveredActionIntent intent.
I am popping a toast with the word "Delivered" and the index number of the message being delivered.
My questions are:
The actual index (idx) is not shown. I get for all toasts the same index number which is the number of mobileList items.
Why is this happening? I expected the index for each mobile by itself.
Is the number of mobileList items limited? Can I have 200 people for instance?
I tested this on a list of 4 mobile numbers but then I got 8-10 toasts. I expected one toast for one mobile delivery.
What is wrong here?
How can I get a notification when all SMSs are delivered? I guess this should be a background action like AsyncTask.
Can someone please show me how to do this?
The code of the SmsManager is shown below.
SmsManager smsManager = SmsManager.getDefault();
for(idx = 0; idx < mobileList.length; idx++) {
String toNumber = mobileList[idx];
String sms = message;
// SMS sent pending intent
Intent sentActionIntent = new Intent(SENT_ACTION);
sentActionIntent.putExtra(EXTRA_IDX, idx);
sentActionIntent.putExtra(EXTRA_TONUMBER, toNumber);
sentActionIntent.putExtra(EXTRA_SMS, sms);
PendingIntent sentPendingIntent = PendingIntent.getBroadcast(this, 0, sentActionIntent, PendingIntent.FLAG_UPDATE_CURRENT);
/* Register for SMS send action */
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String result = "";
switch (getResultCode()) {
case Activity.RESULT_OK:
result = "Transmission successful";
break;
case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
result = "Transmission failed";
break;
case SmsManager.RESULT_ERROR_RADIO_OFF:
result = "Radio off";
break;
case SmsManager.RESULT_ERROR_NULL_PDU:
result = "No PDU defined";
break;
case SmsManager.RESULT_ERROR_NO_SERVICE:
result = "No service";
break;
}
// Toast.makeText(getApplicationContext(), result, Toast.LENGTH_SHORT).show();
}
}, new IntentFilter(SENT_ACTION));
// SMS delivered pending intent
Intent deliveredActionIntent = new Intent(DELIVERED_ACTION);
deliveredActionIntent.putExtra(EXTRA_IDX, idx);
deliveredActionIntent.putExtra(EXTRA_TONUMBER, toNumber);
deliveredActionIntent.putExtra(EXTRA_SMS, sms);
PendingIntent deliveredPendingIntent = PendingIntent.getBroadcast(this, 0, deliveredActionIntent, PendingIntent.FLAG_UPDATE_CURRENT);
/* Register for Delivery event */
registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(getApplicationContext(), "Deliverd " + Integer.toString(idx), Toast.LENGTH_SHORT).show();
}
}, new IntentFilter(DELIVERED_ACTION));
//send
smsManager.sendTextMessage(toNumber, null, sms, sentPendingIntent, deliveredPendingIntent);
}
1) idx changes as you run through the for-loop. Thus, each time you toast, you're showing the current value for idx, which is the number of messages being shown. Since you've packed it in your intent, you can simply show the text "Delivered" + intent.getIntExtra(EXTRA_IDX, -1) in your onReceive method.
2) I'm not sure what you're asking.
3) I'm not sure off-hand, and can't currently debug.
4) You're going to have to keep track of which indices you've received. A HashSet<Integer> should do the trick.
Above your for loop, add this:
final HashSet<Integer> undelivered = new HashSet<Integer>();
In your for loop, add this:
undelivered.add(idx);
To answer your questions for 1, 3, and 4 at once, change your onReceived body to this:
// Get the index from the intent
int idx = intent.getIntExtra(EXTRA_IDX, -1);
if (undelivered.contains(idx)) {
// This index is now delivered. We remove it from the undelivered set, and Toast that it was delivered.
undelivered.remove(idx);
Toast.makeText(getApplicationContext(), "Delivered " + idx, Toast.LENGTH_SHORT).show();
if (undelivered.isEmpty() {
// We've delivered all of the messages ...
Toast.makeText(getApplicationContext(), "All messages were delivered.", Toast.LENGTH_SHORT).show();
}
}
I'm porting a game to use Google Play Game Services with multiplayer support. I'm using RealTimeSocket instead of realtime message because the game already has socket support.
To get the socket I call GamesClient.getRealTimeSocketForParticipant, and then I could get input and output streams as use it as a usual socket.
My problem is that if a device receives data before the call to getRealTimeSocketForParticipant, I will not be able to read this data. For instance:
Device A calls getRealTimeSocketForParticipant.
Device A sends "Hello".
Device B calls getRealTimeSocketForParticipant.
Device B receives nothing.
Device A sends "World".
Device B receives "World".
I have modified one of the example projects (ButtonClicker) and replicated the problem here. I have modified the code to use realtime socket, and modified the startGame method to this:
String mReceivedData = "";
byte mNextByteToSend = 0;
void startGame(boolean multiplayer)
{
mMultiplayer = multiplayer;
updateScoreDisplay();
switchToScreen(R.id.screen_game);
findViewById(R.id.button_click_me).setVisibility(View.VISIBLE);
GamesClient client = getGamesClient();
String myid = mActiveRoom.getParticipantId(client.getCurrentPlayerId());
ArrayList<String> ids = mActiveRoom.getParticipantIds();
String remoteId = null;
for(int i=0; i<ids.size(); i++)
{
String test = ids.get(i);
if( !test.equals(myid) )
{
remoteId = test;
break;
}
}
//One of devices should sleep in 5 seconds before start
if( myid.compareTo(remoteId) > 0 )
{
try
{
//The device that sleeps will loose the first bytes.
Log.d(TAG, "Sleeping in 5 seconds...");
Thread.sleep(5*1000);
}
catch(Exception e)
{
}
}
else
{
Log.d(TAG, "No sleep, getting socket now.");
}
try
{
final RealTimeSocket rts = client.getRealTimeSocketForParticipant(mRoomId, remoteId);
final InputStream inStream = rts.getInputStream();
final OutputStream outStream = rts.getOutputStream();
final TextView textView =((TextView) findViewById(R.id.score0));
//Thread.sleep(5*1000); Having a sleep here instead minimizes the risk to get the problem.
final Handler h = new Handler();
h.postDelayed(new Runnable()
{
#Override
public void run()
{
try
{
int byteToRead = inStream.available();
for(int i=0; i<byteToRead; i++)
{
mReceivedData += " " + inStream.read();
}
if( byteToRead > 0 )
{
Log.d(TAG, "Received data: " + mReceivedData);
textView.setText(mReceivedData);
}
Log.d(TAG, "Sending: " + mNextByteToSend);
outStream.write(mNextByteToSend);
mNextByteToSend++;
h.postDelayed(this, 1000);
}
catch(Exception e)
{
}
}
}, 1000);
}
catch(Exception e)
{
Log.e(TAG, "Some error: " + e.getMessage(), e);
}
}
The code ensures that one of the two devices sleeps 5 seconds before the call to getRealTimeSocketForParticipant. For the device that doesn't sleep the output will be something like:
No sleep, getting socket now.
Sending: 0
Sending: 1
Sending: 2
Sending: 3
Sending: 4
Received data: 0
Sending: 5
Received data: 0 1
Sending: 6
Received data: 0 1 2
That's expected, no data lost. But for the other device I get this:
Sleeping in 5 seconds...
Received data: 4
Sending: 0
Received data: 4 5
Sending: 1
Received data: 4 5 6
Sending: 2
Received data: 4 5 6 7
Sending: 3
The first bytes are lost. Is there anyway to avoid this?
If i'm understanding the API correctly, the messages exchanged through a real time socket are unrealiable, so you can't always have assurance that all players received all messages you sent. I couldn't find info about the network protocol used by RealTimeSocket, but I suspect it's UDP.
If that's really the case, I'm afraid there's little you can do short of implementing some sort of handshake yourself. Choose one device (ex.: the one with the lowest ID) to be the "synchronizer", and have it create a set with every other device. Send a message ("SYN") such as "where are you? x y z" (not literally, of course) every second, until the others respond "I'm here! (y)" ("ACK"). Remove from the set the devices that sent a response, until the set is empty. At this point, send everyone a "game's starting!" and go on.
Note that any of these messages can be lost: if the "ACK" is lost, next time the "SYN" is sent the device should answer again. If the "game's starting" message is lost, tough luck, the device will keep waiting until it receives a different message, at such point it should consider itself free to start (though delayed).
One last note: even if the underlying protocol is TCP, it's still not 100% reliable, no protocol is. See this question for more info, if you don't know this fact already.