Как стать автором
Обновить

PhoneGap — решение проблем в первом приложении

Время на прочтение4 мин
Количество просмотров16K
PhoneGap — HTML5 платформа для разработки приложений под 7 существующих мобильных платформ. На днях они обновились до версии 1.2.0 и переехали под крыло Апачи. Адрес репозитория также обновился. На сайте в документации замечательная пошаговая инструкция для создания первого приложения, так что на вводной части больше не будем останавливаться, об этом уже писали. Мелкие проблемы начинаются, когда немножко выходишь за рамки стандартных возможностей платформы, но все решаемо.

Постановка задачи


Захотел я сделать нидерландско-русский словарь под Андроид за неимением приличного на рынке. Мне попался словарь отсканированный с хорошего бумажного. Процесс извлечения информации с картинок заслуживает отдельной статьи. Поэтому пропустим эту часть. В качестве первого этапа сделал словарь в виде html странички. По инструкции по созданию «hello world» сделал приложение и оно успешно запустилось. Дальше надо было обработать напильником и довести до ума детали.

Настройки

Для хранения настроек воспользовался window.localStorage. Сделал на основной же html страничке диалог с нужными полями ввода и повесил обработчик на события 'menubutton', 'backbutton', чтобы его показывать/прятать/сохранять. Все работает как надо. Позже добавил туда же хранение истории запросов.

Надпись на дефолтовой кнопке

При открывании софтверной клавиатуры дефолтовая кнопка имеет надпись 'GO'. Что не сильно соответствует работе со словарем. Документация фреймворка такую ситуацию никак не освещает. Документация в SDK говорит про установку атрибута android:imeOptions поля ввода. Но конечно внутри браузера это не работает. Несколько раз перерыл инет в поисках решения. Наконец наткнулся на рабочий вариант под iPhone — вместо <input type="text" /> надо использовать <form><input type="search" /></form> Причем элемент формы обязателен. Под Андроид работает и без формы, а форма даже вредна, так как происходит ее отправка и надо это дело предотвращать. Итак используем <input type="search" /> и дефолтовая кнопка волшебных образом превращается в 'Search'.

Выход из приложения

Во фреймворке есть API для этого — navigator.app.exitApp(). Как оказалось, просто из коробки это не работает. Чтобы заставить это работать в AndroidManifest.xml надо прописать <uses-sdk android:minSdkVersion="2" />. В новой версии 1.2.0 проблему уже исправили, так что это еще один повод обновиться.

Перевод из буфера обмена

В читалке(CoolReader) есть копирование слова в буфер. Поэтому, чтобы не делать лишних телодвижений при вызове словаря, а получать сразу перевод, хотелось получить доступ к буферу обмена. По умолчанию такой возможности нет, но платформа легко расширяется плагинами. Нашел плагин, который дает API для работы с буфером. В комплекте оказалась еще куча других (27 штук) — phonegap-plugins. Загляните, не пожалеете.
Теперь процесс выглядел так — увидел незнакомое слово, два раза тапнул( слово в буфере), вызвал менеджер задач( длинный тап), выбрал словарь(еще один тап) и опа — перевод уже тут. Нажал отмену — и снова в читалке.

Автоматический вызов и перевод

Но нет предела совершенству. Хотелось еще меньше телодвижений. Читалка имеет интеграцию с 2мя словарями — Fora Dictionary и 2 способа вызова ColorDict. Скачал исходники читалки, благо они открыты, посмотрел как происходит вызов. К сожалению оба словаря зашиты, хотя и вызываются стандартным способом и могли бы конфигурироваться. Поэтому возникла мысль прикинутся, например, форой. Этой инструкции из документации SDK вполне достаточно, чтобы реализовать нужный поисковый интерфейс, получать переданную для поиска строку и передавать ее параметром в урле. Стандартная реализация onCreate стала выглядеть так:
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		Intent intent = getIntent();
		String url = "file:///android_asset/www/index.html";
		if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
			url += "?search=" + intent.getStringExtra(SearchManager.QUERY);
		}    	
		super.loadUrl(url);
	}

Но этот код передает строку поиска только при создании приложения. Чтобы получать строку поиска, когда приложение уже находится в фоне, понадобилось добавить еще один метод в стандартный ява-код:
	@Override
	protected void onResume() {
		super.onResume();
		Intent intent = getIntent();
		if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
			String sQuery = intent.getStringExtra(SearchManager.QUERY);
			this.appView.loadUrl(
				"javascript:try{PhoneGap.fireDocumentEvent('search', {detail: '" 
				+ sQuery + "'});}catch(e){};"
			);
		}    	
	}

Код генерит новое событие 'search' для яваскрипта и передает нужные данные. Как создавать свои события подсмотрел в исходных кодах PhoneGap.
Чтобы читалка думала, что вызывает фору, пришлось переименовать классы. Нужное имя подсмотрел в исходниках читалки. Это конечно не совсем правильно, но для частного употребления сгодится.
Теперь использование словаря стало идеальным — увидел незнакомое слово, два раза тапнул — словарь показал перевод, нажал отмену — снова в читалке.

Выпадение приложения при смене ориентации экрана

После добавления поискового интерфейса и переименования классов в новый проект приложение стало вываливаться при смене ориентации с ошибкой «couldn't save which view has focus because the focused view… has no id». Так как поиск показал, что это проблема случается, то упомяну как это порешалось. Что именно оказалось решающим я не стал разбираться. При создании нового проекта я пропустил в AndroidManifest.xml
— в корневом элементе manifest:
	<supports-screens
		android:largeScreens="true"
		android:normalScreens="true"
		android:smallScreens="true"
		android:resizeable="true"
		android:anyDensity="true"
	/>

— в application элементе не создал activity:
 			<activity 
				android:name="com.phonegap.DroidGap" 
				android:label="@string/app_name" 
				android:configChanges="orientation|keyboardHidden">
				<intent-filter></intent-filter>
			</activity>        

Во всех activity нужен атрибут android:configChanges="orientation|keyboardHidden". Конечно это я сам накосячил, т.к. в «hello world» все это есть. Просто будьте внимательны.

Приложение получилось очень скромных размеров — 186к (не считая словарных данных). Хотя первоначально была идея после PhoneGap сделать все по стандартному процессу, но т.к. результат устраивает на все 100%, то смысла в этом уже не вижу.

ЗЫ. спасибо Vadim Lopatin за Cool Reader с исходными текстами, спасибо создателям PhoneGap за доступную платформу с исходными текстами, спасибо создателями плагинов с сорцами, гитхабу за доступ к исходникам, и битбакет за хранение моих.
Теги:
Хабы:
Всего голосов 32: ↑29 и ↓3+26
Комментарии20

Публикации

Истории

Работа

Ближайшие события