Cordova-app-loader


#28

If I can’t apply a new update from the app store and know the app will work (regardless of what’s happened before on the device), then I think that’s a problem…


#29

Hi everybody

i ve a fix for the html issue.

I added an HTTP Interceptor to my app.js in the config part. Since every template is fetched via HTTP its easy to change the path to the stored file path

This is just a quick hack but works well on my first tests

$httpProvider.interceptors.push(function () {
                
                var calFiles =  [];  // List of cordova app loader files 
                if(!!localStorage.getItem('manifest')) {

                    //we have a manifest, lets parse it 
                    var manifest = JSON.parse(localStorage.getItem('manifest'));

                    // show me the content ( just for debugging )
                    console.log(manifest);

                   //Iterate over all keys in files 
                    for (var key in manifest.files) {
                        //add them to our cal array
                        calFiles.push(manifest.files[key]);
                    }
                }
                
                // debug can be removed
                console.log(calFiles);
                
                
               //the interceptor code
                return {

                     //Intercepting a request 
                    'request': function (config) {
                        
                        console.log(config.url);

                        // check if the config.url of the request matches a file in manifest and its html
                        calFiles.forEach(function (item) {
                            if(item.filename === config.url && config.url.substr(-5) === '.html') {
                                console.log(item.filename , 'is in the manifest changing ');
                                
                                //change the url to the stored item 
                                config.url = 'cdvfile://localhost/persistent/app/'+item.filename;
                            }
                        });
                        // Return our modified request
                        return config;
                    },

                    //response without modification
                    'response': function (response) {
                        // same as above
                        return response;
                    }
                };
            });

Regards


#30

It would be great if anyone could test my workaround just tested it on a really simple APP ( Starter ) . i now the code is not very robust ( missing checking files are available in the filesystem , request already points to the right location … )

Also i m mit sure if its possible to integrate this into the loader directly, because the workaround works only for angular / ionic projects


#31

Hi everybody

since the angularJS interceptor works great for, i checked several issues again and how they can be solves

Works out of the box:

  • CSS
  • JS (if you take care of the order how the scripts get loaded
    (load array of manifest.json).
  • Fonts

Works after the great work of @rajatrocks

  • Bootstrap of the application after all scripts are ready ( please PR your solution )
  • Generate the a manifest.json even no - is in the file path with grunt

BTW where are the PRs for your solutions :wink:

Works in AngularJS / Ionic apps

  • HTTP templates even with ionic template cache
  • Images ( extends the interceptor or write a directive / watcher like in ngImageCache

So from an Ionic/AngularJs dev view everything seems to work, but there is a problem which can not be fixed without a native plugin ( hope it can but i didnt found a solution ):

  • Interception of file:// calls
    Calls to assets in cordova are done via ( file:// urls) which can not be intercepted with vanilla js ( for http there is a simple solution Hijack AJAX Requests Like A Terrorist

So from my point of view cordova app loader works fine. And its well integrated into my development workflow. Also its nice to have the app and the backend always in sync ( update of the backend causes auto. an update of the app )

I m also working on a simple server app for managing different users and versions of an app ( i think the ionic team is doing the same, but its not ready yet). To increase the speed of development and testing

Regards


#32

That’s great that you’ve figured it all out! After thinking about it, I’ve decided that CAL isn’t a good solution for me for the reason I mentioned above - if I can’t guarantee that an app store update will always work, then I think the solution is too risky. And with CAL, that’s exactly the case - files that have been cached locally, potentially improperly, will continue to be loaded even after an app store update AND a server update. I believe this is what happened in my case:

  1. User installed v1 via app store.
  2. User updated to v2 via CAL. Files now being loaded from local cache. Manifest saved in local storage.
  3. User updated to v3 via app store. v3 was also pushed to the server. Manifest in app (v3) matched the one on the server (v3), so no remote update attempted. But the html files (and potentially other) files that were updated between v2 and v3 were not copied over into the cache correctly, so parts of the app were broken. The only way to fix was to go into the App settings and clear the cache, or completely uninstall and reinstall. Pushing a new v4 to the server and forcing a remote update might have worked as well, but I didn’t try it. None of which are great solutions for a consumer app.

In general it all just seems too prone to problems for my taste, so I’ve pulled it all out of my app for now. Let me know how you feel after you run it in production for a while, and maybe I’ll change my mind :slight_smile:

And re: PRs - I’m being completely serious when I say that all I know how to do in git is check code in. One of these days I’ll learn how to do your fancy forks and branches and pull requests and some such. :wink:


#33

Hi

since i ve added the all the changes. ( Order of loading scripts, http interceptor for template files, imagecache, callback ) It works very well for me.

Tested about ~ 100 changes yesterday ( auto. via script ) and was working fine all the times.

( Tested on Nexus 4 ( Android 5.0.1 ) and IOS-SIM )

I ve modified the bootstrap.js to include just css/js and skip html ( html templates via angular http interceptor )

Today i will create a cordova-app-loader-angularjs-service to remove the “hacky” parts of my code and to get a reusable service which can be used by other applications

I will push the code to github when its done

Regards


#34

Awesome, and kudos for working through all the issues. Looking forward to seeing it!


#35

ok, tested this, looks like a good solution and seems to work great so far… Thanks!!


#36

Thx for testing,

I m still working on a reusable component / service/ factory for angularjs based apps

@rajatrocks
I checked the app cache too
it looks like the html5 cache can not be used by the upcoming wkwebview


#37

Yeah, I just saw that in Shazron’s post as well: https://shazronatadobe.wordpress.com/2015/03/03/wkwebview-and-apache-cordova/ - that’s unfortunate.


#38

did you achieve to have a reusable component, whatever… ? I tried with the normal cordova-app-loader and with many hints from this topic and other places, but still don’t fully succeed.
would be cool to see a working example


#39

Hi

sorry i can not provide a full example, since its a closed source app.

But i works like following

In my app.js i ve added a http interceptor in the config section

$httpProvider.interceptors.push(['UpdateService', function (UpdateService) {
                    return {
                        'request': function (config) {
                            if (UpdateService.isFileCached(config.url)) {

                                var url = UpdateService.getCachedUrl(config.url);
                                config.url = url;
                            }
                            return config;
                        },
                        'response': function (response) {
                            return response;
                        }
                    };
                }]);

The UpdateService looks like following

app.factory('UpdateService', ['$log', 'ConfigService', '$q', function ($log, ConfigService, $q) {


    var fs = new CordovaPromiseFS({
        Promise: Promise
    });

    var loader = new CordovaAppLoader({
        fs: fs,
        serverRoot: 'http://'+ConfigService.getHost()+':'+ConfigService.getPort()+'/update',
        localRoot: 'app',
        cacheBuster: true, // make sure we're not downloading cached files.
        checkTimeout: 10000, // timeout for the "check" function - when you loose internet connection

        manifest: 'manifest.json' + "?" + Date.now()
    });
    var service = {
        check: function () {

            var defer = $q.defer();
            loader.check().then(function (updateAvailable) {
                if (updateAvailable) {
                    defer.resolve(updateAvailable);
                }
                else {
                    defer.reject(updateAvailable);
                }
            });

            return defer.promise;
        },
        download: function (onprogress) {
            var defer = $q.defer();

            loader.download(onprogress).then(function (manifest) {
                defer.resolve(manifest);
            }, function (error) {
                defer.reject(error);
            });
            return defer.promise;
        },
        update: function (reload) {
            loader.update(reload);
        },
        isFileCached: function (file) {
            if (angular.isDefined(loader.cache)) {
                return loader.cache.isCached(file);
            }
            return false;
        },
        getCachedUrl : function (url) {
            if(angular.isDefined(loader.cache)) {
                return loader.cache.get(url);
            }
            return url;
        }



    };

    return service;
}]);

On App start ( and via a button ) the UpdateService gets invoked to check if an update is available

Hope this helps

Regards


#40

@thetoaster was the example helpful or do you need further informations ?


#41

Do I really need an appmanifest and cordova-app-loader if my app only should work online (with a small “sorry-you’re-not-online-fallback”-view)?

Wont it be enough to just point all my JS and css to a remote server like below, and then force a reload of the files when they need to be updated with something like window.location.reload(true)?
All the views could be compiled with ex gulp-angular-templatecache

Or am I missing something here?

<!DOCTYPE html>
<html>
  <head>
    
    <!-- compiled css output -->
    <link href="http://remoteserver.com/css/ionic.app.css" rel="stylesheet">

    <!-- ionic/angularjs js -->
    <script src="http://remoteserver.com/lib/ionic/js/ionic.bundle.js"></script>

    <script src="cordova.js"></script>

    <!-- your app's js -->
    <script src="http://remoteserver.com/app.min.js"></script>
    <script src="http://remoteserver.com//templatecache.js"></script>
  </head>
  <body ng-app="app">
    <ion-nav-view></ion-nav-view>
  </body>
</html>

#42

@tobbe the issue with what you described (as much as i wish it was so simple) is that you miss out on caching those files locally. Every time the app opens it will have to download everything again.


#43

@urbiwan
Based on your input I’ve forked your repo and updated your code to a working state:

I can hot push JavaScript files, but HTML files still don’t work. Maybe you can have a look over it to point me into the right direction.

If you wish a pull request, just ping me.

Thanks a lot!!!


#44

Hi guys,

I’ve thouroughly read all tips of @urbiwan and updated my repo to a working state.
So far HTML/JS/CSS files are working.
Maybe some one has the time to implement the ngCacheImage feature.


#45

@urbiwan Is Cordova App Loader works fine and flawless ?

@rajatrocks should anyone use Application Cache ? As it seems not supported via wkWebView ?

I am in the way to build such app which updates on the fly --> still looking for good to have approch

Thank in advance


#46

Ionic has their own service now: http://blog.ionic.io/announcing-ionic-deploy-alpha-update-your-app-without-waiting/


#47

I switched to my own update plugin ( native ) , which is inspired by ionic deploy, but without the complete functionality