如何在 Android 上将 Qt 应用程序安装为系统应用程序?

Posted

技术标签:

【中文标题】如何在 Android 上将 Qt 应用程序安装为系统应用程序?【英文标题】:How do I install a Qt app as a system app on Android? 【发布时间】:2021-08-17 15:03:34 【问题描述】:

我正在构建一个嵌入式 android 设备,我有一个 Qt/QML 应用我想安装为系统应用。

但是,当我在将其移至 /system/app/system/priv-app 后尝试启动它时,我收到一个弹出框“您的应用程序遇到了致命错误,无法继续”

我在最简单的 QML 项目上尝试了这个,并且尽可能地使用了标准的模拟器配置,但仍然遇到了问题

当我写这个问题时,我现在正在 Windows 上执行此操作,但我在尝试从我的主要 Linux 开发机器上执行此操作时也遇到了同样的问题。

为此我遵循的步骤(有些可能与实际执行的顺序不同,我在反复试验后从记忆中回忆):

    安装 Android Studio Canary (2021.1.1 Canary 7) 安装 Android 29 SDK 和 x86 模拟器映像(Google API,而不是 Google Play),创建 Pixel 5 API 29 虚拟设备 从 Qt 维护工具/在线安装程序安装适用于 Android 的 Qt 5.15.2 安装 AdoptOpenJDK 8 运行 Qt Creator,前往 Tools->Options->Devices->Android,将其指向 AdoptOpenJDK 安装,让它设置所需的工具,并验证所有内容都有绿色复选标记 开始一个新项目并选择 Qt Quick “Swipe” 模板(最低限度的 QML 示例),5.15.2 for Android。在本例中命名为“QMLhello”。 在 5.15.2 multi-abi 的“构建”设置下的“项目”选项卡中,展开“qmake”部分并选中“x86”复选框,以便为 Android 模拟器构建 ABI 验证 Qt Creator 可以作为“普通”应用构建和运行应用(绿色的“运行”按钮成功部署和启动应用,并且可以在页面之间滑动)

我为准备将应用程序移至系统而执行的步骤:

    将环境变量studio.emu.params添加到用户环境,内容为-writable-system 重新启动 Android Studio 并冷启动 AVD 模拟器以使用环境变量中指定的可写系统启动 adb devices 将模拟器列为设备 adb rootadb remount 成功重新挂载

我在四处翻找之后尝试了什么,将 *** 上的一些旧答案结合到我的尝试中:

adb shell
mv /data/app/org.qtproject.example.QMLhello-LpZtuoO0ejyQPg_I-8pWnQ==/lib/x86/* /system/lib
mv /data/app/org.qtproject.example.QMLhello-LpZtuoO0ejyQPg_I-8pWnQ== /system/app

那个 lib 目录的内容是:

generic_x86:/data/app/org.qtproject.example.QMLhello-LpZtuoO0ejyQPg_I-8pWnQ==/lib/x86 # ls -al
total 32892
drwxr-xr-x 2 system system    4096 2021-08-17 10:48 .
drwxr-xr-x 3 system system    4096 2021-08-17 10:48 ..
-rwxr-xr-x 1 system system   18100 1981-01-01 01:01 libQMLhello_x86.so
-rwxr-xr-x 1 system system 5885892 1981-01-01 01:01 libQt5Core_x86.so
-rwxr-xr-x 1 system system 4916776 1981-01-01 01:01 libQt5Gui_x86.so
-rwxr-xr-x 1 system system 1548420 1981-01-01 01:01 libQt5Network_x86.so
-rwxr-xr-x 1 system system  478836 1981-01-01 01:01 libQt5QmlModels_x86.so
-rwxr-xr-x 1 system system   47632 1981-01-01 01:01 libQt5QmlWorkerScript_x86.so
-rwxr-xr-x 1 system system 4236260 1981-01-01 01:01 libQt5Qml_x86.so
-rwxr-xr-x 1 system system  181004 1981-01-01 01:01 libQt5QuickControls2_x86.so
-rwxr-xr-x 1 system system 1392176 1981-01-01 01:01 libQt5QuickTemplates2_x86.so
-rwxr-xr-x 1 system system 4880080 1981-01-01 01:01 libQt5Quick_x86.so
-rwxr-xr-x 1 system system  562364 1981-01-01 01:01 libQt5RemoteObjects_x86.so
-rwxr-xr-x 1 system system  931652 1981-01-01 01:01 libc++_shared.so
-rwxr-xr-x 1 system system   56196 1981-01-01 01:01 libplugins_bearer_qandroidbearer_x86.so
-rwxr-xr-x 1 system system   26304 1981-01-01 01:01 libplugins_imageformats_qgif_x86.so
-rwxr-xr-x 1 system system   34944 1981-01-01 01:01 libplugins_imageformats_qicns_x86.so
-rwxr-xr-x 1 system system   22208 1981-01-01 01:01 libplugins_imageformats_qico_x86.so
-rwxr-xr-x 1 system system  399040 1981-01-01 01:01 libplugins_imageformats_qjpeg_x86.so
-rwxr-xr-x 1 system system   18112 1981-01-01 01:01 libplugins_imageformats_qtga_x86.so
-rwxr-xr-x 1 system system  432080 1981-01-01 01:01 libplugins_imageformats_qtiff_x86.so
-rwxr-xr-x 1 system system   18112 1981-01-01 01:01 libplugins_imageformats_qwbmp_x86.so
-rwxr-xr-x 1 system system  673576 1981-01-01 01:01 libplugins_imageformats_qwebp_x86.so
-rwxr-xr-x 1 system system 1200076 1981-01-01 01:01 libplugins_platforms_qtforandroid_x86.so
-rwxr-xr-x 1 system system  150600 1981-01-01 01:01 libplugins_qmltooling_qmldbg_debugger_x86.so
-rwxr-xr-x 1 system system   67868 1981-01-01 01:01 libplugins_qmltooling_qmldbg_inspector_x86.so
-rwxr-xr-x 1 system system   14076 1981-01-01 01:01 libplugins_qmltooling_qmldbg_local_x86.so
-rwxr-xr-x 1 system system   14076 1981-01-01 01:01 libplugins_qmltooling_qmldbg_messages_x86.so
-rwxr-xr-x 1 system system   22332 1981-01-01 01:01 libplugins_qmltooling_qmldbg_native_x86.so
-rwxr-xr-x 1 system system   45316 1981-01-01 01:01 libplugins_qmltooling_qmldbg_nativedebugger_x86.so
-rwxr-xr-x 1 system system   84564 1981-01-01 01:01 libplugins_qmltooling_qmldbg_preview_x86.so
-rwxr-xr-x 1 system system   63504 1981-01-01 01:01 libplugins_qmltooling_qmldbg_profiler_x86.so
-rwxr-xr-x 1 system system   22268 1981-01-01 01:01 libplugins_qmltooling_qmldbg_quickprofiler_x86.so
-rwxr-xr-x 1 system system   55248 1981-01-01 01:01 libplugins_qmltooling_qmldbg_server_x86.so
-rwxr-xr-x 1 system system   14072 1981-01-01 01:01 libplugins_qmltooling_qmldbg_tcp_x86.so
-rwxr-xr-x 1 system system   52096 1981-01-01 01:01 libqml_QtGraphicalEffects_private_qtgraphicaleffectsprivate_x86.so
-rwxr-xr-x 1 system system   50948 1981-01-01 01:01 libqml_QtGraphicalEffects_qtgraphicaleffectsplugin_x86.so
-rwxr-xr-x 1 system system    9928 1981-01-01 01:01 libqml_QtQml_Models.2_modelsplugin_x86.so
-rwxr-xr-x 1 system system   18128 1981-01-01 01:01 libqml_QtQml_RemoteObjects_qtqmlremoteobjects_x86.so
-rwxr-xr-x 1 system system   69520 1981-01-01 01:01 libqml_QtQml_StateMachine_qtqmlstatemachine_x86.so
-rwxr-xr-x 1 system system    9932 1981-01-01 01:01 libqml_QtQml_WorkerScript.2_workerscriptplugin_x86.so
-rwxr-xr-x 1 system system    9920 1981-01-01 01:01 libqml_QtQml_qmlplugin_x86.so
-rwxr-xr-x 1 system system    9924 1981-01-01 01:01 libqml_QtQuick.2_qtquick2plugin_x86.so
-rwxr-xr-x 1 system system  600836 1981-01-01 01:01 libqml_QtQuick_Controls.2_Fusion_qtquickcontrols2fusionstyleplugin_x86.so
-rwxr-xr-x 1 system system 1611660 1981-01-01 01:01 libqml_QtQuick_Controls.2_Imagine_qtquickcontrols2imaginestyleplugin_x86.so
-rwxr-xr-x 1 system system  744164 1981-01-01 01:01 libqml_QtQuick_Controls.2_Material_qtquickcontrols2materialstyleplugin_x86.so
-rwxr-xr-x 1 system system  602016 1981-01-01 01:01 libqml_QtQuick_Controls.2_Universal_qtquickcontrols2universalstyleplugin_x86.so
-rwxr-xr-x 1 system system  652988 1981-01-01 01:01 libqml_QtQuick_Controls.2_qtquickcontrols2plugin_x86.so
-rwxr-xr-x 1 system system  378820 1981-01-01 01:01 libqml_QtQuick_Templates.2_qtquicktemplates2plugin_x86.so
-rwxr-xr-x 1 system system   40492 1981-01-01 01:01 libqml_QtQuick_Window.2_windowplugin_x86.so

Qt 在作为系统应用程序运行时尝试从 /system/lib 加载,所以我需要将它们移到那里(this *** answer 中引用的补丁集已合并)

以下是 logcat 的日志,从我点击启动器中的应用图标到它似乎已终止:

08-17 10:25:34.303  1965  4949 I ActivityTaskManager: START u0 act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=org.qtproject.example.QMLhello/org.qtproject.qt5.android.bindings.QtActivity bnds=[37,1236][238,1560] from uid 10109
08-17 10:25:34.308  1965  2005 E system_server: Invalid ID 0x00000000.
08-17 10:25:34.308  1965  1965 W ActivityManager: Unable to start service Intent  act=android.service.appprediction.AppPredictionService cmp=com.google.android.as/com.google.android.apps.miphone.aiai.app.AiAiPredictionService  U=0: not found
08-17 10:25:34.308  1965  1965 W RemoteAppPredictionService: could not bind to Intent  act=android.service.appprediction.AppPredictionService cmp=com.google.android.as/com.google.android.apps.miphone.aiai.app.AiAiPredictionService  using flags 67108865
08-17 10:25:34.308  1965  2298 W InputReader: Device has associated, but no associated display id.
08-17 10:25:34.309  1965  2298 I chatty  : uid=1000(system) Binder:1965_6 identical 28 lines
08-17 10:25:34.309  1965  2298 W InputReader: Device has associated, but no associated display id.
08-17 10:25:34.310  4888  4888 W ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@e48f5bf
08-17 10:25:34.314  1965  2298 W InputReader: Device has associated, but no associated display id.
08-17 10:25:34.314  1965  2298 I chatty  : uid=1000(system) Binder:1965_6 identical 8 lines
08-17 10:25:34.314  1965  2298 W InputReader: Device has associated, but no associated display id.
08-17 10:25:34.329  1754  2456 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 10108928
08-17 10:25:34.356  4888  4888 E Qt      : It looks like app deployed as system app. It may be necessary to specify path to system lib directory using android.app.system_libs_prefix metadata variable in your AndroidManifest.xml
08-17 10:25:34.356  4888  4888 E Qt      : Using /system/lib/ as default path
08-17 10:25:34.358  4888  4888 W System  : ClassLoader referenced unknown path:
08-17 10:25:34.384  1965  2005 W InputReader: Device has associated, but no associated display id.
08-17 10:25:34.384  1965  2005 I chatty  : uid=1000(system) android.anim identical 8 lines
08-17 10:25:34.384  1965  2005 W InputReader: Device has associated, but no associated display id.
08-17 10:25:34.387  4888  4913 W System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.os.Bundle.containsKey(java.lang.String)' on a null object reference
08-17 10:25:34.387  4888  4913 W System.err:    at org.qtproject.qt5.android.QtNative$4.run(QtNative.java:495)
08-17 10:25:34.387  4888  4913 W System.err:    at org.qtproject.qt5.android.QtThread$2.run(QtThread.java:87)
08-17 10:25:34.387  4888  4913 W System.err:    at org.qtproject.qt5.android.QtThread$1.run(QtThread.java:61)
08-17 10:25:34.387  4888  4913 W System.err:    at java.lang.Thread.run(Thread.java:919)
08-17 10:25:34.387  4888  4888 W System.err: java.lang.Exception:
08-17 10:25:34.388  4888  4888 W System.err:    at org.qtproject.qt5.android.bindings.QtLoader.loadApplication(QtLoader.java:268)
08-17 10:25:34.388  4888  4888 W System.err:    at org.qtproject.qt5.android.bindings.QtLoader.startApp(QtLoader.java:505)
08-17 10:25:34.388  4888  4888 W System.err:    at org.qtproject.qt5.android.bindings.QtActivityLoader.onCreate(QtActivityLoader.java:166)
08-17 10:25:34.388  4888  4888 W System.err:    at org.qtproject.qt5.android.bindings.QtActivity.onCreateHook(QtActivity.java:267)
08-17 10:25:34.388  4888  4888 W System.err:    at org.qtproject.qt5.android.bindings.QtActivity.onCreate(QtActivity.java:274)
08-17 10:25:34.388  4888  4888 W System.err:    at android.app.Activity.performCreate(Activity.java:7802)
08-17 10:25:34.388  4888  4888 W System.err:    at android.app.Activity.performCreate(Activity.java:7791)
08-17 10:25:34.388  4888  4888 W System.err:    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
08-17 10:25:34.388  4888  4888 W System.err:    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
08-17 10:25:34.388  4888  4888 W System.err:    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
08-17 10:25:34.388  4888  4888 W System.err:    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
08-17 10:25:34.388  4888  4888 W System.err:    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
08-17 10:25:34.388  4888  4888 W System.err:    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
08-17 10:25:34.388  4888  4888 W System.err:    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)08-17 10:25:34.388  4888  4888 W System.err:    at android.os.Handler.dispatchMessage(Handler.java:107)
08-17 10:25:34.388  4888  4888 W System.err:    at android.os.Looper.loop(Looper.java:214)
08-17 10:25:34.388  4888  4888 W System.err:    at android.app.ActivityThread.main(ActivityThread.java:7356)
08-17 10:25:34.388  4888  4888 W System.err:    at java.lang.reflect.Method.invoke(Native Method)
08-17 10:25:34.388  4888  4888 W System.err:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
08-17 10:25:34.389  4888  4888 W System.err:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
08-17 10:25:34.438  1754  2456 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 1495040
08-17 10:25:34.449  1755  2673 W EmuHWC2 : validate: layer 19 CompositionType 1, fallback
08-17 10:25:34.451  1755  2673 W EmuHWC2 : No layers, exit, buffer 0xf0612d20
08-17 10:25:34.452  4888  4909 D EGL_emulation: eglMakeCurrent: 0xe3010e40: ver 2 0 (tinfo 0xe2feea20)
08-17 10:25:34.460  1754  2456 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 1495040
08-17 10:25:34.464  1754  2456 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 1495040
08-17 10:25:34.466  1755  2673 W EmuHWC2 : validate: layer 19 CompositionType 1, fallback
08-17 10:25:34.469  1755  2673 W EmuHWC2 : No layers, exit, buffer 0xf0613080
08-17 10:25:34.479  1754  2456 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 10108928
08-17 10:25:34.483  1755  2673 W EmuHWC2 : validate: layer 19 CompositionType 1, fallback
08-17 10:25:34.489  1755  2673 W EmuHWC2 : No layers, exit, buffer 0xf06130e0
08-17 10:25:34.492  1754  2456 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 10108928
08-17 10:25:34.493  4888  4909 D EGL_emulation: eglMakeCurrent: 0xe3010e40: ver 2 0 (tinfo 0xe2feea20)
08-17 10:25:34.499  1755  2673 W EmuHWC2 : validate: layer 19 CompositionType 1, fallback
08-17 10:25:34.526  1755  2673 W EmuHWC2 : No layers, exit, buffer 0xf0612d20
08-17 10:25:34.527  1755  2673 W EmuHWC2 : validate: layer 19 CompositionType 1, fallback
08-17 10:25:34.530  1755  2673 W EmuHWC2 : No layers, exit, buffer 0xf0613080
08-17 10:25:34.532  1755  2673 W EmuHWC2 : validate: layer 19 CompositionType 1, fallback
08-17 10:25:34.545  1755  2673 W EmuHWC2 : No layers, exit, buffer 0xf06130e0
08-17 10:25:34.546  1754  2456 D gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 10108928
08-17 10:25:34.548  1755  2673 W EmuHWC2 : validate: layer 19 CompositionType 1, fallback
08-17 10:25:34.561  1755  2673 W EmuHWC2 : No layers, exit, buffer 0xf0612d20
08-17 10:25:34.563  4888  4909 D EGL_emulation: eglMakeCurrent: 0xe3010e40: ver 2 0 (tinfo 0xe2feea20)
08-17 10:25:34.565  1755  2673 W EmuHWC2 : validate: layer 19 CompositionType 1, fallback
08-17 10:25:34.569  1755  2673 W EmuHWC2 : No layers, exit, buffer 0xf0613080
08-17 10:25:34.583  1755  2673 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.584  1965  2009 I ActivityTaskManager: Displayed org.qtproject.example.QMLhello/org.qtproject.qt5.android.bindings.QtActivity: +255ms
08-17 10:25:34.586  1755  2673 W EmuHWC2 : No layers, exit, buffer 0xf06130e0
08-17 10:25:34.599  1755  2673 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.611  1755  2673 W EmuHWC2 : No layers, exit, buffer 0xf0612d20
08-17 10:25:34.616  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.618  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf0613080
08-17 10:25:34.633  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.634  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.635  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf06130e0
08-17 10:25:34.640  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.649  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.651  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.652  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf0612d20
08-17 10:25:34.655  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.666  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.668  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf0613080
08-17 10:25:34.670  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.673  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.683  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.685  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf06130e0
08-17 10:25:34.685  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.691  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.699  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.701  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf0612d20
08-17 10:25:34.704  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.709  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.716  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.718  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf0613080
08-17 10:25:34.721  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.725  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.733  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.735  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf06130e0
08-17 10:25:34.741  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.746  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.750  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.752  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf0612d20
08-17 10:25:34.757  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.761  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.766  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.768  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf0613080
08-17 10:25:34.772  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.775  2120  2352 D EGL_emulation: eglMakeCurrent: 0xe2f6dde0: ver 2 0 (tinfo 0xc15443d0)
08-17 10:25:34.783  1755  1755 W EmuHWC2 : validate: layer 20 CompositionType 1, fallback
08-17 10:25:34.786  1755  1755 W EmuHWC2 : No layers, exit, buffer 0xf06130e0
08-17 10:25:34.848  1768  1768 E Layer   : [Surface(name=AppWindowToken607c35c token=Token3592dcf ActivityRecord84abe2e u0 com.google.android.apps.nexuslauncher/.NexusLauncherActivity t8)/@0x2c802ff - animation-leash#0] No local sync point found
08-17 10:25:34.848  1768  1768 E Layer   : [Surface(name=AppWindowToken607c35c token=Token3592dcf ActivityRecord84abe2e u0 com.google.android.apps.nexuslauncher/.NexusLauncherActivity t8)/@0x2c802ff - animation-leash#0] No local sync point found
08-17 10:25:34.848  1768  1768 E Layer   : [Surface(name=AppWindowToken8151314 token=Token6bf8967 ActivityRecord6996926 u0 org.qtproject.example.QMLhello/org.qtproject.qt5.android.bindings.QtActivity t11)/@0x8dbcc29 - animation-leash#0] No local sync point found
08-17 10:25:34.848  1768  1768 E Layer   : [Surface(name=AppWindowToken8151314 token=Token6bf8967 ActivityRecord6996926 u0 org.qtproject.example.QMLhello/org.qtproject.qt5.android.bindings.QtActivity t11)/@0x8dbcc29 - animation-leash#0] No local sync point found
08-17 10:25:34.850  2955  3141 D EGL_emulation: eglMakeCurrent: 0xe2f75c00: ver 2 0 (tinfo 0xbeb4d200)
08-17 10:25:34.852  2308  2944 D EGL_emulation: eglMakeCurrent: 0xe2f66840: ver 2 0 (tinfo 0xe3005990)
08-17 10:25:34.867  2955  3134 I PBSessionCacheImpl: Deleted sessionId[497328440469] from persistence.
08-17 10:25:34.889  2955  3112 W SearchServiceCore: Abort, client detached.
08-17 10:25:34.898  1768  1768 W SurfaceFlinger: couldn't log to binary event log: overflow.

它在异常中引用的那行代码QtLoader.java line 268,如果“调用”失败,它似乎只是抛出一个空字符串异常,而没有任何关于它调用失败原因的信息。

进一步挖掘,看起来原因来自QtNative.java line 495,它在尝试调用 info.metaData.containsKey 时遇到 NullPointerException。但是我无法理解为什么对于普通应用程序没有失败的系统应用程序会失败。

我还缺少什么?

【问题讨论】:

从:***.com/a/24685920/295004 你复制到/system/priv-app 而不是/system/app。相关:source.android.com/devices/tech/config/perms-allowlist @MorrisonChang 啊,是的,也试过了,抱歉应该在问题中提到 【参考方案1】:

我的错误是将库移动到/system/lib。我相信我可能在必要时盲目地复制了先前答案的所有步骤,并且 Qt 和/或 Android 中可能已经发生了一些变化,这导致了我的问题。

出于我的目的,只需将目录从/data/app/ 完全移动/system/priv-app,保留库子目录就足够了。

adb install appname.apk
adb remount
adb shell
cd /data/app
mv appname* /system/priv-app
reboot

QtLoader 能够从/system/lib 加载一些共享库,足以进行下一步。但下一步需要首先将库放在/system/priv-app/org.qtproject.example.QMLhello-LpZtuoO0ejyQPg_I-8pWnQ==/lib/x86 处(至少在x86 模拟器的情况下 - 根据需要替换其他拱门)

否则,它有可能会遇到NullPointerException 并无法启动。

可能的解决方法

AndroidManifest.xml

中的<application>下面直接添加一些<meta-data>

详情

这是 QtNative.java 代码的 sn-p,截至 5.15.2 版本的第 489-497 行(添加了行号)

// ...
/* 489 */ File f = new File(nativeLibraryDir + mainLibNameTemplate);
/* 490 */ if (!f.exists()) 
/* 491 */     try 
/* 492 */         ApplicationInfo info = getContext().getApplicationContext().getPackageManager()
/* 493 */                 .getApplicationInfo(getContext().getPackageName(), PackageManager.GET_META_DATA);
/* 494 */         String systemLibraryDir = QtNativeLibrariesDir.systemLibrariesDir;
/* 495 */         if (info.metaData.containsKey("android.app.system_libs_prefix"))
/* 496 */             systemLibraryDir = info.metaData.getString("android.app.system_libs_prefix");
/* 497 */         f = new File(systemLibraryDir + mainLibNameTemplate);
// ...

489:当 QtNative.java 去加载主应用程序库时,它首先检查 ./lib/x86 子文件夹,在这种情况下。

492-493:当它找不到时,它会在应用程序清单中查找一些元数据,以查看应用程序是否告诉它去哪里查找。但是,当应用程序级别没有元数据时,对象的metaData 成员为空。

    不检查 null,因此会抛出 NullPointerException

空指针是怎么产生的?

Qt默认为该项目生成的AndroidManifest.xml(附在下面)不包含任何<meta-data>直接在<application>级别下的标签--而是包含在@987654336中@。 loadMainLibrary 函数应该查看 activityInfo 而不是(或除了)applicationInfo,并事先检查 null。

这似乎是 Qt 中的一个错误,我会据此报告,但 5.15.x 不会再获得任何开源更新。

<?xml version="1.0"?>
<manifest package="org.qtproject.example.QMLhello" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
    <!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
         Remove the comment if you do not require these default permissions. -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
         Remove the comment if you do not require these default features. -->
    

    <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
    <application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="QMLhello" android:extractNativeLibs="true">
        <activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="QMLhello" android:screenOrientation="unspecified" android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>

            <!-- Application arguments -->
            <!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
            <!-- Application arguments -->

            <meta-data android:name="android.app.lib_name" android:value="QMLhello"/>
            <meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
            <meta-data android:name="android.app.repository" android:value="default"/>
            <meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
            <meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
            <!-- Deploy Qt libs as part of package -->
            <meta-data android:name="android.app.bundle_local_qt_libs" android:value="1"/>

            <!-- Run with local libs -->
            <meta-data android:name="android.app.use_local_qt_libs" android:value="1"/>
            <meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
            <meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
            <meta-data android:name="android.app.load_local_jars" android:value="jar/QtAndroid.jar:jar/QtAndroidBearer.jar"/>
            <meta-data android:name="android.app.static_init_classes" android:value=""/>
            <!-- Used to specify custom system library path to run with local system libs -->
            <!-- <meta-data android:name="android.app.system_libs_prefix" android:value="/system/lib/"/> -->
            <!--  Messages maps -->
            <meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
            <meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
            <meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
            <meta-data android:value="@string/unsupported_android_version" android:name="android.app.unsupported_android_version"/>
            <!--  Messages maps -->

            <!-- Splash screen -->
            <!-- Orientation-specific (portrait/landscape) data is checked first. If not available for current orientation,
                 then android.app.splash_screen_drawable. For best results, use together with splash_screen_sticky and
                 use hideSplashScreen() with a fade-out animation from Qt Android Extras to hide the splash screen when you
                 are done populating your window with content. -->
            <!-- meta-data android:name="android.app.splash_screen_drawable_portrait" android:resource="@drawable/logo_portrait" / -->
            <!-- meta-data android:name="android.app.splash_screen_drawable_landscape" android:resource="@drawable/logo_landscape" / -->
            <!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
            <!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
            <!-- Splash screen -->

            <!-- Background running -->
            <!-- Warning: changing this value to true may cause unexpected crashes if the
                          application still try to draw after
                          "applicationStateChanged(Qt::ApplicationSuspended)"
                          signal is sent! -->
            <meta-data android:name="android.app.background_running" android:value="false"/>
            <!-- Background running -->

            <!-- auto screen scale factor -->
            <meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
            <!-- auto screen scale factor -->

            <!-- extract android style -->
            <!-- available android:values :
                * default - In most cases this will be the same as "full", but it can also be something else if needed, e.g., for compatibility reasons
                * full - useful QWidget & Quick Controls 1 apps
                * minimal - useful for Quick Controls 2 apps, it is much faster than "full"
                * none - useful for apps that don't use any of the above Qt modules
                -->
            <meta-data android:name="android.app.extract_android_style" android:value="default"/>
            <!-- extract android style -->
    </activity>

    <!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->

    </application>

</manifest>

【讨论】:

以上是关于如何在 Android 上将 Qt 应用程序安装为系统应用程序?的主要内容,如果未能解决你的问题,请参考以下文章

sh 通过adb在Android中将应用安装为系统应用

如何使用NSIS脚本将应用程序安装为Windows服务

如何防止 setuptools 将包安装为 .egg

如何将 keycloak 安装为服务,使其自动启动?

pip:为啥有时安装为鸡蛋,有时安装为文件

如何将分叉的 lerna 存储库的子包安装为节点依赖项?