【发布时间】:2014-12-25 22:38:30
【问题描述】:
我正在尝试从文章 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);
}
}
用于启动 Activity 的上下文变量实际上是您应用的上下文。我们本质上是从应用程序内部作为一项新任务启动应用程序。因为默认 Delphi 应用中的原生 Activity 有一个默认名称,所以我们可以直接启动当前应用的 com.embarcadero.firemonkey.FMXNativeActivity。
将其添加到 classes.dex 中
Delphi 有一个预编译的 classes.dex,它在部署步骤中被放入任何 Delphi Android 包中。我们将把这段 Java 代码添加到 classes.dex 中,并使用部署管理器将默认的 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 代码 sn-p。
使用这个新的 classes.dex
使用部署管理器,我们禁用默认的 classes.dex,并使用添加文件按钮添加新的扩展 classes.dex 文件。
DeploymentClassesDex
在设备上运行应用程序
现在在 Android 设备上运行该应用。如果它运行成功,让它运行,然后长按开/关按钮关闭设备。 Android 会询问您是否要关闭它,您当然会这样做。现在重新打开它,您的 Delphi 应用程序将在启动序列完成后自动运行。
提示
Delphi XE5 IDE 确实希望您使用默认的 classes.dex 文件,因此每次切换部署配置时它都会重新启用它。如果您收到“应用程序已停止”消息,请先检查 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)。这意味着用户必须至少运行一次应用程序,因为这将使其脱离锁定状态。此外,如果您使用管理应用程序强制停止应用程序,它将再次处于停止状态并且不再自动运行。只需再次运行该应用程序,自动运行将再次运行。请注意,使用最近的应用按钮关闭应用,然后向上滑动;不等于力关闭,也不会将其置于停止状态。如果您以这种方式关闭应用程序,它将在重新启动后成功自动运行。
有人用这种方法成功了吗?
还是有人知道另一种方法?
【问题讨论】:
-
我们不应该离开这个网站来弄清楚你在问什么。在您的问题中,所有相关内容都需要在这里。如前所述,如果由于某种原因无法使用场外位置,您的问题将毫无意义。请edit 在此处包含详细信息。谢谢。
-
感谢怀特先生的帮助。
-
@Camila 请退后一步,看看你的帖子:编辑后它现在是一大块文本。您刚刚转储了您最初链接到的文章。你能edit your post 让它可读吗?删除不必要的文本,明确引用的位置,添加换行符等。当您在编辑器中时,右侧栏会为您提供帮助并且您可以在编辑窗口下方实时预览您的帖子。我已经开始了一点。
-
@camila 另外,你的代码的相关部分在哪里,它到底在哪里得到错误?
-
嗨 Jan,没有一个。代码完全正确,运行项目时出现错误。 “INSTALL_FAILED_UID_CHANGED”
标签: android delphi firemonkey