Phonegap Android app trigger update programmatical

2019-01-21 21:12发布

问题:

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!

回答1:

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);
});


回答2:

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);
        }
    );
}


回答3:

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.



回答4:

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.



回答5:

Working example in 2018

Based on previous comments I implement this solution

It require:

  • File plugin
  • File transfer plugin
  • Web intent plugin

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));
    });
}