LinkedIn is a popular social-networking site for professionals. The LinkedIn API provides a rich set of integration services for use within your app. For Enterprise-focused apps, LinkedIn features such as Messaging and Contacts can be critical. Common examples of this would be providing a sales agent with access to their contacts within your app.
This recipe demonstrates how to integrate the LinkedIn Contacts API into your Titanium app, in a searchable fashion.
This recipe uses several modules, including the innovative LinkedIn module, linkedin_module-min.js
. This module and other code assets can be downloaded from the source code provided by the book, or individually through the links provided in the See also section at the end of this recipe. Setting up the dependencies for this recipe is straightforward. First, copy the lib
folder to the Resources
folder of your Titanium project, and then, the copy formatters.js
and linkedin_module-min.js
files into the Resources
folder, as shown highlighted in the following screenshot:
After you have set up the recipe's dependencies, the next step is to create your application namespaces in the app.js
file and use require
to import the module into your code, as shown in the following snippet:
//Create our application namespace var my = { isAndroid : (Ti.Platform.osname === 'android'), linkedMod: require('linkedin_module-min'), formatters : require('formatters') };
The first step in using the LinkedIn module is to create a LinkedIn application at https://www.linkedin.com/secure/developer. Once you have registered your application, LinkedIn will provide you with the API and authentication keys needed to interact with their APIs. All of the APIs used in this recipe need OAuth 1.0a
authentication to connect. The LinkedIn module will handle this for you by using the init
method to register your secret and API keys, as shown in the following example:
my.linkedMod.init('YOUR_SECRET_KEY', 'YOUR_API_KEY'),
By default, if no permissions are specified, your app will only have rights to read basic "digital business card" information about the current user. Since this recipe needs access to the user's contacts, we must call the addPermission
method to request for the r_network
privilege, as shown in the following snippet:
my.linkedMod.addPermission('r_network'),
To add multiple permissions, simply call the addPermission
method several times. The following snippet shows how to add the full profile access right to the app:
my.linkedMod.addPermission('r_fullprofile'),
For a full list of all the permissions, please visit https://developer.linkedin.com/documents/authentication.
This section of the recipe outlines how to create the UI that is used to display and search LinkedIn contacts.
Ti.UI.Window
is created. This will be used to attach all of our visual elements and will also trigger a call to the LinkedIn API when the open event is fired.var win = Ti.UI.createWindow({ backgroundColor:'#fff' });
Ti.UI.SearchBar
is then created. The search-bar control provides a search box that filters the contents of Ti.UI.TableView
. In this recipe, we use the search-bar control to filter the user's LinkedIn contacts by last name.var search = Ti.UI.createSearchBar({ barColor:'#385292', showCancel:true, hintText:'Search' });
Ti.UI.Window
is Ti.UI.TableView
that will be used to display the user's LinkedIn contacts.var tableView = Ti.UI.createTableView({ height:Ti.UI.FILL, width:Ti.UI.FILL, search:search, filterAttribute:'lastName' }); win.add(tableView);
The next snippet demonstrates how the LinkedIn module can be used to load a list of your contacts as the Ti.UI.Window
window is loaded.
win.addEventListener('open',function(e){
uiHelper.createWaitMsg
method to display a loading message to the user.uiHelpers.createWaitMsg('Loading please wait...'),
getConnections
method to query the user's contacts from the LinkedIn API. In the next example, an inline function is used as a callback returning the user's contacts as the _e
variable.my.linkedMod.getConnections(function(_e) {
uiHelpers.displayContacts
method is used to format and apply returned contacts for display.uiHelpers.displayContacts(_e); }); }); win.open();
The uiHelpers
object is used to format the results of the LinkedIn Contacts API for display.
var uiHelpers = {
createWaitMsg
function is used to display a waiting message in the tableView
while the LinkedIn API is being called.createWaitMsg : function(msg){ tableView.setData([{title:msg}]); },
displayContacts
method is the primary method used to convert and display the API results.displayContacts : function(apiResults){
tableView
to alert the user that we are now loading their contacts.uiHelpers.createWaitMsg('Loading contacts please wait...'),
convertToObject
method is called to convert the LinkedIn XML results into more manageable JavaScript objects.var resultAsObjects = my.resultParser.convertToObjects(apiResults);
null
, display an error message to the user.if(resultAsObjects == null){ alert('Sorry we ran into an error'), return; }
formatter.createContactTableRows
function, format the JavaScript objects into the Ti.UI.TableViewRow
layout shown earlier in this recipe's screenshots. The tableView
is then updated with the formatted rows.tableView.setData(my.formatters.createContactTableRows( resultAsObjects) ); } };
The resultParser
object is used to parse the XML provided by the LinkedIn API, into more manageable JavaScript objects.
my.resultParser = {
getText
function is used to return a specific key from a provided Ti.XML.Element
. If no key is found, a null value is returned.getText : function(item, key) { var searchItem = item.getElementsByTagName(key).item(0); return ((searchItem == null)? null : searchItem.textContent); },
getQueryParams
function is used to return an object with all query string parameters for a provided URL.getQueryParams : function(url){ var params = {}; url = url.substring(url.indexOf('?')+1).split('&'), var pair, d = decodeURIComponent; for (var i = url.length - 1; i >= 0; i--) { pair = url[i].split('='), params[d(pair[0])] = d(pair[1]); } return params; },
formatUrl
function returns a URL to the contact's profile. If no URL can be determined, a link to linkedin.com is provided.formatUrl : function(findKey){ return ((findKey.hasOwnProperty("key")) ? ("http://www.linkedin.com/profile/view?id=" + findKey.key) : "http://www.linkedin.com"); },
getProfileUrl
function is used to return a URL to the contact's profile. Since the LinkedIn API does not provide this information, a URL is generated by parsing the site-standard-profile-request
node for key details. The construction of this URL is demonstrated in the following snippet:getProfileUrl : function(item) { var searchItem = item.getElementsByTagName("site-standard-profile-request").item(0); if(searchItem == null){ return null; } if(searchItem.hasChildNodes()){ var findKey = my.resultParser.getQueryParams(searchItem.getElementsByTagName('url').item(0).textContent); return my.resultParser.formatUrl(findKey); }else{ return null; } },
isPublic
function is used to determine if a contact's information is public. If the profile is not public, we will not add it to the displayed contact list.isPublic : function(item){ return !((my.resultParser.getProfileUrl(item)==null)); },
convertToObjects
is the primary method responsible for converting the LinkedIn contacts' XML into JavaScript objects.convertToObjects : function(xmlString){ var contacts = [];
Ti.XML.Document
.var doc = Ti.XML.parseString(xmlString);
person
tag.var items = doc.documentElement.getElementsByTagName("person");
person
tag.for (var i = 0; i < items.length; i++) {
if(my.resultParser.isPublic(items.item(i))){
Ti.XML.Node
.contacts.push({ id : my.resultParser.getText(items.item(i), 'id'), headLine : my.resultParser.getText(items.item(i), 'headline'), firstName : my.resultParser.getText(items.item(i), 'first-name'), lastName : my.resultParser.getText(items.item(i), 'last-name'), pictureUrl : my.resultParser.getText(items.item(i), 'picture-url'), profileUrl : my.resultParser.getProfileUrl(items.item(i)) }); } }
null
before returning the converted results.doc = null, xmlString = null; return contacts; } };
clearlyinnovative.linkedIn
module created by Aaron Saunders, of clearlyinnovative.com. For additional documentation, samples, and guidance with the module, please visit http://www.clearlyinnovative.com/blog/post/12521419647/titanium-appcelerator-quickie-linkedin-api-integration. To download the source of the module, please visit the project on Github, at http://github.com/aaronksaunders/clearlyinnovative.linkedIn.18.219.63.95