Пишем клиент для любимого сайта на phoneGap

в 22:28, , рубрики: android development, javascript, phonegap, Разработка под android, Смартфоны и коммуникаторы, метки: , ,

Пишем клиент для любимого сайта на phoneGapБывает что есть сайт, но пользоваться им с мобильного телефона не очень удобно и было бы замечательно иметь отдельное приложение для него. Любители веб разработки легко смогут это сделать использую phoneGap. Под катом речь пойдет про сервис отслеживания почтовых отправлений, которым я часто пользуюсь и написанный для него демонстрационный клиент с базовым функционалом: авторизация, получение списка треков и описания к ним и возможность добавить новый трек. Я не связывался с разработчиком по этому поводу и очень надеюсь что он на меня не обидится за наглость, за копание в JavaScript коде и за то что в приложении не будет показана реклама. Так же прошу простить за костыльность и велосипедность кода, воспринимайте его как пример.

Статья подразумевает, что вы сами сможете разобраться как работает сайт, информация с которого будет отображаться в приложении.
Те кто читали прошлую статью об авторизации через некоторые сайты уже знаю что в phoneGap есть замечательная штука inAppBrowser, которая не только открывает сайт внутри приложения, но и позволяет внедрить в него свой JavaScript код и поменять стили, что пригодится для форм авторизации.
На её основе, по образу и подобию авторизации на хабре был написан вот такой код:

var plugin_www_post_tracker_ru = {
		wwwref: false,
		authOk: false,

		auth: function (force) {
			if (!window.localStorage.getItem("plugin_www_post_tracker_ru_PHPSESSID") || force) { //если нет данных об авторизации или принудительная авторизация
				var authURL="http://post-tracker.ru/login.php";
				this.wwwref = window.open(encodeURI(authURL), '_blank', 'location=no'); // открываем сайт внутри приложения
				this.wwwref.addEventListener('loadstop', this.auth_jsinjection); // по завершении загрузки делаем инъекцию в код
			} else {
				plugin_www_post_tracker_ru.authOk=true;
			}
		},
		
		auth_event_url: function (url) {
			var tmp=url_parser.get_args_cookie(url); // парсин ответов с куками
			if (tmp['PHPSESSID'] && tmp['userid'] && tmp['securehash']) { // если все нужные куки есть, то видимо авторизировалис
				plugin_www_post_tracker_ru.wwwref.close(); // закроем браузер и сохраним полученные параметры
				window.localStorage.setItem("plugin_www_post_tracker_ru_PHPSESSID", tmp['PHPSESSID']);
				window.localStorage.setItem("plugin_www_post_tracker_ru_userid", tmp['userid']);
				window.localStorage.setItem("plugin_www_post_tracker_ru_securehash", tmp['securehash']);
				plugin_www_post_tracker_ru.authOk=true;
				перейдем тут на получение контента
			}
		},
		
		auth_cssinjection: function(){
			plugin_www_post_tracker_ru.wwwref.insertCSS({code:".topline {display:none} .top {display:none} .logo {display:none} .menu {display:none} .counters {display:none} .bottom {display:none} .links {display:none} @-viewport {width: device-width; zoom: 1;"},function(){});
		},
		
		auth_jsinjection: function () {
			plugin_www_post_tracker_ru.auth_cssinjection(); // вставляем CSS код в форму авторизации, для скрытия лишних блоков
			plugin_www_post_tracker_ru.wwwref.executeScript({ // JS код для получения куков
	            code: "document.cookie;"
	        }, function(arg) {
	        	plugin_www_post_tracker_ru.auth_event_url(arg);
	        });
		}
}

Для получения контента будем использовать небольшую AJAX библиотеку, способную делать POST и GET запросы, которая умеет вставлять cookie и отдающая полученный результат в callback функцию (основа взята из miniajax):

AJAX
var ajax = {
	init: function(){
		return new XMLHttpRequest();
		},
	send: function(url,method,args,cookies,async,_callback){
		var q=ajax.init();
		q.open(method,url,async);
		q.onreadystatechange=function(){
				if(this.readyState==4 && this.status==200) {
					_callback(this.responseText);
				}
			};
		if (cookies) {
			q.setRequestHeader('Cookie',cookies);
		}
		if(method=='POST') {
			q.setRequestHeader('Content-type','application/x-www-form-urlencoded');
			q.send(args);
		} else {
			q.send(null);
		}
	}
}

Для получения контента делаем GET запрос на страничку post-tracker.ru/my/ при этом, если в ответе в одном из блоков мы встретим строку <a href="/login.php">Войдите</a> или <a href="/register.php">Зарегистрируйтесь</a>, то нас явно разлогинили и придется пройти процедуру еще раз:

		get_content: function (async) { // делам запрос на страницу с трек кодами
			var cookies="PHPSESSID="+window.localStorage.getItem("plugin_www_post_tracker_ru_PHPSESSID")+"; userid="+window.localStorage.getItem("plugin_www_post_tracker_ru_userid")+"; securehash="+window.localStorage.getItem("plugin_www_post_tracker_ru_securehash"); // формируем cookie
			plugin_www_post_tracker_ru.dataReady=false;
			ajax.send("http://post-tracker.ru/my/",'GET',null,cookies,async,this._parse_content); // делаем ajax запрос и посылаем его содержимое для распарсивания
		},
		
		_parse_content: function (data) {
			var wrapper=document.createElement('div'); // заворачиваем html код внутрь объекта, чтобы удобнее с ним работать
				wrapper.innerHTML=data;
			plugin_www_post_tracker_ru._get_inside_data(wrapper,'trackcode,date,status,comment'); // и отправляем его на получение данных о треккоде, даты последнего изменения, статусе и описании посылки
		},
		
		_get_inside_data: function (wrapper,types) {
			var tmp=wrapper.getElementsByClassName('login')[0].innerHTML; // на всякий случай получаем содежимое div блока login
			if (tmp=='<a href="/login.php">Войдите</a> или <a href="/register.php">Зарегистрируйтесь</a>') { // если там такое, то придется авторизироватья
				plugin_www_post_tracker_ru.auth(true);
			} else { // а иначе продолжаем
				plugin_www_post_tracker_ru.default_folder=wrapper.getElementsByTagName('input')[0].value; // получи ID стандартной папки с кодами, чтобы в дальнейшем можно было добавлять туда новые коды отправлений
				var types=types.split(",");
				for (var typeid in types) { // разбираем html-ку по блокам с заданными типами
					var tmp=wrapper.getElementsByClassName(types[typeid]);
					var id=0;
					for (var i in tmp) {
						if (tmp[i].innerHTML) {
							if (!plugin_www_post_tracker_ru.postdata[id]) plugin_www_post_tracker_ru.postdata[id]=new Array();
							plugin_www_post_tracker_ru.postdata[id][(types[typeid])]=tmp[i].innerHTML.replace(/(rn|n|r)/gm,"").replace(/</?[^>]+>/gmi,"").replace(/^s+|s+$/gm,""); // убираем все ненужности в виде переносов строки, html кода для оформления и лишние пробелы
							id++;
						}
					}
				}
				plugin_www_post_tracker_ru.dataReady=true;
				show_list(); // даем команду на отображение полученных данных
			}
		},
		
		get_list: function () { // это будет запрошено функцией show_list() для "красоты" оформления
			var tmp=new Array();
			for (var i in plugin_www_post_tracker_ru.postdata) {
				tmp[i]="<b>"+plugin_www_post_tracker_ru.postdata[i]['trackcode']+"</b> "+plugin_www_post_tracker_ru.postdata[i]['comment']+"<br/>"+plugin_www_post_tracker_ru.postdata[i]['date']+" "+plugin_www_post_tracker_ru.postdata[i]['status'];
			}
			return tmp;
		}

show_list() в данном коде добавит блоки с подготовленной html-кой внутри div-а со скроллером (кстати рекомендую Overthrow и крайне не рекомендую iscroll-4 по причине ужасной скорости работы).

Настала пора добавить возможность отправки новых кодов для отслеживания, но сперва добавим действие на кнопку MENU вашего Android смартфона. Делается это с помощью события menubutton. К которому мы привяжем появления блока с кнопкой «Добавить трек код», которая, при нажатии, начнет процесс.

		put_trackCode: function(){ // то что будет выполнятя после нажатия на кнопку "Добавить трек код"
			var trackCode = prompt("Введите трек код"); // запросим у пользователя сам треккод
			if (trackCode) {
				this._put_trackCode_getPath(trackCode); // запросим у сайта направление для этого кода (например из Китая в Россию), внимание тут снова не используем асинхронный запрос
				if (plugin_www_post_tracker_ru.default_path) { // если получили направление, добавим описание
					var comment = prompt("комментарий");
					if (comment) {
						this._put_trackCode(trackCode,comment); // и отправим эти данные на сайт
					}
				} else {
					alert("Не правильный трек код");
				}
			} else {
				menuButtonHide(); // если пользователь не захотел вводить, то не забудем скрыть блок с менюшкой
			}
		},
		_put_trackCode_getPath: function (trackCode) { // запрашиваем направление
			var cookies="PHPSESSID="+window.localStorage.getItem("plugin_www_post_tracker_ru_PHPSESSID")+"; userid="+window.localStorage.getItem("plugin_www_post_tracker_ru_userid")+"; securehash="+window.localStorage.getItem("plugin_www_post_tracker_ru_securehash");
			var data="act=getPathForm&trackcode="+encodeURIComponent(trackCode);
			ajax.send("http://post-tracker.ru/ajax/userTrackcodes.php",'POST',data,cookies,false,this._put_trackCode_getPath_result);			
		},
		_put_trackCode_getPath_result: function (data){
			var wrapper=document.createElement('div'); // заворачиваем ответ, представляющий собой html
			wrapper.innerHTML=data;
			var tmp=wrapper.getElementsByTagName('input'); // смотрим есть ли в ответе input
			if (tmp.length>0) {
				plugin_www_post_tracker_ru.default_path=tmp[0].value; // если есть, то значение в нем нам очень пригодится
			}else{
				plugin_www_post_tracker_ru.default_path=false;
			}
		},
		_put_trackCode: function (trackCode,comment){ // отправляем треко код и комментарий к нему, снова не асинхронно
			var cookies="PHPSESSID="+window.localStorage.getItem("plugin_www_post_tracker_ru_PHPSESSID")+"; userid="+window.localStorage.getItem("plugin_www_post_tracker_ru_userid")+"; securehash="+window.localStorage.getItem("plugin_www_post_tracker_ru_securehash");
			var data="act=addTrackcodeAction&folderid="+plugin_www_post_tracker_ru.default_folder+"&trackcode="+encodeURIComponent(trackCode)+"&path="+plugin_www_post_tracker_ru.default_path+"&comment="+encodeURIComponent(comment);
			ajax.send("http://post-tracker.ru/ajax/userTrackcodes.php",'POST',data,cookies,false,this._put_trackCode_result);
		},
		_put_trackCode_result: function(data){ // данные отправились
			menuButtonHide(); // скрываем меню
			plugin_www_post_tracker_ru.get_content(true); // и снова запрашиваем содержимое страницы с кодами посылок
		}

Пишем клиент для любимого сайта на phoneGapЧто бы еще можно было бы добавить к приложение, чтобы потренироваться с phoneGap? В первую очередь не помешает локализация, чтобы в коде не хранился текст и для разных стран не выводился только русский язык. Так же не помешает отрабатывать некоторые состояния, например пропажу интернет соединения или нажатие на кнопку «назад».
В плане самого сервиса отслеживания, стоило бы добавит рекламу, на которую содержится ресурс, а так же увеличить функционал, добавив создание папок, автоматическую проверку с оповещениями и свистелкопезвуковыми эффектами.

Исходный код проекта и собранное приложение для тестов и экспериментов заинтересованных лиц.

Автор: SovGVD

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js