Использование jQuery Mobile для создания нативного новостного приложения на Android: часть 3
() translation by (you can also view the original English article)
В 1 части этой серии уроков мы представили наше приложение, описали макет страницы и обсудили, как создавать страницы в приложении с помощью jQuery Mobile. Во 2 части мы завершили внедрение нашего веб-приложения. В этой заключительной части мы перенесем веб-приложение в нативное приложение для Android.
Перенос в нативное приложение для Android
Веб-приложение, завершенное во 2 части будет преобразовано в нативное приложение для Android. Обсуждение ниже относится к ОС Android версии 2.2 и 2.3.
Приложение Android будет использовать файл index.html
в качестве компонента пользовательского интерфейса. Мы создадим класс android.app.Activity
для определения точки интеграции между index.html
и приложением. Также мы создадим класс android.webkit.WebViewClient
, чтобы убедиться, что страница «Новость» отображается в исходном экземпляре android.webkit.WebView
, где запущено приложение «Новости».
Изменения в index.html
Обновим переменную NEWS_URI
следующим образом:
1 |
var NEWS_URI = 'https://rss.news.yahoo.com/rss/'; |
Нам не нужен файл bridge.php
для Android, чтобы перенаправлять AJAX-запросы на сервер Yahoo! News. Это связано с тем, что здесь не применяется ограничение на источник запроса. Когда он реализован как часть приложения, файл index.html
не загружается с веб-сервера. Таким образом, он может выполнять вызовы AJAX для удаленных URL-адресов.
Кроме того, мы добавляем следующую функцию:
1 |
var EMPTY = ''; |
2 |
...
|
3 |
function changeLocation(varURI){ |
4 |
showProgress(); |
5 |
$.get(EMPTY,function(data){ |
6 |
window.location = varURI; |
7 |
});
|
8 |
}
|
Функция changeLocation()
выполняется из файла android.webkit.WebViewClient
, который будет отображаться мгновенно. Цель этой функции - показать страницу прогресса во время перехода с страницы новостей на страницу новости.
- Первый шаг в
changeLocation()
- отображение страницы прогресса. - Помните, что функция jQuery
get()
является специальной функцией jQueryajax().
Мы вызываем функциюget()
, передавая ему пустой URL-адрес и обработчик обратного вызова, который устанавливает переменнуюwindow.location
как входящий аргумент. Аргумент ввода - это URL-адрес в атрибуте<a href='...'>
, заключенный в тегa
для новостного элемента, описаного в части 2 «Переход на страницу новости». Когда URL загружается, страница прогресса заменяется содержимым этого URL-адреса. - Как мы указывали ниже, функция
changeLocation()
не является важной частью переноса веб-приложения. Это необходимо только для отображения страницы прогресса при переходе со страницы новостей на страницу новости в приложении. - Страница перехода не требуется в веб-приложении при переходе со страницы списка новостей на страницу новости. Это связано с тем, что во время перехода сам веб-браузер отображает индикатор прогресса для пользователя. Например, в Android, как в нативном, так и в Dolphin-браузерах отображается вращающееся колесо и индикатор выполнения на панели навигации. В iOS браузер Safari отображает аналогичный индикатор прогресса.
Класс Activity
Начало нашего класса Activity
, названная NewsActivity
, показана ниже:
1 |
package com.news; |
2 |
|
3 |
import android.app.Activity; |
4 |
import android.webkit.WebView; |
5 |
import android.os.Bundle; |
6 |
...
|
7 |
public class NewsActivity extends Activity { |
8 |
WebView mWebView; |
9 |
|
10 |
public void onCreate(Bundle savedInstanceState) { |
11 |
super.onCreate(savedInstanceState); |
12 |
setContentView(R.layout.main); |
13 |
|
14 |
mWebView = (WebView) findViewById(R.id.webview); |
15 |
mWebView.setWebViewClient(new NewsClient()); |
16 |
mWebView.getSettings().setJavaScriptEnabled(true); |
17 |
mWebView.getSettings().setDomStorageEnabled(true); |
18 |
mWebView.loadUrl("android_asset/www/index.html"); |
19 |
}
|
20 |
...
|
21 |
}
|
- В методе
onCreate()
мы сначала вызываем реализацию по умолчанию из суперкласса, а затем вызываемsetContentView()
для загрузки файла макета для этого действия. Входящим аргументом дляsetContentView()
будетR.layout.main
, который ссылается на файлmain.xml
в папкеres/layout
. - Мы получаем обращение к
WebView
черезfindViewById(R.id.webview)
. Мы устанавливаем пользовательскийWebViewClient
вWebView
с именемNewsClient
(который будет рассмотрен в ближайшее время). Затем мы настраиваемWebView
, чтобы разрешить выполнение JavaScript и API хранилища DOM (последний необходим для использования HTML5localStorage
). - Наконец, мы просим
WebView
загрузить страницуindex.html
с кодом пользовательского интерфейса.
На странице новости нажатие кнопки Назад на устройстве вернет пользователя на страницу Категории. Чтобы убедиться в этом, нам сначала нужно обработать событие onKeyDown
в нашем NewsActivity
. Это действие показано ниже:
1 |
public class NewsActivity extends Activity { |
2 |
WebView mWebView; |
3 |
|
4 |
public void onCreate(Bundle savedInstanceState) { |
5 |
...
|
6 |
}
|
7 |
|
8 |
public boolean onKeyDown(int keyCode, KeyEvent event) { |
9 |
if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) { |
10 |
mWebView.goBack(); |
11 |
return true; |
12 |
}
|
13 |
return super.onKeyDown(keyCode, event); |
14 |
}
|
15 |
...
|
16 |
}
|
Если событие клавиши соответствует кнопке Назад на и WebView
содержит некоторую историю, чтобы вернуться к ней, мы попросим WebView
вернуться на один шаг в своей истории На странице Новости это будет соответствовать файлу index.html
. Когда история возвращается на один шаг назад, страница Категорий будет отображаться в соответствии с шагами, описанными в части 2 «Запуск приложения».
Наконец, давайте посмотрим на пользовательский WebViewClient
, который реализован как внутренний класс NewsActivity
.
1 |
public class NewsActivity extends Activity { |
2 |
WebView mWebView; |
3 |
|
4 |
public void onCreate(Bundle savedInstanceState) { |
5 |
...
|
6 |
mWebView.setWebViewClient(new NewsClient()); |
7 |
...
|
8 |
}
|
9 |
|
10 |
public boolean onKeyDown(int keyCode, KeyEvent event) { |
11 |
...
|
12 |
}
|
13 |
|
14 |
private class NewsClient extends WebViewClient { |
15 |
|
16 |
public boolean shouldOverrideUrlLoading(WebView view, String url) { |
17 |
view.loadUrl("javascript:changeLocation('" + url + "')"); |
18 |
return true; |
19 |
}
|
20 |
}
|
21 |
...
|
22 |
}
|
Единственной операцией, которую мы переопределяем из родительского класса, является shouldOverrideUrlLoading()
, где мы программируем WebView
на вызов функции JavaScript changeLocation()
в index.html
.
- Если мы не определим пользовательский
WebViewClient
, страница новостей будет отображаться в отдельном приложении браузера вне нашего приложения. Поэтому определениеWebViewClient
имеет важное значение для отображения страницы новости как части приложения (т.е. в том жеWebView
, на котором размещается файлindex.html
). - Мы можем написать функцию
shouldOverrideUrlLoading()
более простым способом:1
public boolean shouldOverrideUrlLoading(WebView view, String url)
2
{
3
view.loadUrl(url);
4
return true;
5
}
Этого было бы достаточно, чтобы отобразить страницу новостей в том же
WebView
, на котором размещаетсяindex.html
. Однако переход с страницы новостей на страницу Сведения о новостях не включает показ страницы прогресса
Изучив класс Activity
, рассмотрим другие компоненты нашего приложения.
AndroidManifest.xml
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" |
3 |
package="com.news" android:versionCode="1" android:versionName="1.0"> |
4 |
<application android:icon="@drawable/icon" android:label="@string/app_name"> |
5 |
<activity android:name=".NewsActivity" android:configChanges="orientation|keyboardHidden" |
6 |
android:label="@string/app_name"> |
7 |
<intent-filter>
|
8 |
<action android:name="android.intent.action.MAIN" /> |
9 |
<category android:name="android.intent.category.LAUNCHER" /> |
10 |
</intent-filter>
|
11 |
</activity>
|
12 |
</application>
|
13 |
<uses-permission android:name="android.permission.INTERNET" /> |
14 |
</manifest>
|
Чтобы понять как работает файл AndroidManifest.xml
обратитесь к официальной документации. В этом файле есть два отдельных объекта, достойных внимания.
- Как описано в документации
android.app.Activity
, по умолчанию изменение конфигурации, включая изменение ориентации устройства или доступность клавиатуры, приводит к закрытию текущей активности. Чтобы предотвратить поведение по умолчанию, мы настраиваем наше приложение, указывая изменения конфигурации, которые будут обрабатываться самим приложением. Это определяется в атрибутеconfigChanges
, гдеorientation
устройства соответствует её изменению, аkeyboardHidden
соответствует изменению статуса клавиатуры (например, пользователь открыл клавиатуру устройства). Мы настраиваем приложение таким образом, чтобы при возникновении любого из этих событий текущая активность не была закрыта. - Элемент
<uses-permission android:name="android.permission.INTERNET" />
позволяет приложению получать доступ к Интернету.
strings.xml
1 |
<?xml version="1.0" encoding="utf-8"?>
|
2 |
<resources>
|
3 |
<string name="app_name">News</string> |
4 |
</resources>
|
Этот файл определяет константу с именем app_name
, которая используется для идентификации приложения Новости. Значение этого атрибута отображается в разных местах нашего Android-устройства, как видно ниже. Слева направо: под значком запуска приложения, панель заголовка, «Настройки» - «Управление приложениями».



Рисунок 11. Как отображается имя приложения в Android.
Интеграция HTML-интерфейса с помощью android.app.Activity
Мы реализуем пользовательский интерфейс в нашем Android-приложении, используя файл index.html
и библиотеки JavaScript и css
. Точка интеграции между index.html
и пользовательским классом android.app.Activity
представляет собой следующую строку:
1 |
mWebView.loadUrl("android_asset/www/index.html"); |
Кроме того, обратите внимание на «Класс активности», в котором мы подключаем JavaScript и DOMStorage в объекте android.webkit.WebView
так как в index.html
необходимо запустить JavaScript и получить доступ к HTML5 localStorage
.
1 |
mWebView.getSettings().setJavaScriptEnabled(true); |
2 |
mWebView.getSettings().setDomStorageEnabled(true); |
Наконец, в файле AndroidManifest.xml
мы разрешаем подключение к Интернету из нашего приложения с помощью кода:
1 |
<uses-permission android:name="android.permission.INTERNET" /> |
Скриншоты приложения Android
на Рисунках 1 - 4 в первой части этой серии скриншоты приложения для Android.
Иконка приложения
Чтобы создать иконку для приложения Новости, мы следуем рекомендациям для дизайна приложений Android. В этом ресурсе доступны различные шаблоны в формате Adobe PSD. Мы загрузили icon_templates-v2.0.zip
и извлекли файл Launcher-icon-template.psd
. В этом файле мы выбрали два шаблона для создания иконки приложения:
Мы разместили эти шаблоны в двух отдельных слоях в Adobe Photoshop и добавили графический текст News
на дополнительный слой вверху, чтобы сделать иконку. В соответствии с руководством мы создали три версии иконки для экранов с низким, средним и высоким разрешением с размерами 36 x 36, 48 x 48 и 72 x 72 пикселей соответственно. Каждый из этих значков называется icon.png
, и они помещаются в папки проектов Android в соответствии со следующей таблицей:
Имя папки | Название файла | Размер в пикселях |
res\drawable-ldpi | icon.png | 36 x 36 |
res\drawable-mdpi | icon.png | 48 x 48 |
res\drawable-hdpi | icon.png | 72 x 72 |
В примере указана иконка размером 36 х 36:
Нативная среда разработки приложений для Android
В этом уроке мы подготовили необходимые файлы проекта для импорта приложения для Android-новостей в среду разработки Eclipse. Требованиями проекта являются:
- версия Android SDK 8.
- Eclipse IDE версии 3.5.
- Android Development Tools (ADT), который является плагином Eclipse версии 8.0.1.
Проект был успешно протестирован как для платформы Android 2.2 API 8 уровня так и для API 2.3 уровня 9.
Импорт проекта
Перед импортом проекта в среду Eclipse убедитесь, что плагин Eclipse ADT указывает на правильное расположение Android SDK в вашей локальной системе. Чтобы проверить это, в меню Eclipse перейдите в Окно -> Настройки -> Android
. Окно SDK Location
должно указывать на местоположение Android SDK. После правильной настройки вы должны увидеть что-то похожее на то что есть на изображении ниже:



Рисунок 12. Настройки Eclipse.
Файлы проекта располагаются в архиве с именем news.zip
. Чтобы импортировать проект в меню Eclipse, перейдите в меню File -> Import
, а затем в мастере импорта файлов выберите General -> Existing Projects into Workspace
(см. Ниже).



Рисунок 13. Импорт проекта.
На следующей странице мастера нажмите Select archive file
и найдите, где находится news.zip
в вашей файловой системе. Окно Projects
будет автоматически заполнено, если проект News
уже выбран. Как показано ниже. Нажмите кнопку Finish
, чтобы завершить импорт.



Рисунок 14. Выбор файла проекта.
Eclipse автоматически создаст приложение после импорта. Теперь вы должны увидеть проект Новости в проводнике проекта, как показано ниже:



Рисунок 15. Проводник проекта.
Для создания / отладки вашего проекта вы можете выбрать платформу Android OS 2.3 и 2.2 в качестве сборки. Для этого выберите проект News
в проводнике проекта и в контекстном меню выберите Properties
. В левой части списка свойств выберите Android
в качестве свойства. Доступные цели сборки отображаются справа, как показано ниже:



Рисунок 16. Сборка Android.
Список файлов
Список файлов в проекте приведен ниже.



Рисунок 17. Содержание проекта.
Мы уже обсуждали некоторые из этих файлов. Ниже приведен краткий обзор:
- Папка
src
содержит исходный код для классаNewsActivity
. - Папка
gen
содержит файлы, автоматически созданные Eclipse ADT. - В папке
assets\www
и ее подпапках содержатся все файлы, необходимые для UI, включаяindex.html
;assets\www\css-js
содержит файлыcss
и JavaScript, используемыеindex.html
. В частности:-
jquery-1.4.4.min.js, jquery.mobile-1.0a2.min.js, jquery.mobile-1.0a2.min.css
- это библиотеки фреймворка jQuery Mobile. -
jquery.ba-dotimeout.js
являются библиотеками jQuery-dotimeout-plugin. -
jquery.dst.js
является библиотекой плагина DST.js. -
assets\www\css-js\images\icons-18-white.png
является файлами изображения, на которые ссылается jQuery Mobile.
-
-
assets\www\img\wait.gif
- это иконка, используемая на странице прогресса. - Папки
res\drawable*
сохраняют иконки приложения, которые описаны в разделе «Иконка приложения» в этом руководстве. - Файл
res\layout\main.xml
является файлом макета Android XML. Поскольку пользовательский интерфейс в нашем приложении определен в файлеindex.html
с использованием фреймворка jQuery Mobile, этот файл понятен и не нуждается в дальнейших комментариях. - Мы уже рассмотрели папки
res\values\strings.xml
и файлAndroidManifest.xml
. - Файл
default.properties
определяет объект сборки и является частью архиваnews.zip
. Он будет перезаписан Eclipse ADT в зависимости от выбора объекта сборки.
Вывод
Помимо разработки кросс-платформенных мобильных веб-приложений, платформа jQuery Mobile может использоваться для реализации нативных приложений для Android. В этой серии уроков мы разработали веб-приложение используя jQuery Mobile, а затем перенесли его в нативное приложение Android с небольшими изменениями. Основная идея состоит в том, чтобы использовать объект android.webkit.WebView
в качестве контейнера для запуска html-файла веб-приложения и содержащегося в нем jQuery Mobile JavaScript-кода. Некоторые заключительные замечания приводятся ниже.
- При сборке нативного приложения для Android страница html, работающая в
android.webkit.WebView
, не подвергается ограничениям одного и того же источника запроса при выполнении AJAX. - Плагин jquery-dotimeout и плагин DST.js, хотя и первоначально разработанный для рамки jQuery, хорошо работает в jQuery Mobile. Существует огромное количество плагинов, написанных для jQuery, и, хотя необходимо рассматривать каждый случай отдельно, они могут быть легко доступны в jQuery Mobile. Это огромное преимущество для этого фреймворка!
- Мы протестировали веб-приложение на Android OS 2.2 и iPod Touch iOS 4.1 и 4.2. Нативное приложение для Android было протестировано с помощью эмуляторов Android OS 2.2 и 2.3 и телефона Android OS 2.2. Во всех случаях внешний вид и функциональные атрибуты очень похожи.
- На платформе Android существуют известные приёмы для создания вызовов JavaScript-to-Java и Java-to-JavaScript. Фактически, мы продемонстрировали, как вызвать функцию jQuery Mobile JavaScript из кода Java в нашем приложении. Можно было бы разработать плагины jQuery Mobile для доступа к собственным API-интерфейсам Android. Это говорит о возможностях платформы jQuery Mobile для разработки нативных приложений для Android.