When developing, I didn’t see any issues (and still don’t). I then released my app to both app stores. Deleted my dev versions of the apps and installed the ones from the app stores (on Android 4.4.4 with Crosswalk and iOS 8.1).
Problem 1: Pushed new code to the server and neither of the apps on my test devices detected the new manifest. Could not figure out why. Reinstalled dev versions and it all worked fine. Suspected it might have something to do with the app store deployment being different, but generated and manually installed release apk and ad-hoc ipa onto my devices and they worked fine. Also one of my users was prompted to do the update. Never did figure out why this didn’t work.
Problem 2: I had added a new template file and updated my main js and css files in the update. When the update was applied on an Android phone, the new template file and js seemed fine. The new CSS did not get applied, so things looked bad. I didn’t see this problem on iOS - the updates were applied properly.
There is always the possibility that some or all of this was due to a server problem at the time and that the appropriate data wasn’t being sent down to the app. I’m about to submit new apps to the app stores, and will leave cordova-app-loader in for now and give it another go. I’ll let you know how it goes.
If I can’t get it working, it appears that application cache for “hot code push” is a viable way to go. Here’s what I’ve learned:
There’s a nice description of how @mikemintz implemented it here:
You need to put all the cordova and cordova plugin files on your server as well as your app files, and have different versions per platform. Something like this from @andrewreedy could help: https://github.com/andrewreedy/cordova-loader
it appears that you don’t need to package any of your app code into your binary (which makes the binary lighter), but on first run (and until all the files are cached), you will be running your app from the server, and all the files will be downloaded and cached in the background
if any of the files listed in CACHE can’t be retrieved, the entire cache is disregarded
I had thought that it re-downloaded everything in the manifest, but according to the second link above - “When updating an existing appcache, the browser sends standard If-Modified-Since headers, so it skips re-downloading files that have not changed.” which is nice, although in practice you’re probably uploading newly generated versions of the files, even if they haven’t changed.
i found some time to test the issues mentioned here.
My results:
HTML files
If a new HTML file is added to the $stateProvider its not loaded right
.state('app.search', {
url: "/search",
views: {
'menuContent': {
templateUrl: "templates/searchnew.html" // was search.html before
}
}
})
This issue seems to be caused by the ionic view cache, the request to the new file points to
GET file:///android_asset/www/templates/searchnew.html net::ERR_FILE_NOT_FOUND
Hash issues
Sometimes it happens to me, that a changed file created the same hash value. I m using the grunt task to create the manifest files ( incl. hash )
Not sure if this is just a local issue or not. But it only happens in production mode ( files get minified and uglyfied )
I think that’s the same issue, where the html files are not ending up in the right place, but sitting in the place they downloaded which i guess is not available to the app
I have this component working great in our app right now, fonts and everything, autoupdating, etc., … all except the template files.
I tried clearing the webview cache also, which is good to do anyway, but it didn’t help for this problem
Other than the html templates, everything working fine…
I’m going to get off to some other things for now, but I’ll circle back to this to see if somebody else can help or if not, to dig in a little deeper
that’s a good idea for the manifest.json to force reload, was too sticky
i think this template problem is that the updating files load into some other directory cdvfile://localhost/persistent/ which loads fine for the js and css which get loaded explicitly in the generated document, but not the templates which are still using the default place for templateUrl for the angular application
any amount of restarting, rebooting device, etc. doesn’t seem to fix this
I just updated my app on the play store and noticed this problem as well. I took my wife’s phone, which had the last production release of my app, and updated it from the play store. I had changed one of the templates. and after the update that page no longer worked properly. Going into Settings > Apps > My App and clearing the application’s cache fixed the problem.
Putting all the templates into index.html might fix the problem? Let me know if you figure it out.
I think I’m giving up for now, removing CAL for the time being and resubmitting.
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…
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;
}
};
});
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
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
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
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:
User installed v1 via app store.
User updated to v2 via CAL. Files now being loaded from local cache. Manifest saved in local storage.
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
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.
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
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