TOP 10 MOBILE APPLICATION DEVELOPMENT COMPANIES

Tags

WHY DOES A BRAND REQUIRE A MOBILE APP?

Advertisements

The Ten Golden Rules on Living the Good Life

Credit: By Panos Mourdoukoutas

What is good life? What is happiness? What is success? What is pleasure? How should I treat other people? How should I cope with unfortunate events? How can I get rid off unnecessary worry? How should I handle liberty?

The answers to all these questions are condensed in a little book, The Ten Golden Rules I co-authored with Michael Soupios:

1. Examine life, engage life with vengeance; always search for new pleasures and new destines to reach with your mind. This rule isn’t new. It echoes the verses of ancient Greek philosophers and most notably those of Plato through the voice of his hero, Socrates. Living life is about examining life through reason, nature’s greatest gift to humanity. The importance of reason in sensing and examining life is evident in all phases of life– from the infant who strains to explore its new surroundings to the grandparent who actively reads and assesses the headlines of the daily paper. Reason lets human beings participate in life, to be human is to think, appraise, and explore the world, discovering new sources of material and spiritual pleasure.
2. Worry only about the things that are in your control, the things that can be influenced and changed by your actions, not about the things that are beyond your capacity to direct or alter. This rule summarizes several important features of ancient Stoic wisdom — features that remain powerfully suggestive for modern times. Most notably the belief in an ultimately rational order operating in the universe reflecting a benign providence that ensures proper outcomes in life. Thinkers such as Epictetus did not simply prescribe “faith” as an abstract philosophical principle; they offered a concrete strategy based on intellectual and spiritual discipline. The key to resisting the hardship and discord that intrude upon every human life, is to cultivate a certain attitude toward adversity based on the critical distinction between those things we are able to control versus those which are beyond our capacity to manage. The misguided investor may not be able to recover his fortune but he can resist the tendency to engage in self-torment. The victims of a natural disaster, a major illness or an accident may not be able to recover and live their lives the way they used to, but they too can save themselves the self-torment. In other words, while we cannot control all of the outcomes we seek in life, we certainly can control our responses to these outcomes and herein lies our potential for a life that is both happy and fulfilled.
3. Treasure Friendship, the reciprocal attachment that fills the need for affiliation. Friendship cannot be acquired in the market place, but must be nurtured and treasured in relations imbued with trust and amity. According to Greek philosophy, one of the defining characteristics of humanity that distinguishes it from other forms of existence is a deeply engrained social instinct, the need for association and affiliation with others, a need for friendship. Socrates, Plato, and Aristotle viewed the formation of society as a reflection of the profound need for human affiliation rather than simply a contractual arrangement between otherwise detached individuals. Gods and animals do not have this kind of need but for humans it is an indispensable aspect of the life worth living because one cannot speak of a completed human identity, or of true happiness, without the associative bonds called “friendship.” No amount of wealth, status, or power can adequately compensate for a life devoid of genuine friends.

4. Experience True Pleasure. Avoid shallow and transient pleasures. Keep your life simple. Seek calming pleasures that contribute to peace of mind. True pleasure is disciplined and restrained. In its many shapes and forms, pleasure is what every human being is after. It is the chief good of life. Yet not all pleasures are alike. Some pleasures are kinetic—shallow, and transient, fading way as soon as the act that creates the pleasure ends. Often they are succeeded by a feeling of emptiness and psychological pain and suffering. Other pleasures are catastematic—deep, and prolonged, and continue even after the act that creates them ends; and it is these pleasures that secure the well-lived life. That’s the message of the Epicurean philosophers that have been maligned and misunderstood for centuries, particularly in the modern era where their theories of the good life have been confused with doctrines advocating gross hedonism.

5. Master Yourself. Resist any external force that might delimit thought and action; stop deceiving yourself, believing only what is personally useful and convenient; complete liberty necessitates a struggle within, a battle to subdue negative psychological and spiritual forces that preclude a healthy existence; self mastery requires ruthless cador. One of the more concrete ties between ancient and modern times is the idea that personal freedom is a highly desirable state and one of life’s great blessings. Today, freedom tends to be associated, above all, with political liberty. Therefore, freedom is often perceived as a reward for political struggle, measured in terms of one’s ability to exercise individual “rights.”
The ancients argued long before Sigmund Freud and the advent of modern psychology that the acquisition of genuine freedom involved a dual battle. First, a battle without, against any external force that might delimit thought and action. Second, a battle within, a struggle to subdue psychological and spiritual forces that preclude a healthy self-reliance. The ancient wisdom clearly recognized that humankind has an infinite capacity for self-deception, to believe what is personally useful and convenient at the expense of truth and reality, all with catastrophic consequences. Individual investors often deceive themselves by holding on to shady stocks, believing what they want to believe. They often end up blaming stock analysts and stockbrokers when the truth of the matter is they are the ones who eventually made the decision to buy them in the first place. Students also deceive themselves believing that they can pass a course without studying, and end up blaming their professors for their eventual failure. Patients also deceive themselves that they can be cured with convenient “alternative medicines,” which do not involve the restrictive lifestyle of conventional methods.

6. Avoid Excess. Live life in harmony and balance. Avoid excesses. Even good things, pursued or attained without moderation, can become a source of misery and suffering. This rule is echoed in the writings of ancient Greek thinkers who viewed moderation as nothing less than a solution to life’s riddle. The idea of avoiding the many opportunities for excess was a prime ingredient in a life properly lived, as summarized in Solon’s prescription “Nothing in Excess” (6th Century B.C.). The Greeks fully grasped the high costs of passionate excess. They correctly understood that when people violate the limits of a reasonable mean, they pay penalties ranging from countervailing frustrations to utter catastrophe. It is for this reason that they prized ideals such as measure, balance, harmony, and proportion as much as they did, the parameters within which productive living can proceed. If, however, excess is allowed to destroy harmony and balance, then the life worth living becomes impossible to obtain.

7. Be a Responsible Human Being. Approach yourself with honesty and thoroughness; maintain a kind of spiritual hygiene; stop the blame-shifting for your errors and shortcomings. Be honest with yourself and be prepared to assume responsibility and accept consequences. This rule comes from Pythagoras, the famous mathematician and mystic, and has special relevance for all of us because of the common human tendency to reject responsibility for wrongdoing. Very few individuals are willing to hold themselves accountable for the errors and mishaps that inevitably occur in life. Instead, they tend to foist these situations off on others complaining of circumstances “beyond their control.” There are, of course, situations that occasionally sweep us along, against which we have little or no recourse. But the far more typical tendency is to find ourselves in dilemmas of our own creation — dilemmas for which we refuse to be held accountable. How many times does the average person say something like, “It really wasn’t my fault. If only John or Mary had acted differently then I would not have responded as I did.” Cop-outs like these are the standard reaction for most people. They reflect an infinite human capacity for rationalization, finger-pointing, and denial of responsibility. Unfortunately, this penchant for excuses and self-exemption has negative consequences. People who feed themselves a steady diet of exonerating fiction are in danger of living life in bad faith — more, they risk corrupting their very essence as a human being.

8. Don’t Be a Prosperous Fool. Prosperity by itself, is not a cure-all against an ill-led life, and may be a source of dangerous foolishness. Money is a necessary but not a sufficient condition for the good life, for happiness and wisdom. Prosperity has different meanings to different people. For some, prosperity is about the accumulation of wealth in the form of money, real estate and equities. For others, prosperity is about the accumulation of power and the achievement of status that comes with appointment to business or government positions. In either case, prosperity requires wisdom: the rational use of one’s resources and in the absence of such wisdom, Aeschylus was correct to speak of prosperous fools.

9. Don’t Do Evil to Others. Evildoing is a dangerous habit, a kind of reflex too quickly resorted to and too easily justified that has a lasting and damaging effect upon the quest for the good life. Harming others claims two victims—the receiver of the harm, and the victimizer, the one who does harm.

Contemporary society is filled with mixed messages when it comes to the treatment of our fellow human beings. The message of the Judaeo-Christian religious heritage, for instance, is that doing evil to others is a sin, extolling the virtues of mercy, forgiveness, charity, love, and pacifism. Yet, as we all know, in practice these inspiring ideals tend to be in very short supply. Modern society is a competitive, hard-bitten environment strongly inclined to advocate self-advantage at the expense of the “other.” Under these conditions, it is not surprising that people are often prepared to harm their fellow human beings. These activities are frequently justified by invoking premises such as “payback,” “leveling scores,” or “doing unto others, before they can do unto you.” Implicit in all of these phrases is the notion that malice towards others can be justified on either a reciprocal basis or as a pre-emptive gesture in advance of anticipated injury. What is not considered here are the effects these attempts to render evil have upon the person engaging in such attempts. Our culture has naively assumed that “getting even” is an acceptable response to wrongdoing — that one bad-turn deserves another. What we fail to understand is the psychological, emotional, and spiritual impact victimizing others has upon the victimizer.

10. Kindness towards others tends to be rewarded. Kindness to others is a good habit that supports and reinforces the quest for the good life. Helping others bestows a sense of satisfaction that has two beneficiaries—the beneficiary, the receiver of the help, and the benefactor, the one who provides the help.

Many of the world’s great religions speak of an obligation to extend kindness to others. But these deeds are often advocated as an investment toward future salvation — as the admission ticket to paradise. That’s not the case for the ancient Greeks, however, who saw kindness through the lens of reason, emphasizing the positive effects acts of kindness have not just on the receiver of kindness but to the giver of kindness as well, not for the salvation of the soul in the afterlife, but in this life. Simply put, kindness tends to return to those who do kind deeds, as Aesop demonstrated in his colourful fable of a little mouse cutting the net to free the big lion. Aesop lived in the 6th century B.C. and acquired a great reputation in antiquity for the instruction he offered in his delightful tales. Despite the passage of many centuries, Aesop’s counsels have stood the test of time because in truth, they are timeless observations on the human condition; as relevant and meaningful today as they were 2,500 years ago.

Android M vs. Android Lollipop: What Are The Sweet New Features And Changes?

Google has finally presented the much-anticipated Android M at the Google I/O 2015 conference. While Android 5.0 Lollipop was introduced before as a new interface and design, Android 6.0 codenamed ‘Android M,’ is now the company’s most powerful OS release with several platform improvements. Here is the breakdown of the sweet new changes and features of Android M compared to Android 5.0 Lollipop.

Battery Life

With Project Volta of Android Lollipop, Google positioned the grounds for longer battery life. Android M would be featuring a new battery saving function known as ‘Doze’, which uses motion detection to see if the device has been left unattended for a long time and it will stop real-time updates during that period. Doze would temporarily close unnecessary battery-eating functions and apps. Compared to Android Lollipop, Google claims Doze saves battery life twice as better on Android M’s standby mode.

Fingerprint Sensors Support

Android M also brings fingerprint authentication for individual apps. This new feature will let app developers integrate fingerprint payment and lock systems into their programs as Google finally programmed a standard support for fingerprint sensors.

Android Pay

Android M brings an updated version of Android Pay, which allows purchase with scanned fingerprint over NFC, just like rival’s Apple Pay. Android Pay creates a specific virtual account number for each payment method to protect card details always, from retailers.

App Permissions

There is now an integrated way to manage app permissions with Android M. In Android Lollipop, users have to confirm first app permissions to proceed in downloading apps from the Play Store. However once the userclicked ‘ok,’ there is no way to return and change that permission setting unless through re-installation. However, Android M brings an option in the Settings Menu that allows control and alters the information that each app can use. Apps Permissions now will let you toggle on or off access to information like camera, contact, identity, location, and media.

Other notable improvements

Android M features an app drawer that allows better organization of installed apps. There is now an alphabetized scroll on the left-hand margin and a bar along the top containing four most recently opened applications. Android M placed a search function in the top-right corner.

Android Lollipop provides detailed information about the amount of RAM each app uses. Android M now displays two new fields, which inform users the maximum and average RAM usage of an app.

For users who do not want to see an error due to full internal memory, Android M now allows formatting of micro SD card so that the system would treat it as internal memory. It also permits direct app installation to the micro SD card.

The iOS Design Guidelines

Design great-looking apps for Apple iOS devices. – Credit: http://iosdesign.ivomynttinen.com/

Designing iOS apps can be difficult sometimes, but finding correct and up-to-date information about all of Apples’ devices shouldn’t be. These design guidelines will help any designer who’s building neat things for iOS get started within seconds.

About these guidelines

These guidelines describe how to design apps that follow the official HIG for iOS by Apple, not what you can do with custom controls. Sometimes it makes sense to break the rules. The purpose of this document is to guide you, not to provide solutions for complex and unique design problems.

This unofficial documentation will be updated and extended regularly. Last update: November 11, 2014.

Resolutions and Display Specifications

Device Retina Portrait (px) Landscape (px)
iPhone 6+ Retina HD 1080 x 1920 1920 x1080
iPhone 6 Retina 750 x 1334 1334 x 750
iPhone 55, 5S, 5C Retina 640 x 1136 1136 x 640
iPhone 44, 4S Retina 640 x 960 960 x 640
iPhone1st, 2nd & 3rd Generation No 320 x 480 480 x 320
iPad Air / Retina iPad1st & 2nd Generation / 3rd & 4th No 1536 x 2048 2048 x 1536
iPad Mini2nd & 3rd Generation Retina 1536 x 2048 2048 x 1536
iPadMini, 1st & 2nd Generation No 768 x 1024 1024 x 768

Difference between Points and Pixels

Pixels are the smallest physical element that we can control on a digital display. The more pixels can be fitted into a specific screen size, the higher the PPI (pixels-per-inch), and the clearer the rendered content becomes.

Points are a resolution-independent measurement. Depending on the screens pixel density, a point can contain multiple pixels (e.g., 1 pt contains 2 x 2 pixels on a regular retina display).

When you are designing for various display types, you should think in points, but design in pixels. This means you will still need to export all your assets in 3 different resolutions, no matter in which resolution you are designing your app.

NOTE

As long as it is not stated otherwise (by appending „px“ to a value), this guide always refers to points when it comes to specific dimensions. If you need the value in pixels, just multiply by 2 for Retina screens or by 3 for Retina HD screens.

Device Asset Resolution PPI Display Size
iPhone 6+ @3x 401 5.5″
iPhone 6 @2x 326 4.7″
iPhone 55, 5S, 5C @2x 326 4.0″
iPhone 44, 4S @2x 326 3.5″
iPhone1st, 2nd & 3rd Generation @1x 163 3.5″
iPad Air / Retina iPad1st & 2nd Generation/ 3rd & 4th @2x 264 9.7″
iPad Mini2nd & 3rd Generation @2x 326 7.9″
iPad Mini1st Generation @1x 163 7.9″
iPad1st & 2nd Generation @1x 132 9.7″

Downsampling on iPhone 6+

Rendered pixels and physical pixels are equal on all iOS devices, with one exception: the Retina HD screen of the iPhone 6 Plus. Because its screen has a lower pixel resolution than what would be a natural @3x resolution, the rendered content is automatically resized to approximately 87% of the original size (from 2208 x 1242 pixels to fit the display resolution of 1920 x 1080 pixels).

Difference between iPhone 5S 6 6+ displaysThe difference between displays of iPhone 5S, 6 and 6+. More in-depth information here.

App Icons

Device App Icon AppStore Icon Spotlight Settings
iPhone 6+ 180×180 px 1024×1024 px 120×120 px 87×87 px
iPhone6, 5S, 5, 5C, 4S, 4 120×120 px 1024×1024 px 80×80 px 58×58 px
Old iPhones1st, 2nd, 3rd Generation 57×57 px 1024×1024 px 29×29 px 29×29 px
Retina iPadsMini 2 & 3, Air, 3 & 4 152×152 px 1024×1024 px 80×80 px 58×58 px
Old iPads1, 2, Mini 1 76×76 px 1024×1024 px 40×40 px 29×29 px

Automatically applied effects

App icons assets are generally added to the application package as plain, squared PNG files in various dimensions. When rendered on a device, iOS applies various effects to app icons.

ROUNDED CORNERS

The old simple radii values for rounded corners are gone. Since iOS 7, app icons have been using the shape of a superellipse. Since Apple did not release an official template of the shape, you will have to use one of the unofficial templates out there that replicate the shape in more or less accurate ways.

iOS 8 app icon radius shape

The rounded corners should not be included in the final exported assets, but you might need them in your design process if you want to add effects, such as a stroke or shadows, that are aligned to the corner of the icon.

WARNING

If you are masking your icon asset with the superellipse shape because you want to apply effects aligned to the corners, make sure not to use any transparency for the area outside the mask. Transparency is not supported at all for app icons and instead is rendered as plain black. If your mask is not 100% accurate, users will see small black fragments on the rounded edges. It’s recommend to set the background of the canvas to be the same as the app icon background.

BORDER STROKE (IN SOME SITUATIONS)

If the app icon you are using has a white background, a 1 pixel gray border stroke will be applied to make it easier to recognize the edges of the icon. This is only done in the settings app (if your application is listed there) and the AppStore.

LEGACY EFFECTS (IOS 6 AND PREVIOUS VERSIONS)

On older iOS versions, these effects are applied automatically: rounded corners (not the same shape as iOS 7+ icons are using), drop shadows on the home screen and a gloss effect that can be disabled.

Grid system

iOS 8 app icon grid system

Apple developed a golden ratio grid system that can be used to size and align elements on your icon correctly. Nevertheless, even Apple designers are not following the grid system very strictly with the native apps’ icons. Feel free to break the rules if your icon simply works better without aligning all elements strictly to the grid.

Typography

The default system font on all iOS versions is Helvetica Neue. Since iOS 7, Apple has been using a slightly modified version of the font, but using the original Helvetica Neue for your design process is totally fine. In addition to the default font, many alternative font faces are available to use. You can find a complete list of pre-installed typefaces here.

Custom Fonts

Technically, any True Type Font (.ttf) can be used within an iOS app, but be careful about licenses. It should be safe to use fonts that are completely free for commercial usage. App licenses for commercial fonts are rarely available, and if they are, securing them can turn out to be somewhat expensive. MyFonts currently offers the biggest collection of fonts that can be licensed for mobile app usage.

Color Palette

iOS 8 default colors

Since iOS 7, Apple has been using a vibrant color palette for the interface of the OS and pre-installed apps. While you can use the default iOS color palette listed above, you can also (and probably should, if you want to stand out) use your own colors.

Iconography

In iOS apps, icons have always been a great way to support text labels with a visual relationship to the performed action or to replace text completely (often for very common actions such as „New“, „Delete“, etc.). Usually, we are dealing with icons that are part of the Navigation Bar, Tool Bar or Tab Bar.

Bar Button Icons

Icons used in bars should always have two different states: the default state in outlined style with a stroke width of 1 or 1.5pt and the active state with a solid color fill.

iOS button bar outline and solid icons

You should never include any additional effects such as a drop-shadow or inner shadows on button icons because these are relicts from previous iOS versions (before the iOS 7 redesign). Button icons should be drawn in one solid color on a transparent background—the shape of the icon is used as a mask, and the color will be applied programmatically.

Activity View Icons

Icons in the Activity View (also known as Share Popover) used to be designed in outline style, but since iOS 8, Apple has reverted back to solid fill icons on a plain white background.

iOS activity sheet icons

Commonly used design elements

iOS offers a great collection of ready-to-use views and controls that allow app developers to quickly build interfaces. Some elements can be customized to a certain level, but other cannot and probably also should not be. When designing an application for iOS, you should know your set of tools and stick to them whenever possible. However, in some cases, it might be worthwhile to build a custom control because you need a more custom look or want to change the functionality of an already existing control (danger zone). Almost anything is possible,and sometimes it makes sense to break the rules, but always think twice before doing so.

Status Bar

The Status Bar contains basic system information such as the current carrier, time, battery status and more. It’s visually connected to the Navigation Bar and makes use of the same background fill. To match the style of your app and guarantee readability, the content of the status bar comes in two different styles: dark (black) and light (white).

iOS Status Bar

It is possible to hide the Status Bar, but think twice before doing so. For example, users might be interested in knowing if they are connected to a WiFi network when the app regularly downloads web content or if Bluetooth is enabled when the app requires a Bluetooth link to third-party hardware. A valid reason to hide the Status Bar is when you want to remove all distractions from a single element, for example, when displaying full screen content such as an image gallery.

The navigation bar contains the controls for navigating through the applications views and optionally to manage the content of the current view. It will always appear at the top of the screen, right below the status bar. By default, the background is slightly translucent and blurs content underneath the bar. The background fill of the bar can be set to a solid color, a gradient or a custom bitmap-pattern.

iOS Navigation Bar

Navigation Bar on iPhone 6 in portrait mode.

iOS Navigation Bar Landscape

Navigation Bar on iPhone 4S in landscape mode. The height of the bar is reduced by 12pt, except on iPads. It’s also a common practice to hide the status bar in landscape mode.

The elements should always following a specific alignment pattern.

  • Back button should always be aligned to the left side.
  • Title of the current view should always be centered in the bar.
  • Action buttons should always be aligned to the right side. If possible, there should never be more than one primary action to avoid missed clicks and to maintain simplicity.

Toolbar

A toolbar contains a set of actions for managing or manipulating the content of the current view. On the iPhone, it will always appear aligned at the bottom edge of the screen, while on the iPad, it can also be displayed aligned at the top of the screen.

Similarly to the navigation bar, the background fill of toolbars can be modified, is translucent and blurs the underlaying content by default.

iOS Toolbar

Toolbars should be used when a specific view requires more than three primary actions that would hardly fit or would look messy in the navigation bar.

Search bars come in two different styles by default: prominent and minimal. Both versions do have the same functionality.

  • As long as no text was entered by the user, a placeholder text is shown inside the bar, and, optionally, a bookmarks icon that can be used to access recent or saved searches.
  • Once a search term is entered, the placeholder disappears, and a clear button to delete the entered value appears on the right edge.

Search bars can make use of a prompt — a short sentence to introduce the functionality in the context of the search. For example, „Enter a city, zip code or airport.“

iOS prominent search bar

Prominent search bar style, without and with a prompt.

iOS minimal search bar

Minimal search bar style.

To provide even more control over a search query, it is possible to chain the search Bar with a scope bar. The scope bar will use the same style as the search bar and might be useful when there are clearly defined categories for the search results. For example, in a music app, the search results could be filtered again by interpreters, albums or songs.

Tab Bar

The tab bar is used to allow the user to quickly navigate through the separate views of an application, and it should only be used for this purpose. It always appears at the bottom edge of the screen. By default, its slightly translucent and uses the same system blur for underlaying content as the navigation bar.

iOS Tab Bar

A tab bar can only contain a fixed maximum number of tabs. Once there are more tabs than the maximum count, the last tab displayed will be replaced by a „More-tab“ that will lead to a list of hidden tabs, with an option to re-order the displayed tabs.

While the maximum amount of tabs displayed is five on iPhones, it’s possible to display up to seven tabs on the iPad while avoiding a more-tab.

To notify users about new information on a view, it sometimes makes sense to apply a badge count to a tab bar button. If a view is temporarily disabled, the related tab button should not be completely hidden; instead, it should be faded out to visually communicate the disabled state.

Table View

Table views are used to display small to large amounts of list style information in a single or multiple columns and with the option to divide several rows into separate sections or to group them.

There are two basic table view types that should be used, depending on the type of data you are presenting.

PLAIN

iOS plain table view

A plain table contains a number of rows that can have a header on the top and a footer after the last row. It’s possible to display a vertical navigation on the right edge of the screen to navigate through the table, which makes sense when presenting a big data set that could be sorted in some way (e.g., alphabetically descending).

GROUPED

iOS grouped table view

A grouped table allows you to organize rows in groups. Each group can have a header (best used to describe the context for the group) as well as a footer (good for help text, etc.). A grouped table needs to contain at least one group, and each group needs to contain at least one row.

For both table view types, a few styles are available to present the data in a way that allows users to easily scan, read and probably modify it.

DEFAULT

iOS default table view

A table row in default style has an optional image aligned on the left and a title.

WITH SUBTITLE

iOS subtitle table view

The subtitle table style enables a small subtitle text underneath the row title. It is useful for further explanations or short descriptions.

WITH VALUE

iOS subtitle table view

The value table style allows you to display a specific value that is related to the row title. Similar to the default style, each row can have an image and a title that are both aligned to the left. The title is followed by the right aligned label for the value, which is usually displayed in a slightly more subtle text color than the title.

Modals, Popovers and Alerts

iOS provides various styles of temporary views that can be used to display, edit and manipulate data in a way that fits best in a given situation. While each temporary view exists for a very specific purpose and each one looks different, all temporary views still have one thing in common: When displayed, it’s the highest index layer on the current view (they appear on top of everything else), and content underneath is overlayed by a translucent black background.

ACTIVITY VIEW

An activity view is used to perform specific tasks. These tasks can be default system tasks such as share content via the available options, or they can be completely custom actions. When designing icons for custom task buttons, you should follow the same guidelines as for the active state of bar button icons — solid fill, no effects, on a transparent background.

iOS activity sheet view

ACTIONS

Action Sheets are used to perform one single action from a list of available actions and to force the user of an app to confirm an action or cancel it.

iOS action sheet view

In portrait mode (and on small landscape screen resolutions), actions are always displayed as a list of buttons sliding in and staying at the bottom edge of the screen. In this case, an action sheet should always have a cancel button to close the view and not perform any of the listed actions.

When there is enough space available (e.g., on iPad screens), action sheets visually transform into popovers. A button to close the view is not required anymore because tapping a target anywhere outside the popover will close it automatically.

ALERTS

The purpose of alerts is to inform the user about critical information and optionally to force the user to make a decision about some action.

An alert view does always contain a title text, which should not be longer than one line and one (for pure informational alerts, e.g., „OK“) or two (for alerts that require a decision, e.g., „Send“ and „Cancel“) buttons.

iOS Alerts

Also, you can add a message text, if needed, as well as up to two text input fields, one of which can be a masked input field, which is appropriate for sensitive information like passwords or PINs.

EDIT MENU

iOS minimal search bar

The Edit Menu allows users to perform actions such as Copy, Paste, Cut, etc., when an element is selected (text, images, others). While it is possible to control which operations the user can choose from, the visual appearance of edit menus is set and not configurable unless you build your own completely custom edit menu.

POPOVER

Popovers are useful when a specific action requires multiple user inputs before proceeding. A good example is adding an item, which has a few attributes that need to be set before the item can be created.

In a horizontal environment, popovers reveal underneath the related control (such as a button) with an arrow pointing to that control while opened. The background of a popover uses a slightly reduced opacity and blurs the content underneath, just as many other UI elements have done since iOS 7.

iOS popover view

A popover is a powerful temporary view that can contain various objects such as its own navigation bar, table views, maps or web views. When a popover grows in size due to the number of contained elements and reaches the bottom edge of the viewport, it is possible to scroll within the popover.

MODALS

Modals are a useful view for tasks that require multiple commands or inputs by the user. They appear on top of everything else, and, while open, block interaction with any other interactive elements underneath.

The typical modal usually provides:

  • a title to describe the task;
  • a button to close the modal without saving or performing any other actions;
  • a button to save or submit any entered information; and
  • various elements for user input in the modal body.

There are three different modal styles available:

  1. Full screen: covers the entire screen.
  2. Page sheet: In portrait mode, the modal covers the underlaying content only partially, leaving a small portion of the parent view visible underneath the translucent black background. In landscape mode, the page sheet modal acts just like a full screen modal.
  3. Form sheet: In portrait mode, the modal appears in the center of the screen, keeping the surrounding content of the parent view visible underneath the translucent black background. The position of the modal adjusts automatically when a keyboard needs to be displayed. In landscape mode, the page sheet modal acts just like a full screen modal.

Controls

iOS provides a wide range of controls for basically any required input type you can think of. Listed below you will find the most important (commonly used), but for a full list of the available controls, you should look at the iOS Developer Library.

BUTTONS

Probably the most used control overall is the good old button. Since iOS 7, the default button design hasn’t really looked like a button anymore, but rather more like a plain text link. The button control is highly customizable and allows you to style everything from text style, drop shadows and color to an icon that is either prepended or centered if there is no text label, as well as fully custom backgrounds.

Keep in mind that a button can have several states, which should be communicated with visual language: default, highlighted, selected and disabled.

PICKERS

Pickers are used to select one value from a list of available values. The web equivalent would be a select box (which the picker control is also used for when touching a select in Safari). An extended version of picker is the datepicker, which allows the user to scroll through a list of dates and times and select values for (configurable) day, month and time.

iOS picker controls

Left: datepicker displayed inside a table view, right: picker as keyboard.

Except for the background color, it is not possible to change the visual style or size (same as keyboard) of a picker control. Most often, they appear at the bottom of the screens, where keyboards appear as well, but it is possible to use them in other positions.

SEGMENT CONTROLS

A segment control contains a set of segments (at least two) that can be used for things like filtering content or to create tabs for clearly categorized content types.

iOS segment controls

Segment control without and with icons.

Each segment can contain a text label or an image (icon), but never both. In addition, using a mixed set of segment types (text and images) in one segment control is not really recommended. The width of one segment changes automatically based on the number of segments (two segments: 50% of total control width, 5 segments: 20% of total control width).

SLIDERS

The slider control allows the user to choose one specific value from a range of allowed values. Since choosing a value works pretty smoothly and without any steps, sliders are recommended for selecting an estimated, but not exact, value. For example, a slider would be a good control for setting the sound volume, since the user can hear the difference and can see the difference between loud and very loud, but a text input to set an exact dB value would be impractical.

iOS slider controls

Slider control without and with descriptive icons.

It is possible to set icons for the minimum and the maximum value, which are displayed on the start and end edge of the slider control, thereby allowing you to visually embrace the purpose of the slider.

STEPPER

Steppers should be used when the user should enter an exact value from a limited range of possible values (e.g., 1-10). A stepper always contains two segmented buttons, one for lowering and one for raising the current value.

iOS stepper controls

Visually, the stepper control is highly customizable:

  • you can use your own icons for stepper buttons;
  • when maintaining the native iOS look, you can customize the color of borders, background and icons by using a tint color, which automatically sets the color for each of these elements; and
  • if you want to go further, you can use completely custom background images for the stepper buttons as well as for the separator.

SWITCH

iOS switch controls

A switch allows the user to quickly toggle between two possible states: on and off. It’s the checkbox for iOS apps. It is possible to customize the color for the on and off states, but the appearance of the toggle button and size of the switch are set and cannot be changed.

KEYBOARDS

There are various keyboard types available to provide the best possible keyboard for a specific text input. While it is possible to build your own completely custom keyboard, default keyboards cannot be customized in style or size.

Further Reading and Resources

These guidelines only provide basic information to get you started with iOS design. Once you dig deeper, you might be interested in more details. These articles and resources should help you.

GENERAL

ANIMATIONS & PROTOTYPING

DEVELOPMENT STARTER GUIDES

BAR BUTTON ICONS

APP ICONS

UI KITS

7 Project Management Tools that are making Life Simpler for Project Managers

Today, project management tools available on a cloud model or web-only model come in various types. Some can be all encompassing “does it all” solutions while others are much simpler.

Certain project management tools have specific defining methodology behind how they work. For instance, Trello and Agile Zen along with Blossom.io follow the Kanban method of project management. A few other project management tools are almost like Facebook or Twitter.

The options can be bewildering indeed. So, here’s an attempt to point you in the right direction as far as project management tools are concerned. If you are a project manager looking for a great tool to bring your team together to work collaboratively and manage projects successfully, look out for these options:

Telerik TeamPulse

Telerik TeamPulse is an all-in-one team management solution that enables multiple project management, enhanced collaboration, planning work, and even helps you leverage agile best practices.

Ideally suited for any software project management requirements, you can improve your decision-making, keep up-to-date on team progress, bridge the boundaries between team roles, open gates for communication, manage bugs, and much more. The web-based solution also extends itself for time-tracking, cross-project reporting, and also doubles as an ideas and feedback portal.

Agile Zen

Focused around visualization, communication, improvement of workflows, and efficient organization of work, Agile Zen is project management software that aims to offer a lean solution for businesses.

It renders itself very well for projects of all types – with a slight emphasis on the coding, software and development niche — while featuring some nifty features such as “performance metrics” showing you cycle times, lead times, and percentage efficiency. On the communication tab, you’ll see some inspiration from Trello-like flow with ready, working and complete columns to minimize interference in communication and to make sure that you are able to call attention to problems as they surface in the midst of a project.

Basecamp

The folks led by Jason Fried at 37Signals– the company behind Basecamp, High Rise, and Campfire – practically invented web-based project management. They are still big except that they chose not to add too much cream to the milk. By that, we mean that you won’t find anything fancy in Basecamp. No rich UI motions, no Gantt Charts, no visual reporting (except for a project progress bar, if you can call it that).

Yet, it has a strong following. It’s appeal as a simplistic project management tool is irresistible for many businesses. All you need is to assign projects to teams, and check the progress while keeping everyone on the same page using a calendar.

How much more simple can it get?

Asana

It’s amazing how many different ways a simple but powerful project management software tool can be used. Asana is the brainchild of Facebook’s co-founder Dustin Moscovitz and it’s rapidly growing to be a hugely popular web-based project management tool and it’s completely free to use for up to 15 users.

You can choose to run private or public projects, have granular control on who gets to see what, use Harvest App for time tracking, and Google Drive for document uploads and usage (In addition to Dropbox and your own computer hard drive). The project tool makes project management accountable with work assigned efficiently to the right people.

Deskaway.com

Project collaboration tools are getting smarter and with that, project managers and teams get the best of what is available. Deskaway.com is a smart, web-based collaboration tool, which provides you with project collaboration, which includes time tracking, project templates, documents, timesheets, and milestones.

It also provides you with a choice of options for reporting and analytics such as Gantt Charts, individual project and user reports. Deskaway does integrate with third-party apps while also being made available on your mobile devices.

Workzone

For project management, you need security along with plenty of other features that teams find useful. Some of the web-based project management tools either go overboard with features or underplay it completely missing out on what’s important.

Workzone focuses on exactly what teams need with features such as Status alerts, secure file sharing, flexible and manageable permissions, approvals workflow, file version, a group calendar, and even image markup. It has the ability to manage multiple projects and easily duplicate tasks that have similar workflows. It’s easy, intuitive to use, and gets you to work.

Worketc

How about using a single tool for almost everything you’d ever need to do for your business, managing projects and even billing or invoicing? Worketc.com is one single, web-based app that almost gets there with integrated CRM, project management, Billing, Help Desk (Customer Support), and much more.

The cost of using Worketc is much less than if you were to use CRM and project management separately. Further, everything remains on the cloud (much like all other project management tools) with business-wide visibility and real-time accountability. It’s the perfect way to get your team onboard and give them one single office to work from. Even the remote workers feel at home with this tool.

There’s no one tool that’s the best as most of these listed project management tools have some great features and each has their own breed of users. Asana, Workzone, and Basecamp for instance, can fit any type of project while Agile Zen and TeamPulse make better choices for software development projects.

As a project manager, try to fit a project management solution around your needs instead of picking up any project management tool. You’d need a fairly flexible solution, which is also easy on the eye and easy to use. Look for the third-party apps your project management tool integrates with – sometimes, that will decide which tool to go for.

For instance, Agile Zen mostly integrates with development tools and not with some popular apps such as Google Apps, High Rise, Zen Desk, etc. Do your due diligence and you won’t have to waste time working with the wrong project management solution.

What’s your favourite when it comes to project management solutions?

5 Tips for Improving Your Project Schedule

You have a project schedule, right? It’s probably the most important document for a project manager, whether you have plotted it with sticky notes on flip chart paper or used sophisticated project management software to produce it. It is the document that the whole team uses to work out what they are supposed to do by when. It’s the document your project sponsor will use to understand the project work, and you will use it too for project reporting and monitoring status.

In fact, without a project schedule, you could say that you don’t have a project! However, a project schedule is more than just a list of ordered tasks. It also needs to include much more to be useful. Here are 5 things that you can include on your schedule to ensure that it a great tool for your project.

1. Resources

Schedules aren’t just for tasks. While you resourcesmight start out by creating a comprehensive task list, you can do a lot more with your project schedule, including adding resources to each task. Adding the details of who is doing the activity to the entry on the schedule makes it easy to see what work each individual is doing. The information will automatically feed through to your reporting software if you are using an enterprise-standard project management tool and you’ll be able to create resource reports with just a few clicks. The benefit of these is that you’ll quickly be able to see who has too much work and who needs some more tasks allocated to them so they aren’t sitting around waiting for things to do.

There is also a benefit for your team members as they will instantly be able to see what they are supposed to be doing when. It can really help them plan their diaries and it’s a visual reminder of deadlines. Some software will even let you send automated reminders to team members when tasks are due.

2. Milestones

If you start off your project planning by creating a long task list, the chances are you are short of a few milestones. Milestones aren’t tasks per se, they are moments in time where you can take stock of what’s going on – activities that mark the end of a phase, the start of a stage or something similar.

Scatter some milestones through your project schedule at logical points. Aim for a couple of milestones per month so that you can use these in your project reporting to track your progress. Milestones are normally marked on a schedule by including a task with a duration of zero days or specifically marking the task as a milestone in the task properties.

3. Summary Tasks

A summary task, also known as a hammock task, is an overarching task that comprises of several smaller tasks. It is different from a milestone, which marks (for example) the end of a phase. Instead, a summary task would be for the whole phase. All the tasks within that phase sit underneath it.

Summary tasks are useful because they allow you to group together related activities. Again, this makes project reporting easier as you can focus on the status of the project at a higher level.

4. Actual Dates

It’s great to plan out your project at the beginningcalendar and add in all of the forecasted dates. In fact, you definitely need to do this! It gives you a schedule to work to and it ensures that your team have deadlines to aim for.

But when the work starts, you’ll also find it useful to record actual start and actual finish dates. You can use these to compare to your project baseline. A baseline is a snapshot of your schedule in time, so when you then begin work you can look back and see how well you are doing.

Using your actual start and actual finish dates will help you see if you are hitting your original target dates for task completion. They can show you if you are running late, in comparison to your forecasted plan, or even early! And they can help with task estimating, as if you notice that a particular task has taken a lot longer than you expected, next time you come to schedule that task on a project you’ll know exactly how long it really takes.

5. Dependencies

Dependencies are the links between tasks. They help determine how long a project will take because some tasks can only be done in a certain order. Most tasks run one after the other, so your dependencies will run from the end of one task to the beginning of another. However, you may also find on your project that you have tasks that need to be done in parallel, or which have to start before another task. Dependencies will let you link all the tasks in the appropriate way.

Dependencies normally appear on your project schedule as little lines that end with an arrow. The arrow shows you which way the link goes, so it makes it clear which task is dependent on something else. A task can be dependent on several tasks so you can find your schedule looking very messy with lines going up, down and across it! Think about the order of tasks on your schedule and try to put related tasks next to each other so that the dependency lines don’t get too messed up.

Project schedules obviously include a lot of information – they are the most important thing for managing a project professionally so they need to really help you do a good job. They are a very useful tool, and so much more than a task list, but they are only as good as the information you include in them. Do your project schedules include all these elements?

Create beautiful, comprehensive project schedules with ProjectManager.com. You can even upload your task information from other software applications and share it instantly with your project team members. Never miss a deadline again.

Project Management: Warning Signs Your Project May Be in Trouble

All projects have the potential of getting into trouble, but generally, project management can work well as long as: 1) the requirements do not impose severe pressure on the project manager, and 2) a project sponsor exists as an ally to assist when trouble does appear.

Unfortunately, in today’s chaotic environment, this pressure appears to be increasing because:

  • Companies are accepting high-risk and highly complex projects as a necessity for survival
  • Customers are demanding low-volume, high-quality products with some degree of customization
  • Project life cycles and new product development times are being compressed
  • Enterprise environmental factors are having a greater impact on project execution
  • Customers and stakeholders want to be more actively involved in the execution of projects
  • Companies are developing strategic partnerships with suppliers, and each supplier can be at a different level of project management maturity
  • Global competition has forced companies to accept projects from customers that are all at different levels of project management maturity and have different reporting requirements

These pressures tend to slow down the decision-making processes at a time when stakeholders want the projects and processes to be accelerated. One person, while acting as the project sponsor, may have neither the time nor the capability to address all of these additional issues. The result will be a project slowdown, which can occur because of:

  • The project manager being expected to make decisions in areas where he/she has limited knowledge
  • The project manager hesitating to accept full accountability and ownership for the projects
  • Excessive layers of management being superimposed on the project management organization
  • Risk management being pushed up to higher levels in the organizational hierarchy, resulting in delayed decisions
  • The project manager demonstrating questionable leadership ability on some of the nontraditional projects

The problems resulting from these pressures may not be able to be resolved by a single project sponsor, at least easily and in a timely manner. These problems can be resolved using effective project governance. Project governance is actually a framework by which decisions are made. Governance relates to decisions that define expectations, accountability, responsibility, the granting of power or verifying performance, and relates to consistent management, cohesive policies, processes, and decision-making rights for a given area of responsibility. It enables efficient and effective decision making to take place.

Every project can have different governance even if each project uses the same enterprise project management methodology. The governance function can operate as a separate process or as part of project management leadership. Governance is not designed to replace project decision making, but to prevent undesirable decisions from being made.

Historically, governance was provided by a single project sponsor. Today, governance is a committee and can include representatives from each stakeholder’s organization. Exhibit 1 shows one such governance approach. The membership of the committee can change from project to project and industry to industry. The membership may also vary based on the number of stakeholders and whether the project is for an internal or external client. On long-term projects, membership can change throughout the project.

 Exhibit 1: Typical Governance Structure 

Project Management: Warning Signs Your Project May Be in Trouble image Post PIc 1 300x241

Governance on projects and programs sometimes fails because people confuse project governance with corporate governance. The result is that members of the committee are not sure what their roles should be. For governance to work correctly, each member of the governance committee must clearly understand the committee’s responsibility and decision-making authority in relation to the project team’s responsibility and decision-making authority. If significant overlap exists, confusion will reign and problems will occur. If clarification is not made, the project team runs the risk of micromanagement by the governance committee. This understanding must be made early on in the project, preferably before the project actually begins.

6 Characteristics of Superstar Project Managers

You’re good at your job, right? Brilliant, in fact. You have all the bases covered, all of the time and you always get the job done, usually on time and on budget. But are you really a good project manager?

There is a world of difference between being good and being efficient, and the two do not necessarily always go together. A superstar project manager is one that is highly efficient and is good at the human side of the job; a person could be fantastic at delivering results, but dreadful at man management and the soft skills that make a truly great manager.

What makes a superstar project manager then?

—

  1. A true people person, a superstar project manager knows how to build relationships with people in order to get the best out of them without having to crack the whip.
  2. Someone who can teach their team members new methods and new ways of looking at things, as well as being open to their ideas and suggestions. Help your team to better themselves and help them along within their own careers if progression is on their mind, you are building a much stronger team that way.
  3. A social butterfly. Social media presents a magnificent opportunity to learn and teach, as well as to reach out to others in your profession with tips and leads. A social project manager, that actively engages with others in online communities, is one that is open to new ideas – as well as being more discoverable by prospective clients.
  4. A moving target. Project managers cannot sit and waste away behind a desk all day, delegating tasks and communicating by email and the like. While delegation and communication are important, getting out and meeting with managers and team members is equally as important. If you are connecting with people ‘on the ground’ you are being more proactive, and things are more likely to move forward a little quicker because you able to respond and communicate faster and more effectively.
  5. Someone who can be aware of other peoples strengths and weaknesses. This means you can assign tasks that you know an individual can accomplish. For example, do not ask Paul, a graphic artist, to go and set up a sound studio for a recording session that needs to take place. You need be aware of which member of your team is best in which area, and you have play to those strengths to the benefit of not just the project at hand, but the stability and confidence of the team moving forward too.
  6. —Someone who has the willingness to learn and improve upon their craft, the best project managers are constantly looking to learn new skills that will help them with present and future projects; attending PM courses or brushing up on current think by listening to PM podcasts. We all know about the people that have medals on their chests, but have never seen the front line – don’t be that guy; work hard, and work harder at being even more awesome than you already are.

Tutorial: Developing a PhoneGap Application

In this tutorial, you create a fully functional employee directory application with PhoneGap. You will learn:

  • How to use different local data storage strategies.
  • How to use several PhoneGap APIs such as Geolocation, Contacts, and Camera.
  • How to handle specific mobile problems such as touch events, scrolling, styling, page transitions, etc.
  • How to build an application using a single page architecture and HTML templates.
  • How to build (compile and package) an application for 6 platforms using PhoneGap Build.

To complete this tutorial, all you need is a code editor, a modern browser, and a connection to the Internet. A working knowledge of HTML and JavaScript is assumed, but you don’t need to be a JavaScript guru.

Setting Up

  1. Download the assets for the workshop here.
  2. Unzip the file anywhere on your file system.
  3. If your code editor allows you to “open a directory”, open the phonegap-workshop-master directory.
  4. Follow the instructions below.
Step-by-step solution files are also available here.

Part 1: Choosing a Local Storage Option


Step 1: Explore different persistence mechansisms

Open the following files in phonegap-workshop-master/js/storage, and explore the different persistence stores they define:

  1. memory-store.js (MemoryStore)
  2. ls-store.js (LocalStorageStore)
  3. websql-store.js (WebSqlStore)

Step 2: Test the application with different persistence mechanisms

To change the local persistence mechanism for the application:

  1. In index.html: add a script tag for the corresponding .js file: memory-store.js, ls-store.js, or websql-store.js.
  2. In js/main.js: Instantiate the specific store in the initialize() function of the app object: MemoryStore, LocalStorageStore, or WebSqlStore.
  3. To test the application, open index.html in your browser, or simply double-click index.html on your file system. Type a few characters in the search box to search employees by name. Clicking an employee link doesn’t produce any result at this time.

Part 2: Building with PhoneGap Build


  1. If you don’t already have one, create an account on http://build.phonegap.com.
  2. Click the “new app” button to create a new application on PhoneGap Build.
  3. Either point to a GitHub repository where you push your code for this workshop, or zip up your phonegap-workshop directory and upload it to PhoneGap Build.
  4. Click the Ready to build button.
    The iOS button will immediately turn red because the iOS build requires that you upload your Apple Developer certificate and an application provisioning profile. You can find more information here if you haven’t already signed up for the Apple Developer Program. If you don’t have an iOS device, or if you are not ready to upload your developer certificate, you can skip step 5 and keep running the application in the browser or a non iOS device.
  5. To upload your Apple developer certificate and your application provisioning profile:
    • Click the red iOS button.
    • Select “add a key” in the “No key selected” dropdown.
    • Provide a title for your developer certificate/provisioning profile combination (for example: EmployeeDirectory), select your developer certificate and provisioning profile, enter your developer certificate password, and click “submit key”.
    • Go back to the list of apps. Click the iOS button for your application again. Select your newly added key in the iOS dropdown. The iOS build will start automatically.
  6. When the build process completes, use a QR Code reader app to install the Employee Directory application on your device.

To fine tune your build preferences:

  1. In the phonegap-workshop directory, create a file namedconfig.xml file defined as follows (make the necessary adjustments for id, author, etc.):
    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
    <?xml version="1.0" encoding="UTF-8"?>
    <widget xmlns       = "http://www.w3.org/ns/widgets"
            xmlns:gap   = "http://phonegap.com/ns/1.0"
            id          = "org.coenraets.employeedirectory"
            versionCode = "10"
            version     = "1.1.0">
      
        <name>Employee Directory</name>
      
        <description>
            A simple employee directory application
        </description>
      
        <author href="http://coenraets.org" email="ccoenraets@gmail.com">
            Christophe Coenraets
        </author>
      
        <feature name="http://api.phonegap.com/1.0/camera"/>
        <feature name="http://api.phonegap.com/1.0/contacts"/>
        <feature name="http://api.phonegap.com/1.0/file"/>
        <feature name="http://api.phonegap.com/1.0/geolocation"/>
        <feature name="http://api.phonegap.com/1.0/media"/>
        <feature name="http://api.phonegap.com/1.0/network"/>
        <feature name="http://api.phonegap.com/1.0/notification"/>
      
    </widget>
  2. If you used the GitHub approach, sync with GitHub and click the Update Code button in PhoneGap Build.
    If you used the zip file approach, zip up your phonegap-workshop directory and upload the new version to PhoneGap Build
There are many other parameters you can specify in config.xml to configure the build process. See the documentation for config.xml here.

Part 3: Using Native Notification


A default webview alert gives away the fact that your application is not native. In this section, we set up the basic infrastructure to display native alerts when the application is running on a device, and fall back to default browser alerts when running in the browser.

  1. In index.html, add the following script tag (as the first script tag at the bottom of the body):
    1
    <script src="phonegap.js"></script>

    This instructs PhoneGap Build to inject a platform specific version of phonegap.js at build time. In other words, phonegaps.js doesn’t need to be (and shouldn’t be) present in your project folder.

  2. In main.js, define a function named showAlert() inside the app object. If navigator.notification is available, use its alert() function. Otherwise, use the default browser alert() function.
    1
    2
    3
    4
    5
    6
    7
    showAlert: function (message, title) {
        if (navigator.notification) {
            navigator.notification.alert(message, null, title, 'OK');
        } else {
            alert(title ? (title + ": " + message) : message);
        }
    },
  3. Test the notification logic by displaying a message when the application store has been initialized: Pass an anonymous callback function as an argument to the constructor of the persistence store (the store will call this function after it has successfully initialized). In the anonymous function, invoke the showAlert() function.
    1
    2
    3
    4
    5
    6
    7
    initialize: function() {
        var self = this;
        this.store = new MemoryStore(function() {
            self.showAlert('Store Initialized', 'Info');
        });
        $('.search-key').on('keyup', $.proxy(this.findByName, this));
    }
  4. Test the application: When you run the application in the browser, you should see a standard browser alert. When you run the application on your device, you should see a native alert.

Part 4: Setting Up a Single Page Application


A single page application is a web application that lives within a single HTML page. The “views” of the application are injected into- and removed from the DOM as needed as the user navigates through the app. A single page application architecture is particularly well suited for mobile apps:

  • The absence of continual page refreshes provides a more fluid / closer to native experience.
  • The UI is entirely created at the client-side with no dependency on a server to create the UI, making it an ideal architecture for applications that work offline.

In this section, we set up the basic infrastructure to turn Employee Directory into a single page application.

  1. In index.html: remove the HTML markup inside the body tag (with the exception of the script tags).
  2. In main.js, define a function named renderHomeView() inside the app object. Implement the function to programmatically add the Home View markup to the body element.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    renderHomeView: function() {
        var html =
                "<div class='header'><h1>Home</h1></div>" +
                "<div class='search-view'>" +
                "<input class='search-key'/>" +
                "<ul class='employee-list'></ul>" +
                "</div>"
        $('body').html(html);
        $('.search-key').on('keyup', $.proxy(this.findByName, this));
    },
  3. Modify the initialize() function of the app object. In the anonymous callback function of the store constructor, call the renderHomeView() function to programmatically display the Home View.
    1
    2
    3
    4
    5
    6
    initialize: function() {
        var self = this;
        this.store = new MemoryStore(function() {
            self.renderHomeView();
        });
    }

Part 5: Using Handlebar Templates


Writing HTML fragments in JavaScript and programmatically inserting them into the DOM is tedious. It makes your application harder to write and harder to maintain. HTML templates address this issue by decoupling the UI definition (HTML markup) from your code. There are a number of great HTML template solutions: Mustache.js, Handlebar.js, and Underscore.js to name a few.

In this section, we create two templates to streamline the code of the Employee Directory application. We use Handlebar.js but the smae result can be achieved using the other HTML template solutions.

Modify index.html as follows:

  1. Add a script tag to include the handlebar.js library:
    1
    <script src="lib/handlebars.js"></script>
  2. Create an HTML template to render the Home View. Add this script tag as the first child of the body tag:
    1
    2
    3
    4
    5
    <script id="home-tpl" type="text/x-handlebars-template">
        <div class='header'><h1>Home</h1></div>
        <div class='search-bar'><input class='search-key' type="text"/></div>
        <ul class='employee-list'></ul>
    </script>
  3. Create an HTML template to render the employee list items. Add this script tag immediately after the previous one:
    1
    2
    3
    4
    5
    <script id="employee-li-tpl" type="text/x-handlebars-template">
        {{#.}}
        <li><a href="#employees/{{this.id}}">{{this.firstName}} {{this.lastName}}<br/>{{this.title}}</a></li>
        {{/.}}
    </script>

Modify main.js as follows:

  1. In the initialize() function of the app object, add the code to compile the two templates defined above:
    1
    2
    this.homeTpl = Handlebars.compile($("#home-tpl").html());
    this.employeeLiTpl = Handlebars.compile($("#employee-li-tpl").html());
  2. Modify renderHomeView() to use the homeTpl template instead of the inline HTML:
    1
    2
    3
    4
    renderHomeView: function() {
        $('body').html(this.homeTpl());
        $('.search-key').on('keyup', $.proxy(this.findByName, this));
    },
  3. Modify findByName() to use the employeeLiTpl template instead of the inline HTML:
    1
    2
    3
    4
    5
    6
    findByName: function() {
        var self = this;
        this.store.findByName($('.search-key').val(), function(employees) {
            $('.employee-list').html(self.employeeLiTpl(employees));
        });
    },
  4. Test the application.

Part 6: Creating a View Class


It’s time to provide our application with some structure. If we keep adding all the core functions of the application to the app object, it will very quickly grow out of control. In this section we create a HomeView object that encapsulates the logic to create and render the Home view.

Step 1: Create the HomeView Class

  1. Create a file called HomeView.js in the js directory, and define a HomeView class implemented as follows:
    1
    2
    3
    4
    var HomeView = function(store) {
      
      
    }
  2. Add the two templates as static members of HomeView.
    1
    2
    3
    4
    5
    6
    7
    var HomeView = function(store) {
      
      
    }
      
    HomeView.template = Handlebars.compile($("#home-tpl").html());
    HomeView.liTemplate = Handlebars.compile($("#employee-li-tpl").html());
  3. Define an initialize() function inside the HomeView class. Define a div wrapper for the view. The div wrapper is used to attach the view-related events. Invoke the initialize() function inside the HomeView constructor function.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var HomeView = function(store) {
      
        this.initialize = function() {
            // Define a div wrapper for the view. The div wrapper is used to attach events.
            this.el = $('<div/>');
            this.el.on('keyup', '.search-key', this.findByName);
        };
      
        this.initialize();
      
    }
      
    HomeView.template = Handlebars.compile($("#home-tpl").html());
    HomeView.liTemplate = Handlebars.compile($("#employee-li-tpl").html());
  4. Move the renderHomeView() function from the app object to the HomeView class. To keep the view reusable, attach the html to the div wrapper (this.el) instead of the document body. Because the function is now encapsulated in the HomeView class, you can also rename it from renderHomeView() to just render().
    1
    2
    3
    4
    this.render = function() {
        this.el.html(HomeView.template());
        return this;
    };
  5. Move the findByName() function from the app object to the HomeView class.
    1
    2
    3
    4
    5
    this.findByName = function() {
        store.findByName($('.search-key').val(), function(employees) {
            $('.employee-list').html(HomeView.liTemplate(employees));
        });
    };

Step 2: Using the HomeView class

  1. In index.html, add a script tag to include HomeView.js (just before the script tag for main.js):
    1
    <script src="js/HomeView.js"></script>
  2. Remove the renderHomeView() function from the app object.
  3. Remove the findByName() function from the app object.
  4. Modify the initialize function() to display the Home View using the HomeView class:
    1
    2
    3
    4
    5
    6
    initialize: function() {
        var self = this;
        this.store = new MemoryStore(function() {
            $('body').html(new HomeView(self.store).render().el);
        });
    }

Part 7: Adding Styles and Touch-Based Scrolling


Step 1: Style the Application

  1. Add the Source Sans Pro font definition to the head of index.html
    1
    <script src="css/source-sans-pro.js"></script>

    Source Sans Pro is part of the free Adobe Edge Web Fonts.

  2. Add styles.css to the head of index.html
    1
    <link href="css/styles.css" rel="stylesheet">
  3. In index.html, modify the home-tpl template: change the search-key input type from text to search.
  4. Test the application. Specifically, test the list behavior when the list is bigger than the browser window (or the screen)

Step 2: Native Scrolling Approach

  1. Modify the home-tpl template in index.html. Add a div wrapper with a scroll class around the ul element with a scroll:
    1
    2
    3
    4
    5
    <script id="home-tpl" type="text/x-handlebars-template">
        <div class='header'><h1>Home</h1></div>
        <div class='search-bar'><input class='search-key' type="search"/></div>
        <div class="scroll"><ul class='employee-list'></ul></div>
    </script>
  2. Add the following class definition to css/styles.css:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    .scroll {
        overflow: auto;
        -webkit-overflow-scrolling: touch;
        position: absolute;
        top: 84px;
        bottom: 0px;
        left: 0px;
        right: 0px;
    }
If the platforms you target support touch-based scrolling of fixed regions, this approach is all you need (you can skip step 3 below). If not, you’ll need to implement a programmatic approach, typically with the help of a library such as iScroll.

Step 3: iScroll Approach

  1. Add a script tag to include the iscroll.js library:
    1
    <script src="lib/iscroll.js"></script>
  2. In HomeView.js, modify the findByName() function: Instantiate an iScroll object to scroll the list of employees returned. If the iScroll object already exists (), simply refresh it to adapt it to the new size of the list.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    this.findByName = function() {
        store.findByName($('.search-key').val(), function(employees) {
            $('.employee-list').html(HomeView.liTemplate(employees));
            if (self.iscroll) {
                console.log('Refresh iScroll');
                self.iscroll.refresh();
            } else {
                console.log('New iScroll');
                self.iscroll = new iScroll($('.scroll', self.el)[0], {hScrollbar: false, vScrollbar: false });
            }
        });
    };
More information on iScroll is available here.

Part 8: Highlighting Tapped or Clicked UI Elements


  1. In styles.css, add a tappable-active class definition for tapped or clicked list item links. The class simply highlights the item with a blue background:
    1
    2
    3
    4
    li>a.tappable-active {
        color: #fff;
        background-color: #4286f5;
    }
  2. In main.js, define a registerEvents() function inside the app object. Add a the tappable_active class to the selected (tapped or clicked) list item:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    registerEvents: function() {
        var self = this;
        // Check of browser supports touch events...
        if (document.documentElement.hasOwnProperty('ontouchstart')) {
            // ... if yes: register touch event listener to change the "selected" state of the item
            $('body').on('touchstart', 'a', function(event) {
                $(event.target).addClass('tappable-active');
            });
            $('body').on('touchend', 'a', function(event) {
                $(event.target).removeClass('tappable-active');
            });
        } else {
            // ... if not: register mouse events instead
            $('body').on('mousedown', 'a', function(event) {
                $(event.target).addClass('tappable-active');
            });
            $('body').on('mouseup', 'a', function(event) {
                $(event.target).removeClass('tappable-active');
            });
        }
    },
  3. Invoke the registerEvents() function from within the app object’s initialize() function.
  4. Test the application.

Part 9: View Routing


In this section, we add an employee details view. Since the application now has more than one view, we also add a simple view routing mechanism that uses the hash tag to determine whether to display the home view or the details view for a specific employee.

Step 1: Create the employee template

Open index.html and add a template to render a detailed employee view:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script id="employee-tpl" type="text/x-handlebars-template">
    <div class='header'><a href='#' class="button header-button header-button-left">Back</a><h1>Details</h1></div>
    <div class='details'>
        <img class='employee-image' src='img/{{firstName}}_{{lastName}}.jpg' />
        <h1>{{firstName}} {{lastName}}</h1>
        <h2>{{title}}</h2>
        <span class="location"></span>
        <ul>
            <li><a href="tel:{{officePhone}}">Call Office<br/>{{officePhone}}</a></li>
            <li><a href="tel:{{cellPhone}}">Call Cell<br/>{{cellPhone}}</a></li>
            <li><a href="sms:{{cellPhone}}">SMS<br/>{{cellPhone}}</a></li>
        </ul>
    </div>
</script>

Step 2: Create the EmployeeView class

  1. Create a file called EmployeeView.js in the js directory, and define an EmployeeView class implemented as follows:
    1
    2
    3
    4
    var EmployeeView = function() {
      
      
    }
  2. Add the template as a static member of EmployeeView.
    1
    2
    3
    4
    5
    6
    var EmployeeView = function() {
      
      
    }
      
    EmployeeView.template = Handlebars.compile($("#employee-tpl").html());
  3. Define an initialize() function inside the HomeView class. Define a div wrapper for the view. The div wrapper is used to attach the view related events. Invoke the initialize() function inside the HomeView constructor function.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var EmployeeView = function(employee) {
      
        this.initialize = function() {
            this.el = $('<div/>');
        };
      
        this.initialize();
      
     }
      
    EmployeeView.template = Handlebars.compile($("#employee-tpl").html());
  4. Define a render() function implemented as follows:
    1
    2
    3
    4
    this.render = function() {
        this.el.html(EmployeeView.template(employee));
        return this;
    };
  5. In index.html, add a script tag to include EmployeeView.js (just before the script tag for main.js):
    1
    <script src="js/EmployeeView.js"></script>

Step 3: Implement View Routing

  1. In the app’s initialize() function, define a regular expression that matches employee details urls.
    1
    this.detailsURL = /^#employees\/(\d{1,})/;
  2. In the app’s registerEvents() function, add an event listener to listen to URL hash tag changes:
    1
    $(window).on('hashchange', $.proxy(this.route, this));
  3. In the app object, define a route() function to route requests to the appropriate view:
    • If there is no hash tag in the URL: display the HomeView
    • If there is a has tag matching the pattern for an employee details URL: display an EmployeeView for the specified employee.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    route: function() {
        var hash = window.location.hash;
        if (!hash) {
            $('body').html(new HomeView(this.store).render().el);
            return;
        }
        var match = hash.match(app.detailsURL);
        if (match) {
            this.store.findById(Number(match[1]), function(employee) {
                $('body').html(new EmployeeView(employee).render().el);
            });
        }
    }
  4. Modify the initialize() function to call the route() function:
    1
    2
    3
    4
    5
    6
    7
    8
    initialize: function() {
        var self = this;
        this.detailsURL = /^#employees\/(\d{1,})/;
        this.registerEvents();
        this.store = new MemoryStore(function() {
            self.route();
        });
    }
  5. Test the application.

Part 10: Using the Location API


In this section, we add the ability to tag an employee with his/her location information. In this sample application, we display the raw information (longitude/latitude) in the employee view. In a real-life application, we would typically save the location in the database as part of the employee information and show it on a map.

The code below works when running the application as a PhoneGap app on your device. It should also work in Chrome on the desktop when the page is served with the http:// protocol, and in Firefox, regardless of the protocol (http:// or file://).
  1. In index.html, add the following list item to the employee-tpl template:
    1
    <li><a href="#" class="add-location-btn">Add Location</a></li>
  2. In the initialize() function of EmployeeView, register an event listener for the click event of the Add Location list item:
    1
    this.el.on('click', '.add-location-btn', this.addLocation);
  3. In EmployeeView, define the addLocation event handler as follows:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    this.addLocation = function(event) {
        event.preventDefault();
        console.log('addLocation');
        navigator.geolocation.getCurrentPosition(
            function(position) {
                $('.location', this.el).html(position.coords.latitude + ',' + position.coords.longitude);
            },
            function() {
                alert('Error getting location');
            });
        return false;
    };
  4. Test the Application

Part 11: Using the Contacts API


In this section, we use the PhoneGap Contacts API to provide the user with the ability to add an employee to the device’s contact list.

The code below only works when running the application on your device as a PhoneGap app. In other words, you can’t test it in a browser on the desktop.
  1. In index.html, add the following list item to the employee template:
    1
    <li><a href="#" class="add-contact-btn">Add to Contacts</a></li>
  2. In the initialize() function of EmployeeView, register an event listener for the click event of the Add to Contacts list item:
    1
    this.el.on('click', '.add-contact-btn', this.addToContacts);
  3. In EmployeeView, define the addToContacts event handler as follows:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    this.addToContacts = function(event) {
        event.preventDefault();
        console.log('addToContacts');
        if (!navigator.contacts) {
            app.showAlert("Contacts API not supported", "Error");
            return;
        }
        var contact = navigator.contacts.create();
        contact.name = {givenName: employee.firstName, familyName: employee.lastName};
        var phoneNumbers = [];
        phoneNumbers[0] = new ContactField('work', employee.officePhone, false);
        phoneNumbers[1] = new ContactField('mobile', employee.cellPhone, true); // preferred number
        contact.phoneNumbers = phoneNumbers;
        contact.save();
        return false;
    };
  4. Test the Application

Part 12: Using the Camera API


In this section, we use the PhoneGap Camera API to provide the user with the ability to take a picture of an employee, and use that picture as the employee’s picture in the application. We do not persist that picture in this sample application.

The code below only works when running the application on your device as a PhoneGap app. In other words, you can’t test it in a browser on the desktop.
  1. In index.html, add the following list item to the employee template:
    1
    <li><a href="#" class="change-pic-btn">Change Picture</a></li>
  2. In the initialize() function of EmployeeView, register an event listener for the click event of the Change Picture list item:
    1
    this.el.on('click', '.change-pic-btn', this.changePicture);
  3. In EmployeeView, define the changePicture event handler as follows:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    this.changePicture = function(event) {
        event.preventDefault();
        if (!navigator.camera) {
            app.showAlert("Camera API not supported", "Error");
            return;
        }
        var options =   {   quality: 50,
                            destinationType: Camera.DestinationType.DATA_URL,
                            sourceType: 1,      // 0:Photo Library, 1=Camera, 2=Saved Photo Album
                            encodingType: 0     // 0=JPG 1=PNG
                        };
      
        navigator.camera.getPicture(
            function(imageData) {
                $('.employee-image', this.el).attr('src', "data:image/jpeg;base64," + imageData);
            },
            function() {
                app.showAlert('Error taking picture', 'Error');
            },
            options);
      
        return false;
    };
  4. Test the Application

Part 13: Sliding Pages with CSS Transitions


  1. Add the following classes to styles.css:
    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
    .page {
        position: absolute;
        width: 100%;
        height: 100%;
        -webkit-transform:translate3d(0,0,0);
    }
      
    .stage-center {
        top: 0;
        left: 0;
    }
      
    .stage-left {
        left: -100%;
    }
      
    .stage-right {
        left: 100%;
    }
      
    .transition {
        -moz-transition-duration: .375s;
        -webkit-transition-duration: .375s;
        -o-transition-duration: .375s;
    }
  2. Inside the app object, define a slidePage() function implemented as follows:
    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
    slidePage: function(page) {
      
        var currentPageDest,
            self = this;
      
        // If there is no current page (app just started) -> No transition: Position new page in the view port
        if (!this.currentPage) {
            $(page.el).attr('class', 'page stage-center');
            $('body').append(page.el);
            this.currentPage = page;
            return;
        }
      
        // Cleaning up: remove old pages that were moved out of the viewport
        $('.stage-right, .stage-left').not('.homePage').remove();
      
        if (page === app.homePage) {
            // Always apply a Back transition (slide from left) when we go back to the search page
            $(page.el).attr('class', 'page stage-left');
            currentPageDest = "stage-right";
        } else {
            // Forward transition (slide from right)
            $(page.el).attr('class', 'page stage-right');
            currentPageDest = "stage-left";
        }
      
        $('body').append(page.el);
      
        // Wait until the new page has been added to the DOM...
        setTimeout(function() {
            // Slide out the current page: If new page slides from the right -> slide current page to the left, and vice versa
            $(self.currentPage.el).attr('class', 'page transition ' + currentPageDest);
            // Slide in the new page
            $(page.el).attr('class', 'page stage-center transition');
            self.currentPage = page;
        });
      
    },
  3. Modify the route() function as follows:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    route: function() {
        var self = this;
        var hash = window.location.hash;
        if (!hash) {
            if (this.homePage) {
                this.slidePage(this.homePage);
            } else {
                this.homePage = new HomeView(this.store).render();
                this.slidePage(this.homePage);
            }
            return;
        }
        var match = hash.match(this.detailsURL);
        if (match) {
            this.store.findById(Number(match[1]), function(employee) {
                self.slidePage(new EmployeeView(employee).render());
            });
        }
    },

 CREDIT FOR THIS ARTICLE GOES TO: Christophe Coenraets

 

Using PhoneGap for Hybrid App Development

Most businesses today want mobile apps for iOS and Android. They don’t care too much about the other popular mobile platforms because these two giants let them reach nine out of ten users.

However, when you are building an enterprise mobile app for a company that has implemented BYOD and needs to support BlackBerry and Windows mobile devices too, you are forced to develop four separate apps. Or, when an app achieves universal popularity, most app owners want to make sure that they dominate the same category on all mobile platforms.

Having flirted with website and web app development before hitching my cart to the mobile app development bandwagon, I felt that I should give a shot to cross-platform mobile development. When I started out, my web development skills were a little rusty while I was pretty good at iOS app development and average at Android app development. I chose PhoneGap because it supports a large number of development platforms: iOS, Android, BlackBerry, Windows, Symbian, and even Tizen.

Another reason for choosing PhoneGap was that it is a native WebView component with HTML5-CSS3 application and it has a structured API that uses JavaScript to access native functionalities of mobile devices. This means that an app you build on PhoneGap can access native functions from the devices as well as the mobile operating system. Theoretically, you can build high-performance apps on PhoneGap and make them work on several mobile platforms.

Beginning PhoneGap Development 

As with most other cross-platform mobile development apps, PhoneGap apps use HTML5 and CSS3 for rendering, while JavaScript is used for logic. This means that I had to wake up the dormant web developer within me.

Once I was up to speed on HTML5, JS and CSS3, I had to learn how PhoneGap worked. I spent a lot of time reading and skimming through the documentation, app building and GitHub pages for PhoneGap.

Most web developers don’t realize that you need to put in a lot of effort to understand how PhoneGap works. But you won’t lack for resources and sound advice from the community while you’re at it. While developing my first app (for iOS, Android and Windows), I ran into many problems. Some of them arose from my rusty skills, but I felt few had a lot to do with the nature of cross-platform development.

These are the most common problems that an app built on PhoneGap can run into:

  1. Mobile apps with numerous graphic elements or animations may slow things down on some mobile devices and make the app browsing experience a little choppy. Even with general apps there is a noticeable lag as most mobile phones are not fast enough to run hybrid apps. Android, especially, with its numerous versions of OS and devices, is a bigger nightmare than usual.
  2. The app cannot take the benefit of ALL the features of a phone. And trying to use device features requires a lot of hard work. Also, if you want to build an app for the latest version of any operating system, you need to wait for the PhoneGap update. It is bound to stay one step behind native platforms.
  3. The code you write runs everywhere – but you also need to do some coding and tweaking specific to different mobile platforms. This is pretty time consuming. Also, for newbies, fixing (and even identifying) errors can be a huge headache.
  4. I did not enjoy building and deploying on PhoneGap as I have to wait for PhoneGap to finish building. It can take from 2 to 20 minutes – if you’re impatient, this is a problem. Otherwise, it is not much of an issue.

While these are pretty common problems, there are solutions to most of them. And if you become an expert at PhoneGap development, there are many obvious advantages:

  1. You write one code, tweak it a little for all operating systems, and you have apps for 2-6 mobile platforms.
  2. If you have a background in web development and are good with JavaScript, PhoneGap’s learning curve is not too steep.
  3. PhoneGap is better than most other platforms that offer multi-platform development capability as it enables expert developers to support native features and functionality in the app.
  4. There is no dearth of tools – there are several places where you can find quick solutions to your problems and there are several JavaScript libraries that will make your work easier.

Should a native app developer try hybrid app development with PhoneGap?

I, personally, did not have a very good experience with PhoneGap (although I have an app with PhoneGap that works okay on three mobile platforms) as my web development skills needed some work. So, it took too much time to develop, debug, submit and re-submit the app for approval. But as the demand for apps that run across mobile platforms increases, it is important to build expertise in development with a multi-platform app development technology.

Do you know your way around HTML5, JavaScript and CSS3? If yes, PhoneGap presents a great opportunity for using those skills to create mobile apps.

If you are already into native app development, you know Java or Objective-C; those skills will also be needed.

You first foray in PhoneGap app development is bound to be a little deflating (as it is difficult to get good results without delving deep in the technology), but it can help you cut down the time and effort for development once you get better at it.

However, if you are not that much into HTML5 and JavaScript, there is no point in trying your hands at hybrid app development – native app development is going to be around for a long while yet.