14

I am building an Android app that is hosted on a server outside Google Play. I need the app to check for new version and prompt user to update when the app starts.

I built a mechanism to check for new version (the app checks for a file on server and compares version) which is working well. Then I prompt user to update, but if user chooses to proceed with the update, I'm not able to trigger the download and installation of the apk.

I tried simply opening the apk url:

window.open(apkURL);

where the apkURL is the full http link to the .apk file hosted on server.

But it doesn't seem to do anything.

I've been researching but I don't find an answer on how to do this. I found some suggestions using native code, like this post Install Application programmatically on Android but I don't know how to do that from within my Phonegap app.

Intent promptInstall = new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse("file:///path/to/your.apk"))
.setType("application/vnd.android.package-archive");
startActivity(promptInstall); 

Is this the right way to trigger the update? How can something like this be done from within a Phonegap app?

Thanks!

Community
  • 1
  • 1
Vero
  • 1,742
  • 3
  • 15
  • 29

5 Answers5

16

I finally managed to implement this, using the File api and the WebIntent plugin. I will post the solution here in case it helps anyone.

The code downloads the apk from a remote server to the download folder in the sdcard and then triggers the install.

window.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function(fileSystem){
fileSystem.root.getFile('download/filename.apk', {
    create: true, 
    exclusive: false
  }, function(fileEntry) {
    var localPath = fileEntry.fullPath,
    fileTransfer = new FileTransfer();        
    fileTransfer.download(apkURL, localPath, function(entry) {
        window.plugins.webintent.startActivity({
            action: window.plugins.webintent.ACTION_VIEW,
            url: 'file://' + entry.fullPath,
            type: 'application/vnd.android.package-archive'
            },
            function(){},
            function(e){
                alert('Error launching app update');
            }
        );                              

    }, function (error) {
        alert("Error downloading APK: " + error.code);
  });
  }, function(evt){
      alert("Error downloading apk: " + evt.target.error.code);                                               
  });
}, function(evt){
alert("Error preparing to download apk: " + evt.target.error.code);
});
Vero
  • 1,742
  • 3
  • 15
  • 29
  • 1
    after install apk using phonegap how can i auto start that apk ? is there any specific method in fileapi or in webintent plugin please let me know – nida Oct 22 '13 at 04:54
  • 1
    I want to download update from http://download.com/update/myapp.apk. Then what will be the code? Please help. – Md Riad Hossain Aug 06 '15 at 04:45
12

For you guys that use Cordova 3+, a similar solution like that of Vero is possible:

So we're first going to download the .apk file. We need the file-transfer plugin for this. You can install it with following command:

phonegap local plugin add org.apache.cordova.file-transfer

Secondly, we need another plugin to start a webintent. This webintent prompts the user if there is an update. You can install it with the following command:

phonegap local plugin add https://github.com/Initsogar/cordova-webintent.git

Then, you can use this 2 functions in your code to download the .apk and to prompt the user if there is an update of the application:

/*
 * Uses the filetransfer plugin
 */
function downloadApkAndroid(data) {
    var fileURL = "cdvfile://localhost/persistent/CegekaMon.apk";

    var fileTransfer = new FileTransfer();
    var uri = encodeURI(data.android);

    fileTransfer.download(
        uri,
        fileURL,
        function (entry) {

            console.log("download complete: " + entry.fullPath);

            promptForUpdateAndroid(entry);
        },
        function (error) {
            console.log("download error source " + error.source);
            console.log("download error target " + error.target);
            console.log("upload error code" + error.code);
        },
        false,
        {

        }
    );
}
/*
 * Uses the borismus webintent plugin
 */
function promptForUpdateAndroid(entry) {
    window.plugins.webintent.startActivity({
            action: window.plugins.webintent.ACTION_VIEW,
            url: entry.toURL(),
            type: 'application/vnd.android.package-archive'
        },
        function () {
        },
        function () {
            alert('Failed to open URL via Android Intent.');
            console.log("Failed to open URL via Android Intent. URL: " + entry.fullPath);
        }
    );
}
RobinCominotto
  • 959
  • 8
  • 18
  • 2
    thanks for your answer. What's 'data' parameter in downloadApkAndroid function? can you share an example calling it? – carlospiles Nov 20 '14 at 10:55
  • Just an array of strings, 'data.android' contains the URL of the APK to download. – janpio Nov 17 '15 at 04:14
  • How do I call that function? downloadApkAndroid({ android: "/files/app.apk" }) – Iago Bruno Dec 27 '15 at 19:57
  • 1
    This almost worked for me except I kept getting a "Parse error - there was a problem parsing the package" alert. Changing the fileURL to this solved my issue: var fileURL = cordova.file.externalDataDirectory + '.apk' – Paul Spaulding Apr 25 '17 at 20:59
0

Sadly you cannot access that kind of native feature within a Phonegap web container without using a plugin, all you can do is link the user to the apk (by opening the native browser for instance) and let him install it.

zakinster
  • 10,508
  • 1
  • 41
  • 52
  • Thanks for you answer. I am checking the [webintent](https://github.com/phonegap/phonegap-plugins/tree/master/Android/WebIntent) phonegap plugin now, to see if it could work. When you say link to the apk, is it a regular link? Why would the link work but not my window.open? Thanks. – Vero Apr 08 '13 at 21:48
  • Of course using a plugin you can bypass the limitations of Cordova, I didn't know this plugin but i think it should work. By link, I was actually thinking of opening the native browser to open the apk with something like navigator.app.loadUrl. – zakinster Apr 09 '13 at 07:45
0

thank you Vero for answer ... it is help me so much... there is a problem with your code in cordova file plugin last version. replace entry.fullPath with entry.toURL() if you use file plugin version 1.0.0 or newer. if you use entry.fullPath , it throw error 'there is a problem parsing package'.

from file-transfer plugin on github

These paths were previously exposed in the fullPath property of FileEntry and DirectoryEntry objects returned by the File plugin. New versions of the File plugin, however, no longer expose these paths to JavaScript.

If you are upgrading to a new (1.0.0 or newer) version of File, and you have previously been using entry.fullPath as arguments to download() or upload(), then you will need to change your code to use filesystem URLs instead.

FileEntry.toURL() and DirectoryEntry.toURL() return a filesystem URL of the form

cdvfile://localhost/persistent/path/to/file which can be used in place of the absolute file path in both download() and upload() methods.

Community
  • 1
  • 1
0

Working example in 2018

Based on previous comments I implement this solution

It require:

constructor(public navCtrl: NavController, private transfer: FileTransfer, private file: File, private webIntent: WebIntent) {
    const fileTransfer: FileTransferObject = this.transfer.create();
    const url = 'urlApkFile';//Modified this
    fileTransfer.download(url, this.file.externalDataDirectory + 'file.apk').then((entry) => 
    {
        webIntent.startActivity({
            action: (window).plugins.intentShim.ACTION_INSTALL_PACKAGE,
            url: entry.toURL(),
            type: 'application/vnd.android.package-archive'
        }).then(function () {
            //OK
        }, function (e) {
            alert('Error launching app update' + JSON.stringify(e));
        });
    }, (error) => {
        alert("downdload finish" + JSON.stringify(error));
    });
}
    
DanielGatti
  • 653
  • 8
  • 21