My focus on this post will be controlled distribution where you as a developer have physical control over the devices.
Following are the two approaches that you can take depending on your expertise and skill.
This approach is the easiest one that you can take, developing a Launcher application is fairly simple and you can quickly get going without much of a trouble. Let me roughly list out the items which you need to do:
As mentioned above make it a Launcher app and ensure that it is the default launcher app, after installation you can disable the old launcher app using pm disable <PACKAGE_OR_COMPONENT>
command. Now as your launcher app is the default one so it will be started automatically on boot, nothing fancy here.
In order to enforce control, you may need to detect when a new application is opened to figure out whether it is an allowed application or not. There are two ways that you can go about it:
ActivityManager.killBackgroundProcess()
to kill that app (will not work for system apps though). There are caveats to this approach, it is heavy on resources and drains battery very quickly.Settings --> Accessibility
. Assuming physical control over the devices, so this should not be an issue, but it’s manual and that’s the downside.Android provides broadcast receivers for you to track when a new application is installed or uninstalled. Use them and log the activities accordingly.
You cannot override the status bar, so the only option is to run a background service and create a opaque overlay view and position it on top of the status bar, this status bar should consume all touch events (this is how custom status bar replacements apps work I think), you’ll need android.permission.SYSTEM_ALERT_WINDOW
permission to put your view on top of all other windows. Also you can make your Launcher app fullscreen as well.
Take advantage of Device Administrator features, this will provide some elevated access rights to perform administrative tasks, like remotely lock screen, wipe out the data etc.
If you need automatic update support but don’t want to distribute your app through Play Store, then you need to “root” the device and run a separate app which will update your app when there is a new version. This requires you to build a backend as well. I wrote a blog post on this topic some time ago, Android auto-updating homescreen application.
This is by far the most preferable and a reliable approach. You can create your custom build right out of AOSP source code, but based on your device you will need some proprietary files. Take a look at the AOKP/CynogenMod for custom ROMS for your device.
Building custom ROM is bit difficult as it will take you some time to fully grok the process but once you’re through with this, then it will be alright. I suggest you try building a custom ROM from vanilla AOSP source and test it in Emulator using Virtual Device. It will also be a very good learning exercise for you.
You need to build your own backend infrastructure for distribution and remote management.
Developing kiosk based applications are difficult but not impossible, the problem begins when you start to control the device’s default functions, if you see that you need to completely lock-down a device then it is wiser that you go down the custom ROM path instead of trying to make it work in consumer grade Android phones.
Note: I have developed a generic Kiosk Management Solution called MobiLock Pro which has the above functionality as well as many other features. If you want to have a fully managed Cloud Based Kiosk solution then do check out MobiLock Pro.
]]>Important features of the Volley library:
NetworkImageView
, ImageLoader
etc)In Android it is always a good practice to make HTTP requests asynchronously, in fact from HoneyComb onwards it is no longer just a “good practice”, you must make HTTP requests asynchronously off the main thread or else you’ll get this nasty exception android.os.NetworkOnMainThreadException
. Blocking the main thread has some serious consequences, it hampers UI rendering, harmful to smooth user experience and above all it can cause dreaded ANR (Application Not Responding). To avoid all these pitfalls you as a developer should always ensure that your HTTP requests are on a different thread.
We are going to cover the following items in this blog post, by the end of it you should be able to have a clear understanding of Volley and how to use it in your application.
Volley is part of AOSP and right now it is not being distributed as a JAR, the easiest way to include Volley to your project is to clone the Volley repository and set it as a library project.
Git clone the repository using the following command and then import it as Android library project:
1
|
|
Clone the repository as shown above and then run the following commands to export it as JAR and after that add the JAR file to your project’s /libs
folder:
1 2 3 4 |
|
All requests in Volley are placed in a queue first and then processed, here is how you will be creating a request queue:
1
|
|
Ideally you should have one centralized place for your Queue, and the best place to initialize queue is in your Application class. Here is how this can be done:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
|
Volley provides the following utility classes which you can use to make asynchronous HTTP requests:
Note: To send parameters in request body you need to override either getParams()
or getBody()
method of the request classes (as required) described below.
This class can be used to send and receive JSON object. An overloaded constructor of this class allows to set appropriate request method (DELETE, GET, POST and PUT). This is the class which you should be using frequently if you are working with a RESTful backend. The following examples show how to make GET and POST requests.
Using HTTP GET method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
Using HTTP POST method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
This class can be used to retrieve JSON array but not JSON object and only HTTP GET is supported as of now. As it supports only GET, so if you are to specify some querystring parameters then append those in the URL itself. The constructor does not accept request parameters.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
This class can be used to retrieve the response from server as String, ideally you should use this class when you intend to parse the response by yourself, e.g. if it is XML. It also provides overloaded constructors to further customize your request.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
Setting a priority to the request is possible, this may be desirable in some cases where you want to move certain requests higher up in the order. The requests are processed from higher priorities to lower priorities, in FIFO order. To set a priority you need to override the getPriority()
method of the request class. The current available priorities are – Priority.LOW
, Priority.NORMAL
, Priority.HIGH
and Priority.IMMEDIATE
.
Volley provides powerful APIs to cancel pending or ongoing requests, one reason when you need to do this is if user rotates his device while a request is ongoing you need to cancel that because the Activity is going be restarted. The easiest way to cancel a request is to call the cancelAll(tag)
method of the request queue, this will only work if you have set a tag on the request object before adding it to the queue. The ability to tag requests allows you to cancel all pending requests for that tag in one method call.
Adding a request to the queue using a tag:
1
|
|
As per the ApplicationController class shown above, this is how you’ll add the request to the queue:
1
|
|
Cancelling all requests with the specified tag:
1
|
|
As per the ApplicationController class shown above, this is how you’ll cancel the requests:
1
|
|
There is no direct way to specify request timeout value in Volley, but there is a workaround, you need to set a RetryPolicy on the request object. The DefaultRetryPolicy
class takes an argument called initialTimeout, this can be used to specify a request timeout, make sure the maximum retry count is 1 so that volley does not retry the request after the timeout has been exceeded.
1
|
|
If you want to retry failed requests (due to timeout) you can specify that too using the code above, just increase the retry count. Note the last argument, it allows you to specify a backoff multiplier which can be used to implement “exponential backoff” that some RESTful services recommend.
Sometimes it is necessary to add extra headers to the HTTP requests, one common case is to add an “Authorization” header for HTTP Basic Auth. Volley Request class provides a method called getHeaders()
which you need to override to add your custom headers if necessary.
Adding custom headers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
There is no direct API through which you can set cookies in Volley. This makes sense because the core philosophy of Volley is to provide clean APIs to write RESTful HTTP requests, these days most of the RESTful API providers prefer authentication tokens instead of cookies. Using cookies in Volley is a bit more involed process and not very straight forward.
Here is a modified version of the getRequestQueue()
method of our ApplicationController class shown above, also contains the rough code required to set a cookie:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
As you have seen in the above code examples when you create a request object in Volley you need to specify an error listener, Volley invokes the onErrorResponse
callback method of that listener passing an instance of the VolleyError
object when there is an error while performing the request.
The following is the list of exceptions in Volley:
NetworkError
and NoConnectionError
together and treat them similarly.JsonObjectRequest
or JsonArrayRequest
if the received JSON is malformed then this exception will be generated. If you get this error then it is a problem that should be fixed instead of being handled.You can use a simple helper like the following to display appropriate message when one of these exceptions occurs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
|
Volley is really a nice library and you should seriously consider giving this a try. It will help you simplify your network requests and also add a ton of additional benefits.
I understand that it’s a tl;dr post, actually I tried to be as comprehensive as possible, I am planning to come up with another post about image loading using Volley and some gotchas that I noticed while using the library in one of my projects, till then stay tuned.
Thanks for reading, I hope you enjoyed this :–)
I’ll skip the part of creating the project and drive straight to the code. Here is our sample AndroidManifest.xml
file, remember to pay attention to the comments in the code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
The important line in the above XML file is <category android:name="android.intent.category.HOME" />
, this intent-filter
allows you to set your application as Home Screen application. Android looks for this particular intent filter and whenever you install your app with this intent-filter set then your application will appear in the list of installed launchers (a tap on the Home button will reveal the list).
Now as we have finished with the manifest file, let’s add some code to display the list of installed applications in our Home Screen, this way we can at least use the app after installing.
Here is the code to load the applications list asynchronously, we’re using a custom AsyncTaskLoader class, later we’ll hook it up in our fragment class using the Android Loaders.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
|
The loader class above will only retrieve the applications for which a “good” launch intent is available, put simply we’re only displaying those applications for which getLaunchIntentForPackage
returns a valid launch intent.
A simple adapter used to populate the applications’ icons and names in a GridView
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
Grid view container fragment class, uses Android Loaders to load the list of applications and displays them in the Grid view.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
|
A simple layout file to embed the grid fragment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
As it’s a Launcher app, so when you install it you don’t get to see anything unless you tap on the home button. The tap on the Home button shows you a chooser dialog from which you can select the appropriate Launcher app.
That’s it, you now have your own custom launcher application. Although a full-fledged launcher app like the ones that come with Android phones has many features built into them, but you can use this as a basic building block and start writing a more advanced and complex launcher as you learn.
For those who wants to investigate further, do take a look at the default launcher application code here: Android Stock Launcher App
Update: I wrote another post which provides a high-level overview of what all things are required to develop a “kiosk-mode” Android application. You can check it out here – Developing kiosk-mode applications in Android
You can download the full source code used in this article from this Github repository.
Note: I have developed a generic Kiosk Management Solution called MobiLock Pro which has the above functionality as well as many other features. If you want to have a fully managed Cloud Based Kiosk solution then do check out MobiLock Pro.
]]>The AndroidHttpClient
module offers a way to achieve this, when you’re sending JSON requests you can gzip the content of the request params and add some necessary HTTP headers, which will provide a hint to your server that it has to decode the content before it is usable. Needless to say that this technique is not just limited to sending JSON, you can of course use it if you’re sending CSV or text file over the network to server.
I’ll show a way how this can be done using a Rails backend (that’s what I use), but I presume this should not be too difficult to implement in case you’re not using Rails. I’ll be using JSON as an example here:
To encode or decode the JSON content you can use the following utility module in Android:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
|
The HTTP header, which indicates to server that the request content is gzipped, is Content-Encoding: gzip
. On the Rails side you can use the following Rack middleware to decode JSON requests (you can set your webserver for example nginx to do the encoding on JSON responses):
A Rack middleware to decode the gzipped JSON, thanks to this gist by relistan:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Now put this in somewhere in your Rails web application directory for example lib/middleware
, just make sure that the file is loaded when Rails boots. To include the file in Rails’ autoload path, add it like this:
1
|
|
Once that is done, then you need to add this tiny little Rack app as a middleware, and the important trick is to add it before the ActionDispatch::ParamsParser
middleware in Rails 3:
1 2 3 |
|
That’s all you need both on client and server to send and receive Gzipped content. If you’re sending JSON from client and you wan’t rails to interpret it as JSON, then don’t forget to add Content-Type: application/json
on your HTTP Request header.
Happy coding! If you have anything to say feel free to contact me on Twitter @arnabc
]]>Do not use same password everywhere
Why not? No one can guess my password, it’s ultra-strong, it contains letters, digits and even some special characters, I have even tested it with Password Strength Meter, so it’s simply unbreakable :–).
Indeed your password is unbreakable and even unguessable but there is a very good chance that you’ll lay it bare without even knowing it. Surprised right? Want to know how is this possible? Keep reading, I am going to tell you about the possibilities.
These days we spend a considerable amount of time on the Internet looking for useful stuff that we would like to use. Most of these websites require signing up to the service in order to use it, during that process it also asks you to create an “username/password” and also your email id so that they can communicate with you. The problem lies right there in the process when you create an “username” and “password”. If you are a person who mostly uses same password everywhere, then you are at risk without even realizing it.
So what is the risk? The risk is, you don’t know whether the site that you are signing up is actually storing your password in plain text or not. Logically, the website should encrypt your password before storing it in the database, but not all websites do that. There aren’t many ways that you can discover whether they are storing it in plain text or in encrypted form. But, there is a way and that is if you receive a confirmation email from that site where they have mentioned your username and password then it clearly is an indication that they are storing it in plain text – remember one thing a one-way encrypted password cannot be converted back to plain text (theoretically and the cost of decrypting is much higher), so it is technically impossible for that website to send you your password in plain text form. The other option is to try out the “Forget Password” facility and see if they are sending you your old password in plain text to retrieve your account.
You may ask why storing password in plain text is wrong ? It is wrong because nothing in this world is completely secure. If that site is ever compromised and the attacker gets hold of the database then he will have a list of users with their usernames, emails and passwords ( in plain text ), the damage is not limited to that website only, it is much bigger than you can even think of. Let’s imagine that you are an attacker and you have successfully compromised “example.com” which stores the user detail (password) in plain text, now you have a list of users with their email ids and the passwords that they have used while signing up to “example.com”, now if you try to log in to the users’ email accounts using the password you have on that list for each email ids, you’ll see that at least 20-30% of users or even more have the same password. See the pattern? There is a Domino effect once you lose access to your email account, you’ll lose access to your Facebook, Twitter and probably other services for example Bank accounts.
Here is a list of things that you can follow to minimize the damage as much as possible:
I know even all the steps mentioned above are not 100% foolproof, but at least if you are aware of the fact then it will surely help you minimize the risk. This is more like a “Social Engineering” problem, if you can understand this then take necessary steps to prevent it as much as possible.
The safety and security of users’ data is extremely important, it is always a good practice ( rather a must-have practice ) to encrypt sensitive user data. Storing passwords in plain text is utterly irresponsible and disrespectful act to the users. Also make sure that passwords are filtered out from your server’s log files. A little bit common sense can help protect the Internet as well as users.
]]>Here is a webcomic from XKCD on password reuse – http://xkcd.com/792/
The term remotely managed means that the app will be automatically updated over the air, there will be a provisioning server where the admins can publish/upload a new build, and that build will automatically be installed in the devices. Other than that the device can also be remotely restarted or shut down. The content that users can access or play using the app is stored in the device for faster access, and that content is synced (i.e. updated) periodically from a remote content syncing server. All of these are happening over the internet and the devices are equipped with a 3G chip, which makes it easier to download large amount of data with a decent network speed, else the content syncing would be a real pain. Below is the list of rough requirements that we had:
If you look at the requirements above, this ain’t an easy task and sure it’s not, we’re developing the app since last few months and are close to completion, the app is currently being field tested and hopefully it’ll soon be live out there in the wild.
So the big question is what are the challenges that we faced while we pulled off this effort, the purpose of this blog post is to share some of the findings/knowledge that we’ve gained over the period of time while developing the app. The ways that we’ve adopted are not the ones which can be adopted if you’re going to have your app be distributed through the Android market, our app isn’t or will not be distributed from the Android market, this is a custom application developed for a very specific/limited set of devices in mind. I’ll cover each of the requirements mentioned above and will share some of the rough design choices that we made in order to meet the requirements.
There’s only one way that you can have this kind of application in Android, make your app a homescreen app, so that whenever users press home/back button they’ll land up right there in your app, and they can’t get out of it (provided your app is the default one). In order to prevent users from exiting your app, you may need to handle some other stuff like options menu, disable recent items, and may be some extra buttons (some Chinese devices come with extra buttons on 7″ Android tablets) etc. These extra keys can be handled/prevented using Android key handling code.
This is an interesting part, you may be aware of that in Android the automatic update of an app can only happen through Marketplace, there’s no other way to update an app. But our app is not going to be distributed through Marketplace, so how do we update then? Well there’s no easy way to do it, and the process is complicated.
First of all, in Android in order to silently install an app, you need special permission called INSTALL_PACKAGES which is a system permission and IS NOT available to apps not signed with system/firmware certificate. This is an issue that we need to get past in order to make it happen, after few days of searching and testing several options, I narrowed it down to the following options:
At first I tried the rageagainstthecage exploit to root, but it were only able to temporarily root the device and it wouldn’t survive a reboot. Then I used psneuter to root the device and installed busybox and the modified su binary provided by the excellent guys from SuperOneClick installer. Along with that I also installed the Superuser app to manage the su permissions. Once the rooting procedure is in place it’s time to move on to code and write an Android service which can automatically install our application.
This service is the crux of this application, it acts as a “remote control” to manage the device as well as our homescreen application. We decided to build it as a separate app not part of the homescreen application, because this app is not going to have any GUI. So how does this work? Below is the rough diagram of it’s architecture:
In the above diagram, our Updater app is started whenever the device is rebooted (as per our installation process, we reboot the device after installing the update service app), it sets up a repeating alarm using a PendingIntent, which is invoked after a certain period of time, in the mean time it also makes a quick request to the provisioning server for any available update. If there’s an update then the UpdateService downloads the APK (link provided in the update check response) and once it’s downloaded (stored in the SDcard) it then fires up an intent to start the PackageInstaller and gives the APK file path as part of the intent payload. The PackageInstaller then runs the pm install -r <apkPath>
command with su
privilege. In order to execute the commands as root I used a modified version of the excellent piece of code available from here. Once the installation process is complete we notify the backend server that the device has been updated with the latest app (by the way it may already be clear to you that the provisioning server has the list of devices running in the wild and knows which device is running what version of the app). Anyway, this cycle of checking for updates continues as every time the alarm fires or the device is rebooted.
Although the entire procedure went smoothly, it wasn’t without a hitch, as I mentioned that our app is a homescreen application and in Android when you have multiple homescreen apps, every time you click on the home button you’re presented with a list of homescreen apps to choose from. So in our case we have two homescreen apps one is the default Android Launcher and the other is our homescreen app, as part of the installation procedure we set that app up to be the default one. But after update that settings was getting reset and pressing on the home button again was displaying that list of homescreen apps to choose from. We tried to solve this through code by setting our own Activity
as the default homescreen app using the Android API addPreferredActivty()
but that didn’t work because it has been removed/disabled by Google from Android 2.2 Froyo onwards (it was available till 2.1), the device that we’re using has the Android version 2.2.2. This was almost a dead end and that time we came up with a very interesting hack, and the trick is very simple just rename the launcher APK, ya that’s it just rename it and it’s gone :–). So here’s the steps that we have:
/system
folder as RW volume using busybox
, by default it’s readonly./system
back to it’s original ReadOnly mode.Example commands:
1 2 3 |
|
/system
folder as RW volume using busybox
, by default it’s readonly./system
back to it’s original ReadOnly mode.Example commands:
1 2 3 |
|
Note: In some devices the Launcher apk may be named as Launcher2.apk.
Similarly to the update service above, the Content Syncing part is also a separate app without a GUI, it gets started on RECEIVE_BOOT_COMPLETED intent and checks for updated content once a day. We download a pretty large amount of data which can range anywhere from 100MB-1GB. Below is the sequence diagram of the rough architecture that we have:
Once the download sync is complete, the app sends an Intent notifying the Main homescreen application about the content update so that it can display a friendly message to the user in case the device content is being used/played at that time. The main app stores some of the data in memory or in a SQLite database when it starts, so in order to cleanly rebuild that entire data structure we’re currently rebooting the device. But in future we’re planning to avoid it, so that the content update does not need a reboot.
This project has helped us gain a lot of valuable knowledge and insight into the Android platform and development practices as a whole. It has been a tremendous learning exercise for all of us. Even though the project is nearing completion, there are still some cases where we can optimize a bit, for example if you have gone through the above diagrams then you may have realized that the flows can be simplified even further by introducing Android Push Messaging (C2DM), this we’ll do sometime in later months, and as we already have the provisioning server in place then it’s just a matter of time that we develop the feaures and push it to the wild.
On a closing note, if you want to build an app like this, then you can get in touch with me at arnabc@webgyani.com, I’d be happy to help you.
Thanks for reading!
Note: I have developed a generic Kiosk Management Solution called MobiLock Pro which has the above functionality as well as many other features. If you want to have a fully managed Cloud Based Kiosk solution then do check out MobiLock Pro.
]]>The PhoneGap project has been moved to Apache Incubator and now it is known as “Apache Callback”. PhoneGap project is divided into several sub-projects where each one represents a separate platform. In order to develop for iPhone and iPad, you need Mac OSX and XCode installed, similarly for Android you need Google Android SDK, Eclipse ADT Plugin, Ant as well as Eclipse IDE.
The official project detail can be found here Apache Cordova. It is currently hosted in GitHub and once the Apache infrastructure is ready it will be moved there.
PhoneGap supports several mobile platforms, which enables web developers to write code using their existing HTML/JS skills and deploy to multiple platforms:
The environment setup for each of the above mentioned platforms can be found in “Getting Started”.
PhoneGap is not a “native application development” framework, even though it provides access through several device features using an abstraction layer, which otherwise are inaccessible to a normal webpage. In simple words, it provies a “WebView” with extended capabilities. Using PhoneGap one can access the following device features:
The following diagram explains how does a PhoneGap architecture look like:
In the above dialogram we can see that PhoneGap provides a “WebView” which is nothing but a bare bone web browser without a Chrome UI. The native code in PhoneGap SDK exposes uniform APIs across multiple device platforms which are accessible to JavaScript running inside the WebView.
As a web developer if you are using PhoneGap then it’s less likely that you’ll need to know the internals of the SDK (although it is always recommended to go through the source code in case you want to enlighten yourself as well as get fascinated by the tremendous efforts that the PhoneGap developers have put into it)
Even though you’re using HTML/CSS and JavaScript to develop applications, remember that it’s not a traditional desktop browser environment and the user experience pattern is significantly different. The PhoneGap apps are downloadable from App Store, so user might not know(or they don’t even care) that your app is built using PhoneGap or HTML/CSS, it’s always a good practice to be consistent with the platform UI guidelines so that you don’t confuse your users. A simple example could be if you’re developing a PhoneGap app for Android then be sure to handle the hardware/software(ICS) “back key”, if you don’t do that then your users might get confused.
Another important factor is handling scaling and device orientation, you should always make sure that your app looks proper in both Portrait and Landscape orientations.
The recommended way to start PhoneGap development is below:
PhoneGap as development platform is very attractive and promises to bring uniformity across several mobile platforms. It aims to become a de facto mobile application development framework using HTML5 based technologies. But as said above the capabilities offered by the framework is limited to what a “WebView” can do. The following are a list of things to watch out for:
As your app runs inside WebView (aka a browser), you should not allow untrusted third-party code to execute in the page, because this can compromize the security, the JS code downloaded from internet will suddenly have access to several device features that they can make substantial damage to user’s privacy and security. Do not load an iFrame in your app, or redirect to some other websites when the app is loaded, as this will likely get your app rejected in Apple app store, beacuse Apple does not like applications opening public websites inside the app as it makes it difficult or almost impossible to enforce policies regarding content.
The following resouces can be useful for HTML5 based mobile apps development (not all are related to PhoneGap):
PhoneGap provides an opportunity to a vast pool of web developers reusing their existing skills to develop applications for mobile phones, which in future is going to be one of the most important medium to access information and content in internet. As the phones become more powerful, the new capabilities will be available in your arsenal. The recent developments in HTML5 based technologies also usher a new change in this segment. Do not miss the bus and keep exploring PhoneGap.
]]>new
which we use to create an instance of an object (i.e Constructor function). So, what does new do? Well, it ensures that you always get an object when you use it with a constructor function. By the way, there’s no difference between a constructor function and a normal function, both are same. The term constructor function is used to indicate that we can create an object of that type using the new operator.
Consider the following example:
1 2 3 4 5 |
|
The above code pretty much says that you first create an instance of the constructor function (note the upper case first letter, it is a convention not a rule ) using new
operator, once that statement executes you now have an object as the value of foo
and in the next line it simply prints the “name” property of that object, which in this case is an instance variable of the constructor function “Foo”.
Take a look at the example below and guess what would be the value of foo
:
1 2 3 4 5 6 |
|
Interesting thing is that in this case the value of foo
is still an object, but we did return a String, so why the hell foo
contains an object? Well, the purpose of the new keyword is to ensure that you always get an object, so anything other than object is discarded, if you return an object then that will be used else a new object is created and returned. Now if we replace our return statement using this code return { prop: 'Foo' };
then the value of foo
will have a different value altogether and accessing foo.name
will result in undefined
.
Interestingly, if you return null
then that will be NOT be used, even though you might think that null is an object and typeof(null) === 'object'
, so it should use that. In fact, it does not, it appears that new returns only objects which can evaluate to truthy value.
The last but not the least, if you return a function other than object then the function will be used. Why? Because functions are objects too, only difference is that they are special objects, that’s why there’s a separation between objects and functions, the typeof
operator handles that properly, but in this case it appears that the new doesn’t really care about that.
Below are the list of things that I would expect to see in a would be frontend engineer:
Well if you want to be a frontend engineer make sure that you know stuff I mentioned above, these are just the beginning by the way, there are a lot of things that you will learn eventually, but don’t forget to make sure that your base is strong, do a lot of practice, ask questions, read articles and blogs and finally think like a frontend engineer. All the best.
Disclaimer: The use of the word ‘engineer’ is not meant to do anything with ‘Engineering discipline’ at all, I know traditional engineers do a lot of hard work to achieve that academic qualification, as working in Frontend also involves similar amount of hard work that’s why the term has been used here to refer the collective effort of these hard-working people.
]]>