Статьи

Преобразование динамического веб-сайта в приложение PhoneGap

Ранее сегодня читатель спросил меня о возможности преобразования своего мобильного сайта в «настоящее» приложение через PhoneGap. Я сказал ему, что это может быть очень легко. Вы можете взять свой HTML, загрузить его в службу PhoneGap Builder и посмотреть, что вы получите. Это работает с простыми сайтами HTML, но не будет работать хорошо с динамическими сайтами, созданными на серверных языках. В этом посте я объясню, почему это не сработает, а также расскажу о примере преобразования (простого) динамического веб-сайта в приложение PhoneGap.

Прежде чем начать — две быстрые заметки. Я буду использовать jQuery Mobile для пользовательского интерфейса и ColdFusion для серверной части. Это совершенно несущественно для поставленной задачи. Хорошо готов?

Сначала давайте обсудим, почему динамический веб-сайт не может быть просто преобразован в приложение PhoneGap. Большинство моих читателей — веб-разработчики, поэтому вы должны это знать, но когда дело доходит до динамических серверных языков, таких как ColdFusion, PHP, Ruby и т. Д., HTML-код, который получает ваш браузер, создается динамически.

Взять хотя бы этот простой сайт ColdFusion . Когда вы запрашиваете этот URL в своем браузере, мой веб-сервер передает запрос ColdFusion. ColdFusion делает свое дело (попадает в базу данных) и выводит необработанный HTML. Этот HTML возвращается в браузер и отображается как есть. То же самое относится и к PHP, Ruby и т. Д. Когда вы нажимаете на страницу сведений , мы нажимаем на один шаблон, которому передается параметр URL, который указывает коду загрузить конкретную запись и отобразить ее.

Теперь рассмотрим PhoneGap. PhoneGap берет ваши HTML-файлы и упаковывает их в собственное приложение для вашей мобильной платформы. Но это не веб-сервер. Вы не можете связать в ColdFusion или PHP и заставить его выполнять код на стороне сервера, как в примере выше.

Значит ли это, что тебе не повезло? Не за что. Давайте посмотрим, как мы можем преобразовать наш код в приложение PhoneGap.

Сначала давайте посмотрим на первоначальное приложение. Как я уже говорил выше, выбор серверного языка не имеет отношения к обсуждению. Поэтому я не буду вдаваться в подробности о том, что делает код ColdFusion. Те из вас, кто не знает ColdFusion, должны быть в состоянии мысленно отобразить его на выбранном вами языке. Сначала — страница указателя.

<cfset artService = new art()>
<cfset art = artService.getArtList()>

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Art Lister</title>
<link rel="stylesheet" href="css/jquery.mobile-1.1.0.min.css" />
<script src="js/jquery-1.7.2.min.js"></script>
<script src="js/jquery.mobile-1.1.0.min.js"></script>
</head>

<body>

<div data-role="page">

<div data-role="header">
<h1>Art</h1>
</div>

<div data-role="content">
<ul data-role="listview" data-inset="true">
<cfoutput query="art">
<li><a href="detail.cfm?id=#artid#">#artname#</a></li>
</cfoutput>
</ul>
</div>

<div data-role="footer">
<h4>Raymond Camden</h4>
</div>

</div>

</body>
</html>

 Тогда детальная страница:

<cfparam name="url.id" default="">
<cfset artService = new art()>
<cfset art = artService.getArt(url.id)>

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<cfoutput><title>Art: #art.name#</title></cfoutput>
<link rel="stylesheet" href="css/jquery.mobile-1.1.0.min.css" />
<script src="js/jquery-1.7.2.min.js"></script>
<script src="js/jquery.mobile-1.1.0.min.js"></script>
</head>

<body>

<div data-role="page">

<div data-role="header">
<cfoutput><h1>Art: #art.name#</h1></cfoutput>
</div>

<div data-role="content">
<cfoutput>
<p>
#art.description#
</p>
<p>
Price: #dollarFormat(art.price)#<br/>
Sold: <cfif art.sold>Yes<cfelse>No</cfif>
</p>

<p>
<img src="/cfdocs/images/artgallery/#art.image#">
</p>
</cfoutput>
</div>

<div data-role="footer">
<h4>Raymond Camden</h4>
</div>

</div>

</body>
</html>

 And finally — here is the component that drives the data. Basically it just wraps up the logic to get our list and detail.

component {

public struct function getArt(required numeric id) {
var q = new com.adobe.coldfusion.query();
q.setDatasource("cfartgallery");
q.setSQL("select artid, artname, description, price, issold, largeimage from art where artid = :artid");
q.addParam(name="artid", value=arguments.id, cfsqltype="cf_sql_integer");
var result = q.execute().getResult();
//convert the Query into a simple structure
var art = {id=result.artid[1], name=result.artname[1], description=result.description[1], price=result.price[1], sold=result.issold[1], image=result.largeimage[1]};
return art;
}

public query function getArtList() {
var q = new com.adobe.coldfusion.query();
q.setDatasource("cfartgallery");
q.setSQL("select artid, artname from art order by artname asc");
return q.execute().getResult();
}

}

 Ok — so that’s our old school (although nicely mobile optimized) web site. To begin the conversion to PhoneGap, I create a new file for my home page that is pure HTML, no ColdFusion.

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Art Lister</title>
<link rel="stylesheet" href="css/jquery.mobile-1.1.0.min.css" />
<script src="js/jquery-1.7.2.min.js"></script>
<script src="js/jquery.mobile-1.1.0.min.js"></script>
<script src="js/main.js"></script>
</head>

<body onload="init()">

<div data-role="page" id="indexPage">

<div data-role="header">
<h1>Art</h1>
</div>

<div data-role="content">
<ul data-role="listview" data-inset="true" id="artList">
</ul>
</div>

<div data-role="footer">
<h4>Raymond Camden</h4>
</div>

</div>

</body>
</html>

 Notice that the layout is the same as before, but our content is gone. Previously that was sourced on the server by a database call. So how do we add this dynamic data back in? With JavaScript.

First — let’s add some logic to run when the home page is created. This specific event is based on how jQuery Mobile does things, but again, you could do this without any particular UI framework.

$("#indexPage").live("pageinit", function() {
console.log("Getting remote list");
$.mobile.showPageLoadingMsg();
$.get("http://localhost/testingzone/phonegaptests/conversion/service/artservice.cfc?method=getArtList&returnformat=json", {}, function(res) {
$.mobile.hidePageLoadingMsg();
var s = "";
for(var i=0; i<res.length; i++) {
s+= "<li><a href='detail.html?id=" + res[i].id + "'>" + res[i].name + "</a></li>";
}
$("#artList").html(s);
$("#artList").listview("refresh");
},"json");

});

 This code block performs a HTTP request to our server. (Note: I’m using localhost in the example above but in a real application it would be your site’s domain, something.com.) I’ve built a new set of server-side code just to handle getting and returning data in JSON format. So there’s still a server involved, but now it’s simply returning data, nothing more. I loop over the result and render it out into the page.

The detail page is built much like the index page. It’s a copy of the earlier version minus any code or actual content.

<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
<link rel="stylesheet" href="css/jquery.mobile-1.1.0.min.css" />
<script src="js/jquery-1.7.2.min.js"></script>
<script src="js/jquery.mobile-1.1.0.min.js"></script>
</head>

<body>

<div data-role="page" id="detailPage">

<div data-role="header">
<h1></h1>
</div>

<div data-role="content" id="detailContent">
</div>

<div data-role="footer">
<h4>Raymond Camden</h4>
</div>

</div>

</body>
</html>

 To handle this, back in my JavaScript I added code to run when the page is loaded.

$("#detailPage").live("pageshow", function() {
var page = $(this);
var query = page.data("url").split("?")[1];
var id = query.split("=")[1];
console.log("Getting remote detail for "+id);
$.mobile.showPageLoadingMsg();
$.get("http://localhost/testingzone/phonegaptests/conversion/service/artservice.cfc?method=getArt&returnformat=json", {id:id}, function(res) {
$.mobile.hidePageLoadingMsg();
$("h1",page).text("Art: " + res.name);
var s = "<p>" + res.description + "</p>";
s += "<p>Price: "+res.price + "<br/>";
s += "Sold: ";
if(res.sold == 1) s += "Yes</p>";
else s+= "No</p>";

s+= "<p><img src='" + res.image + "'></p>";
$("#detailContent").html(s);
},"json");

});

 And that — as they say — is basically it. To summarize:

  • The code in the PhoneGap application is just HTML and JavaScript.
  • The dynamic data from the earlier application was rewritten to expose itself remotely.
  • PhoneGap then simply uses Ajax to fetch that data.

I’ve attached a zip of all the code used for this blog post below. If any part of this doesn’t make sense, let me know, and I hope this was helpful.

Download attached file