How read JPendingIntent in Delphi?

2019-04-15 15:51发布

问题:

how to read deliveryIntent in this code?

uses
  Androidapi.JNI.JavaTypes, Androidapi.JNI.Telephony;

    procedure TForm1.Button1Click(Sender: TObject);
var
  smsTo: JString;
  smsManager: JSmsManager;
begin
  smsManager := TJSmsManager.JavaClass.getDefault;
  smsTo := StringToJString(ENum.text);
  PendIntent1:=TJPendingIntent.JavaClass.getBroadcast();
  PendIntent2:=TJPendingIntent.JavaClass.getBroadcast();
  smsManager.sendTextMessage(smsTo, nil, StringToJString(MSms.lines.text),PendIntent1,PendIntent2);
end;

Because I understand that SMS is gone or not?

Thank you

回答1:

If you read the SmsManager.sendTextMessage() documentation, you are supposed to provide your own Intent objects (JIntent in Delphi) that are wrapped in PendingIntent objects (JPendingIntent in Delphi).

So, you would create two Intent objects that have the desired action strings assigned to them, and then wrap them inside of two PendingIntent objects using the PendingIntent.getBroadcast() method (TJPendingIntent.JavaClass.getBroadcast() in Delphi), and then pass those to sendTextMessage() in the sentIntent and deliveryIntent parameters, respectively.

After the SMS has been sent/failed, the Intent inside of the sentIntent parameter will be broadcast. If the SMS is successfully delivered to the recipient, the Intent inside of the deliveryIntent parameter will be broadcast.

To process those Intent objects, you need to create and register a broadcastReceiver in your app. When you receive a broadcasted Intent, then you can retrieve its action value (see the Intent.getAction() method) and act accordingly.

There are no String conversions involved, unless you want to convert between a Delphi String and an Android JString.



回答2:

Here is how I did it on Delphi 10.1 Berlin:

  1. Based on example of Java code, I took here or here
  2. Here is full code of Delphi Broadcast receiver. With this code you can catch intent, and ResultCode (getResultCode). Here is a simple example how to implement it.

unit

unit BroadcastReceiver;

interface

{$IFDEF ANDROID}
uses
  Androidapi.JNI.Embarcadero, Androidapi.JNI.GraphicsContentViewText, Androidapi.helpers,
  Androidapi.JNIBridge, FMX.Helpers.Android, Androidapi.JNI.JavaTypes,
  System.Classes, System.SysUtils;

type
  TBroadcastReceiver = class;

  TListener = class(TJavaLocal, JFMXBroadcastReceiverListener)
  private
    fOwner: TBroadcastReceiver;
    fReceiver: JFMXBroadcastReceiver;
  public
    constructor Create(aOwner: TBroadcastReceiver);
    destructor Destroy; override;
    procedure onReceive(context: JContext; intent: JIntent); cdecl;
  end;


  TOnReceive = procedure (aContext: JContext; aIntent: JIntent; aResultCode: integer) of object;

  TBroadcastReceiver = class
  private
    fListener : TListener;
    fRegistered: boolean;
    fOnReceive: TOnReceive;
  public
    constructor Create(aOnReceiveProc: TOnReceive);
    destructor Destroy; override;
    procedure AddActions(const Args: array of JString);
    procedure SendBroadcast(const aValue: string);
  end;
{$ENDIF}

implementation

{$IFDEF ANDROID}

{ TBroadcastReceiver }

constructor TBroadcastReceiver.Create(aOnReceiveProc: TOnReceive);
begin
  inherited Create;
  fListener := TListener.Create(Self);
  fOnReceive := aOnReceiveProc;
end;

destructor TBroadcastReceiver.Destroy;
begin
  fListener.Free;
  inherited;
end;

procedure TBroadcastReceiver.AddActions(const Args: array of JString);
var
  vFilter: JIntentFilter;
  i: Integer;
begin
  if fRegistered then
    TAndroidHelper.context.getApplicationContext.UnregisterReceiver(fListener.fReceiver);

  vFilter := TJIntentFilter.JavaClass.init;
  for i := 0 to High(Args) do
    vFilter.addAction(Args[i]);

  TAndroidHelper.context.getApplicationContext.registerReceiver(fListener.fReceiver, vFilter);
  fRegistered := true;
end;

procedure TBroadcastReceiver.SendBroadcast(const aValue: string);
var
  Inx: JIntent;
begin
  Inx := TJIntent.Create;
  Inx.setAction(StringToJString(aValue));
  TAndroidHelper.Context.sendBroadcast(Inx);
end;

constructor TListener.Create(aOwner: TBroadcastReceiver);
begin
  inherited Create;
  fOwner := aOwner;
  fReceiver := TJFMXBroadcastReceiver.JavaClass.init(Self);
end;

destructor TListener.Destroy;
begin
  TAndroidHelper.context.getApplicationContext.unregisterReceiver(fReceiver);
  inherited;
end;

// usually android call it from "UI thread" - it's not main Delphi thread
procedure TListener.onReceive(context: JContext; intent: JIntent);
begin
  if Assigned(fOwner.fOnReceive) then
    fOwner.fOnReceive(Context, Intent, fReceiver.getResultCode);
end;

{$ENDIF}

end.

Then

  fBroadcast := TBroadcastReceiver.Create(OnReceiveBroadcast);
  fBroadcast.AddActions([StringToJString(SENT_ACTION)]);

SENT_ACTION - can be any string, e.g. 'SENT' or 123 - that is ID for filter.

Then I send it:

procedure TAndroidSMS.SendSMS(const aText, aPhone: string);
var
  Intent: JIntent;
  PendingIntent: JPendingIntent;
  vSmsManager: JSmsManager;
begin
  Result := seNotUpdated;
  Intent := TJIntent.Create;
  Intent.setAction(StringToJString(SENT_ACTION));
 // Intent.putExtra( StringToJString(EXTRA_PHONE_PARAM), StringTojString(aPhone));

  PendingIntent := TJPendingIntent.JavaClass.getBroadcast(TAndroidHelper.Context, 0, Intent, 0);

  vSmsManager := TJSmsManager.JavaClass.getDefault;
  vSmsManager.sendTextMessage( StringToJString(aPhone), nil, StringToJString(aText), PendingIntent, nil);
end;

And receive with Broadcast Receiver:

{ usually android call it from "UI thread" - it's not main Delphi thread}
procedure TAndroidSMS.OnReceiveBroadcast(aContext: JContext; aIntent: JIntent; aResultCode: integer);
begin
 // vAction := JStringToString(aIntent.getAction);
 // vNum := JStringToString(aIntent.getStringExtra( StringToJString(EXTRA_PHONE_PARAM) ) );

   // now change value, another thread is cheking periodically for this flag
    {Intel, Arm, write to a single byte, or to a properly aligned 2- or 4-byte value will always be an atomic write.}
  if aResultCode = TJActivity.JavaClass.RESULT_OK then
    Result := seSent
  else if aResultCode = TJSmsManager.JavaClass.RESULT_ERROR_RADIO_OFF then
    Result := seRadioOff
  else if aResultCode = TJSmsManager.JavaClass.RESULT_ERROR_GENERIC_FAILURE then
    Result := seGenericFail
  else if aResultCode = TJSmsManager.JavaClass.RESULT_ERROR_NO_SERVICE then
    Result := seNoService
  else if aResultCode = TJSmsManager.JavaClass.RESULT_ERROR_NULL_PDU then
    Result := seNullPDU
  else Result := seUnknown;
 end;