Перейти к содержанию
Fire Monkey от А до Я

[Статья]Как создать простой Android Broadcast Receiver. How to implement simplest Android Broadcast Receiver in Delphi


Рекомендуемые сообщения

Как создать простейший Android Broadcast Receiver.

Создайте класс, для приема Intent уведомлений:

 

uses
  Androidapi.JNIBridge,
  Androidapi.JNI.Embarcadero,
  Androidapi.JNI.GraphicsContentViewText;

type
  TMyReceiver = class(TJavaLocal, JFMXBroadcastReceiverListener)
  public
    constructor Create;
    procedure onReceive(context: JContext; intent: JIntent); cdecl;
  end;

uses 
  Androidapi.Helpers,
  Androidapi.JNI.JavaTypes;

{ TMyReceiver }

constructor TMyReceiver.Create;
begin
  inherited;
end;

procedure TMyReceiver.onReceive(context: JContext; intent: JIntent);
begin
  Log.d('Broadcast Received = ' + JStringToString(intent.getAction));
end;

 

Регистрируем тип уведомлений и приемник в событиях формы:

 

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private  }
    FMyListener: TMyReceiver;
    FBroadcastReceiver: JFMXBroadcastReceiver;
  public
    { public  }
  end;

procedure TForm1.FormCreate(Sender: TObject);
var
  Filter: JIntentFilter;
begin
  FMyListener := TMyReceiver.Create;
  FBroadcastReceiver := TJFMXBroadcastReceiver.JavaClass.init(FMyListener);

  Filter := TJIntentFilter.JavaClass.init;
  Filter.addAction(TJIntent.JavaClass.ACTION_SCREEN_OFF);
  Filter.addAction(TJIntent.JavaClass.ACTION_SCREEN_ON);
  TAndroidHelper.context.getApplicationContext.registerReceiver
    (FBroadcastReceiver, Filter);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  TAndroidHelper.context.getApplicationContext.unregisterReceiver
    (FBroadcastReceiver);
end;

Все.

Теперь когда вы запустите программу и выключите\включите экран, лог покажет :

FMX: BroadcastSample: Broadcast Received = android.intent.action.SCREEN_OFF
FMX: BroadcastSample: Broadcast Received = android.intent.action.SCREEN_ON

Takashi Yamamoto

Изменено пользователем ENRGY
Ссылка на комментарий

Мой вариант Broadcast Receiver, на мой взгляд наиболее оптимизирован и удачен. По сравнению с известным кодом от barisatalay .

Отличия -

исправлена утечка,

чуть быстрее работает, за счет того что создается один фильтр в него добавляется несколько Actions  и одна регистрация на него, 

нет лишних конвертирований с Jstring to string и обратно,

адаптирован под Delphi 10 (JFMXBroadcastReceiver) ,

упрощена работа с классом (не нужно помнить о регистрации и вызывать ее заранее) ,

и самое главное - может получать getResultCode текущего ресивера (к примеру он нужен при получении статуса смс сообщения и в других случаях.). 

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.

 

Как использовать

 

  // указывать нужно сразу все нужные вам Actions в Add через запятую, не по одной. 
  fBroadcast := TBroadcastReceiver.Create(OnReceiveBroadcast);
  fBroadcast.AddActions([StringToJString(SENT_ACTION)]); << Custom action
-------------
  // или например сразу несколько Actions
  fBroadcast.AddActions([TJIntent.JavaClass.ACTION_SCREEN_OFF, TJIntent.JavaClass.ACTION_SCREEN_ON]);

 

Изменено пользователем ENRGY
Ссылка на комментарий
  • 10 месяцев спустя...

Можно пример, как использовать Ваш ресивер для перехвата входящих и исходящих звонков с получением номера телефона.

И ещё вопрос. В AndroidManifest.template.xml что-то надо прописывать в <%receivers%>?

 

Ссылка на комментарий
Только что, x11 сказал:

Можно пример, как использовать Ваш ресивер для перехвата входящих и исходящих звонков с получением номера телефона.

И ещё вопрос. В AndroidManifest.template.xml что-то надо прописывать в <%receivers%>?

 

Конкретно перехватом звонков я не занимался.

Вы можете поискать как это сделать на Java на StackOverflow напр, и адаптировать код на Delphi, это самый простой путь.

Ссылка на комментарий

Как правильно уничтожить BroadcastReceiver?

Есть код

procedure TDMSrv.BroadCastReiverFree;
begin
  if Assigned(BroadcastReceiver) then
  begin
    Log('BR is assigned');
    BroadcastReceiver.Destroy;
  end;

  if Assigned(BroadcastReceiver) then
  begin
    Log('BR is assigned');
  end;
end;

 

Так вот, в лог попадает строка "BR is assigned" два раза подряд, т.к. после строки:

BroadcastReceiver.Destroy 

объект BroadcastReceiver всё равно не равен nil и Assigned возвращает True.

Но если после ещё добавить строку:

BroadcastReceiver := nil;

то на этой строке появляется исключение.

 

Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...