ENERGY

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

В теме 7 сообщений

Как создать простейший 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты
Только что, x11 сказал:

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

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

 

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот, что у меня получилось http://fire-monkey.ru/topic/4723-служба-перехват-номера/

Покритикуйте, пожалуйста.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как правильно уничтожить 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;

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

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти

  • Похожий контент

    • От Alexey Shumkin
      Для работы с USB-устройствами (на девайсах с USB-хостом) нужно использовать BroadcastReceiver.
      Нашёл пример работы с ними (https://github.com/freeonterminate/delphi/tree/master/BroadcastReceiver). 
      Проверял на XE10. Долго мучался с проверкой, пока не выяснилось, что под XE7 работает, а под XE10 - нет.
      Выдаёт ошибку "Interface not supported" в момент создания JFMXBroadcastReceiver (или около того, точно непонятно).
      Для демонстрации я создал отдельный простой проект - https://github.com/ashumkin/Delphi-Android-BroadcastSample.
      В XE7 он работает (при нажатии на кнопку Register вешается слушатель, который ловит и выводит в лог (см. adb logcat) события включения/выключения экрана). А в XE10 - выдаёт вышеупомянутую ошибку "Interface not supported".
      В логах есть строки
      W/dalvikvm(31735): dvmFindClassByName rejecting 'com/embarcadero/firemonkey/broadcast/FMXBroadcastReceiverListener'
      W/dalvikvm(31735): dvmFindClassByName rejecting 'com/embarcadero/firemonkey/broadcast/FMXBroadcastReceiver'
      (но они есть и при запуске приложения, собранного в XE7)
      Пробовал по-разному: и удалял AndroidManifest.template.xml от XE7, и пересоздавал .dproj в XE10, - пофик.
      В чём засада?
  • Последние посетители   0 пользователей онлайн

    Ни одного зарегистрированного пользователя не просматривает данную страницу