Pages

Saturday 13 October 2012

integrating facebook and twitter in iOS 6 Apps (Social Framework)

Hello friends!! In this post, i am going to talk about social framework(introduce in iOS6). How to integrate facebook or twitter in iOS6 App.
        Social framework is introduce in iOS6 and by using it we can connect to facebook, twitter or weibo.com, no need of any third party SDKs. To learn social framework in iOS6 you should have Xcode 4.5. Lets start without wasting time first create a single view application and design your first screen as following screen -

Now add Social framework to your project - 
  1. Click on project name in project navigator
  2. Select the project under target in middle pan of Xcode
  3. Make sure that "Build Phases" tab is selected
  4. Expand the "Link binary with libraries", click on triangle
  5. Click on add item(+ button) in left corner of this section 
  6. Search social in search bar (comes after clicking on + button)
  7. Select the "Social.framework" framework and click on "Add" button 

Cheers you have completed the first step of this tutorial. Now import the social framework header file "Social.h" in ViewController.h file of your project.
// import social header file
 #import<Social/Social.h>

Add following two methods to "ViewController.h" file and connect them to respective button's touch event in respective view controller.
 //called on tap of facebook button
 - (IBAction)postOnFacebookButtonTapped:(id)sender;
 //called on tap of tweet button 
 - (IBAction)tweetButtonTapped:(id)sender;


Similarly add body of these two methods in "ViewController.m" file
- (IBAction)postOnFacebookButtonTapped:(id)sender {
}

- (IBAction)tweetButtonTapped:(id)sender {
}


We have added the required framework and methods to our project now it is the time to write the actual code. Social framework provides built in composer (SLComposeViewController), which we can pressent to user with pre loaded text, URL, and images so that user can tweet or post on their timeline. To present the composer we need to create an instance of this class. We can not edit or add any thing to the composer without informing the user. So we must add any initial content before presenting the composer to the user. After presenting the composer, only user can edit the content. 
        
+(SLComposeViewController*)composeViewControllerForServiceType:(NSString*) serviceType  

Above method is use to create the instance of SLComposeViewController and for it we need to pass service type. Service type tells the targeted social website like facebook, twitter and weibo. Service types are as follows -
  • SLServiceTypeTwitter
  • SLServiceTypeFacebook
  • SLServiceTypeSinaWeibo 
You should pass desire service type to create the respective composer. Before creating or presenting the composer we should check the availability of service type  or reachability of site. For this we can use following class method - 

+ (BOOL)isAvailableForServiceType:(NSString *)serviceType

This methods returns BOOL value where NO represents one of following - 
  1. User's twitter or facebook account is not set up on device
  2. Desire site is  not available 
Now lets implement postOnFacebookButtonTapped: method 
- (IBAction)postOnFacebookButtonTapped:(id)sender {
    if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {
        SLComposeViewController *fbComposer = [SLComposeViewController
                                               composeViewControllerForServiceType:SLServiceTypeFacebook];
        //set the initial text message
        [fbComposer setInitialText:@"Hi i am coding for bugs!!"];
        //add url
        if ([fbComposer addURL:[NSURL URLWithString:@"www.kmithi.blogspot.com"]]) {
            NSLog(@"Blog url added");
        }
        
        
        // you can remove all added URLs as follows
        //[fbComposer removeAllURLs];
        
        //add image to post
        if ([fbComposer addImage:[UIImage imageNamed:@"strongBinary"]]) {
            NSLog(@"strong binary added to the post");
        }
        if ([fbComposer addImage:[UIImage imageNamed: @"scan.jpg"]]) {
            NSLog(@"scan is added to the post");
        }
        
        //remove all added images
        //[fbComposer removeAllImages];
        
        //present the composer to the user
        [self presentViewController:fbComposer animated:YES completion:nil];
        
    }else {
        UIAlertView *alertView = [[UIAlertView alloc]
                                  initWithTitle:@"Facebook Error"
                                  message:@"You may not have set up facebook service on your device or\n                                  You may not connected to internent.\nPlease check ..."
                                  delegate:self
                                  cancelButtonTitle:@"OK"
                                  otherButtonTitles: nil];
        [alertView show];
    }
}


Yah!! It is this much easy any one can add facebook and twitter to their applications. All methods use to set initial text or add/ remove URLs and images returns BOOL values  where YES tells that successfully added/ removed image or URL.  You can add more than one image but not URL only last URL will be posted to your timeline. If your account is not set up then first set up it (Settings --> facebook) otherwise it will returns NO while checking the availability of service or error while posting. Similarly we can implement  tweetButtonTapped: method-
- (IBAction)tweetButtonTapped:(id)sender {
    if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeTwitter]) {
        
        SLComposeViewController *twitterComposer = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
        
        //add initial text
        [twitterComposer setInitialText:@"Tweeting from iPhone 5 #TesingApp"];
        
        //present composer
        [self presentViewController:twitterComposer animated:YES completion:nil];
    } else {
        UIAlertView *alertView = [[UIAlertView alloc]
                                  initWithTitle:@"twitter Error"
                                  message:@"You may not have set up twitter service on your device or\n                                  You may not connected to internent.\nPlease check ..."
                                  delegate:self
                                  cancelButtonTitle:@"OK"
                                  otherButtonTitles: nil];
        [alertView show];
    }
}


Composer view controllers looks like follow -





















Now i am going to discussed the last but not least feature of SLComposeViewController class. It is the completion handler. SLComposeViewController class define a block property of type SLComposeViewControllerCompletionHandler. SLComposeViewControllerCompletionHandler takes a parameter of type SLComposeViewControllerResult. Parameter indicate wether user finished or cancelled composing the post. Parameter will be one of following - 
  • SLComposeViewControllerResultCancelled,
       It indicates  that user has cancelled composing the post
  •  SLComposeViewControllerResultDone
       It indicates  that user has finished composing the post 
 //add completion handler
        twitterComposer.completionHandler = ^(SLComposeViewControllerResult result) {
            if (result == SLComposeViewControllerResultCancelled) {
                NSLog(@"User has cancled composing the post, and tapped the cancle button");
            }
            
            if (result == SLComposeViewControllerResultDone) {
                NSLog(@"User has finished composing the post, and tapped the send button");
            }
        };


To know more about block programming check this!
Thanks for reading!! Please leave your valuable suggestions!! Bye Bye !!

Thursday 30 August 2012

iOS Application Directory Structure : Document, Cache and tmp

Hello friends!!

In this post i am going to talk about iOS application directory structure. iOS applications run in sandbox like environment that means Application (A) can not access the resources of Application(B). In more easy words i can say that a closed room is allocated to each Application where they have to eat and sleep, of course  room is closed so they can not access resources of each other. However an Application can request Operating System( OS ) to run other Application. Following image shows directory structure of a typical iOS application.


Apple reserve all rights to change the directory structure and you may find different structure on different OS version for example  "Libarary/ Application Support " does not exists in iOS 5 and older versions. Most important directories are app bundle(myApp.app), Document, cache and tmp. 
             When our Application is installed on iPhone, iTunes creates a home directory(In above image "App" is home directory) for application. This directory is same as closed room(ad discussed above) for the App. It contains everything that Application can access. Applications can create file, delete file under home directory. 
            You should be selective while storing file in directories because wrong selection of directory may affect the iCloud syncing process and waste the user space, that encourage the user to delete your App. So you should be selective to where you place which file.  
           iOS uses a unique ID instead of application name, so you can not give absolute or relative path of any directory. 
Now let me describe the usage of directories and code to access these directories. 

Bundle Directory(myApp.app) -

     This is the place(bundle) where your App exists. You should not modify this directory, it prevent your app from launching again. All resources you put in your project will stored in this directory. How to get the path of bundel directory -
//get the main bundel 
NSBundle *bundle = [NSBundle mainBundle];
//get the path of home directory 
NSString *bundlePath = [bundle bundlePath];
 You can find the path of your resources by appending resource name to bundlePath or  as follows
//Find the path of a image(myPhoto.png)
NSString *pathTomyPhoto = [[NSBundle mainBundle] pathForResource:@"myPhoto" ofType:@"png"];
NSLog(@"\n%@\n",pathTomyPhoto);

OUTPUT-
.../Applications/99C1AFFA-0908-4968-B6C7-E2644385D86D/appName.app/myPhoto.png

To protect this directory from tempering iOS sign it with unique id, any modification in this ID prevent your app from launching.

Document Directory

Use this directory to store important files of your application like sqlite database. Data of this directory is backup in iTunes so don't store temporary and large fiels. If you will store large amount of data in document directory, Apple may reject your App see this. In more general you should store only those data which can not be recreated by your app.  How to get the path of document directory?

/*use following c function to find any directory, just you need to provide the directory type*/
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
//find the actual path
NSString* docDir = [paths objectAtIndex:0];
NSLog(@"\n%@\n",docDir);

Document/Inbox Directory 

This directory is used by other applications to open files with the help of your application. For example email app places email attachement in inbox directory before opening the attachement with the help of your application. We have only read and delete permission on this directory means we can not create new file or edit fiels in this directory. If you want to edit any file, then you must move that file to document or other directory. You can access this directory by adding a path component "Inbox" to document directory path.

Library Directory

This directory is used to store app specific files. Content of this directory is also backup in iTunes but not exposed to user. You should not store user specific files in directory. iOS applications are not permitted to use this directory although you can use the subdirectories of this directory. 

NOTE: data of cache directory is not backup in iTunes. 

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES);
NSString *libDirectory = [paths objectAtIndex:0];
NSLog(@"%@",libDirectory);

Library/Caches Directory

Content of this directory is not backup by the iTunes. You should store only those files which can be recreated easily. System may delete content of this directory (to free up the disk space) when it is required, so your app should gracefully handel this type of situations  Eligible candidate of this directory are downloadable contents, database cache files etc . You can create, edit, delete content of this directory. You can get the path of cache directory as follows -
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [paths objectAtIndex:0];
NSLog(@"%@",cachesDirectory);

Library/Application Support Directory

This directory was introduced in iOS 5.0.1 and content of this directory is also backup in iTunes. You can use this directory to store App created fiels, templates for example we can store newly purchased levels of game in this directory. You can find the path of this directory by passing "NSApplicationSupportDirectory" as searchPathDirectory in "NSSearchPathForDirectoriesInDomains" method.

Library/Preferences Directory

Apple recommend us to not create any file in this directory and instead of this we should use "NSUserDefault" class to set and get preference values of our APP. Purpose of this directory is to store app preference files, generally our app creates files in this directory. You can set preference values in user default as follows -
//get user default object
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
    
//set values in user default
[userDefault setValue:@"mithi" forKey:@"nickname"];
[userDefault setBool:NO forKey:@"shoulShowDOB"];
[userDefault synchronize];
    
//get values from user default
NSString *nickName = [userDefault valueForKey:@"nickname"];
NSLog(@"Nickname = %@",nickName);
BOOL shouldShowDOB = [userDefault boolForKey:@"shoulShowDOB"];
    
if (shouldShowDOB) {
    NSLog(@"We have permission to show DOB");
}else {
    NSLog(@"We do not have permission to show DOB");
}

tmp Directory

Last but not least tmp directory is use to store temporary files, you should use this directory to store those files which are not required to persist or required for a few time. You should delete the files when that is not required. Content of this directory can be deleted any time. You can get the path of this directory as follows -
NSString *tmpDirectory = NSTemporaryDirectory();
NSLog(@"%@",tmpDirectory);

Don't forget to leave your valuable comments!! bye bye!!

Friday 23 March 2012

Blocks Programming in iOS

Hello friends!!
In this post i am going to talk about "Blocks programming in iOS". iOS4 and latter supports blocks programming.

Blocks:
     Blocks are code snippet that can be use as a function or can be written as inline code at time of method invocation.

I think defining blocks is wasting of time because i can not define whole thing about blocks as it has lots of features , lots more than the above definition. You will get good understanding of blocks programming by examples of course! because examples are good way to explain anything.Let's start

Syntax to declare inline block:
     
^(parameter list){
   //you code
}

Inline block means blocks defined at time of function call.Caret (^) indicate the start of block literal and curly braces {} indicate the body of block.For example -
//following method use the block to print the square of given number 
-(void)printSquareOf:(NSInteger)number byExecutingBlock:(int(^)(int))block{

    NSLog(@"Square of %i = %i",number,block(number));
    //you can call block same as c functions 
    //syntax to call block using block name - blockName(commas separated parameter list)
    //like block(number); block1() and so on 
}

//call above method to print the square fo desire number
//block will square the given number and called method will print result in log

[self printSquareOf:4 byExecutingBlock:^(int n){return n*n;}];

OUTPUT:                                                                                                                             
   Square of 4 = 16                                                                                                                

We have define a inline block at line number 13 which take a integer as parameter and returns square of that number and "printSquareOf: byExecutingBlock: " prints the result.You can declare block as function argument like -

(return_type(^)(parameters list))block_name
For examples -
-(void)myLog:(void(^)())block;
-(void)printSquareOf:(NSInteger)number byExecutingBlock:(int(^)(int))block;
We need to writes inline blocks again and again, thats not good, now question is how can we writes once and use many times? of course we can do it by assigning blocks to a block variable, call blocks using block variable. 
Syntax to declare a block Variable -
  returnType (^blockVariableName)(parametersTypeList);
For example - 
  void(^now)(void);
  void(^doSquare)(int);
  void(^sayHelloTo)(NSString*);

Syntax to assign block literal to block variable -
  blockName = ^(parameterList){};

Following example shows that how to declare block variables and assign block literal in two different steps

    //declare block variable
    void(^sayHello)(void);//sayHello is block variable name
    //assign block literal to block variable sayHello
    sayHello = ^{NSLog(@"Hello,I am coding for bugs");};
    
    //call block using block variable
    sayHello();

In above example we have declare block variable at line number 2 which return type is void, name is "sayHello" and it does not accept any parameter so void in parameter list. We have assigned block literal at line number 4 which print "Hello,I am coding for bugs". We are calling block at line number 7.

In one shot we can declare block variable and assign block literals like this - 
 returnType (^blockVariableName)(parameterTypeList) = ^(parameterList){};

Following example shows that how to declare block variable and assign block literal in one shot -
    //this block calculate factorial of given number 
    NSInteger(^calculateFactorialOf)(NSInteger) = ^(NSInteger n){
        NSInteger fact = 1;
        if (n==0) {//factorial of 0 is 1 
            return fact;
        }
        for (int i=n; i>0; i--) {
            fact = fact*i;
        }
        
        return fact;
    };
    //call block, factorial will be assign to result 
    NSInteger result = calculateFactorialOf(4);
    NSLog(@"factorial = %i",result);//print 24
In above example you have seen how to use inline block and block variables.One main thing left about block is - it captures surrounding state that's why it is called as closures. Blocks are called closures because they are closed around variables that are in scope at the time of block declaration. Its means that a variable declare before of block declaration can be directly used in block.Block keeps a read only copy of in scope variables for example -
//calculate half of the given number using provided block and print the result 
-(void)calculateHalfOf:(NSInteger)number byExecutingBlock:(int(^)(int))block{
    NSLog(@"Half of %i = %i",number,block(number));
    //you can call block same as c functions 
    //syntax to call block using block name - blockName(commas separated parameter list)
    //like block(number); block1() and so on 
}

//cal the calculate method from viewDidLoad: method
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    NSInteger divider = 2;
    [self calculateHalfOf:4 byExecutingBlock:^(int n){return n/divider;}];
    //above block will carry a read only copy of divider variable 
}

OUTPUT:                                                                                                                            
     Half of 4 = 2                                                                                                                    

In above block we have not define the divider variable but we are using we can't modify the value of divider if we will do that it will give error as -


In above screenshot we can see that error - Variable is not assignable(missing __block type specifier).
Oh! Its not good, What will we do?if need to modify the divider variable. Don't worry take long breath and think what is __block? Yeah you are thinking right by using __block  storage type modifier we can make divider mutable.For example -
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    
   __block NSInteger divider = 1;//__block makes variable mutable
    //see the above example for calculateHalfOf: byExecutingBlock: definition 
    [self calculateHalfOf:4 byExecutingBlock:^(int n){
        //modify divider, now it is not read only 
        divider = divider*2;
        return n/divider;}];
}
OUTPUT:                                                                                                                            
     Half of 4 = 2                                                                                                                    

When we use __block storage type modifier, variables passed by reference into the block.
Note: We should not use __block causally because it moves variables to heap, so please do not use it unless you really need it.
Hey cheers! We have completed basic of block programming.I can't believe that still you guys are reading! I salute your enthusiasm.Now i am going to discuss last things.
Declare block as property:

BlockDemo.h

#import<uikit/uikit.h>
typedef int (^devideEquallyBlock)(int);
@interface BlockDemo : UIViewController{
     devideEquallyBlock callbackBlock;
}
@property (nonatomic, copy) devideEquallyBlock callbackBlock;
-(void)calculateHalfOf:(NSInteger)number byExecutingBlock:(devideEquallyBlock)block;
@end
BlockDemo.m
#import "BlockDemo.h"

@implementation BlockDemo

@synthesize callbackBlock;

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    [super viewDidLoad];

   __block NSInteger divider = 1;//__block makes variable mutable
    //assigning block to property 
    callbackBlock = ^(int n){
        divider = divider*2;
        return n/divider;};
    [self calculateHalfOf:4 byExecutingBlock:callbackBlock];
}
-(void)calculateHalfOf:(NSInteger)number byExecutingBlock:(devideEquallyBlock)block{
    NSLog(@"Half of %i = %i",number,block(number));
    //you can call block same as c functions 
    //syntax to call block using block name - blockName(commas separated parameter list)
    //like block(number); block1() and so on 
}
- (void)dealloc {
    [callbackBlock release];
    [super dealloc];
}
@end
In .h file i have used typedef, it is a c construct that assign a name to existing data type.For example i have given a new name devideEquallyBlock to block type "(int(^)(int))". Even Apple uses typedef to assign names to block because it keeps our code clean and readable.We should also use typedef.I have released block at line number 27 in .m file because i have called copy at time of property  declaration at line number 6 in .h file.

Thanks for reading, please leave your comments below,bye bye! 

Wednesday 21 March 2012

Sharing data among iOS applications using UIPasteboard

Hello Friends,
As iOS apps have their own sandbox and one app can't read data of other application, for security reason its look good and really its good.One day i got a requirement in which i need to share data of one app with other app.First i thought it is not possible in an environment like sandbox, i searched on google and got a luck on  stackoverflow saying use UIPasteboard but a programmer like me expect some code. That day i  did not get any thing more than a little luck saying don't worry it is possible using UIpasteboard so in this post i am going to talk about UIPasteboard and write some basic codes.

UIPasteboard:
   UIPasteboard is a class given in UIKit.framework.You can use it to share data within the application and with other applications.

I am using two application to demonstrate the use of UIPasteboard.
  1. PBWriter
  2. PBReader 
let's create first application named as PBWriter or you can name something else.This application take some input from user and save those in UIPasteboard.User Interface of this application look like this - 

Enter data in above fields, hit "Save in PB" button it will save the data in Pasteboard.Oh! i have not discussed any thing about code. let's write code -

You can use any of following methods to create/get Pasteboard object, i am using "pasteboardWithName:create:"
  • +generalPasteboar //use this to get system pasteboard
  • +pasteboardWithName:create: //use this to create your own pasteboard

//use reverse DNS notation to keep you Paste board unique 
NSString *PBNAME = @"com.codingForBugs.PBDemo.PBDemo";


 UIPasteboard *pb = [UIPasteboard pasteboardWithName:PBNAME create:YES];//create a new PB if does not exists 

By default custom pasteboards are not persistent, you need to make it manually.If not required in your case just ignore it.

//pass yes to make pasteboard persistent 
[pb setPersistent:YES];


If you are not setting Persistent  property to YES, remamber that pastboard will be removed when your application quit.Now we have pasteboard and we need to write user information in it.

Note:Pasteboard will be removed when application uninstalled not matter it is persistent or not. 

There are some predefine properties in which you can write your data like string, strings, url,image, items etc.For example you have only one string you can use "string" property of UIPasteboard. If you want to save more than one item than better to use items properties like - 
    NSMutableArray *pbValues = [[NSMutableArray alloc] init];
    NSDictionary *d1 = [NSDictionary dictionaryWithObject:name.text forKey:@"name"];
    NSDictionary *d2 = [NSDictionary dictionaryWithObject:s1Value.text forKey:@"dob"];
    NSDictionary *d3 = [NSDictionary dictionaryWithObject:s2Value.text forKey:@"age"];
    NSDictionary *d4 = [NSDictionary dictionaryWithObject:s3Value.text forKey:@"height"];
    [pbValues addObject:d1];
    [pbValues addObject:d2];
    [pbValues addObject:d3];
    [pbValues addObject:d4];
    
    //save all items in pasteboard
    [pb setItems:pbValues];
When you will hit "Save in PB" it call a method "saveButtonClicked:", this method look like this
- (IBAction)saveButtonClicked:(id)sender {
    //get paste board 
    
    UIPasteboard *pb = [UIPasteboard pasteboardWithName:PBNAME create:YES];//create a new PB if does not exists 
    
    //make PB persistent. PB will be deleted when its owner application uninstalled
    [pb setPersistent:YES];
    
    //save values in PB with unique key so thet other application can read it
    NSLog(@"name = %@",name.text);
    NSMutableArray *pbValues = [[NSMutableArray alloc] init];
    NSDictionary *d1 = [NSDictionary dictionaryWithObject:name.text forKey:@"name"];
    NSDictionary *d2 = [NSDictionary dictionaryWithObject:nameValue.text forKey:@"dob"];
    NSDictionary *d3 = [NSDictionary dictionaryWithObject:ageValue.text forKey:@"age"];
    NSDictionary *d4 = [NSDictionary dictionaryWithObject:heightValue.text forKey:@"height"];
    [pbValues addObject:d1];
    [pbValues addObject:d2];
    [pbValues addObject:d3];
    [pbValues addObject:d4];
    
    //save all items in pasteboard
    [pb setItems:pbValues];
    
}

If you calls setItems: again, it overwrites previous values to prevent it use addItems: as [pb addItems:newValues]
Now we have finish the writer part we need to write a reader application that will read the data save in pasteboard. Reader app ui look like this - 
When you will hit the "Read PB" button one pop-up will come displaying whatever information we have saved in pasteboard.To read data first we need to get the pasteboard, we will retrieve dat using any of following function - 
  • dataForPasteboardType:
  • string
  • strings
  • items and so on 


Data will be returned in form of NSData and of particular type same as properties. For example if you are assigning value to string property it will return string, when we access using other method, we need to convert it in string from NSData. When you will hit "Read PB" button "- (IBAction)readPB:(id)sender" called this method look like this -
- (IBAction)readPB:(id)sender {
    //get pasteboard with predefine name
    UIPasteboard *pb = [UIPasteboard pasteboardWithName:PBNAME create:NO];//no because we doesn't want to create a new one 
    if (pb) {
        NSArray *dataArray = [pb items];
        NSDictionary *name = [dataArray objectAtIndex:0];
        //valuesInPb use to create message text
        NSString *valuesInPb = [NSString stringWithFormat:@"Name = %@\n",
                                [[NSString alloc] initWithData:[name valueForKey:@"name"] encoding:NSUTF8StringEncoding]];
        NSDictionary *info = [dataArray objectAtIndex:1];
        valuesInPb = [NSString stringWithFormat:@"%@D.O.b = %@\n",valuesInPb,
                      [[NSString alloc] initWithData:[info valueForKey:@"dob"] encoding:NSUTF8StringEncoding]];
        NSDictionary *info1 = [dataArray objectAtIndex:2];
        valuesInPb = [NSString stringWithFormat:@"%@Age = %@\n",valuesInPb,
                      [[NSString alloc] initWithData:[info1 valueForKey:@"age"] encoding:NSUTF8StringEncoding]];
        NSDictionary *info2 = [dataArray objectAtIndex:3];
        valuesInPb = [NSString stringWithFormat:@"%@Height = %@\n",valuesInPb,
                      [[NSString alloc] initWithData:[info2 valueForKey:@"height"] encoding:NSUTF8StringEncoding]];
        [self showText:valuesInPb target:self];
        NSLog(@"%i",[dataArray count]);
    }else{
        [self showText:@"PB doesn't exists.\nYou should run PBWritter app first" target:self];
    }
}


//this method is use to display the alert vew
-(void)showText:(NSString*)textMessage target:(id)target{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"pbReader" message:textMessage delegate:target cancelButtonTitle:@"OK" otherButtonTitles: nil];
    [alert show];
    [alert release];
}
I think it  may help you, plese leave you comments.bye bye!

Sunday 26 February 2012

Callling Web services in PhoneGap

Hello Friends!! Now a Days PhoneGap getting fame and used by a lots of developer. I have done my very first PhoneGap application and i want to share my experience, so  in this blog I am going to talk about PhoneGap and web services more frankly How to call a web service in PhoneGap or javascript?

 PhoneGap:
      It is a cross platform framework to develop mobile application using web technologies like - HTML,javaScript,css.

 Web Services:
      Web services are methods hosted and executed by server. Electronic devices use it to communicate to server.It remove the platform dependency of devices that means a device running iOS can communicate with a device running Linux/Mac etc.

I assume that you have installed the PhoneGap and created a demo application to test- How to call a web service using javaScript?If not please create a demo application or you may use your original application.
  
Now we are going to write code to call web services

Create a file named as xui-<version number>.js, paste api code from link http://xuijs.com/downloads/xui-2.3.2.js   place xui-2.3.2.js in desired folder inside www folder, you can creates a folder called api. I use api folder to put all apis at one place.You can include xui api as follow -

We have included api, now we need to write javaScript function to call web service, i am using a separate function because it will keep my code clean and clear and we can reuse it easily  or call on a particular event.

function callWebService(){
       //create url 
       var url = "http://search.twitter.com/search.json?q=PhoneGap&rpp=1";
       x$.data = {};
       x$("#search_tweet_button").xhr(url,{
          error: function(){alert("failed"+this.responseText)},
          callback: function(){
             var jsonResponse = eval("("+this.responseText+")");
             var tweets =  jsonResponse.results;
             if(tweets.length>0){
             x$("#tweet").html(tweets[0].text);
             }
           }
        });//end of xhr
    }//end of method

xhr(url,{ callback:{ }}); method is use to access web services, function defined in front of error will get called when some error occurred while processing the request in other words if response code is not 200 and callback will be called on success of request.If you will not specify callback then response text will be inserted in html element, in this case "search_tweet_button".

eval("("+this.responseText+")"); is used to get correct json object.

tweetsPage.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
  <head>
    <title></title>
    <script type="text/javascript" charset="utf-8" src="phonegap-1.4.1.js"></script>
    <script type="text/javascript" src="api/xui-2.3.2.js"></script>
    <script type="text/javascript" charset="utf-8">
      function callWebService(){
        //create url 
        var url = "http://search.twitter.com/search.json?q=PhoneGap&rpp=1";
        x$.data = {};
        x$("#search_tweet_button").xhr(url,{
          error: function(){alert("failed"+this.responseText)},
          callback: function(){
             var jsonResponse = eval("("+this.responseText+")");
             var tweets =  jsonResponse.results;
             if(tweets.length>0){
                x$("#tweet").html(tweets[0].text);
             }
          }
        });//end of xhr
      }//end of method
    </script>
  </head>
  <body>
    <h1 style="color:green;">Tweets Page</h1>
    <div id ="tweet" style="color:blue;">tweet will come here</div>
    <button type="button" onclick="callWebService()"                 id="search_tweet_button">Search     Tweets</button>
  </body>
</html>

Note : set ExternalHosts value as * in PhoneGap.plist file other wise it may not work for you.




























Example of post request :
function callWebService(){
    var url = "http://example.com/webser/xyzWebService/?&contentId=170;
    x$.data = {};
    x$("#html_element_name").xhr((url),
       { method:'post',
         headers:{'Content-Type':'application/xml'},
         data:' PhoneGap ',
         error: function(){//handle errors here },
         callback: function(){
           //do whatever you want
           //you can access response text as "this.responseText"
         }
       });
   }

If you are setting  Content-Type then you should comment the default content- type value in xui.js it was giving error for me.If your is OK, ignore it.
if (method.toLowerCase() == 'post') {
   //req.setRequestHeader('Content-Type','application/json');
   ;
}
If this blog is useful, please leave your comments. bye bye!!

 Download  Android Source Code developed by my friend Ajay Sharma.