2012 год. Каждый стартап, каждая торговая сеть, каждый ресторан хотел мобильное приложение. iPhone существовал пять лет. В App Store было 650 000 приложений. Android только что обогнал iOS по мировой доле рынка. Каждый клиент хотел присутствовать в обоих магазинах.
Бюджетная реальность: нативная разработка под iOS означала Objective-C, Xcode, Mac-оборудование и разработчика, знающего Cocoa Touch. Нативный Android требовал Java, Eclipse (или едва вышедшую Android Studio) и другого разработчика, знающего Android SDK. Два кодовых репозитория, две команды, два процесса публикации, две линии поддержки.
PhoneGap обещал решить это. Пишешь один раз на HTML, CSS и JavaScript. Деплоишь на обе платформы. Мы были скептиками. Попробовали всё равно.
Что такое PhoneGap на самом деле
PhoneGap (переданный в Apache в 2011 году, переименованный в Apache Cordova) оборачивал WebView - нативный браузерный компонент - в оболочку нативного приложения. Ваш HTML/CSS/JavaScript работал внутри этого WebView. JavaScript-мосты вызывали нативные API устройства: камера, GPS, акселерометр, контакты.
// PhoneGap 1.x - доступ к камере
document.addEventListener('deviceready', function() {
navigator.camera.getPicture(
function(imageData) {
document.getElementById('preview').src = 'data:image/jpeg;base64,' + imageData;
},
function(error) {
alert('Ошибка камеры: ' + error);
},
{
quality: 50,
destinationType: Camera.DestinationType.DATA_URL,
sourceType: Camera.PictureSourceType.CAMERA
}
);
}, false);
Событие deviceready было критически важным. Нативные плагины не были доступны, пока Cordova не заканчивала инициализацию. Каждый Cordova-разработчик учился этому на ошибке - вызвав navigator.camera до deviceready и получив undefined.
Что работало в гибридном подходе
Контентно-насыщенные приложения: читалки новостей, каталоги, приложения-документации. Если приложение состояло в основном из текста и изображений в прокручиваемом списке, WebView было трудно отличить от нативного. Мы сделали каталог товаров для оптового дистрибьютора на Cordova: 4000 позиций, офлайн-хранилище на SQLite, простая форма оформления заказа. Клиент никогда не знал, что приложение не было нативным.
Корпоративные формы: табели рабочего времени, чеклисты проверок, формы ввода данных. Пользователям была важна точность, а не анимации. HTML-формы отличные; нативные аналоги в Objective-C требовали больше работы.
Что провалилось в гибридном подходе
Производительность скролла. WebView в 2012 году не использовал GPU-ускоренный скролл. Прокрутка списка из 100 элементов в Cordova-приложении на iPhone 4 ощущалась рывками по сравнению с UITableView, который использовал нативный графический слой.
/* 2012 - CSS-хак «сделать похожим на нативное» */
* {
-webkit-tap-highlight-color: transparent;
-webkit-user-select: none;
-webkit-touch-callout: none;
}
.page-transition {
-webkit-transform: translateZ(0); /* Принудительная GPU-компоновка */
-webkit-backface-visibility: hidden;
}
Хаки помогали. Они не решали основную проблему.
Отклонение App Store. Apple становилась всё более враждебной к WebView-приложениям в 2012-2014 годах. Правило 2.1: «Приложения, которые не несут ценности, являются уникальными или представляют собой просто сайты, обёрнутые в приложения». У нас отклонили два приложения. Одно в итоге приняли после добавления значительных нативных функций. Второе превратилось в мобильный сайт.
Verdict, к которому мы пришли в 2012
Мы выработали правило: используй Cordova для слоя данных, нативный код - для слоя UI.
Для приложений с настоящим нативным ощущением мы строили нативный UI на Objective-C или Java, но запрашивали данные из наших бэкенд API. Для приложений с низкими ожиданиями по производительности и где контент - главное - использовали чистый Cordova.
Обещание «один кодовый репозиторий» никогда не выполнялось полностью. Приходилось поддерживать платформо-специфичные плагины, разбираться с различиями поведения iOS/Android, публиковаться в двух магазинах. Но соотношение изменилось: 70% общего кода, 30% платформо-специфичного вместо 100% дублированного на двух языках.
Что пришло после
React Native (2015) и Flutter (2017) решили большинство проблем, с которыми мы боролись. Вместо WebView они компилировались в нативные компоненты или использовали собственный движок рендеринга. Анимации на 60fps. Нативные UI-примитивы. Один кодовый репозиторий, который действительно выглядел нативно на обеих платформах.
Вклад Cordova - не конечный продукт, а доказательство рынка: миллионы разработчиков, знающих HTML и JavaScript, могут делать мобильные приложения. Этот рыночный спрос заставил Facebook создать React Native, а Google - Flutter. Гибридный спор 2012 года посеял кросс-платформенное будущее, которое наступило в 2017.