Qt/C++/Android - 如何安装 .APK文件以编程方式
Qt/C++/Android - How to install an .APK file programmatically?
我正在我的应用程序中实现自己的自动更新程序。我能够成功地将较新版本的.apk文件下载到SD卡上的/Download文件夹中,但是我不知道如何打开/运行该文件,以便向用户显示新的安装对话框。
我唯一能想到的:
QString downloadedAPK = "/storage/emulated/0/Download/latest.apk"; // Not hardcoded, but wrote it here this way for simplicity
QDesktopServices::openUrl(QUrl(downloadedAPK));
调试器输出:
D/Instrumentation(26418): checkStartActivityResult :Intent { act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/latest.apk }
D/Instrumentation(26418): checkStartActivityResult inent is instance of inent:
W/System.err(26418): android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=file:///storage/emulated/0/Download/latest.apk }
W/System.err(26418): at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1660)
W/System.err(26418): at android.app.Instrumentation.execStartActivity(Instrumentation.java:1430)
W/System.err(26418): at android.app.Activity.startActivityForResult(Activity.java:3532)
W/System.err(26418): at android.app.Activity.startActivityForResult(Activity.java:3493)
W/System.err(26418): at android.app.Activity.startActivity(Activity.java:3735)
W/System.err(26418): at android.app.Activity.startActivity(Activity.java:3703)
W/System.err(26418): at org.qtproject.qt5.android.QtNative.openURL(QtNative.java:110)
W/System.err(26418): at dalvik.system.NativeStart.run(Native Method)
我到处寻找,但从未找到有关从Qt打开APK的任何信息。我唯一发现的是使用 JNI 的 solutoin(我不想使用它,因为用 C++ 做更简单,而且因为我对整个 C++/JNI 的事情没有经验(,它没有很好的文档,所以我不明白如何让它工作。
那么,打开下载的apk的最简单方法是什么?
编辑:
我遵循了Tumbus的回答,但由于一些编译错误,我不得不对他的JNI代码进行一些修改,如下所示:
void Updater::InstallApp(const QString &appPackageName)
{
qDebug() << "[+] APP: " << appPackageName; // Which is the string ("/storage/emulated/0/Download/latest.apk")
QAndroidJniObject app = QAndroidJniObject::fromString(appPackageName);
QAndroidJniObject::callStaticMethod<jint>("AndroidIntentLauncher",
"installApp",
"(Ljava/lang/String;)I",
app.object<jstring>());
}
当我在Android设备上运行我的应用程序时,它会从我的服务器中提取最新的.apk文件,然后什么也没发生。为什么?(到目前为止.xml我还没有对AndroidManifest进行任何更改(。
您必须自定义意图才能安装APK。有关详细信息,请参阅此问题。
恐怕这种特定于平台的想法必须调用特定于平台的 API。好消息是Qt框架简化了JNI的总结,你可以在Android项目中包含一个Java类。因此,我会从Qt调用自己的静态Java函数。
例
爪哇类
package io.novikov.androidintentlauncher;
import org.qtproject.qt5.android.QtNative;
import java.lang.String;
import java.io.File;
import android.content.Intent;
import android.util.Log;
import android.net.Uri;
import android.content.ContentValues;
import android.content.Context;
public class AndroidIntentLauncher
{
protected AndroidIntentLauncher()
{
}
public static int installApp(String appPackageName) {
if (QtNative.activity() == null)
return -1;
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(appPackageName)),
"application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
QtNative.activity().startActivity(intent);
return 0;
} catch (android.content.ActivityNotFoundException anfe) {
return -3;
}
}
}
请注意,startActivity(( 应该作为 *QtNative.activity(( 中的方法调用。我们必须根据常规规则维护 java 的特殊目录结构。该示例位于下面的生成文件部分。
杰尼
调用此方法C++代码有点棘手。
const static char* MY_JAVA_CLASS = "io/novikov/androidintentlauncher/AndroidIntentLauncher";
static void InstallApp(const QString &appPackageName) {
QAndroidJniObject jsText = QAndroidJniObject::fromString(appPackageName);
QAndroidJniObject::callStaticMethod<jint>(MY_JAVA_CLASS,
"installApp",
"(Ljava/lang/String;)I",
jsText.object<jstring>());
}
字符串文字"(Ljava/lang/String;(I"是java方法的签名。Java 类的名称必须采用完整的格式"my/domain/my_app/MyClass">
生成文件
最后一个挑战是将 java 代码正确包含在项目中。在 .pro 文件的相应片段下方。
android {
QT += androidextras
OTHER_FILES += android_src/src/io/novikov/androidintentlauncher/AndroidIntentLauncher.java
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android_src
}
QMake 为此作业提供了一个特殊的变量ANDROID_PACKAGE_SOURCE_DIR。Java 源代码必须位于 ANDROID_PACKAGE_SOURCE_DIR/src/my/domain 目录中。另外不要忘记将java源代码添加到OTHER_FILES并包含androidextras QT选项。
- .cpp和.h文件中的模板专用化声明
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 文本文件中的单词链表
- CMake-按正确顺序将项目与C运行时对象文件链接
- 使用新行和不使用新行读取文件
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 挂起和取消挂起一个文件DLL
- 如何确定我已使用非编码文件到达 EOF?
- 命名空间中具有.h和.cpp文件的类
- 如何使用ndk-build.cmd构建Android.so文件
- 从包含m行的文件中提取n行,必要时(惰性地)重复该文件
- 读取文件并输入到矢量中
- Android Studio使用本机可执行文件并将其运送到APK中
- Android Studio 项目中的 c++ 代码是否最终出现在 apk 文件中(除了 .so 文件)
- 从本地代码访问apk中的压缩文件(从zip中读取zip)
- 对APK中的C++文件进行逆向工程
- 如何将qt资源添加到安卓APK文件
- Qt/C++/Android - 如何安装 .APK文件以编程方式
- 我如何保护.所以我正在嵌入我的.apk文件
- 仅通过本机代码检查apk中是否存在目录(文件夹)