|
|
PhoneGap: Rapid Android Development, 3/3Posted by Salvador Mora on 02/03/2012 in salesforce , phonegap , mobile , javascript , iOS , Android |
This post is the last of three where you can learn how to create a mobile app using PhoneGap. In this final post, you'll learn how to build upon the code the code we have so far created to create a working Android app.
In this post, we will modify several Java and HTML files to correctly map for the Product object in your Salesforce account. If you haven't done so, yet, now would be a good time to review my previous post, where that's explained in detailed.
First we need to modify the Activity file , on my example It is called: PhoneGapAndroidActivity.java.
- Change the code to contain the next structure and save it:
package com.example.android;
import android.os.Bundle;
import com.phonegap.DroidGap;
public class PhoneGapAndroidActivity extends DroidGap {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.loadUrl("file:///android_asset/www/index.html");
}
}
- Before changing the HTML code, it is important to verify that you have your free Salesforce development account. You have to make sure you have the Product custom object already created to be able to continue with this tutorial. The Product custom object should have at least the Price field in it.
- You should have something pretty similar to this in your Salesforce account.
- If you have that object like that, then you are ready to keep going. If not, follow the tutorial.
- Inside Salesforce we have to prepare a Remote Site which will provide the way to get communicated using oAuth. Follow the next simple steps
- Go to Remote Access
- Create a new remote access. Specify the next required fields.
- After clicking on Save, you will get a very important string code.
- That Consumer Key will be used in our PhoneGap application to get authenticated using Salesforce.
Modifying the HTML and JS Files
Now it is time to modify the HTML file called Index.html. It includes the code from metadaddy-sfdc, but we are going to modify it to be able to run on Android and to use our own Salesforce account by mapping the Product custom object.
- Open the Index.html and edit the tag with the next code:
<head>
<title>Products</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="stylesheet" href="/static/jquery.mobile-1.0a4.1.min.css" />
<script type="text/javascript" src="/static/jquery-1.5.2.min.js"></script>
<script type="text/javascript" src="/static/jquery.mobile-1.0a4.1.min.js"></script>
<script type="text/javascript" src="/static/forcetk.js"></script>
<script type="text/javascript" src="/static/mobileapp.js"></script>
<script type="text/javascript" charset="utf-8" src="/phonegap.0.9.5.js"></script>
<script type="text/javascript" charset="utf-8" src="/childbrowser.js"></script>
<script type="text/javascript">
// OAuth Configuration
var loginUrl = 'https://login.salesforce.com/';
var clientId = '3MVG9yZ.WNe6byQDOtUfpo5TK.XDRz4.G9p3O3QytKIJraSlaz8ix4Yqm6VRmzDW3csPF_vQ9oSBQq82hHFRs';
var redirectUri = 'https://login.salesforce.com/services/oauth2/success';
var client = new forcetk.Client(clientId, loginUrl);
// Make our own startsWith utility fn
String.prototype.startsWith = function(str) {
return (this.substr(0, str.length) === str);
}
function getAuthorizeUrl(loginUrl, clientId, redirectUri) {
return loginUrl + 'services/oauth2/authorize?display=touch'
+ '&response_type=token&client_id=' + escape(clientId)
+ '&redirect_uri=' + escape(redirectUri);
}
function sessionCallback(oauthResponse) {
client.setSessionToken(oauthResponse.access_token, null, oauthResponse.instance_url);
addClickListeners();
$j('#logoutbtn').click(function(e) {
client.setRefreshToken(null);
$j.mobile.changePage('#loginpage', "slide", false, true);
$j.mobile.pageLoading();
window.plugins.childBrowser.onLocationChange = function(loc) {
if (loc.startsWith(redirectUri)) {
window.plugins.childBrowser.close();
oauthCallback(unescape(loc));
}
};
window.plugins.childBrowser.showWebPage(getAuthorizeUrl(loginUrl, clientId, redirectUri));
});
$j.mobile.changePage('#mainpage', "slide", false, true);
$j.mobile.pageLoading();
getProducts(function() {
$j.mobile.pageLoading(true);
});
}
function oauthCallback(loc) {
var oauthResponse = {};
var fragment = loc.split("#")[1];
if (fragment) {
var nvps = fragment.split('&');
for (var nvp in nvps) {
var parts = nvps[nvp].split('=');
oauthResponse[parts[0]] = unescape(parts[1]);
}
}
if (typeof oauthResponse === 'undefined' || typeof oauthResponse['access_token'] === 'undefined') {
errorCallback({
status: 0,
statusText: 'Unauthorized',
responseText: 'No OAuth response'
});
} else {
sessionCallback(oauthResponse);
}
}
// We use $j rather than $ for jQuery
if (window.$j === undefined) {
$j = $;
}
$j(document).ready(function() {
document.addEventListener("deviceready", onDeviceReady, false);
function onDeviceReady() {
window.plugins.childBrowser.onLocationChange = function(loc) {
if (loc.startsWith(redirectUri)) {
window.plugins.childBrowser.close();
oauthCallback(unescape(loc));
}
};
window.plugins.childBrowser.showWebPage(getAuthorizeUrl(loginUrl, clientId, redirectUri));
}
});
</script>
</head>
Note: I have modified the original source file to use the correct method names that work with Android versions.
- It is very important that you change the clientIdwith the consumer key you got from Saleforce while creating the remote Access.
var clientId = '3MVG9yZ.WNe6byQDOtUfpo5TK.XDRz4.G9p3O3QytKIJraSlaz8ix4Yqm6VRmzDW3csPF_vQ9oSBQq82hHFRs'; - Save the file.
- Now modify the tag with this code and save the file
<body>
<div data-role="page" data-theme="b" id="loginpage">
<div data-role="header">
<h1>Login</h1>
</div>
<div data-role="content" style="margin-left: auto; margin-right: auto; text-align: center;">
Connecting to Force.com
</div>
<div data-role="footer">
<h4>Force.com</h4>
</div>
</div>
<div data-role="page" data-theme="b" id="mainpage">
<div data-role="header" data-backbtn="false">
<h1>Product List</h1>
</div>
<div data-role="content">
<form>
<button data-role="button" id="newbtn">New</button>
</form>
<ul id="productlist" data-inset="true" data-role="listview"
data-theme="c" data-dividertheme="b">
</ul>
<form>
<button data-role="button" id="logoutbtn">Logout</button>
</form>
</div>
<div data-role="footer">
<h4>Force.com</h4>
</div>
</div>
<div data-role="page" data-theme="b" id="detailpage">
<div data-role="header">
<h1>Product Detail</h1>
</div>
<div data-role="content">
<table>
<tr><td>Product Name:</td><td id="Name"></td></tr>
<tr><td>Price:</td><td id="Price__c"></td></tr>
</table>
<form name="productdetail" id="productdetail">
<input type="hidden" name="Id" id="Id" />
<button data-role="button" id="editbtn">Edit</button>
<button data-role="button" id="deletebtn" data-icon="delete" data-theme="e">Delete</button>
</form>
</div>
<div data-role="footer">
<h4>Force.com</h4>
</div>
</div>
<div data-role="page" data-theme="b" id="editpage">
<div data-role="header">
<h1 id="productformheader">New Product</h1>
</div>
<div data-role="content">
<form name="productform" id="productform">
<input type="hidden" name="Id" id="Id" />
<table>
<tr>
<td>Product Name:</td>
<td><input name="Name" id="Name" data-theme="c"/></td>
</tr>
<tr>
<td>Price:</td>
<td><input name="Price__c" id="Price__c" data-theme="c"/></td>
</tr>
</table>
<button data-role="button" id="actionbtn">Action</button>
</form>
</div>
<div data-role="footer">
<h4>Force.com</h4>
</div>
</div>
</body>
- Open the mobileapp.js SPAN. We are going to modify some methods that will provide the product list, we won’t cover all the functionality, we just need to modify the method that displays the product list. In later chapters we could extend the complete functionality like: Edit, create, delete, etc.
- Locate the method called getAccounts SPAN, and replace all that method with the next method and save the file:
// Populate the Products list and set up click handling
function getProducts(callback) {
$j('#productlist').empty();
client.query("SELECT Id, Name, Price__c FROM Product__c ORDER BY Name LIMIT 20",
function(response) {
$j.each(response.records,
function() {
var id = this.Id;
$j('<li></li>')
.hide()
.append('<a href="#"><h2>' + this.Name + ' - price : $' + this.Price__c+ '</h2></a>')
.click(function(e) {
e.preventDefault();
$j.mobile.pageLoading();
// We could do this more efficiently by adding Industry and
// TickerSymbol to the fields in the SELECT, but we want to
// show dynamic use of the retrieve function...
client.retrieve("Product__c", id, "Name,Id,Price__c",
function(response) {
$j('#Name').html(response.Name);
$j('#Price__c').html(response.Price__c);
$j('#Id').val(response.Id);
$j.mobile.pageLoading(true);
$j.mobile.changePage('#detailpage', "slide", false, true);
}, errorCallback);
})
.appendTo('#productlist')
.show();
});
$j('#productlist').listview('refresh');
if (typeof callback != 'undefined' && callback != null) {
callback();
}
}, errorCallback);
}
- Run the project as an Android application.
- The AVD (Android Virtual Device) should open and deploy your code into the Android emulator you already have configured.
- You are rocking now!



If you want to see the code already running , take a look at my personal GIT repository and play with it.
TweetBacks (Tweet this post)
Trackback(0)
TrackBack URI for this entryComments (0)
Show/hide comments



