How to autorun application with background service

2019-06-09 10:53发布

问题:

Is there a possibility to create an android application (with background service) in Delphi 10 Seattle that will automatically start after boot android device?

I found one solution (Auto start Delphi XE5 Android App after boot), but it is for the version Delphi XE5 and there is no option to automatically start the background service.

Any of you tried to solve this problem? If so sharing with us your solution?

UPDATED:

I do not know what's wrong.

  1. Add BroadcastReceiver to uses

  2. Registration 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. Setting 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. Update 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. Enabled the RECEIVE_BOOT_COMPLETED permission

  2. Launched the application.

  3. Stopped the application.

  4. Rebooted the machine.

  5. After rebooting the system shows an error message Application stopped.

What am I doing wrong. What is error?

回答1:

An Android service does not start running until an activity/component explicitly requests it to start running. You still need to create and register a BroadcastReceiver to receive the BOOT_COMPLETED event (like the XE5 article you linked to describes) and have your event handler start your service as needed:

Creating Android Services | Starting a Service



回答2:

You can change DanyWind's BroadcastReceiver to start a service instead of the app (host):

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);  
        }

} 

You also need to update all the XE5 paths in the build.bat to point to the equivalent paths for D10 or later.

Danny's build.bat merges the BootReceiver.dex with the default Embaracdero Classes.dex instead of using the generated classes.dex of your application (host). The paths in the batch file must be corrected. See my answer here for a more detailed description.



回答3:

I successfully worked through the problem to auto-launch an app during last week at work, using Delphi Tokyo 10.2. I'm currently looking into starting the background service, instead of the app after boot-up as the splash-screen and application currently "pop-up" each time the device starts up. (I stumbled on your question while looking into how to start the service only, and I'll try a variation of the suggested "startService" Java approach this coming weekend. Having gone through the pain, I can alleviate yours.)

Basically for the newer compilers, you no longer need the steps in Danny Wind's article that modify the "Classes.dex" file. What I describe below works for Tokyo, and will probably work for Seattle if it works the same way, which I believe it does.

You cannot use the Delphi code to register the BroadcastReceiver. That has to be done in Java, with the compiled class being in a JAR. Danny Wind's Java package will continue to do exactly the trick, on condition that you include step 4 of your question in the manifest file and step 5 of your question in the project's Android permissions.

BTW, you should not be editing the "AndroidManifest.xml" file, but rather the "AndroidManifest.template.xml" file.

If you understand how to add the JAR for the background service, you follow the same approach to add the JAR containing your BroadcastReceiver for "BOOT_COMPLETED", by going to the "Libraries" folder under the "Android" target platform and right-mouse-clicking and choosing "Add". Instead of adding your background-service JAR (which should already be there), in this case you add your JAR containing the BroadcastReceiver.

In order to compile the Java into a class, and then include that in a JAR, I use the following batch-file, which is based on Danny Wind's article and the command that Delphi runs to compile the Java it generates for the background service (which you can see in the Output tab of the Messages window):

@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=""

The batch file takes 3 parameters:

  1. Name of Java file, minus any extension.
  2. Name of JAR file, minus any extension.
  3. Name of configuration (i.e. "Debug" or "Release")

If there is only one parameter, the JAR filename will have the same name as Java file and configuration will be set to "Debug".

If there are only two parameters, configuration will be set to "Debug".

Note, the batch-file doesn't do any error checking regarding parameters right now.

The batch file uses slightly different parameters when calling "javac" than that in Danny Wind's article. These I took from what the Delphi IDE uses (as seen in the Output tab).

You will need to change the line that sets environment variable "ANDROID_JAR" to have the correct path to your compiler's "android.jar" file.

You will also need to set an environment variable named "JAVASDK" to the path of your Java SDK's "bin" folder. On my machine that is "C:\Program Files\Java\jdk1.8.0_60\bin". This I have set via "System Properties / Advanced / Environment Variables".

After compilation and archiving, the JAR containing the BroadcastReceiver will be in the "Debug" or "Release" folder depending on which configuration you've opted for.

Having added the JAR containing the BroadcastReceiver to your project, the newer versions of Delphi will then automatically link the JAR file into "Classes.dex" and ultimately the APK for your app.

Deploy the APK to your device, run the app at least once, and then restart your device. You should see your app startup once the boot has completed.