Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Android auto update
Qt 6.11 is out! See what's new in the release blog

Android auto update

Scheduled Pinned Locked Moved Unsolved Mobile and Embedded
13 Posts 5 Posters 3.5k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • KutyusK Offline
    KutyusK Offline
    Kutyus
    wrote on last edited by
    #1

    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.

    1 Reply Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      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:

      1. 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>
      
      1. 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>
      
      1. 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 :-(

      1. 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!

      (Z(:^

      KutyusK 2 Replies Last reply
      0
      • sierdzioS sierdzio

        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:

        1. 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>
        
        1. 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>
        
        1. 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 :-(

        1. 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!

        KutyusK Offline
        KutyusK Offline
        Kutyus
        wrote on last edited by
        #3

        @sierdzio
        Thanks for the reply, it's a little complicated for me, I absolutely don't understand the java, maybe I'll try it later.

        ekkescornerE 1 Reply Last reply
        0
        • KutyusK Kutyus

          @sierdzio
          Thanks for the reply, it's a little complicated for me, I absolutely don't understand the java, maybe I'll try it later.

          ekkescornerE Offline
          ekkescornerE Offline
          ekkescorner
          Qt Champions 2016
          wrote on last edited by
          #4

          @Kutyus my share example has implemented Android FileProvider https://github.com/ekke/ekkesSHAREexample

          ekke ... Qt Champion 2016 | 2024 ... mobile business apps

          K 1 Reply Last reply
          2
          • ekkescornerE ekkescorner

            @Kutyus my share example has implemented Android FileProvider https://github.com/ekke/ekkesSHAREexample

            K Offline
            K Offline
            koahnig
            wrote on last edited by
            #5

            @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?

            Vote the answer(s) that helped you to solve your issue(s)

            ekkescornerE 1 Reply Last reply
            0
            • K koahnig

              @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?

              ekkescornerE Offline
              ekkescornerE Offline
              ekkescorner
              Qt Champions 2016
              wrote on last edited by
              #6

              @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)

              ekke ... Qt Champion 2016 | 2024 ... mobile business apps

              K 1 Reply Last reply
              3
              • ekkescornerE ekkescorner

                @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)

                K Offline
                K Offline
                koahnig
                wrote on last edited by
                #7

                @ekkescorner

                Thanks. Report created

                Vote the answer(s) that helped you to solve your issue(s)

                ekkescornerE 1 Reply Last reply
                0
                • K koahnig

                  @ekkescorner

                  Thanks. Report created

                  ekkescornerE Offline
                  ekkescornerE Offline
                  ekkescorner
                  Qt Champions 2016
                  wrote on last edited by
                  #8

                  @koahnig thx reporting. will test when I've done my switch from 5.13 --> 5.15

                  ekke ... Qt Champion 2016 | 2024 ... mobile business apps

                  1 Reply Last reply
                  1
                  • sierdzioS sierdzio

                    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:

                    1. 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>
                    
                    1. 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>
                    
                    1. 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 :-(

                    1. 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!

                    KutyusK Offline
                    KutyusK Offline
                    Kutyus
                    wrote on last edited by
                    #9

                    @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.

                    KroMignonK 1 Reply Last reply
                    0
                    • sierdzioS Offline
                      sierdzioS Offline
                      sierdzio
                      Moderators
                      wrote on last edited by
                      #10

                      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

                      (Z(:^

                      1 Reply Last reply
                      0
                      • KutyusK Kutyus

                        @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.

                        KroMignonK Offline
                        KroMignonK Offline
                        KroMignon
                        wrote on last edited by KroMignon
                        #11

                        @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());
                        
                        

                        It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                        KutyusK 1 Reply Last reply
                        0
                        • KroMignonK KroMignon

                          @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());
                          
                          
                          KutyusK Offline
                          KutyusK Offline
                          Kutyus
                          wrote on last edited by
                          #12

                          @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.

                          KroMignonK 1 Reply Last reply
                          0
                          • KutyusK Kutyus

                            @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.

                            KroMignonK Offline
                            KroMignonK Offline
                            KroMignon
                            wrote on last edited by KroMignon
                            #13

                            @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());
                            

                            It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

                            1 Reply Last reply
                            1

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved