我正在尝试从文章Auto start Delphi XE5 Android App after boot构建一个在启动时启动的Android FireMonkey应用,但始终出现错误 INSTALL_FAILED_UID_CHANGED
引用文章:
如何使用广播接收器在Android设备上BOOT_COMPLETED后自动启动Delphi XE5应用程序。
在良好的DOS时代,我们可以在启动后通过将其添加到autoexec.bat来启动应用程序。在Windows下,您可以使用注册表添加程序以启动,或使用msconfig查看启动程序。但是这在Android下如何运作?
设备启动后自动启动Delphi XE5 Android应用程序可以通过创建一个侦听BOOT_COMPLETED广播意图的广播接收器来完成。
本文介绍了使用Delphi XE5创建此类广播接收器所需的步骤:
创建一个新的Delphi XE5 Android项目 set使用权限来接收启动完成 修改AndroidManifest.template.xml让Android系统知道你有一个广播接收器 写一些Java代码 将它添加到classes.dex中 在项目中使用这个新的classes.dex 在设备上运行应用程序 创建一个新的Delphi XE5 Android项目
这一步应该很简单,File |新的| Firemonkey移动应用程序。只需将它保存在您也可以使用命令提示符控制台访问的位置。
设置使用权限
所有Android应用必须在Android Manifest中注册所需的权限。安装应用程序包时,Android系统会读取清单,并通知用户所请求的权限。如果您忘记列出所需的权限,系统将拒绝访问该功能。在这种情况下,我们需要获得接收启动权限。
打开项目|选项并使用权限将此权限设置为true。
ReceiveBootCompleted
修改AndroidManifest.template.xml
每次将项目部署到apk时,Delphi IDE都会使用Android Manifest模板为您的Android软件包(.apk)重新创建清单。如果你想修改Manifest,可以这样做。
在此清单中,我们将通知Android系统我们有广播意图BOOT_COMPLETED的接收器。新代码是黑色的,现有的蓝色代码:
</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) –>
编写一些Java代码
不幸的是,当前版本的Delphi没有预先定义的接收器,我们可以使用它来自动启动应用程序。为了实现这一点,我们必须编写一些Java代码并将其包含在Delphi Android应用程序的classes.dex文件中。
Java代码如下。使用BootReceiver.java作为文件名:
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);
}
}
用于启动活动的上下文变量实际上是您的应用程序的上下文。我们基本上是从应用程序内部启动应用程序作为新任务。因为默认Delphi应用程序中的本机活动具有默认名称,所以我们可以启动当前应用程序的com.embarcadero.firemonkey.FMXNativeActivity。
将其添加到classes.dex
Delphi有一个预编译的classes.dex,它在部署步骤中被放入任何Delphi Android包中。我们将把这个Java代码添加到classes.dex中,并使用Deployment Manager将默认的classes.dex替换为我们的修改版本。
在项目目录中创建一个子目录java \ src \ com \ dannywind \ delphi并将BootReceiver.java代码放在那里。使用以下批处理文件代码构建Java代码:
@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
上面的批处理文件最初是由Brian Long编写的,用于将您自己的Java脚本与classes.dex合并。感谢Brian让它可用。我对它进行了一些小修改。
将build.bat文件放入项目目录project \ java下的java子目录中,打开命令提示符,然后运行build.bat。
运行批处理文件时,您会看到警告“未设置引导类路径”。我们使用与Delphi XE5捆绑在一起的Java SDK 1.7为classes.dex构建1.6兼容的源代码。如果您安装了1.6,则可以添加此选项以消除警告“-bootclasspath C:\ _jdk1.6.0 \ lib \ rt.jar”,但您也可以安全地忽略它,因为它不会以任何方式干扰用我们的Java代码片段。
使用这个新的classes.dex
使用Deployment Manager,我们禁用默认的classes.dex,并使用add files按钮添加新的扩展classes.dex文件。
DeploymentClassesDex
在设备上运行应用
现在在Android设备上运行该应用。如果它成功运行,只需让它运行,然后长按开/关按钮关闭设备。 Android会询问您是否要将其关闭,当然这样做。现在重新打开它,你的Delphi应用程序将在启动序列完成后自动运行。
提示
Delphi XE5 IDE确实希望您使用默认的classes.dex文件,因此每次切换部署配置时它都会重新启用它。如果您收到“App已停止”消息,请先检查Delphi是否未重新启用默认的classes.dex文件。您也可以通过扫描logcat查找“未找到类”com.dannywind.delphi.BootReceiver“”来确认这一点。
使用Project |时部署,Delphi在您的本地硬盘上创建一个.apk文件。它实际上并未部署到您的Android设备。要部署到设备,只需运行它。
如果处于停止状态,您的自动运行Delphi应用程序将不会收到启动已完成的事件。此功能已添加到Android 3.1以提高安全性(http://developer.android.com/about/versions/android-3.1.html#api)。这意味着用户必须至少运行一次应用程序,因为这将使其无法锁定。此外,如果您使用管理应用程序强制停止应用程序,它将再次处于停止状态,并且将不再自动运行。只需再次运行应用程序,自动运行将再次运行。请注意,使用最近的应用按钮关闭应用,然后向上滑动;不等于力接近并且不使其处于停止状态。如果您以这种方式关闭应用程序,它将在重新启动后成功自动运行。
有没有人用这种方法取得成功? 或者有人知道另一种方法?
答案 0 :(得分:0)
我在android中有一个示例应用程序。
宣言文件:
<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>
和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
}
}
从github下载我的完整示例:link is here
答案 1 :(得分:0)
我刚才有理由重新访问我的可启动服务Delphi Android项目,所以我想我会在这里添加一个答案。
Brian Long(后来由Danny Wind)提供的原始批处理文件的问题在于它使用EMBT classes.dex,而不是使用项目本身构建中的classes.dex!也就是说: EMBO_DEX 变量应指向以下内容:
SET EMBO_DEX = C:\ MyProject \ Android \ Debug \ classes.dex
换句话说,为了实现目标,首先构建MyProject,然后在生成项目的classes.dex之后,运行批处理文件以生成合并的dex文件(可在java \ output \中找到) dex文件夹)。
然后必须使用您的应用程序部署合并的dex,而不是C:\ MyProject \ Android \ Debug \文件夹中的classes.dex!调整项目 - >部署以确保它能够做到这一点。当您从IDE运行应用程序时,会发生部署(合并的dex文件)。
根据您使用的Delphi版本,bat文件中的某些路径也需要更新:
例如,对于Delphi 10.1,这些变量看起来像:
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"
并且取决于您在系统上安装的Java版本
set JAVASDK="C:\Program Files\Java\jdk1.8.0_60\bin"
对于与此相关的其他任务,Danny Wind的原始指南仍然有效。