Cordova / Phonegap: Live update codebase - android

We are using Cordova along with AngularJS for iOS and Android applications.
One big disadvantage of iOS are the long review times from Apple. In Google's Playstore, your app is available nearly immediately, or within a few hours. But Apple takes ages to review your app, even when it's only a small change.
So I was thinking, if there is a way to support some kind of live update.
That means, I could provide a ZIP file or something else with a new codebase, my app checks for updates and then installs the new files.
I've read something from appmobi, but are there any open source solutions?

cordova-app-loader is an easy to use plugin to update app files via 3 simple steps:
check() for a new manifest
download() files
update() your app!
It supports android and iOS

I don't know of any ready made solutions for that, but it should be easy enough to program something like this on your own.
Here are some points to get you started and to consider:
If you want to distribute updates via zip, you need a nativ plugin which handles the extraction
You might not be able to override files in the default location of your app (depending on OS). So, all files you want to update in the future have to sit in a folder your app has read/write access to (iOS: e.g. Library or Documents folder)
Now you simply need to download the zip-package, unpack the zip to your chosen directory, and restart/reload your app.
you will not be able to update native plugins!
Apple probably doesn't like that, since you are able to change the whole application without passing
their review process

I'm doing this inside my cordova app and haven't had any issues with ios app store review.
I'm using Jquery's ajax function to download both a javascript and a css file from a server that I can change without an app store approval and then I can inject those scripts once they downloaded on app startup.
I tried using the cordova File api and I'd then save the file locally, but offline support ins't the important to me at the moment and Jquery's ajax is much simpler.
Here is the jquery code I use. I have a bundle id that I use to detect if a new javascript file is available, otherwise jquery's ajax caches the previous requests to speed up download time.
This solution lets you have a subset of your code be dynamic. I still have a base set of code that is bundled with the app, along with native plugin js and native code which would need to go through the app store. But this atleast lets me push bug fixes without going through the app store.
Otherwise, I'd look at a solution like this: http://docs.build.phonegap.com/en_US/tools_hydration.md.html
function insertScript(version) {
var scriptUrl = "";
try {
// get javascript file...
scriptUrl = mobileWebServiceUrl + "/DynamicContent/Bundles/Scripts/dynamic";
scriptUrl += "_" + bundleVersion.replace(/\./g, "_") + ".js?v=" + version;
console.log("downloading script: " + scriptUrl);
// Allow user to set any option except for dataType, cache, and url
options = {
dataType: "script",
cache: true,
url: scriptUrl
};
// Use $.ajax() since it is more flexible than $.getScript
// Return the jqXHR object so we can chain callbacks
return $.ajax(options).success(function(response) {
console.log("insertScript success");
dynamicContentScriptLoaded = true;
});
} catch (e) {
//console.error(e);
ReportError("problem downloading javscript: " + scriptUrl);
}
}
function insertCSS(version) {
try {
// get css file...
var cssUrl = mobileWebServiceUrl + "/DynamicContent/Bundles/Css/dynamic";
cssUrl += "_" + bundleVersion.replace(/\./g, "_") + ".css?v=" + version;
console.log("downloading dynamic css: " + cssUrl);
$.ajax(cssUrl)
.success(function (response) {
console.log("successfully downloaded dynamic css");
var script = document.createElement("style");
script.type = "text/css";
script.innerHTML = response;
$('head link').each(function () {
if ($(this).attr('href').search('MobileFrame') > -1) {
$("#MobileFrameCSS").before(script);
}
});
dynamicContentCssLoaded = true;
// TODO: implement caching at a later date
//if (isPhoneGap())
// saveFile("DynamicStyles", response);
});
} catch (e) {
ReportError("problem downloading css");
}
}

Well, Adobe offers exactly that service in their Phonegap Build service. It's called Hydration.
The example shows using it with Android and iOS platforms, so I guess they made it compatible with the iOS Dev Program License Agreement.
If you are using Cordova, you probably will have to switch to the Phonegap CLI if you want to use their build cloud services, which is basically the same as Cordova's with some extra commands to upload to their cloud, etc.
I think there are some plugin like Splashscreen wich also have some minor changes (using <gap>for params into config.xml instead of <preference>). Again, if Hydration solves the problem for you, the changes are minor and you get a really nice feature.

I think the best choice would be to not try to do this with Phonegap, but rather identify your dynamic parts and implement these in Javascript.
Yes, I mean you should indeed use Javascript yourself without Phonegap, for example via JavaScriptBridge:
https://github.com/kishikawakatsumi/JavaScriptBridge
It may require more work initially to redesign your app into a "static" part (your PhoneGap app) and dynamic part (dynamic created views via JavascriptBirdge), and interacte seemlessly between them. But in my opinion, that will be ultimately the best software design.
However, also make sure you still meet Apples AppStore requirements.

The Meteor framework provides exactly this functionality when combined with PhoneGap. It's even sanctioned by Apple in the latest Developer Agreement. Here are some technical details and then some about Apple's view on it.

I think there is no such solution is available, but you can do it by programmatic way.you can update your cardova app by fetching files from server and updating it.

Check out CodePush from Microsoft. Works with Cordova and React Native.
Appears to be very similar to the "live update" feature from Ionic Cloud.

If you migrate to capacitor, the successor of Cordova there open source solution now.
Capacitor-updater, is the only alternative to ionic AppFlow.
The updater allows you to manage update by yourself, store your zip update where you want and use the download method.
How to start
npm install #capgo/capacitor-updater
npx cap sync
Then in your main JS, this is required to let the updater know the update is valid
import { CapacitorUpdater } from '#capgo/capacitor-updater'
CapacitorUpdater.notifyAppReady()
And lately after checking yourself the current version need update:
const version = await CapacitorUpdater.download({
url: 'https://github.com/Cap-go/demo-app/releases/download/0.0.4/dist.zip',
})
await CapacitorUpdater.set(version); // sets the new version, and reloads the app
After many request of people didn't want to do that themselves, I started Capgo a business to manage all the update process.
All is open source and can be replicate on your own as well.
Doing things for Capacitor is now my main activity, I produce open-source plugin as my main channel of Marketing, I'm solo founder and bootstrapped.
Hope my tool will help you !

Related

Call phone number phonegap

After open webpage in app browser where phone number is set I need get phone number in popup for call.
Any plugin for phonegap?
GL
Not sure what your question means, but as far as I understand you need to make a call to the number on button click. Try the following in your HTML file:
<a class="button" href="tel://123456">1234563</a>
If you are getting the number from controller, use:
<a class="button" href="tel://{{number}}">123456</a>
Today I came across a feature request that I had not done before – dialing a number from within an app. Some quick research shows that its possible using a specific URI scheme.
What are URI schemes? Honestly Wikipedia does a better job than I ever could in describing them but I think of them as something that allows a specific piece of functionality to happen over the internet, and thus they are usually referred to as protocols. You probably have already seen them – the most common ones are http: and https: (for web browsing), and ftp:, among others. Some are unique to an application and really don’t qualify as schemes and are definitely not a “protocol”, such as mailto: (to open up the mail client on a person’s computer), javascript: or about: – in fact, try typing about: in the address bar of your browser and hit “enter” on your keyboard, notice what happens…
In our case where we want to dial a number from within our app we need a way of telling the mobile phone that we want to make a call. There is a scheme for this purpose called tel:. A sample number using this scheme would look like this: “tel:+1-800-555-1234”. If you wanted a number to work around the world you would use an international number which includes the country code.
Implementing this is simple, we could do this within our mobile html5 app like so:
...
call this number
...
Ideally though we would delegate the event and fire a function to call our mythical phone number. To send the url (the “tel” url) to the browser we would write the following:
...
document.location.href = 'tel:+1-800-555-1234';
...
As of PhoneGap 3.6 all schemes are subject to whitelists. This means you have to add the tel scheme to a second whitelist that will allow your app to launch external applications. To do this you need to edit your config.XML to include the following (a mailto example is included):
Go here for more information: Cordova 3.6.0 Whitelist Guide.
Of interest to this topic is getting Android to treat phone numbers (as well as URLs and mailto schemes) as clickable links in text fields. I’ve not tested it but try adding the following to your config.xml.
Additional information on this can be found here: http://developer.android.com/reference/android/widget/TextView.html#attr_android:autoLink.
[EDIT: Note that what follows no longer applies but remains here for historical purposes.]
When we run the above code in Android 2.3.6 the phone dialer appears and does so with our number pre-populated ready to be dialed. Unfortunately on iOS 5 this doesn’t happen. A quick review of iOS documentation implies that it should work – so I suppose its just broken.
No need to panic, there is a PhoneGap plugin available which will take care of things. The plugin can be downloaded from here:
Click here to download the iOS Phone Dialer PhoneGap plugin
Its simple to install – just drag and drop the “m” and “h” files on to the classes folder of your xcode project. When you do this a dialog will appear with some options – be sure to click the radio button for copying “…files if needed..”.
Next, update the PhoneGap.plist file to reflect that you are adding a new plugin. The link for downloading the plugin explains the plist values as being “phonedialer > PhoneDialer”… but I think its easier to explain with an image:
The final step is to place the “PhoneDialer.js” javascript file somewhere within the root of your project and then to add it to your index.html file via a script tag.
Now that the Phone Dialer plugin is installed you’ll naturally want to know how to use it:
...
window.plugins.phoneDialer.dial('1-800-555-1234');
...
All in all pretty easy and straight forward, however now you have two methods of dialing a number within a single project. What you want is to use the tel: url scheme in Android and the Phone Dialer plugin in iOS.
Within Sencha Touch we have something called the Ext.is object whose attributes reflect everything that you could possibly want to know about the environment that your mobile app is living within.
For our purposes all we want to know is if we are in iOS or if we are in Android. These two lines provide us the answer:
...
Ext.is.Android // boolean, "true" for android, false otherwise
Ext.is.iOS // boolean, "true" for iOS, false otherwise
...
Thats all we need to impliment phone dialing across the two platforms within our mobile app. Lets build a function that makes use of one of the above (we don’t need both) and we should also give the user a choice in the matter, so the code below includes a message to the user to see if they really do want to suspend the app in favor of the device’s phone dialer:
...
function callSomeone(){
var msg = Ext.Msg.confirm('Please Confirm','Are you sure you want to make a phone call?',
function(r){
if (r == 'yes'){
if (Ext.is.Android){
document.location.href = 'tel:+1-800-555-1234';
} else { // we assume the device is running iOS
window.plugins.phoneDialer.dial('1-800-555-1234');
}
}
});
msg.doComponentLayout();
}
...
All done… I suppose the very last thing to do here is to provide a complete working Sencha Touch example, and some screen captures…
...
Ext.setup({
onReady: function(){
var rootPanel = new Ext.form.FormPanel({
fullscreen: true,
items: [
{
xtype:'button',
text:'Call 1-800-555-1234',
scope:this,
handler: callSomeone
}
],
dockedItems:[
{
xtype:'toolbar',
dock:'top',
title:'Phone Dialer Example'
}
]
}
);
function callSomeone(){
var msg = Ext.Msg.confirm('Please Confirm','Are you sure you want to make a phone call?',
function(r){
if (r == 'yes'){
if (Ext.is.Android){
document.location.href = 'tel:+1-800-555-1234';
} else { // we assume the device is running iOS
window.plugins.phoneDialer.dial('1-800-555-1234');
}
}
}
);
msg.doComponentLayout();
}
}
});
...
From http://rickluna.com/wp/2012/02/making-a-phone-call-from-within-phonegap-in-android-and-ios/

Save app data on Android/iOS using Haxe/OpenFL

So, I've created a Haxe function (using the OpenFL library) that saves text and image data to the game's folder on desktop targets. A little while ago, however, I was notified in this thread that the function would not work on mobile targets. The same user, thiagojabur, also gave me a solution (scroll down in the same thread). My main problem is that I don't have a mobile device myself that I can test on (I have a Galaxy Tab4, but I haven't gotten it working with my Haxe projects). Rather than send 100 versions to someone who can test it, I've decided to ask my questions here.
The goal is to save the data into a folder with the game's App ID. For instance, if the App ID is com.potato.potatogame, then the data will be saved (on Android) in the application storage directory, in the folder /Android/data/com.potato.potatogame/. I believe I can get the first part of the path using openfl.utils.SystemPath.applicationStorageDirectory(), but I'm stuck on how to get the App ID. Does anyone know of a function which can do so?
Alternatively, I may be misunderstanding a part of the code. From the way thiagojabur used the code, it would seem that SystemPath.userDirectory() returns "/Android/data/com.potato.potatogame" on Android. Is this correct, or would I still need to build the path manually?
Any help is appreciated. Thanks in advance!
In one of my apps using OpenFL in legacy mode I saved an images using following code:
static var IMAGES_PATH:String = SystemPath.documentsDirectory + "/MyAppName/";
public function saveImage()
{
var filename:String = IMAGES_PATH + name + ".png";
try {
if(!FileSystem.exists(IMAGES_PATH)) {
FileSystem.createDirectory(IMAGES_PATH);
}
File.saveBytes(filename, app.canvas.bitmap.encode("png"));
}
catch(e:Dynamic) {
trace(e);
}
}
With modern non-legacy code, I guess the path getting should be changed to lime.system.System.applicationStorageDirectory
Also if you still need to get the App ID, it can be achieved by Application.current.config.packageName

Dynamic screens in Android application

i am programming an android application which can be use by different business and/or users, each can have its own configuration.
each business will set his required configuration (screens, text, and so) in a back office site (data will be saved in database).
on Splash screen i will fetch a Json string from the server which
contain this business specific configuration.
from now on the application should work base on this json.
my questions:
is it recommended to build it this way?
is it good practice to have a workflow manager class that will take care of screens transitions.
can you please recommend a strategy you would go with.
here is a function that handle screen transitions
public static void startNext(String FromActivity, Context context)
{
try
{
Intent intent = new Intent(context, Class.forName(context.getPackageName() + getNextActivity(FromActivity)));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
catch (ClassNotFoundException ex)
{
Log.e("test", ex.getMessage());
}
}
the getNextActivity function return a class that should be open next based on the json string.
and example of call from activity 1 to move to next activity
FlowManager.startNext(this.getLocalClassName(),getApplicationContext());
When you have a customization like that it is best to make a build script which will download the latest code for a specific publisher from github/svn or something like that. It should also download publisher specific strings, launcher icons, name of the app and the end package package name, version, certificate to sign the application with, assets, rename all occurrences of default package... Make sure you exclude any unnecessary libraries that some publishers don't need and comment out the stuff related to that library. You can define start/end tags in code and then search for the start tag, replace it with /* and then replace the end tag with */ effectively commenting everything between them out. At the end the script runs gradle wrapper. First run clean and then build. It's also good to define the end output location of apk so it's easier to find.
The most easy way to build a build script like that is using bash scripts. They run on linux/mac or even both if you do it the right way. The whole think should run on a build server like Jenkins
After the build is done, it is good to upload the final *.apk to a server where publishers can download the latest apk and then upload it to Google Play Store.
Happy Coding!

can i use android AsyncTask in sencha application (Android)

In my previous question, i asked "how to download Facebook profile picture" and i got answer that "Use an AsyncTask to download it and save it to your app's disk space".
i am using sencha touch (its all about java script and html) for creating views with phonegap. i need to download image from web (from this url https://graph.facebook.com/username/picture).
so, when i was learning AsyncTask, i had a doubt that "can i use AsyncTask in sencha android application?", because i didn't create views (i mean button, panel, etc..) using activity xml.
is there any other solution to download picture from web in sencha touch application (Android) ?
Update for the solution
i used below facebook api to get the profile picture url and Phonegap file Api for downloading picture as #Lukas K said.
FB.api('/'+fbusername+'/picture?redirect=false', function(response) {
localStorage.fbpicurl = response.data.url;
});
You can convert it into base64 and store it in the localStorage.
But the space of the LocalStorage is limited to 5MB. After reaching the Limit the device will prompt the user to give more space.
Do you use phonegap in addition to Sencha Touch? Phonegap provides access to the phone's file system, where you can store your pictures.
Phonegap File Api: http://docs.phonegap.com/en/2.3.0/cordova_file_file.md.html#File
You can use sencha's delayed task like this:
var task = Ext.create(
'Ext.util.DelayedTask',
function() {
Ext.getCmp("imageId").setSrc( 'https://graph.facebook.com/username/picture' );
}
);
task.delay(100);
This will start downloading the image after 100ms.
I hope this is what you wanted to do, If not then do whatever as delayed task in the function.

phonegap mobile apps and version control and updates

I have currently built an application using phone gap targeting the android and blackberry platforms.
I use a combination of Jquery mobile and Phonegap for my application, since both are open source frameworks and improvements as well as bug fixes keep happening I wanted to know what would be a good solution for alerting my users to update their application when I upgrade the above frameworks in my application.
One solution I had in mind is maintain a version numbering on my server for the apps, when the app is loaded on the users device we can make an ajax call to check for version update and then alert the user to upgrade their application.
Android market also has an auto update feature how does that work! How do I go about this what would be a good approach.
If you are planning to build "native", in this case localy installed apps. You don't have to worry about informing the user. As soon as you uplad the new versions to the Android market or App World the App market systems will let the users know automatically.
I think (in most cases) it is not necessary to let the user know about updates within the app. Some apps do that but I see it less often since it really does not make much sense.
But in case you want to build such a feature, I would store a version number somwhere in the code and make a server request eg. when the app starts which then compares the latest version number of your app stored on your server.
Eg.
Client:
$.ajax({
url: webservice_host + '&callback=?',
dataType: 'jsonp',
success: function (data) {
//data -> remote version
var local_version;
if (local_version < data ){
alert("There is a newer version available");
}
}
});
Server (php in this case):
<?php
print mysql_real_escape_string($_GET['callback']). '( 1.1 )';
?>
I didn't test the code for typos etc. But this should do the trick.

Categories

Resources