Как автозапустить приложение с фоновой службой в Delphi?

Есть ли возможность создать приложение для Android (с фоновой службой) в Delphi 10 Seattle, которое будет автоматически запускаться после загрузки устройства Android?

Я нашел одно решение (Автозапуск Android-приложения Delphi XE5 после загрузки), но это для версии Delphi XE5 и нет опции автоматического запуска фоновой службы.

Кто-нибудь из вас пытался решить эту проблему? Если да, поделитесь с нами своим решением?

ОБНОВЛЕНО:

Я не знаю, что случилось.

  1. Добавить BroadcastReceiver для использования

  2. Регистрация BroadcastReceiver

    procedure TForm1.CreateBroadcastReceiver;
    begin
      if not Assigned(BroadcastReceiver) then
        begin
          BroadcastReceiver:= TCSBroadcastReceiver.Create(nil);
          BroadcastReceiver.OnReceive:= BroadcastReceiverOnReceive;
          BroadcastReceiver.RegisterReceive;
          BroadcastReceiver.Add('android.intent.action.BOOT_COMPLETED');
        end;
    end;
    
  3. Настройка BroadcastReceiver OnReceive

    procedure TForm1.BroadcastReceiverOnReceive(csContext: JContext; csIntent: JIntent);
    var
      Inx: JIntent;
    begin
      if JStringToString(csIntent.getAction).Contains('android.intent.action.BOOT_COMPLETED') then
        begin
          Inx := TJIntent.Create;
          Inx.setClassName(csContext, StringToJString('com.embarcadero.firemonkey.FMXNativeActivity'));
          Inx.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK);
          TAndroidHelper.Context.startActivity(Inx);
        end;
    end;
    
  4. Обновить AndroidManifest.xml

<receiver android:name="com.embarcadero.rtl.notifications.NotificationAlarm" />
<receiver android:name="com.embarcadero.ProjectBCTA"
  android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
    <intent-filter>
    <action android:name="android.intent.action.BOOT_COMPLETED" />
    <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</receiver>
  1. Включено разрешение RECEIVE_BOOT_COMPLETED

  2. Запустил приложение.

  3. Остановил приложение.

  4. Перезагрузил машину.

  5. После перезагрузки система показывает сообщение об ошибке Приложение остановлено.

Что я делаю неправильно? Что такое ошибка?


person KJAN    schedule 10.12.2015    source источник
comment
Я узнал, что этот широковещательный приемник нельзя использовать, потому что это не сервис, а только динамический.   -  person KJAN    schedule 12.12.2015
comment
Вы должны попытаться создать свой собственный файл jar, а затем включить в проект другие файлы jar в библиотеках? См. docwiki.embarcadero.com/RADStudio/Seattle/en/.   -  person pudnivec74    schedule 12.12.2015
comment
Привет КЯН. Вам когда-нибудь удавалось написать BroadcastReceiver для BOOT_COMPLETED, используя только код Delphi? Я тоже застрял здесь. Ваш подход может потерпеть неудачу, потому что BroadcastReceiver необходим для запуска приложения и создания основной формы, а в вашем коде форма создает BroadcastReceiver.   -  person Joachim Marder    schedule 31.08.2017


Ответы (3)


Служба Android не запускается до тех пор, пока действие/компонент явно не запросит ее запуск. Вам по-прежнему необходимо создать и зарегистрировать BroadcastReceiver для получения события BOOT_COMPLETED (например, описывается статья XE5, на которую вы ссылаетесь), и ваш обработчик событий запускает вашу службу по мере необходимости:

Создание служб Android | Запуск службы

person Remy Lebeau    schedule 10.12.2015
comment
Я создал широковещательный приемник (использовал этот: stackoverflow.com/questions/33609494/). Как мне продолжить регистрацию BOOT_COMPLETED во время загрузки системы? Например, при регистрации android.intent.action.PHONE_STATE? Должно быть что-то еще вручную отредактировано? - person KJAN; 11.12.2015
comment
Вам необходимо отредактировать файл Manifest File вашего проекта, чтобы включить RECEIVE_BOOT_COMPLETED разрешение, и зарегистрироваться для получения BOOT_COMPLETED намерение. К счастью, внутри IDE вы можете зайти в параметры проекта и включить параметр Receive boot completed в Uses Permissions раздел. Но вам нужно отредактировать AndroidManifest.xml напрямую, чтобы зарегистрироваться для BOOT_COMPLETED. В статье XE5 показано, как это сделать. - person Remy Lebeau; 11.12.2015
comment
Спасибо за совет. Завтра попробую эту процедуру и отпишусь как все получилось. - person KJAN; 11.12.2015
comment
Поэтому я попытался создать. У меня возникла ошибка Watchtower Приложение остановлено после перезагрузки системы. Посмотрите на мой ОБНОВЛЕННЫЙ ОТВЕТ. Где ошибка? - person KJAN; 11.12.2015
comment
Вы говорите нам. Отладьте код и расскажите нам, как далеко он продвинулся, прежде чем произошел сбой. Вызывается ли TForm1.CreateBroadcastReceiver() (и откуда он вызывается)? TForm1.BroadcastReceiverOnReceive() звонят? TAndroidHelper.Context.startActivity() звонят? Кстати, все приложения FireMonkey используют FMXNativeActivity, поэтому вы не можете запустить конкретное приложение, используя это имя класса. Кроме того, это неправильный способ запуска службы. Вы прочитали ссылку в моем ответе? - person Remy Lebeau; 11.12.2015
comment
Я узнал, что этот широковещательный приемник нельзя использовать, потому что это не сервис, а только динамический. - person KJAN; 12.12.2015

Я успешно решил проблему автоматического запуска приложения на прошлой неделе на работе, используя Delphi Tokyo 10.2. В настоящее время я изучаю запуск фоновой службы вместо приложения после загрузки, поскольку заставка и приложение в настоящее время «всплывают» каждый раз при запуске устройства. (Я наткнулся на ваш вопрос, изучая, как запустить только службу, и я попробую вариант предложенного Java-подхода «startService» в ближайшие выходные. Пройдя через боль, я могу облегчить вашу.)

В основном для более новых компиляторов вам больше не нужны шаги в статье Дэнни Винд, которые изменяют файл «Classes.dex». То, что я описываю ниже, работает для Токио и, вероятно, сработает для Сиэтла, если будет работать так же, как я думаю, так оно и есть.

Вы не можете использовать код Delphi для регистрации BroadcastReceiver. Это должно быть сделано на Java, а скомпилированный класс находится в JAR. Пакет Дэнни Винд для Java будет по-прежнему делать то же самое, при условии, что вы включите шаг 4 своего вопроса в файл манифеста и шаг 5 своего вопроса в разрешениях проекта Android.

Кстати, вы не должны редактировать файл «AndroidManifest.xml», а скорее файл «AndroidManifest.template.xml».

Если вы понимаете, как добавить JAR для фоновой службы, вы следуете тому же подходу, чтобы добавить JAR, содержащий ваш BroadcastReceiver для «BOOT_COMPLETED», перейдя в папку «Библиотеки» под целевой платформой «Android» и щелкнув правой кнопкой мыши. нажав и выбрав «Добавить». Вместо добавления JAR-файла фоновой службы (который уже должен быть там) в этом случае вы добавляете JAR-файл, содержащий BroadcastReceiver.

Чтобы скомпилировать Java в класс, а затем включить его в JAR, я использую следующий пакетный файл, основанный на статье Дэнни Винд и команде, которую запускает Delphi для компиляции Java, которую он генерирует для фоновой службы ( который вы можете увидеть на вкладке «Вывод» окна «Сообщения»):

@ECHO OFF
rem Path to Android classes JAR-file
SET ANDROID_JAR="C:\Users\Public\Documents\Embarcadero\Studio\19.0\PlatformSDKs\android-sdk-windows\platforms\android-26\android.jar"
rem Setup parameters
SET SOURCE_FILE=%1
SET JAR_FILE=%2
IF x%2 == x SET JAR_FILE=%SOURCE_FILE%
SET CONFIGURATION=%3
IF x%3 == x SET CONFIGURATION=Debug
rem Ensure directory to hold Java Class files exists for Java Archive
MKDIR JavaClasses\%JAR_FILE% 2> NUL
rem Indicate actions
ECHO .
ECHO Compiling %SOURCE_FILE%.java to %SOURCE_FILE%.class and storing in %CONFIGURATION%\%JAR_FILE%.jar...
ECHO .
rem Compile Java Class file
"%JAVASDK%\javac" -Xlint:deprecation -classpath %ANDROID_JAR% -bootclasspath %ANDROID_JAR% -d JavaClasses\%JAR_FILE% -target 1.6 -g -source 1.6 %SOURCE_FILE%.java
rem Create Java Archive file containing class file
"%JAVASDK%\jar" cf %CONFIGURATION%\%JAR_FILE%.jar -C .\JavaClasses\%JAR_FILE% com
rem Clean-up
SET ANDROID_JAR=""
SET SOURCE_FILE=""
SET JAR_FILE=""
SET CONFIGURATION=""

Пакетный файл принимает 3 параметра:

  1. Имя файла Java без расширения.
  2. Имя файла JAR без расширения.
  3. Имя конфигурации (например, «Отладка» или «Выпуск»)

Если имеется только один параметр, имя файла JAR будет совпадать с именем файла Java, а для конфигурации будет установлено значение «Отладка».

Если есть только два параметра, конфигурация будет установлена ​​на «Отладка».

Обратите внимание, что сейчас пакетный файл не проверяет параметры на наличие ошибок.

Пакетный файл использует несколько другие параметры при вызове «javac», чем в статье Дэнни Винд. Я взял их из того, что использует Delphi IDE (как показано на вкладке «Вывод»).

Вам нужно будет изменить строку, которая устанавливает переменную среды «ANDROID_JAR», чтобы иметь правильный путь к файлу «android.jar» вашего компилятора.

Вам также потребуется установить переменную среды с именем «JAVASDK» на путь к папке «bin» вашего Java SDK. На моей машине это «C:\Program Files\Java\jdk1.8.0_60\bin». Это я установил через «Свойства системы/Дополнительно/Переменные среды».

После компиляции и архивирования JAR-файл, содержащий BroadcastReceiver, будет находиться в папке «Debug» или «Release» в зависимости от выбранной вами конфигурации.

После добавления JAR-файла, содержащего BroadcastReceiver, в ваш проект, более новые версии Delphi автоматически свяжут JAR-файл с «Classes.dex» и, в конечном итоге, с APK для вашего приложения.

Разверните APK на своем устройстве, запустите приложение хотя бы один раз, а затем перезагрузите устройство. Вы должны увидеть запуск вашего приложения после завершения загрузки.

person Roland Skinner    schedule 08.03.2018
comment
Ты был прав. Больше нет необходимости объединять .dex. :-) - person nolaspeaker; 01.03.2020

Вы можете изменить BroadcastReceiver DanyWind, чтобы запустить службу вместо приложения (хоста):

package com.dannywind.delphi;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.Context;

public class BootReceiver extends BroadcastReceiver
{

        @Override
        public void onReceive(Context context, Intent intent) 
        {
           Intent launchintent = new Intent();
           launchintent.setClassName(context, "com.embarcadero.services.MyLocationService");           
           context.startService(launchintent);  
        }

} 

Вам также необходимо обновить все пути XE5 в build.bat, чтобы они указывали на эквивалентные пути для D10 или более поздней версии.

build.bat Дэнни объединяет BootReceiver.dex с Embaracdero Classes.dex по умолчанию вместо использования сгенерированного class.dex вашего приложения (хоста). Пути в пакетном файле должны быть исправлены. См. мой ответ здесь для более подробного описания.

person nolaspeaker    schedule 14.12.2015