Бывает что есть сайт, но пользоваться им с мобильного телефона не очень удобно и было бы замечательно иметь отдельное приложение для него. Любители веб разработки легко смогут это сделать использую 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):
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? В первую очередь не помешает локализация, чтобы в коде не хранился текст и для разных стран не выводился только русский язык. Так же не помешает отрабатывать некоторые состояния, например пропажу интернет соединения или нажатие на кнопку «назад».
В плане самого сервиса отслеживания, стоило бы добавит рекламу, на которую содержится ресурс, а так же увеличить функционал, добавив создание папок, автоматическую проверку с оповещениями и свистелкопезвуковыми эффектами.
Исходный код проекта и собранное приложение для тестов и экспериментов заинтересованных лиц.
Автор: SovGVD