Android auto update
-
Hi!
I want to make an automatic update solution on Android, the apk download works, but I can't start it. I found this solution for it:
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); if (activity.isValid()) { QAndroidJniObject kindOfActivity = QAndroidJniObject::fromString("android.intent.action.VIEW"); QAndroidJniObject apkFile = QAndroidJniObject::fromString(QString("file://%1/latest.apk").arg(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation))); QAndroidJniObject apkUri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", apkFile.object()); QAndroidJniObject mimetype = QAndroidJniObject::fromString("application/vnd.android.package-archive"); QAndroidJniObject intent("android/content/Intent", "(Ljava/lang/String;)V", kindOfActivity.object()); intent = intent.callObjectMethod("setDataAndType", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/content/Intent;", apkUri.object(), mimetype.object()); intent = intent.callObjectMethod("setFlags", "(I)Landroid/content/Intent;", FLAG_ACTIVITY_NEW_TASK); activity.callMethod<void>("startActivity", "(Landroid/content/Intent;)V", intent.object()); } QApplication::exit();
But gives error message:
JNI DETECTED ERROR IN APPLICATION: JNI GetStaticMethodID called with pending exception android.os.FileUriExposedException: file: ///storage/emulated/0/Download/latest.apk exposed beyond app through Intent.getData ()
Thanks in advance for the answers.
-
You need to process the URI through FileProvider. It's an awfully awkward and tedious thing, but Android requires it since version 6 IIRC.
Basically you need to:
- Add file provider to
res/xml/fileprovider.xml
. Example contents:
<?xml version="1.0" encoding="utf-8"?> <paths> <cache-path name="exports" path="." /> <!--Uncomment below to share the entire application specific directory --> <!--<external-path name="all_dirs" path="."/>--> </paths>
- Register that provider in your manifest:
<provider android:name="android.support.v4.content.FileProvider" android:authorities="your.application.domain.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/fileprovider" /> </provider>
- In every place in Java you need to use the file provider to "access" that file, instead of regular File/ Intent. I don't have Qt code for this, only some Java (and written for different purpose so it might be incorrect for your case):
import android.support.v4.content.FileProvider; // ... Uri providerUri = FileProvider.getUriForFile( this, "your.application.domain.fileprovider", fileName);
You probably need to do the opposite (get file for URI). Not sure. I wrote this ages ago and APIs in Android keep changing all the time :-(
- You may also need to add the v4 compat library in gradle config, I'm not sure. It could be something like this:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) compile 'com.android.support:support-v4:23.+' }
I hope this will help you at least a bit. And sorry for not being more specific, I'm not sure about any of it :D This won't be easy, good luck!
- Add file provider to
-
@Kutyus my share example has implemented Android FileProvider https://github.com/ekke/ekkesSHAREexample
-
@ekkescorner said in Android auto update:
@Kutyus my share example has implemented Android FileProvider https://github.com/ekke/ekkesSHAREexample
Great example.
Got it to work immediately with Qt5.12.7, but failure with Qt5.14.2.
Are you interested to get a bug report? And when where? -
@koahnig said in Android auto update:
Got it to work immediately with Qt5.12.7, but failure with Qt5.14.2.
Are you interested to get a bug report? And when where?please report at gihub issues https://github.com/ekke/ekkesSHAREexample/issues
unfortunately most of my examples are 3 years or more old and last 2 years I had to develop so many mobile business apps, so I didn't found enough spare time
the good thing: starting with Qt 5.15 I'll rework all my examples and blogs to get mobile apps ready for Qt6 / strict QML 3. will reduce work for customers next months and concentrate on 5.15 / 6.0. with some luck all of this will finally end in a book (fingers crossed)
-
Thanks. Report created
-
@koahnig thx reporting. will test when I've done my switch from 5.13 --> 5.15
-
@sierdzio
Hi!
I made the settings, but on this line, there is always an error:QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android.support.v4.content.FileProvider", "FileProvider.getUriForFile", "(Landroid/content/Context;Ljava/lang/String;Ljava.io.File;)Landroid/net/Uri;", activity.object(), authority.object(), file.object());
System.err: java.lang.NoSuchMethodError: no static method "Landroid/support/v4/content/FileProvider;.FileProvider.getUriForFile(Landroid/content/Context;Ljava/lang/String;Ljava.io.File;)Landroid/net/Uri;"
I also tried the getUriForFile method without the FileProvider prefix, the same error anyway.
-
I don't know JNI enough to answer, for me it's always a bunch of trial and error to get it to work :D
-
@Kutyus Your JNI call is not correct, you pass wrong method name!
It should be:QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod( "android.support.v4.content.FileProvider", "getUriForFile", // only the function name!! "(Landroid/content/Context;Ljava/lang/String;Ljava.io.File;)Landroid/net/Uri;", activity.object(), authority.object(), file.object());
-
@KroMignon said in Android auto update:
I tried anyway. The error in the second parameter was slashes instead of periods in the java.io.File section.
If I log out after the call, I get an error that there is no activity handling the intent, if I don't log out immediately, there is no error, but nothing happens. I don't know where the error might be. -
@Kutyus You are right, there are many typos!
QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod( "android/support/v4/content/FileProvider", "getUriForFile", // only the function name!! "(Landroid/content/Context;Ljava/lang/String;Ljava/io/File;)Landroid/net/Uri;", activity.object(), authority.object(), file.object());