- Every startup, every retail chain, every restaurant wanted a mobile app. The iPhone had been out five years. The App Store had 650,000 apps. Android had just passed iOS in global market share. Every client wanted to be in both stores.
The budget reality: native iOS development meant Objective-C, Xcode, Mac hardware, and a developer who knew Cocoa Touch. Native Android meant Java, Eclipse or Android Studio (barely released), and a different developer who knew the Android SDK. Two codebases, two teams, two submission processes, two maintenance tracks.
PhoneGap promised to solve this. Write once in HTML, CSS, and JavaScript. Deploy to both platforms. We were skeptical. We tried it anyway.
What PhoneGap Actually Was
PhoneGap (open-sourced to Apache in 2011, renamed Apache Cordova) wrapped a WebView - a native browser component - inside a native app shell. Your HTML/CSS/JavaScript ran inside that WebView. JavaScript bridges called native device APIs: camera, GPS, accelerometer, contacts, local storage.
// PhoneGap 1.x - accessing the camera
document.addEventListener('deviceready', function() {
// Device APIs are now available
navigator.camera.getPicture(
function(imageData) {
// imageData is base64 encoded JPEG
document.getElementById('preview').src = 'data:image/jpeg;base64,' + imageData;
},
function(error) {
alert('Camera error: ' + error);
},
{
quality: 50,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.CAMERA
}
);
}, false);
The deviceready event was critical. Native plugins weren't available until Cordova finished initializing. Every Cordova developer learned this the hard way by calling navigator.camera before deviceready and getting undefined.
The iOS Side: Objective-C in 2012
For comparison, the same camera call in Objective-C:
// AppDelegate.m - Objective-C 2012 style
#import <MobileCoreServices/MobileCoreServices.h>
- (void)openCamera {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
picker.mediaTypes = @[(NSString *)kUTTypeImage];
[self presentViewController:picker animated:YES completion:nil];
}
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *image = info[UIImagePickerControllerOriginalImage];
self.imageView.image = image;
[picker dismissViewControllerAnimated:YES completion:nil];
}
Verbose, bracket-heavy syntax. Memory management with alloc/release (ARC came in 2011 but wasn't universally adopted). But it was fast, native UI components, and full access to every iOS API.
Objective-C felt hostile to web developers. ARC or not, the mental model of retain counts leaked through. The syntax - [receiver message:argument] - was deeply foreign after years of C-style languages. Xcode crashes were frequent.
What Worked in Hybrid
For certain app categories, Cordova was genuinely good:
Content-heavy apps: News readers, catalogs, documentation apps. If the app was primarily text and images in a scrollable list, a WebView was hard to distinguish from native. We built a product catalog for a wholesale distributor in Cordova. It had 4,000 products, offline storage with SQLite, and a simple checkout form. The client never knew it wasn't native.
Form-heavy enterprise apps: Corporate time-sheet apps, inspection checklists, data entry tools. Users didn't care about animations. They cared about accuracy. HTML forms are excellent; native form equivalents in Objective-C were more work.
Rapid prototyping: A Cordova prototype in 2 weeks vs a native prototype in 6 weeks. For validating an idea, the hybrid path was a clear win.
What Failed in Hybrid
Scroll performance. The WebView in 2012 didn't use GPU-accelerated scrolling. Scrolling a list of 100 items in a Cordova app on an iPhone 4 felt sticky compared to a UITableView, which recycled cells and rendered with the native graphics layer. We spent days applying -webkit-overflow-scrolling: touch and CSS transforms to get GPU compositing, with mixed results.
Complex animations and transitions. Page transitions in PhoneGap looked wrong. The 60fps swipe-to-go-back gesture on iOS was impossible to replicate precisely in a WebView. Users felt it immediately, even if they couldn't articulate why.
/* The 2012 "make it feel native" CSS hack */
* {
-webkit-tap-highlight-color: transparent; /* Remove blue flash on tap */
-webkit-user-select: none; /* Prevent text selection on tap */
-webkit-touch-callout: none; /* Prevent callout on long-press */
}
.page-transition {
-webkit-transform: translateZ(0); /* Force GPU compositing */
-webkit-backface-visibility: hidden;
}
These hacks helped. They didn't fix the underlying problem.
App Store rejection. Apple's App Store Review Guidelines became increasingly hostile to WebView-wrapper apps between 2012-2014. Guideline 2.1: "Apps that are not very useful, unique, are simply web sites bundled as apps." We had two apps rejected. One was eventually approved after adding significant native features. The other became a mobile website instead.
The jQuery Mobile Layer
Most Cordova apps used jQuery Mobile or Sencha Touch for the UI components. jQuery Mobile gave you styled buttons, list views, and page transitions:
<!-- jQuery Mobile page structure -->
<div data-role="page" id="home">
<div data-role="header">
<h1>Catalog</h1>
</div>
<div data-role="content">
<ul data-role="listview" data-inset="true">
<li><a href="#product-1">Product One</a></li>
<li><a href="#product-2">Product Two</a></li>
</ul>
</div>
<div data-role="footer">
<h4>Aunimeda</h4>
</div>
</div>
jQuery Mobile's theming and touch event handling were genuinely useful. But it was heavyweight - loading jQuery + jQuery Mobile was adding 200KB+ to an app before writing a single line of your own code. On a phone with 256MB RAM running iOS 5, this mattered.
The Verdict We Reached in 2012
We settled on a rule: use Cordova for the data layer, native for the UI layer.
For apps that needed a genuine native feel, we built native UI in Objective-C or Java, but called our backend APIs for data. For apps where performance expectations were lower and content was the product, we went full Cordova.
The "one codebase" promise of hybrid was never fully true. You still maintained platform-specific plugins, dealt with iOS/Android behavioral differences, and submitted to two stores. But the ratio changed: 70% shared code, 30% platform-specific, versus 100% duplicated in two languages.
What Came Next
React Native (2015) and Flutter (2017) solved most of the problems we were fighting. Instead of running your app inside a WebView, they compiled to native components or used their own rendering engine. 60fps animations. Native UI primitives. One codebase that actually looked native on both platforms.
Looking back, Cordova's contribution wasn't the final product - most Cordova apps have been replaced or rewritten. Its contribution was proving the market: millions of developers who knew HTML and JavaScript could build mobile apps. That market demand drove Facebook to build React Native, drove Google to build Flutter.
The hybrid debate of 2012 seeded the cross-platform future that arrived in 2017.
Aunimeda develops mobile applications for iOS and Android - from MVP to production-ready apps with full backend integration.
Contact us to discuss your mobile project. See also: Mobile App Development, Mobile Game Development