Monday 16 January 2012

Extending titanium project with iOS module development-Implementing Bitly API

I spend my weekends reading about titanium and exploring its power. And being an iOS developer, I really loved the way we can create iOS modules for my existing titanium project and extend it to a great extend.
The modules created can be easily created and deployed.
Today I will tell you how we can easily integrate an iOS module and use its power in our titanium project.

Overview
We will be creating a simple application with the titanium studio, which will accept a long url and give us a short url.
In short, we will be implementing Bitly API.
Here the UI will be designed in our Titanium studio  and out Bitly API implementation will be done in our iOS module that we will develop.



Then we gonna include that module in our project and use it to convert our long URL to short one.

So, Lets get Started.

Creating Our Titanium Project

As you will be familier with the titanium development so I will skip that project creation wizard. :)
I will name my project as ShortUrl.
Now edit the default code in the app.js(you will find it in Resource folder under your Application folder) file with this code.

var window = Ti.UI.createWindow({
backgroundColor:'white' 
});

var txtLongUrl = Ti.UI.createTextField({ 
top: 10
left: 10
width: 300,
height: 30,
  borderStyle: 1
  hintText: 'Enter your long url...'
}); 
window.add(txtLongUrl);

var btnShorten = Ti.UI.createButton({ 
title: 'Shorten it with Bit.ly!'
width: 200
right: 10,
height: 30,
top: 50 
});

btnShorten.addEventListener('click', function(e)
         // here we will add the code that will call our module later
}); 
window.add(btnShorten);

var txtShortUrl = Ti.UI.createTextField({ 
top: 100
left: 10
width: 300,
height: 30
borderStyle: 1
hintText: 'Your short url appears here...'
}); 

window.add(txtShortUrl);

window.open();


When you run your project you will see the similar screen below.




















Now we have our UI, lets build our iOS Module.
Setting Up your Module Environment

Note: The below steps are taken from the Appcelerator documentation and guides. In case you face any problem refer below given link:
https://wiki.appcelerator.org/display/guides/iOS+Module+Development+Guide
To set up your Module environment on OSX, you'll need to place a helper script on your path or set up an environment alias to the file. In this document, we recommend you create an alias.

Note: You'll need to determine where your Titanium 1.4.0 SDK (or more recent version) is installed. It may be installed in /Library/Application\ Support/Titanium, or it may be in ~/Library/Application\ Support/Titanium. The steps below assume that it is below /Library. If it is below ~/Library instead, you'll need to make the appropriate change to the line in step 3.
  1. Open the Console application. The Console application is located under /Applications/Utilities/Console.
  2. Edit the file named .bash_profile in your $HOME directory.
  3. In this file, add the following line at the end of the file:
    alias titanium='/Library/Application\ Support/Titanium/mobilesdk/osx/1.7.5/titanium.py'
    This will create an alias to the titanium.py helper script. You should substitute the version above (1.4.0) with the version of Titanium mobile SDK you're using.
  4. Save the file.
  5. Type the following command in the console:
    source ~/.bash_profile
  6. Type the following command in the console:
    titanium
    You should see the following output (or substantially similar):
    Appcelerator Titanium
    Copyright (c) 2010 by Appcelerator, Inc.
    commands:create  - create a project
    run              - run an existing project
    help             - get help
  7. Keep open the console as you'll need it in subsequent steps.

Building Our Bitly Module

Create the module with the following script:
In your terminal type:
titanium create --platform=iphone --type=module --dir=~/Projects --name=BitlyModule --id=com.ajeet.BitlyModule

Now open the /Projects/BitlyModule directory in Finder, and what you will see is a list of mostly standard looking XCode project files. Double click the BitlyModule.xcodeproj file to open it up in XCode for editing.
Before you can use the module, you'll need to sign up for a Bitly API Key, which you can do for free at: https://bitly.com/a/sign_up?rd=/a/your_api_key.
Additionally, we're going to need the open source SBJSON framework for Objective-C, which is capable of natively reading and writing JSON formatted data streams. You can download the SBJSON framework from https://github.com/stig/json-framework/.

Now we have our SBJSON framework and our Bitly API key, so now lets start with our Module.

First, unzip the SBJSON framework, and drag all of the files from the Classes folder in Finder to the Classes folder in your module's XCode project.

Open up ComAjeetBitlyModuleModule.h and ensure it looks like the following (ignoring the header comments at the top of the file):

#import "TiModule.h"
#import <Foundation/Foundation.h>
@interface ComAjeetBitlyModuleModule : TiModule 
{
}

@end

Now open the ComAjeetBitlyModuleModule.m file and ensure it looks like the following source code (ignoring the header comments at the top of the file).
Remember to replace the login and key values in the QueryString section of the URL with those you were assigned by the Bit.ly API:

In your .m file you will have many function prewritten for you, so for now dont touch them.

include the Sbjson files in your .m files.
so that it looks like below,


#import "ComAjeetBitlyModuleModule.h" 
#import "TiBase.h" 
#import "TiHost.h" 
#import "TiUtils.h"
#import "SBJson.h" 
#import "SBJsonParser.h"

@implementation ComAjeetBitlyModuleModule

// all your other code

#pragma Public APIs

//here we will create a public method that will interact with our titanium project.

//add this function here

- (id)getShortUrl:(id)args 
{
    NSString *baseURLString = @"http://api.bit.ly/shorten?version=2.0.1&longUrl=";
    NSString *longUrl = [TiUtils stringValue:args];

    longUrl = [longUrl stringByReplacingOccurrencesOfString:@"(" withString:@""];
    longUrl = [longUrl stringByReplacingOccurrencesOfString:@")" withString:@""];
    longUrl = [longUrl stringByReplacingOccurrencesOfString:@"\"" withString:@""];

    longUrl = [longUrl stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];  
  
    baseURLString = [baseURLString stringByAppendingString:longUrl];
    baseURLString = [baseURLString stringByAppendingString: @"&login=username&apiKey=yourKey"];  // your username and API key

    NSURL* baseURL = [[NSURL alloc]initWithString:baseURLString];
    NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:baseURL];
    NSHTTPURLResponse* urlResponse = nil
    NSError *error = [[[NSError alloc] init] autorelease];
    NSData *data = [NSURLConnection sendSynchronousRequest:req returningResponse:&urlResponse error:&error];

    if ([urlResponse statusCode] >= 200 && [urlResponse statusCode] < 300)
    {
        NSLog(@"Got a response from bit.ly"); 
        SBJsonParser* jsonParser = [SBJsonParser new]; 
        NSString* jsonString = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        NSDictionary* dict = (NSDictionary*)[jsonParser objectWithString:jsonString];
        [jsonString release]; 
        [jsonParser release];
        NSString *statusCode = [dict objectForKey:@"statusCode"];

        if([statusCode isEqualToString:@"OK"]) 
        {
            // retrieve shortURL from results NSLog([dict description]);
            NSString *shortURL = [[[dict objectForKey:@"results"] objectForKey:longUrl] objectForKey:@"shortUrl"];
            return shortURL;
        }
        else
        {
            return @"Unable to shorten this URL, please check its format.";
        }
        
    }
    return baseURLString;
}


@end

Now at this point we have created a function getShortUrl, save you .m file.

Now we will package our module, so on the terminal

type the following:  ./build.py

the terminal will throw bunch of lines and in the end you will see build succeed .

If you have any error first resolve it.


To install your Module so that it can be used in a real application, you will need to install it. In the console, run the following:
you will find this .zip file in your module folder.
> cp com.ajeet-iphone-0.1.zip /Library/Application\ Support/Titanium/
This will copy your Module distribution file into your Titanium directory. The Titanium compiler is smart enough to automatically expand your module into the correct directory when referenced in your application.
Your module will be expanded into the following directory:
/Library/Application Support/Titanium/modules/iphone/com.ajeet/0.1
Now we are done with our Module development, lets attach it to our titanium project.
Open up your Titanium project that we created earlier, i.e. shortUrl
1. open the tiApp.xml file and in the end add this line in place of this <modules/>
<modules>
<module version="0.1">com.ajeet.BitlyModule</module>
</modules>
Here we added our module, It means our app will be needing it. 
2. In your app.js, on the top add this line
var mybitly = require('com.ajeet.BitlyModule');
Ti.API.info("module is => " + mybitly);
3. Now in our btnShorten function we will call our getShortUrl function defined in our .m file.
btnShorten.addEventListener('click', function(e){ 
Titanium.API.info("longUrl is----> "+ txtLongUrl.value);
var result = mybitly.getShortUrl(txtLongUrl.value); 
Titanium.API.info("result is----> "+ result);
txtShortUrl.value = result;
}); 
By doing this we completed our module integration.
just run the application, and enter any url in the long url textbox and by clicking on the button 
we get our short bitly url..
Hope you enjoyed the tutorial..:)
Here is the output:





















13 comments:

  1. hey dude how pass multiple attributes ??

    ReplyDelete
  2. Hi Luis..
    you can pass the multiple attributes in the form of array as "(id)args" will be of type NSArray..
    so to fetch your arguments you can do [args objectAtIndex:0]. this way you can access multiple arguments/attributes

    ReplyDelete
  3. Hi,

    How you sending nsurlconnection request in ios titanium module. it's not working...
    References:
    http://developer.appcelerator.com/question/144514/module-development----nsurlrequest (tested with google.com)
    http://developer.appcelerator.com/question/122673/nsurlconnection-in-ios-module
    http://stackoverflow.com/questions/13311908/appcelerator-titanium-module-development-http-requests-not-working

    ReplyDelete
  4. Could you please add project source code. both titanium mobile application and module project...

    ReplyDelete
    Replies
    1. I am just passing a string to the titanium module and its the module which is taking the string and considering it as URL.
      Sorry, I don't have the project source code, I created this a year ago. But I am definitely sure that I was using the same code which I have written in this blog, and the titanum SDK was 1.8 I guess

      Delete
  5. Hi,

    I'm getting the error below, any ideas why?

    [ERROR] : ** BUILD FAILED **
    [ERROR] : The following build commands failed:
    [ERROR] : Ld build/Debug-iphonesimulator/ShortUrl.app/ShortUrl normal i386
    [ERROR] : (1 failure)

    Thanks! :)
    Tony

    ReplyDelete
  6. Below code fixes many issues and works. You will also need to comment out the section in the SBJSON Framework files, that section is:

    #if !__has_feature(objc_arc)
    #error "This source file must be compiled with ARC enabled!"
    #en

    and the modified code is:

    #pragma Public APIs

    - (id)getShortUrl:(id)args
    {
    NSString *baseURLString = @"http://api.bit.ly/v3/shorten?&longUrl=";
    NSString *longUrl = [TiUtils stringValue:args];

    longUrl = [longUrl stringByReplacingOccurrencesOfString:@"(" withString:@""];
    longUrl = [longUrl stringByReplacingOccurrencesOfString:@")" withString:@""];
    longUrl = [longUrl stringByReplacingOccurrencesOfString:@"\"" withString:@""];

    longUrl = [longUrl stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

    baseURLString = [baseURLString stringByAppendingString:longUrl];
    baseURLString = [baseURLString stringByAppendingString: @"&login=YOUR_USERNAME&apiKey=YOUR_API_KEY"];

    // Create the request.
    NSURLRequest *theRequest;
    theRequest=[NSURLRequest requestWithURL:[[NSURL alloc]initWithString:baseURLString] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
    //Sending sendSynchronousRequest
    NSData *data = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:nil error:nil];
    NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

    NSLog(@"Got a response from bit.ly");
    SBJsonParser* jsonParser = [SBJsonParser new];
    NSDictionary* dict = (NSDictionary*)[jsonParser objectWithString:responseString];
    [responseString release];
    [jsonParser release];

    NSDictionary* dict2 = [dict objectForKey:@"data"];
    NSString *shortURL = [dict2 valueForKey:@"url"];
    return shortURL;
    }
    ```

    ReplyDelete
  7. It is quickly constructable, test, bundle and distribute portable applications utilizing just JavaScript and a solitary code base. Presently, engineers with web
    Titanium frameworkadvancement abilities can quickly construct rich, local versatile applications. You probably won't have to oversee various designer tool stash, dialects and systems.

    ReplyDelete
  8. I think the things you covered through the post are quiet impressive, good job and great efforts. I found it very interesting and enjoyed reading all of it...keep it up, lovely job..
    xamarin app development

    ReplyDelete
  9. Enriched application tools and integrated component store make it much easier for the developers to deal with.

    Xamarin app development Company India

    ReplyDelete
  10. I have read your article, it is very informative and helpful for me.I admire the valuable information you offer in your articles. Thanks for posting it..
    mobile app development services in pakistan

    ReplyDelete
  11. Glitter as Data Scientist in your future with Data Science Training in Chennai with Infycle Technologies the important Data Science Training institute in Chennai with the best authorization. Along with Data Science, get the knowledge of the power BI and Tableau tools for a better understanding of data visualization. To reach on 7504633633 or 7502633633.

    ReplyDelete

Pages