簡體   English   中英

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 的解決方案(我不想使用它,因為用 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 文件,然后什么也沒有發生。 為什么? (到目前為止,我還沒有對 AndroidManifest.xml 進行任何更改)。

您必須自定義 Intent 才能安裝 APK。 有關詳細信息,請參閱此問題

恐怕這種特定於平台的想法必須需要調用特定於平台的 API。 好消息是 Qt 框架簡化了對 JNI 的總結,您可以將 Java 類包含到 Android 項目中。 因此,我將創建自己的從 Qt 調用的靜態 Java 函數。

例子

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 維護特殊的目錄結構。 該示例位於下面的Makefile部分。

JNI

調用此方法的 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 選項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM