Android Question How to send sms on Android 34?

jefflynn1974

Member
Licensed User
Longtime User
I have an app that has been working for years, but now I want to update it to the latest android sdk. This is I have done so far. I have updated b4a to version 13.00, jdk to 19.0.2, the android sdk to 34. I use the following code to send sms:
Send sms:
        beep.Initialize(300, 500) '300 milliseconds, 500 hz
        Log("0")
        beep.Beep
        Log("1")
        Dim p As PhoneSms
        Log("2")
        p.Send(title.SubString(title.IndexOf(":")+1),body)
        Log("3")
and I get the following log:
Error log:
0
1
2
java.lang.RuntimeException: java.lang.IllegalArgumentException: com.kampfner.positionserver: Targeting U+ (version 34 and above) disallows creating or retrieving a PendingIntent with FLAG_MUTABLE, an implicit Intent within and without FLAG_NO_CREATE and FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT for security reasons. To retrieve an already existing PendingIntent, use FLAG_NO_CREATE, however, to create a new PendingIntent with an implicit Intent use FLAG_IMMUTABLE.
    at anywheresoftware.b4a.keywords.Common$14.run(Common.java:1750)
    at android.os.Handler.handleCallback(Handler.java:958)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:230)
    at android.os.Looper.loop(Looper.java:319)
    at android.app.ActivityThread.main(ActivityThread.java:8919)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
Caused by: java.lang.IllegalArgumentException: com.kampfner.positionserver: Targeting U+ (version 34 and above) disallows creating or retrieving a PendingIntent with FLAG_MUTABLE, an implicit Intent within and without FLAG_NO_CREATE and FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT for security reasons. To retrieve an already existing PendingIntent, use FLAG_NO_CREATE, however, to create a new PendingIntent with an implicit Intent use FLAG_IMMUTABLE.
    at android.os.Parcel.createExceptionOrNull(Parcel.java:3073)
    at android.os.Parcel.createException(Parcel.java:3053)
    at android.os.Parcel.readException(Parcel.java:3036)
    at android.os.Parcel.readException(Parcel.java:2978)
    at android.app.IActivityManager$Stub$Proxy.getIntentSenderWithFeature(IActivityManager.java:7041)
    at android.app.PendingIntent.getBroadcastAsUser(PendingIntent.java:752)
    at android.app.PendingIntent.getBroadcast(PendingIntent.java:735)
    at anywheresoftware.b4a.phone.Phone$PhoneSms.Send2(Phone.java:681)
    at anywheresoftware.b4a.phone.Phone$PhoneSms.Send(Phone.java:664)
    at com.kampfner.positionserver.firebasemessaging$ResumableSub_fm_MessageArrived.resume(firebasemessaging.java:187)
    at anywheresoftware.b4a.keywords.Common$14.run(Common.java:1748)
    ... 8 more
Caused by: android.os.RemoteException: Remote stack trace:
    at com.android.server.am.ActivityManagerService.getIntentSenderWithFeatureAsApp(ActivityManagerService.java:6488)
    at com.android.server.am.ActivityManagerService.getIntentSenderWithFeature(ActivityManagerService.java:6431)
    at android.app.IActivityManager$Stub.onTransact$getIntentSenderWithFeature$(IActivityManager.java:11943)
    at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:3400)
    at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3199)

My question is, how to do this properly?
 

DonManfred

Expert
Licensed User
Longtime User
Basically, your app can not send an SMS without user intervention unless:

1) Your app is configured to be the "default" sms app for the device (which will disable the factory SMS app that came with the phone)
2) Or use a third party service like Twilio to send the SMS (but then it will NOT be from the devices phone number, it will be from the number reserved with the third-party service)

And Erels answer in the same Thread
@JohnC is correct (https://www.b4x.com/android/forum/t...og-permissions-are-no-longer-available.98100/).
The only exception is for non-Google Play apps.
If your App is in the Playstore then you can not Send SMS on your Device anylonger.
 
Upvote 0

jefflynn1974

Member
Licensed User
Longtime User
Thank you for your answer. This is a private app, not uploaded in Play Store. The code I wrote ealrier has been working for years and it would be great if it worked without user intervention. I am the only user and I'm too lazy to press the send button :)
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
Here you go, this is extract from one of our apps. You can adapt it for your needs. You can put in in a class, this code is from a service

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
   
    Dim    NativeMe                 As JavaObject
    Dim PE                         As PhoneEvents
    Dim smsParts, smsPartsACK     As Int

End Sub


Sub Service_Create
   
Try
        ' // phone events
        PE.Initialize("PE")        
    Catch
log($"svc_sms::Service_Create:: - error -  ${LastException.Message}"$)
    End Try

End Sub

Sub Service_Start (StartingIntent As Intent)
 
   Try
        NativeMe.InitializeContext
    Catch
        log($"svc_sms::Service_Start:: - error -  ${LastException.Message}"$)
    End Try
   
End Sub

Sub SendLargeSMS(Destination As String, Message As String)
   
    Dim Extra As Map, id As String, ph As Phone

   
    id = DateTime.now
    Extra.Initialize
    Extra.Put("message_id", id )
    Dim tM As String = DateTime.Now
    Extra.Put("message_time", tM)
   
    Try
        smsPartsACK = 0
        If ph.SdkVersion >= 31 Then
            smsParts = NativeMe.RunMethod("Send4", Array(Destination, Message, Extra, True, False))
        Else
            smsParts = NativeMe.RunMethod("Send3", Array(Destination, Message, Extra, True, False))
        End If
        If smsParts = 0 Then
            smsParts = 1
        End If       
    Catch       
       
        log($"SendLargeSMS_ERROR ${LastException.Message}"$)
    End Try
   
End Sub

#If JAVA
import java.util.Random;
import java.util.ArrayList;
import java.util.Map;
import android.content.Context;
import android.content.Intent;
import android.app.PendingIntent;
import android.telephony.SmsManager;


public static int Send3(String PhoneNumber, String Text, Map<String, String> Extra, boolean ReceiveSentNotification, boolean ReceiveDeliveredNotification) {
    SmsManager sm = SmsManager.getDefault();

    /* Generate a unique requestCode for each Intent */
    Random randomNo = new Random();
    int requestCode = (int)(System.currentTimeMillis()/1000) + randomNo.nextInt(1000);
    int numParts = 0;
   
    Intent mSendIntent = new Intent("b4a.smssent");
    mSendIntent.putExtra("phone", PhoneNumber);

    // Add additional Extra Data
    for (Map.Entry<String, String> entry : Extra.entrySet()) {
        mSendIntent.putExtra(entry.getKey(), entry.getValue());
    }
    PendingIntent sentIntent = ReceiveSentNotification ? PendingIntent.getBroadcast(BA.applicationContext, requestCode, mSendIntent, PendingIntent.FLAG_UPDATE_CURRENT) : null;

    Intent mDeliveryIntent = new Intent("b4a.smsdelivered");
    mDeliveryIntent.putExtra("phone", PhoneNumber);

    // Add additional Extra Data
    for (Map.Entry<String, String> entry : Extra.entrySet()) {
        mDeliveryIntent.putExtra(entry.getKey(), entry.getValue());
    }
    PendingIntent deliveryIntent = ReceiveDeliveredNotification ? PendingIntent.getBroadcast(BA.applicationContext, requestCode, mDeliveryIntent, PendingIntent.FLAG_UPDATE_CURRENT) : null;

    ArrayList<String> parts = sm.divideMessage(Text);
    numParts = parts.size();
    ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
    ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>();
       
        for (int i = 0; i < numParts; i++) {
            if (ReceiveSentNotification) {
                sentIntents.add(PendingIntent.getBroadcast(BA.applicationContext, requestCode, mSendIntent, PendingIntent.FLAG_UPDATE_CURRENT));
            }
            if (ReceiveDeliveredNotification) {
                deliveryIntents.add(PendingIntent.getBroadcast(BA.applicationContext, requestCode, mDeliveryIntent, PendingIntent.FLAG_UPDATE_CURRENT));
            }
        }
        sm.sendMultipartTextMessage(PhoneNumber, null, parts, ReceiveSentNotification ? sentIntents : null, ReceiveDeliveredNotification ? deliveryIntents : null);       

    return numParts;
}


public static int Send4(String PhoneNumber, String Text, Map<String, String> Extra, boolean ReceiveSentNotification, boolean ReceiveDeliveredNotification) {
    SmsManager sm = SmsManager.getDefault();

    /* Generate a unique requestCode for each Intent */
    Random randomNo = new Random();
    int requestCode = (int)(System.currentTimeMillis()/1000) + randomNo.nextInt(1000);
    int numParts = 0;
   
    Intent mSendIntent = new Intent("b4a.smssent");
    mSendIntent.putExtra("phone", PhoneNumber);

    // Add additional Extra Data
    for (Map.Entry<String, String> entry : Extra.entrySet()) {
        mSendIntent.putExtra(entry.getKey(), entry.getValue());
    }
    PendingIntent sentIntent = ReceiveSentNotification ? PendingIntent.getBroadcast(BA.applicationContext, requestCode, mSendIntent, PendingIntent.FLAG_MUTABLE) : null;

    Intent mDeliveryIntent = new Intent("b4a.smsdelivered");
    mDeliveryIntent.putExtra("phone", PhoneNumber);

    // Add additional Extra Data
    for (Map.Entry<String, String> entry : Extra.entrySet()) {
        mDeliveryIntent.putExtra(entry.getKey(), entry.getValue());
    }
    PendingIntent deliveryIntent = ReceiveDeliveredNotification ? PendingIntent.getBroadcast(BA.applicationContext, requestCode, mDeliveryIntent, PendingIntent.FLAG_MUTABLE) : null;

    ArrayList<String> parts = sm.divideMessage(Text);
    numParts = parts.size();
    ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>();
    ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>();
       
        for (int i = 0; i < numParts; i++) {
            if (ReceiveSentNotification) {
                sentIntents.add(PendingIntent.getBroadcast(BA.applicationContext, requestCode, mSendIntent, PendingIntent.FLAG_MUTABLE));
            }
            if (ReceiveDeliveredNotification) {
                deliveryIntents.add(PendingIntent.getBroadcast(BA.applicationContext, requestCode, mDeliveryIntent, PendingIntent.FLAG_MUTABLE));
            }
        }
        sm.sendMultipartTextMessage(PhoneNumber, null, parts, ReceiveSentNotification ? sentIntents : null, ReceiveDeliveredNotification ? deliveryIntents : null);       

    return numParts;
}


#End If
 
Upvote 0

Jmu5667

Well-Known Member
Licensed User
Longtime User
Thank you for your answer. This is a private app, not uploaded in Play Store. The code I wrote ealrier has been working for years and it would be great if it worked without user intervention. I am the only user and I'm too lazy to press the send button :)
Dont be lazy !
 
Upvote 0

jefflynn1974

Member
Licensed User
Longtime User
Thank you both. I ended up using this code. Took it from here
Send sms:
Sub SendLargeSms(Destination As String, Message As String, MessageKey As String) 
    Dim ctxt As JavaObject
    ctxt.InitializeContext
    Dim smsManager As JavaObject
    smsManager = smsManager.InitializeStatic("android.telephony.SmsManager").RunMethod("getDefault", Null)
    Dim parts As JavaObject = smsManager.RunMethod("divideMessage", Array(Message))
 
    Dim i As Intent
    i.Initialize("b4a.smssent", "")
    i.PutExtra("message_id", MessageKey)
    Dim pi As JavaObject
    pi = pi.InitializeStatic("android.app.PendingIntent").RunMethod("getBroadcast", Array(ctxt, Rnd(0, 0x7fffffff), i,  67108864   ))
 
    Dim i2 As Intent
    i2.Initialize("b4a.smsdelivered", "")
    i2.PutExtra("message_id", MessageKey)
    Dim pi2 As JavaObject
    pi2 = pi2.InitializeStatic("android.app.PendingIntent").RunMethod("getBroadcast", Array(ctxt, 0, i2, 67108864))
 
    Dim size As Int = parts.RunMethod("size", Null)
    Dim al, al2 As JavaObject
    al.InitializeNewInstance("java.util.ArrayList", Null)
    al2.InitializeNewInstance("java.util.ArrayList", Null)
    For ii = 0 To size - 2
        al.RunMethod("add", Array(Null))
        al2.RunMethod("add", Array(Null))
    Next
    al.RunMethod("add", Array(pi))
    al2.RunMethod("add", Array(pi2))
    smsManager.RunMethod("sendMultipartTextMessage", Array(Destination, Null, parts, al, al2))   
End Sub
 
Upvote 0
Top