1
votes

I am trying from the article Auto start Delphi XE5 Android App after boot to build a Android FireMonkey app that starts on boot, but always got the error INSTALL_FAILED_UID_CHANGED

Quoting from the article:


How to use a broadcast receiver to automatically start a Delphi XE5 App after BOOT_COMPLETED on an Android device.

In good ol’ DOS days we could start an application after boot by adding it to autoexec.bat. Under Windows you can add a program to startup using the registry or view startup programs with msconfig. But how does this work under Android?

Automatically starting a Delphi XE5 Android app after the device has booted up can be done by creating a broadcast receiver that listens to the BOOT_COMPLETED broadcast intent.

This article descibes the steps necessary to create such a broadcast receiver with Delphi XE5:

create a new Delphi XE5 Android project set uses permissions to receive boot completed modify AndroidManifest.template.xml to let the Android system know you have a broadcast receiver write some Java code add it to the classes.dex use this new classes.dex in your project run the app on device Create a new Delphi XE5 Android project

This step should be easy enough, File | New | Firemonkey Mobile Application. Just save it someplace that you can also reach with the command prompt console.

Set uses permissions

All Android apps must register which permissions they need in the Android Manifest. The manifest is read by the Android system when installing the app package and the user is notified of the requested permissions. If you forgot to list a permission you need, access to that function will be denied by the system. In this case we need the receive boot completed permission.

Open Project | Options and uses permissions to set this permission to true.

ReceiveBootCompleted

Modify AndroidManifest.template.xml

The Android Manifest template is used by the Delphi IDE to re-create the manifest for your Android package (.apk), each time you deploy the project to an apk. If you want to modify the Manifest, this is the place to do so.

In this manifest we will notify the Android system that we have a receiver for the broadcast intent BOOT_COMPLETED. The new code is in black, existing stuff in blue:

</activity>
<receiver android:name=”com.embarcadero.firemonkey.notifications.FMXNotificationAlarm” />
<receiver android:name=”com.dannywind.delphi.BootReceiver”
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>
</application>
</manifest>
<!– END_INCLUDE(manifest) –>

Write some Java code

Unfortunately the current version of Delphi does not have a pre-defined receiver that we can use to autostart the app. To make this possible we have to write a bit of Java code and include this into the classes.dex file of your Delphi Android app.

The Java code is as follows. Use BootReceiver.java as the file name:

package com.dannywind.delphi;import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.Context;
import android.util.Log;
public class BootReceiver extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
Intent launchintent = new Intent();
launchintent.setClassName(context, “com.embarcadero.firemonkey.FMXNativeActivity”);
launchintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(launchintent);
}
}

The context variable used to start the activity is actually your app’s context. We’re essentially starting the app, from within the app as a new task. Because the native activity in a default Delphi app has a default name, we can just start the com.embarcadero.firemonkey.FMXNativeActivity of the current app.

Add it to the classes.dex

Delphi has a pre-compiled classes.dex which is put into any Delphi Android package in the deployment step. We are going to add this Java code to the classes.dex, and use the deployment manager to replace the default classes.dex with our modified version.

In your project directory create a subdirectory java\src\com\dannywind\delphi and place the BootReceiver.java code there. Build the Java code using the following batch file code:

@echo off
echo.
echo Compiles your Java code into classes.dex
echo Verified to work in Delphi XE5 Update 1 and 2
echo.
echo Place this batch in a java folder below your project (project\java)
echo Place the source in project\java\src\com\dannywind\delphi
echo If your source file location or name is different, please modify it below.
echo.setlocal
set ANDROID_JAR=”C:\Users\Public\Documents\RAD Studio\12.0\PlatformSDKs\adt-bundle-windows-x86-20130522\sdk\platforms\android-17\android.jar”
set DX_LIB=”C:\Users\Public\Documents\RAD Studio\12.0\PlatformSDKs\adt-bundle-windows-x86-20130522\sdk\build-tools\android-4.2.2\lib”
set EMBO_DEX=”C:\Program Files (x86)\Embarcadero\RAD Studio\12.0\lib\android\debug\classes.dex”
set PROJ_DIR=%CD%
set VERBOSE=0
set JAVASDK=”C:\Program Files\Java\jdk1.7.0_25\bin”
set DX_BAT=”C:\Users\Public\Documents\RAD Studio\12.0\PlatformSDKs\adt-bundle-windows-x86-20130522\sdk\build-tools\android-4.2.2\dx.bat”
echo.
echo Compiling the Java source files
echo.
pause
mkdir output 2> nul
mkdir output\classes 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=-verbose
%JAVASDK%\javac %VERBOSE_FLAG% -Xlint:all -classpath %ANDROID_JAR% -d output\classes -source 1.6 -target 1.6 src\com\dannywind\delphi\BootReceiver.java

echo.
echo Creating jar containing the new classes
echo.
pause
mkdir output\jar 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=v
%JAVASDK%\jar c%VERBOSE_FLAG%f output\jar\test_classes.jar -C output\classes com

echo.
echo Converting from jar to dex…
echo.
pause
mkdir output\dex 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=–verbose
call %DX_BAT% –dex %VERBOSE_FLAG% –output=%PROJ_DIR%\output\dex\test_classes.dex –positions=lines %PROJ_DIR%\output\jar\test_classes.jar

echo.
echo Merging dex files
echo.
pause
%JAVASDK%\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.
echo Now use output\dex\classes.dex instead of default classes.dex
echo And add broadcastreceiver to AndroidManifest.template.xml
echo.

:Exit
endlocal

The above batch file was originally written by Brian Long for merging your own Java scripts with classes.dex. Thanks to Brian for making it available. I have made some minor modifications to it.

Place the build.bat file into the java subdirectory under your project directory project\java, open a command prompt and just run build.bat.

When running the batch file you’ll see a warning “bootstrap class path not set”. We are using the Java SDK 1.7 that is bundled with Delphi XE5 to build 1.6 compatible source code for classes.dex. If you do have 1.6 installed you can add this option to get rid of the warning “-bootclasspath C:\jdk1.6.0\lib\rt.jar”, but you can also just ignore it safely as it will not in any way interfere with our snippet of Java code.

Use this new classes.dex

Using the deployment manager we disable the default classes.dex, and add our new expanded classes.dex file with the add files button.

DeploymentClassesDex

Run the app on device

Now run the app on the Android device. If it runs succesfully, just let it run, and switch the device off with a long press on the on/off button. Android will ask you if you want to switch it off, which of course you do. Now turn it back on and your Delphi app will autorun after the boot sequence is completed.

Tips

The Delphi XE5 IDE really wants you to use the default classes.dex file, so it will re-enable it every time you switch deployment configuration. If you get a “App has stopped” message, please check first if Delphi hasn’t re-enabled the default classes.dex file. You can also confirm this by scanning logcat for “Didn’t find class “com.dannywind.delphi.BootReceiver””.

When you use Project | Deploy, Delphi creates an .apk file on your local harddisk. It does not actually deploy to your Android device. To deploy to device, just run it.

Your autorun Delphi app will not receive a boot completed event if it is in a stopped state. This is a feature that was added to Android 3.1 to improve security (http://developer.android.com/about/versions/android-3.1.html#api). What this means is the user must run the app at least once, as this will get it out of lockdown. Also if you force stop the app using manage applications it will again be in a stopped state and will no longer autorun. Just run the app once again and autorun will work again. Please note that closing the app with the recent apps button and then swiping it up; does not equal a force close and does not put it in a stopped state. If you close your app this way it will succesfully autorun after reboot.


Does anybody got success with this method?
Or someone knows another method?

2
We should not have to leave this site to figure out what you're asking. All relevant content needs to be here, in your question. As written, your question is meaningless if the off-site location is unavailable for some reason. Please edit to include the details here. Thanks.Ken White
Thanks for your help Mr. White.Camila Camargo
@Camila Please step back and look at your post: after your edit it is now one large blob of text. You have just dumped the article in that you originally linked to. Can you edit your post to make it readable? Remove non-essential text, make clear where you are quoting, add line feeds etc. When you are in the editor the right side bar gives you help and you can preview your post live below the edit window. I have started a little already.Jan Doggen
@camila Also, where is the relevant part of your code and where exactly does it get the error?Jan Doggen
Hi Jan, none of them. The code is complet correct, the error appears when i run the project. "INSTALL_FAILED_UID_CHANGED"Camila Camargo

2 Answers

0
votes

I have a sample app in android.

Manifesto file:

<uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.errorpoint.startupapp.StartupActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
            android:name="com.errorpoint.startupapp.RebootReceiving" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>


    </application>

And BroadCastReceiver:

public class RebootReceiving extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "Reboot completed! Starting your app!!!.", Toast.LENGTH_LONG).show();
        Intent i = new Intent(context, StartupActivity.class);
        i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(i);

        //all works is done in manifest file
    }

}

Download my full example from github: link is here

0
votes

I've just had a reason to revisit my bootable service Delphi Android project, so I thought I'd add an answer here.

The problem with the original batch file supplied by Brian Long (and later by Danny Wind) is that it uses the EMBT classes.dex, instead of using the classes.dex from a build of the project itself! That is: the EMBO_DEX variable should point to something like:

SET EMBO_DEX=C:\MyProject\Android\Debug\classes.dex

In other words to achieve the goal, you build your MyProject first, then once the project's classes.dex has been generated, you run the batch file to generate a merged dex file (which will be found in the java\output\dex folder).

It is the merged dex must then be deployed with your app and not the classes.dex from C:\MyProject\Android\Debug\ folder! Adjust your project->deployment to make sure it does that. Deployment (of the merged dex file) occurs when you RUN the app from the IDE.

Depending on the Delphi version you are using, some of the paths in the bat file need to be updated also:

For Delphi 10.1, for example, these vars look like:

set ANDROID_JAR="C:\Users\Public\Documents\Embarcadero\Studio\18.0\PlatformSDKs\android-sdk-windows\platforms\android-22\android.jar"
set DX_LIB="C:\Users\Public\Documents\Embarcadero\Studio\18.0\PlatformSDKs\android-sdk-windows\build-tools\22.0.1\lib"
set DX_BAT="C:\Users\Public\Documents\Embarcadero\Studio\18.0\PlatformSDKs\android-sdk-windows\build-tools\22.0.1\dx.bat"

and depending on which version of Java you have installed on your system

set JAVASDK="C:\Program Files\Java\jdk1.8.0_60\bin"

For the other tasks related to making this work, the Danny Wind's original guide is still as valid as ever.