Вопросы с меткой [android-alarm-manager]
Служба системы Android, которая используется для выполнения каких-либо действий в заданное время, один раз или циклично. Она сработает даже в том случае, если приложение, которое запланировало какие-либо операции, завершилось.
75 вопросов
Конкурсные
Неотвеченные
- Конкурсные 0
- Неотвеченные
- Цитируемые
- Рейтинг
- Неотвеченные (мои метки)
Ошибка при получении сериализованного объекта из интента. Failure filling in extras
Я пишу будильник на kotlin. Когда я передаю объект любого класса через интент (put extra), чтобы при срабатывании Alarm Manager (в классе Alarm Receiver), этот объект был принят, то возникает ошибка (.
Как реализовать таймер в Android с помощью AlarmManager?
Народ, выручите пожалуйста, я никак не могу найти объяснение работы подобного таймера или примеров такой реализации которая бы удоволетворяла условию задачи: Условие задачи: Нужно чтобы AlarmManager .
Как обнаружить, что приложение было остановлено
Есть ли какой-нибудь способ обнаружить, что прошлый запуск приложения закончился остановкой (force stop, terminate)? Может быть временный флаг или состояние, то что можно проверить на стороне .
104 показа
AlarmManager не работает будильник если выйти из приложения
У меня есть приложение будильник. Когда я создаю будильник то оно работает хорошо (Если не выходить из приложения), а если выйти — то будильник не срабатывает. Вот мой код: AlarmFragment (С которого .
543 показа
AlarmManager: бесконечная работа
Ребята, у меня стоит следующая задача: выполнять определённую задачу каждые 15 минут. Я пробовал использовать сервис, в котором использовал обычный Timer public void myTimer()< Timer myTimer = .
- android
- android-alarm-manager
279 показов
Как решить проблему: Attempt to invoke virtual method on a null object reference
Всем привет. Я тут решил в своё android-приложение календаря добавить уведомления (Notifications) по времени с помощью AlarmManager. Но у меня появилась проблема: при вызове функции notifyUser() по .
- java
- android
- android-notification
- android-alarm-manager
Отправка уведомлений по дням недели
Нужно, чтобы приложение отправляло уведомление, к примеру, только по понедельникам в определенное время. Для этого лучше использовать AlarmManager или Notification или Push-notification или есть более .
- android
- android-notification
- android-alarm-manager
Как забиндить сервис в повторяющейся задаче?
В своём приложения я использую Work Manager для выполнения определённых задач. Логика работы такая: На устройство приходит push(с периодичностью 5 минут). Он в свою очередь запускает одноразовый work. .
- android
- android-service
- android-alarm-manager
- android-data-binding
- android-binder
439 показов
Неубиваемый сервис в текущих реалиях
Нужно сделать сервис который остаётся активным, даже если телефон находится в режиме ожидания. То есть заблокирован и лежит в кармане. Или телефон перезагрузился/выключился, сервис перезапустился. В .
- java
- android
- android-service
- android-alarm-manager
- android-broadcastreceiver
39 показов
как остановить push уведомления идущие от alarmmanager
есть alarmManager @SuppressLint(«ShortAlarm») private void scheduleAlarm(String hh, int id, String title) < Intent alarmIntent = new Intent(this, AlarmReceiver.class); .
Почему AlarmManager не срабатывает?
Я пытаюсь вызвать в определенное (8:25) время с интервалом в день уведомление, оно работает иногда, то есть бывают дни когда она вообще не работает MainActivity класс: private NotificationManager nm; .
- android
- уведомления
- android-notification
- android-alarm-manager
Как заставить работать AlarmManager или TiME_TICK
Мое приложение — это чат, и я должен улавливать сообщения даже когда приложение закрыто(как вк или телеграмм), в голову пришла мысль что бы через определенное время запускался Broadcast, который бы .
194 показа
Как проверить, запущен ли Alarm Manager
Когда мое приложение запускается в onCreate() я запускаю метод: private void startNotifyService() < Calendar timeNotification = Calendar.getInstance(); timeNotification.set(Calendar.
Как Вернутся в активность после того, как появилось уведомление. Уведомление не кликабельно, не реагирует на нажатия
Проблема — не получается вернуться в основную активность после нажатия по полученному уведомлению. Само уведомление не кликабельно. Уведомление запускается в методе onPause (в фоновом режиме) Моя .
- java
- android-notification
- android-alarm-manager
- android-broadcastreceiver
- pendingintent
Вернуть для кнопки исходное состояние через определенное время
Подскажите, какие есть варианты. Необходимо, вернуть кнопку в исходное состояние, но через конкретно заданное время. Если делать через alarm, подскажите как? Нужно сделать так чтобы и после .
- android
- android-alarm-manager
Локальные уведомления в Xamarin.Forms (Xamarin local notifications)
Локальные уведомления в Xamarin – это предупреждения, отправляемые приложениями, установленными на мобильном устройстве. Локальные уведомления часто используются для таких функций, как:
- события календаря;
- напоминания;
- триггеры на основе местоположения.
Каждая платформа по-разному обрабатывает создание, отображение и потребление локальных уведомлений. В этой статье объясняется, как создать кроссплатформенную абстракцию для отправки, планирования и получения локальных уведомлений в Xamarin.Forms.

Создание кроссплатформенного интерфейса
Приложение Xamarin.Forms должно создавать и использовать уведомления, не обращая внимания на реализацию базовой платформы. Следующий интерфейс INotificationManager реализован в библиотеке общего кода и определяет кроссплатформенный API, который может использовать приложением для взаимодействия с уведомлениями:
public interface INotificationManager
Этот интерфейс будет реализован в каждом проекте платформы. Событие NotificationReceived позволяет приложению обрабатывать входящие уведомления. Метод Initialize должен выполнять любую встроенную логику платформы, необходимую для подготовки системы уведомлений. Метод SendNotification должен отправить уведомление в необязательное время DateTime. Метод ReceiveNotification должен вызываться базовой платформой при получении сообщения.
Использование интерфейса в Xamarin.Forms
После создания интерфейса его можно использовать в общем проекте Xamarin.Forms, даже если реализация платформы еще не создана. Пример приложения содержит страницу ContentPage под названием MainPage.xaml со следующим содержимым:
StackLayout Margin="0,35,0,0" x:Name="stackLayout"> Label Text="Click the button below to create a local notification." TextColor="Red" HorizontalOptions="Center" VerticalOptions="Start" /> Button Text="Create Notification" HorizontalOptions="Center" VerticalOptions="Start" Clicked="OnSendClick" /> Label Text="Click the button below to schedule a local notification for in 10 seconds time." TextColor="Red" HorizontalOptions="Center" VerticalOptions="Start" /> Button Text="Create Notification" HorizontalOptions="Center" VerticalOptions="Start" Clicked="OnScheduleClick" /> /StackLayout>
Макет содержит элементы Label, которые объясняют инструкции, и элементы Button, которые отправляют или планируют уведомление при нажатии.
Код-behind класса MainPage управляет отправкой и получением уведомлений:
public partial class MainPage : ContentPage < INotificationManager notificationManager; int notificationNumber = 0; public MainPage() < InitializeComponent(); notificationManager = DependencyService.Get(); notificationManager.NotificationReceived += (sender, eventArgs) =>< var evtData = (NotificationEventArgs)eventArgs; ShowNotification(evtData.Title, evtData.Message); >; > void OnSendClick(object sender, EventArgs e) < notificationNumber++; string title = $"Local Notification #"; string message = $"You have now received notifications!"; notificationManager.SendNotification(title, message); > void OnScheduleClick(object sender, EventArgs e) < notificationNumber++; string title = $"Local Notification #"; string message = $"You have now received notifications!"; notificationManager.SendNotification(title, message, DateTime.Now.AddSeconds(10)); > void ShowNotification(string title, string message) < Device.BeginInvokeOnMainThread(() =>< var msg = new Label() < Text = $"Notification Received:\nTitle: \nMessage: " >; stackLayout.Children.Add(msg); >); > >
Конструктор класса MainPage использует Xamarin.Forms DependencyService для получения специфического для платформы экземпляра INotificationManager. Методы OnSendClick и OnScheduleClicked используют экземпляр INotificationManager для отправки и планирования новых уведомлений. Метод ShowNotification вызывается из обработчика события, присоединенного к событию NotificationReceived, и вставляет новую метку на страницу при вызове этого события.
Обработчик события NotificationReceived приводит свои аргументы события к NotificationEventArgs. Этот тип определен в общем проекте Xamarin.Forms:
public class NotificationEventArgs : EventArgs < public string Title < get; set; >public string Message < get; set; >>
Создание реализации интерфейса Android
Чтобы приложение Xamarin.Forms могло отправлять и получать уведомления на Android, приложение должно предоставить реализацию интерфейса INotificationManager.
Создание класса AndroidNotificationManager
Класс AndroidNotificationManager реализует интерфейс INotificationManager:
using System; using Android.App; using Android.Content; using Android.Graphics; using Android.OS; using AndroidX.Core.App; using Xamarin.Forms; using AndroidApp = Android.App.Application; [assembly: Dependency(typeof(LocalNotifications.Droid.AndroidNotificationManager))] namespace LocalNotifications.Droid < public class AndroidNotificationManager : INotificationManager < const string channelId = "default"; const string channelName = "Default"; const string channelDescription = "The default channel for notifications."; public const string TitleKey = "title"; public const string MessageKey = "message"; bool channelInitialized = false; int messageId = 0; int pendingIntentId = 0; NotificationManager manager; public event EventHandler NotificationReceived; public static AndroidNotificationManager Instance < get; private set; >public AndroidNotificationManager() => Initialize(); public void Initialize() < if (Instance == null) < CreateNotificationChannel(); Instance = this; >> public void SendNotification(string title, string message, DateTime? notifyTime = null) < if (!channelInitialized) < CreateNotificationChannel(); >if (notifyTime != null) < Intent intent = new Intent(AndroidApp.Context, typeof(AlarmHandler)); intent.PutExtra(TitleKey, title); intent.PutExtra(MessageKey, message); PendingIntent pendingIntent = PendingIntent.GetBroadcast(AndroidApp.Context, pendingIntentId++, intent, PendingIntentFlags.CancelCurrent); long triggerTime = GetNotifyTime(notifyTime.Value); AlarmManager alarmManager = AndroidApp.Context.GetSystemService(Context.AlarmService) as AlarmManager; alarmManager.Set(AlarmType.RtcWakeup, triggerTime, pendingIntent); >else < Show(title, message); >> public void ReceiveNotification(string title, string message) < var args = new NotificationEventArgs() < Title = title, Message = message, >; NotificationReceived?.Invoke(null, args); > public void Show(string title, string message) < Intent intent = new Intent(AndroidApp.Context, typeof(MainActivity)); intent.PutExtra(TitleKey, title); intent.PutExtra(MessageKey, message); PendingIntent pendingIntent = PendingIntent.GetActivity(AndroidApp.Context, pendingIntentId++, intent, PendingIntentFlags.UpdateCurrent); NotificationCompat.Builder builder = new NotificationCompat.Builder(AndroidApp.Context, channelId) .SetContentIntent(pendingIntent) .SetContentTitle(title) .SetContentText(message) .SetLargeIcon(BitmapFactory.DecodeResource(AndroidApp.Context.Resources, Resource.Drawable.xamagonBlue)) .SetSmallIcon(Resource.Drawable.xamagonBlue) .SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate); Notification notification = builder.Build(); manager.Notify(messageId++, notification); >void CreateNotificationChannel() < manager = (NotificationManager)AndroidApp.Context.GetSystemService(AndroidApp.NotificationService); if (Build.VERSION.SdkInt >= BuildVersionCodes.O) < var channelNameJava = new Java.Lang.String(channelName); var channel = new NotificationChannel(channelId, channelNameJava, NotificationImportance.Default) < Description = channelDescription >; manager.CreateNotificationChannel(channel); > channelInitialized = true; > long GetNotifyTime(DateTime notifyTime) < DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(notifyTime); double epochDiff = (new DateTime(1970, 1, 1) - DateTime.MinValue).TotalSeconds; long utcAlarmTime = utcTime.AddSeconds(-epochDiff).Ticks / 10000; return utcAlarmTime; // milliseconds >> >
Атрибут assembly над пространством имен регистрирует реализацию интерфейса INotificationManager в DependencyService.
Android позволяет приложениям определять несколько каналов для уведомлений. Метод Initialize создает базовый канал, который приложение-пример использует для отправки уведомлений. Метод SendNotification определяет специфическую для платформы логику, необходимую для создания и отправки уведомления. Метод ReceiveNotification вызывается ОС Android при получении сообщения и вызывает обработчик события.
Метод SendNotification создает локальное уведомление немедленно или в точное время даты. Уведомление может быть запланировано на точное время с помощью класса AlarmManager, и оно будет получено объектом, производным от класса BroadcastReceiver:
[BroadcastReceiver(Enabled = true, Label = "Local Notifications Broadcast Receiver")] public class AlarmHandler : BroadcastReceiver < public override void OnReceive(Context context, Intent intent) < if (intent?.Extras != null) < string title = intent.GetStringExtra(AndroidNotificationManager.TitleKey); string message = intent.GetStringExtra(AndroidNotificationManager.MessageKey); AndroidNotificationManager manager = AndroidNotificationManager.Instance ?? new AndroidNotificationManager(); manager.Show(title, message); >> >
Важно. По умолчанию уведомления, запланированные с помощью класса AlarmManager, сбрасываются при перезагрузке устройства. Однако вы можете разработать свое приложение для автоматического повторного планирования уведомлений при перезагрузке устройства.
Обработка входящих уведомлений на Android
Класс MainActivity должен обнаруживать входящие уведомления и уведомлять экземпляр AndroidNotificationManager. Атрибут Activity класса MainActivity должен указывать значение LaunchMode, равное LaunchMode.SingleTop:
[Activity( //. LaunchMode = LaunchMode.SingleTop] public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity < // . >
Режим SingleTop предотвращает запуск нескольких экземпляров активности, пока приложение находится на переднем плане. Этот режим LaunchMode может не подойти для приложений, запускающих несколько активностей в более сложных сценариях уведомлений.
В классе MainActivity модифицирован класс для получения входящих уведомлений:
protected override void OnCreate(Bundle savedInstanceState) < // . global::Xamarin.Forms.Forms.Init(this, savedInstanceState); LoadApplication(new App()); CreateNotificationFromIntent(Intent); >protected override void OnNewIntent(Intent intent) < CreateNotificationFromIntent(intent); >void CreateNotificationFromIntent(Intent intent) < if (intent?.Extras != null) < string title = intent.GetStringExtra(AndroidNotificationManager.TitleKey); string message = intent.GetStringExtra(AndroidNotificationManager.MessageKey); DependencyService.Get().ReceiveNotification(title, message); >>
Метод CreateNotificationFromIntent извлекает данные уведомления из аргумента намерения intent и предоставляет их AndroidNotificationManager с помощью метода ReceiveNotification. Метод CreateNotificationFromIntent вызывается как из метода OnCreate, так и из метода OnNewIntent:
- Когда приложение запускается с помощью данных уведомления, данные intent будут переданы в метод OnCreate.
- Если приложение уже находится на переднем плане, данные Intent будут переданы в метод OnNewIntent.
Android предлагает множество дополнительных опций для уведомлений
Создание реализации интерфейса iOS
Чтобы приложение Xamarin.Forms могло отправлять и получать уведомления на iOS, приложение должно предоставить реализацию INotificationManager.
Создайте класс iOSNotificationManager
Класс iOSNotificationManager реализует интерфейс INotificationManager:
using System; using Foundation; using UserNotifications; using Xamarin.Forms; [assembly: Dependency(typeof(LocalNotifications.iOS.iOSNotificationManager))] namespace LocalNotifications.iOS < public class iOSNotificationManager : INotificationManager < int messageId = 0; bool hasNotificationsPermission; public event EventHandler NotificationReceived; public void Initialize() < // request the permission to use local notifications UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert, (approved, err) =>< hasNotificationsPermission = approved; >); > public void SendNotification(string title, string message, DateTime? notifyTime = null) < // EARLY OUT: app doesn't have permissions if (!hasNotificationsPermission) < return; >messageId++; var content = new UNMutableNotificationContent() < Title = title, Subtitle = "", Body = message, Badge = 1 >; UNNotificationTrigger trigger; if (notifyTime != null) < // Create a calendar-based trigger. trigger = UNCalendarNotificationTrigger.CreateTrigger(GetNSDateComponents(notifyTime.Value), false); >else < // Create a time-based trigger, interval is in seconds and must be greater than 0. trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(0.25, false); >var request = UNNotificationRequest.FromIdentifier(messageId.ToString(), content, trigger); UNUserNotificationCenter.Current.AddNotificationRequest(request, (err) => < if (err != null) < throw new Exception($"Failed to schedule notification: "); > >); > public void ReceiveNotification(string title, string message) < var args = new NotificationEventArgs() < Title = title, Message = message >; NotificationReceived?.Invoke(null, args); > NSDateComponents GetNSDateComponents(DateTime dateTime) < return new NSDateComponents < Month = dateTime.Month, Day = dateTime.Day, Year = dateTime.Year, Hour = dateTime.Hour, Minute = dateTime.Minute, Second = dateTime.Second >; > > >
Атрибут assembly над пространством имен регистрирует реализацию интерфейса INotificationManager в DependencyService.
На iOS перед попыткой запланировать уведомление необходимо запросить разрешение на использование уведомлений. Метод Initialize запрашивает разрешение на использование локальных уведомлений. Метод SendNotification определяет логику, необходимую для создания и отправки уведомления. Метод ReceiveNotification будет вызван iOS при получении сообщения и вызовет обработчик события.
Примечание. Метод SendNotification создает локальное уведомление немедленно, используя объект UNTimeIntervalNotificationTrigger, или в точное время DateTime, используя объект UNCalendarNotificationTrigger.
Обработка входящих уведомлений на iOS
На iOS для обработки входящих сообщений необходимо создать делегат, подкласс UNUserNotificationCenterDelegate. В примере приложения определен класс iOSNotificationReceiver:
public class iOSNotificationReceiver : UNUserNotificationCenterDelegate < public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action completionHandler) < ProcessNotification(notification); completionHandler(UNNotificationPresentationOptions.Alert); >void ProcessNotification(UNNotification notification) < string title = notification.Request.Content.Title; string message = notification.Request.Content.Body; DependencyService.Get().ReceiveNotification(title, message); >>
Этот класс использует DependencyService для получения экземпляра класса iOSNotificationManager и предоставляет данные входящих уведомлений методу ReceiveNotification.
Класс AppDelegate должен указать объект iOSNotificationReceiver в качестве делегата UNUserNotificationCenter во время запуска приложения. Это происходит в методе FinishedLaunching:
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
Тестирование приложения
После того как проекты платформы содержат зарегистрированную реализацию интерфейса INotificationManager, приложение можно протестировать на обеих платформах. Запустите приложение и нажмите любую из кнопок Create Notification, чтобы создать уведомление.
На Android уведомления появятся в области уведомлений. При нажатии на уведомление приложение получает уведомление и выводит сообщение:

На iOS входящие уведомления автоматически принимаются приложением, не требуя ввода данных пользователем. Приложение получает уведомление и выводит сообщение:

Оглавление
- Использование интерфейса в Xamarin.Forms
- Создание реализации интерфейса Android
- Обработка входящих уведомлений на Android
- Создание реализации интерфейса iOS
- Тестирование приложения
Приложение будильник. Использование AlarmManager в FireMonkey на Андроиде


В этой статье вы узнаете, как создать будильник, построенный на системном планировщике задач AlarmManager Андроида в FireMonkey. AlarmManager позволяет поставить на выполнение задачу, которую требуется выполнить в определенный момент времени. Главным отличием от обычного таймера является то, что задание будет выполнено не зависимо от того, живо ли ваше приложение или нет.
Система автоматически по наступлению указанного времени, выполнит ваш код. О том, как это работает и как этим пользоваться будет описано в этой статье.
Описание проблемы
Представьте, что вам требуется сделать приложение будильник, которое должно в определенное время подать звуковой сигнал и разбудить пользователя. Мы могли бы использовать компонент TTimer для этого и по наступлению определенного времени подать звуковой сигнал:
procedure TFormAlarm.Timer1Timer(Sender: TObject); begin if Now = AlarmTime then PlayAlarmSound; end;
Но, как только приложение будет закрыто, ваш будильник не сработает. Такая реализация требует, чтобы приложение постоянно находилось в памяти и постоянно работало. Как вы понимаете в реальности на мобильных устройствах такой подход не допустим и приложение может быть, как выгружено системой в целях экономии ресурсов, так и приостановлено. Я уж не говорю о практичности такого будильника, который запрещает вам работать с другими приложениями на устройстве.
Что нам требуется, чтобы будильник сработал даже, когда приложение закрыто?
Нам нужно, чтобы кто-нибудь подал нам сигнал, когда придет время просыпаться. По этому сигналу мы могли бы запустить наше приложение и выполнить наш код. Например, проиграть звонок. Оказывается, Андроид уже предусмотрел для этих целей специальных механизм. Он называется AlarmManager.
Решение в виде AlarmManager
AlarmManager — это специальный системный сервис, позволяющий выполнить пользовательский код в определенный момент времени. Этот менеджер является частью системы Андроид, постоянно находится в памяти и бдит за временем и задачами. Как только приходит положенное время, он извлекает помещенную в него заранее задачу и инициирует выполнение задачи.
Типичный алгоритм работы с сервисом такой:
- Создаем класс «задачи». Наследник от BroadcastReceiver (об этом в этой статье позже), который предоставляет специальный абстрактный метод OnReceive, который будет вызван сервисом AlarmManager в указанный момент времени. В метод OnReceive через параметр сервис AlarmManager передаст наше заранее заготовленное сообщение с нашими параметрами.
- Регистрируем наш ресивер в нашем приложении. Говорим системе, что у нас есть такой ресивер.
- Формируете сообщение с нашими параметрами. Сообщение — это отложенное намерение PendingIntent (далее в статье).
- Запрашиваете у системы сервис AlarmManager
- Отправляете задачу, указывая: время/интервал выполнения задачи, отложенный интент (2 пункт).
Что такое интент?
Интент (Intent) — это дословно намерение на выполнение какого-то действия. По сути, интент представляет собой аналог сообщения или посылки в реальной жизни. Сообщение, имеющее:
- Адрес получателя — если получатель один.
- Категорию адресатов — если получателей несколько
- Набор данных, который мы хотим послать адресатам.
Интенты бывают двух видов:
- Intent — Мгновенные, которые отправляются сразу и выполняются сразу
- PendingIntent — Отложенные, которые складываются в очереди и отправляются уже в будущем.
В этой статье нас интересуют только отложенные уведомления. Так как мы хотим разбудить человека в определенный момент времени в будущем, а не прямо сейчас.
Шаг 0. Пара слов об использовании java в нативных приложения Delphi
Перед тем, как мы рассмотрим все шаги подробнее. Я хочу обратить ваше внимание на понимание процесса, как используются любые java классы в Delphi. Именно понимание этого, облегчит вам процесс интеграции ваших java классов в ваше нативное приложение.
Ваше Delphi приложение с точки зрения исполняемого кода состоит из двух главных частей:
- Нативная so библиотека с вашим кодом на языке Delphi
- Исполняемый код вашего приложения — classes.dex. Именно этот файл содержит стартовое активити вашего приложения. И именно этот файл загружает нативную so библиотеку с вашим кодом. Именно этот файл содержит java реализацию дополнительных классов, требующих для работы FireMonkey.

Если вы хотите добавить ваш собственный java класс, его нужно добавить в classes.dex файл. Это делается при помощи специальных утилит идущих в поставке с Android SDK.
Dex файл — это файл с инструкциями для исполняемой java машины Dalwik. Именно он и запускается на андроиде и выполняется на исполняемой машине Dalwik. Поскольку нам не доступны исходники из которых этот файл был построен, мы можем только добавить в этот файл свои классы.
Общий алгоритм добавления своих java классов такой:
- Создаем файлы с java классами.
- Компилируем java классы java компилятором javac и получаем class файлы
- Пакуем ваши class файлы в jar файл (архив со специальной внутренней структурой, манифестом и тд)
- Получаем dex файл из jar
- Смешиваем полученный dex файл c dex файлом Embarcadero. (Результирующий файл содержит старые классы и ваши новые.)
- Заменяем dex файл embarcadero новым через Deployment Manager.
Теперь ваши классы будут в вашем приложении. Остается только понять, как их вызывать и использовать из нативного кода. Для этого нужно получить «хедера» для них при помощи утилиты java2op, которая идет в поставке RAD Studio. Натравив ее на ваш jar файл, утилита выдаст pas файл с классами для работы с вашими java классами.
Теперь перейдем непосредственно к созданию BroadcastReceiver.
Шаг 1. Создание BroadcastReceiver
BroadcastReceiver — это абстрактный java, класс выступающий в качестве получателя интентов. Другими словами — он является тем получателем посылок, которые мы будем ему отправлять. Именно здесь мы и будем будить пользователя звонком будильника.
Теперь нам требуется сделать наследника этого класса и написать код воспроизведения мелодии. Сделать в Delphi мы это не можем, так как JNI не позволяет наследовать java классы в нативном коде.
JNI — это специальная библиотека Java виртуальной машины для использования java их нативных языков C++, Delphi и тд.
Поэтому используя java создаем нашего наследника com.test.AlarmReceiver. Создаем в обычном текстовом редакторе текстовый файл AlarmReceiver.java, перекрываем метод OnReceive и выполняем проигрывание стандартной мелодии будильника. Для этого используем RingtoneManager.
package com.test; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.media.Ringtone; import android.media.RingtoneManager; import android.net.Uri; public class AlarmReceiver extends BroadcastReceiver < @Override public void onReceive(Context context, Intent intent) < Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); Ringtone ringtone = RingtoneManager.getRingtone(context.getApplicationContext(), notification); ringtone.play(); >>
Этот файл обязательно помещаем в каталоги: «com\test«. Так как пакет этого класса назван com.test.
Теперь необходимо этот файл скомпилировать и добавить в наше приложение, чтобы мы могли его использовать (смотрите шаг 0). Наверное, это наиболее сложная часть — внедрение вашего класса в уже готовый файл от Embarcadero.
Воспользуемся bat файлом для сборки файла (я позаимствовал его у Андрея Ефимов). Я взял за основу батник и немного модифицировал его.
Вам требуется указать правильные пути в своем окружении:
- ANDROID — путь к sdk адроида
- ANDROID_PLATFORM — путь к версии андроида.
- DX_LIB — путь к инструментам для получения и соединения dx файлов
- EMBO_DEX — путь к местоположению эмбаркадеровского classes.dex файлы
@echo off setlocal REM Здесь указываем каталог к Android SDK if x%ANDROID% == x set ANDROID=C:\Users\Public\Documents\Embarcadero\Studio\14.0\PlatformSDKs\adt-bundle-windows-x86-20131030\sdk REM Здесь указываем версию Android платформы set ANDROID_PLATFORM=%ANDROID%\platforms\android-19 set DX_LIB=%ANDROID%\build-tools\19.0.1\lib set EMBO_DEX="C:\Program Files\Embarcadero\Studio\14.0\lib\android\debug\classes.dex" set PROJ_DIR=%CD% set VERBOSE=0 echo ========================================================================================== echo. echo 1. Compiling the Java service activity source files echo. mkdir output 2> nul mkdir output\classes 2> nul if x%VERBOSE% == x1 SET VERBOSE_FLAG=-verbose javac %VERBOSE_FLAG% -Xlint:deprecation -cp %ANDROID_PLATFORM%\android.jar -d "output\classes" "src\com\test\AlarmReceiver.java" echo ========================================================================================== echo. echo 2. Creating jar containing the new classes echo. mkdir output\jar 2> nul if x%VERBOSE% == x1 SET VERBOSE_FLAG=v jar c%VERBOSE_FLAG%f %PROJ_DIR%\output\jar\test_classes.jar -C output\classes com\test\AlarmReceiver.class echo ========================================================================================== echo. echo 3. Converting from jar to dex. echo. mkdir output\dex 2> nul if x%VERBOSE% == x1 SET VERBOSE_FLAG=--verbose call %DX_LIB%\dx.jar --dex %VERBOSE_FLAG% --output=output\dex\test_classes.dex output\jar\test_classes.jar echo ========================================================================================== echo. echo Merging dex files echo.com.android.dx.merge.DexMerger java -cp %DX_LIB%\dx.jar com.android.dx.merge.DexMerger %PROJ_DIR%\output\dex\classes.dex %PROJ_DIR%\output\dex\test_classes.dex %EMBO_DEX% echo Tidying up echo. rmdir /s /q output\classes del output\dex\test_classes.dex rmdir /s /q output\jar echo ========================================================================================== echo Now we have the end result, which is output\dex\classes.dex :Exit endlocal
После того, как вы вызовите эту утилиту, в папке «output\dex» будет находиться новый classes.dex файл. Теперь нужно заменить им classes.dex файл по умолчанию. Для этого открываем Deployment в RAD Studio (Menu -> Project -> Deployment) и добавляем новый файл. Важно, что путь назначения (Remote Path) для этого файла должен быть «classes\«.

Теперь, нужно получить delphi хедеры для нашего AlertReceiver java класса. Для этого пользуемся утилитой java2Op (утилита располагается в папке bin или bin\converterers\java2op в каталоге с Rad Studio):
java2op -jar output\jar\test_classes.jar -unit Androidapi.JNI.AlarmReceiver
на выходе получаем хедер:
unit Androidapi.JNI.AlarmReceiver; interface uses Androidapi.JNIBridge, Androidapi.JNI.JavaTypes; type // ===== Forward declarations ===== JAlarmReceiver = interface;//com.test.AlarmReceiver //JStringBuffer = interface;//java.lang.StringBuffer //JStringBuilder = interface;//java.lang.StringBuilder // ===== Interface declarations ===== JAlarmReceiverClass = interface(JObjectClass) [''] function init: JAlarmReceiver; cdecl; end; [JavaSignature('com/test/AlarmReceiver')] JAlarmReceiver = interface(JObject) [''] end; TJAlarmReceiver = class(TJavaGenericImport) end; // java.lang.StringBuffer // java.lang.StringBuilder implementation procedure RegisterTypes; begin TRegTypes.RegisterType('Androidapi.JNI.AlarmReceiver.JAlarmReceiver', TypeInfo(Androidapi.JNI.AlarmReceiver.JAlarmReceiver)); //TRegTypes.RegisterType('Androidapi.JNI.AlarmReceiver.JStringBuffer', TypeInfo(Androidapi.JNI.AlarmReceiver.JStringBuffer)); //TRegTypes.RegisterType('Androidapi.JNI.AlarmReceiver.JStringBuilder', TypeInfo(Androidapi.JNI.AlarmReceiver.JStringBuilder)); end; initialization RegisterTypes; end.
Шаг 2. Регистрация AlarmReceiver
Процесс регистрации прост. Нужно всего лишь добавить в манифест приложения эту информацию. Открываем в текстовом редакторе файл AndroidManifest.template.xml, расположенный в папке с исходниками вашего приложения. И добавляем строчку
После . Таким образом мы сказали операционной системе, что у нас есть ресивер AlarmManager и он находится в пакете com.test.
Шаг 3. Формирование интента
Интент формируется просто:
function CreateAlarmIntent(const AID: Integer): JPendingIntent; var Intent: JIntent; begin Intent := TJIntent.Create; Intent.setClass(TAndroidHelper.Context, TJlang_Class.Wrap(TJAlarmReceiver.GetClsID)); Result := TJPendingIntent.JavaClass.getBroadcast(TAndroidHelper.Context, AID, Intent, TJPendingIntent.JavaClass.FLAG_UPDATE_CURRENT); end;
В 5 строчке делаем сообщение, и в 6 строчке указываем, что класс, который должен принять этот сообщение — это наш AlarmReceiver. В положенное время:
- Сервис системы посмотрит на сообщение
- Извлечет название класса
- Создаст класс
- Передаст туда это сообщение в метод OnReceive
В 7 строчке мы создаем отложенное сообщение. Указывая контекст — приложения в рамках которого будет наше сообщение. AID — уникальный ID для возможности отменить задание в будущем. FLAG_UPDATE_CURRENT — указывает, что задание нужно обновить, если такое уже было в системе.
Шаг 4/5. Запрашиваем сервис AlarmManager и отправляем нашу задачу
Создаем интент и посылаем его через метод set.
procedure TForm19.Button1Click(Sender: TObject); var PendingIntent: JPendingIntent; begin PendingIntent := CreateAlarmIntent(1); AndroidHelper.AlarmManager.&set(TJAlarmManager.JavaClass.RTC_WAKEUP, DateTimeLocalToUnixMSecGMT(Now + EncodeTime(0, 0, 10, 0)), PendingIntent); end;
- RTC_WAKEUP — указывает, что когда время выполнения задания придет, нужно разбудить устройство, если оно находится в спящем состоянии.
- Второй параметр — время, когда требуется выполнить задание.
Код метода конвертирующего TDateTime во время андроида.
function DateTimeLocalToUnixMSecGMT(const ADateTime: TDateTime): Int64; begin Result := DateTimeToUnix(ADateTime) * MSecsPerSec - Round(TTimeZone.Local.UtcOffset.TotalMilliseconds); end;
Теперь можно запустить приложение. Выберите время, когда вы хотите проснуться и и нажмите кнопку поставить будильник.
Запуск уведомления через AlarmManager
Вот код для запуска AlarmManager, каждый день в 12 часов, который в свою очередь будет запускать ваш ресивер.
Calendar notifyTime = DateHelper.getTodayCalendarWithoutTime(); notifyTime.set(Calendar.HOUR_OF_DAY, 12); notifyTime.set(Calendar.MINUTE, 0); notifyTime.set(Calendar.SECOND, 0); Intent intent = new Intent(this, NotificationReceiver.class); PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, notifyTime.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pendingIntent);
Внутри ресивера проверяете условия запуска уведомления (нужно ли вообще запускать) и запускаете нужное уведомление или несколько уведомлений, в зависимости от ситуации.
public class NotificationReceiver extends BroadcastReceiver < @Override public void onReceive(Context context, Intent intent) < if (reminder != null) < // Запускаем уведомление MyNotification.notify(context, message, number); >> >
Сами уведомления лучше хранить отдельно и рекомендую в Android Studio добавлять их через правую кнопку мыши — UI Component / Notification. Там очень правильные шаблоны для разных типов уведомлений с подробными комментариями.